diff options
Diffstat (limited to 'net')
542 files changed, 19377 insertions, 10719 deletions
diff --git a/net/802/garp.c b/net/802/garp.c index 5d9630a0eb93..b38ee6dcba45 100644 --- a/net/802/garp.c +++ b/net/802/garp.c | |||
| @@ -397,7 +397,7 @@ static void garp_join_timer_arm(struct garp_applicant *app) | |||
| 397 | { | 397 | { |
| 398 | unsigned long delay; | 398 | unsigned long delay; |
| 399 | 399 | ||
| 400 | delay = (u64)msecs_to_jiffies(garp_join_time) * net_random() >> 32; | 400 | delay = (u64)msecs_to_jiffies(garp_join_time) * prandom_u32() >> 32; |
| 401 | mod_timer(&app->join_timer, jiffies + delay); | 401 | mod_timer(&app->join_timer, jiffies + delay); |
| 402 | } | 402 | } |
| 403 | 403 | ||
diff --git a/net/802/hippi.c b/net/802/hippi.c index 51a1f530417d..5ff2a718ddca 100644 --- a/net/802/hippi.c +++ b/net/802/hippi.c | |||
| @@ -172,14 +172,14 @@ EXPORT_SYMBOL(hippi_mac_addr); | |||
| 172 | int hippi_neigh_setup_dev(struct net_device *dev, struct neigh_parms *p) | 172 | int hippi_neigh_setup_dev(struct net_device *dev, struct neigh_parms *p) |
| 173 | { | 173 | { |
| 174 | /* Never send broadcast/multicast ARP messages */ | 174 | /* Never send broadcast/multicast ARP messages */ |
| 175 | p->mcast_probes = 0; | 175 | NEIGH_VAR_INIT(p, MCAST_PROBES, 0); |
| 176 | 176 | ||
| 177 | /* In IPv6 unicast probes are valid even on NBMA, | 177 | /* In IPv6 unicast probes are valid even on NBMA, |
| 178 | * because they are encapsulated in normal IPv6 protocol. | 178 | * because they are encapsulated in normal IPv6 protocol. |
| 179 | * Should be a generic flag. | 179 | * Should be a generic flag. |
| 180 | */ | 180 | */ |
| 181 | if (p->tbl->family != AF_INET6) | 181 | if (p->tbl->family != AF_INET6) |
| 182 | p->ucast_probes = 0; | 182 | NEIGH_VAR_INIT(p, UCAST_PROBES, 0); |
| 183 | return 0; | 183 | return 0; |
| 184 | } | 184 | } |
| 185 | EXPORT_SYMBOL(hippi_neigh_setup_dev); | 185 | EXPORT_SYMBOL(hippi_neigh_setup_dev); |
diff --git a/net/802/mrp.c b/net/802/mrp.c index 3ed616215870..72db2785ef2c 100644 --- a/net/802/mrp.c +++ b/net/802/mrp.c | |||
| @@ -583,7 +583,7 @@ static void mrp_join_timer_arm(struct mrp_applicant *app) | |||
| 583 | { | 583 | { |
| 584 | unsigned long delay; | 584 | unsigned long delay; |
| 585 | 585 | ||
| 586 | delay = (u64)msecs_to_jiffies(mrp_join_time) * net_random() >> 32; | 586 | delay = (u64)msecs_to_jiffies(mrp_join_time) * prandom_u32() >> 32; |
| 587 | mod_timer(&app->join_timer, jiffies + delay); | 587 | mod_timer(&app->join_timer, jiffies + delay); |
| 588 | } | 588 | } |
| 589 | 589 | ||
diff --git a/net/8021q/Kconfig b/net/8021q/Kconfig index b85a91fa61f1..42320180967f 100644 --- a/net/8021q/Kconfig +++ b/net/8021q/Kconfig | |||
| @@ -6,11 +6,11 @@ config VLAN_8021Q | |||
| 6 | tristate "802.1Q/802.1ad VLAN Support" | 6 | tristate "802.1Q/802.1ad VLAN Support" |
| 7 | ---help--- | 7 | ---help--- |
| 8 | Select this and you will be able to create 802.1Q VLAN interfaces | 8 | Select this and you will be able to create 802.1Q VLAN interfaces |
| 9 | on your ethernet interfaces. 802.1Q VLAN supports almost | 9 | on your Ethernet interfaces. 802.1Q VLAN supports almost |
| 10 | everything a regular ethernet interface does, including | 10 | everything a regular Ethernet interface does, including |
| 11 | firewalling, bridging, and of course IP traffic. You will need | 11 | firewalling, bridging, and of course IP traffic. You will need |
| 12 | the 'vconfig' tool from the VLAN project in order to effectively | 12 | the 'ip' utility in order to effectively use VLANs. |
| 13 | use VLANs. See the VLAN web page for more information: | 13 | See the VLAN web page for more information: |
| 14 | <http://www.candelatech.com/~greear/vlan.html> | 14 | <http://www.candelatech.com/~greear/vlan.html> |
| 15 | 15 | ||
| 16 | To compile this code as a module, choose M here: the module | 16 | To compile this code as a module, choose M here: the module |
diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index b3d17d1c49c3..ec9909935fb6 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c | |||
| @@ -301,7 +301,7 @@ static void vlan_sync_address(struct net_device *dev, | |||
| 301 | !ether_addr_equal(vlandev->dev_addr, dev->dev_addr)) | 301 | !ether_addr_equal(vlandev->dev_addr, dev->dev_addr)) |
| 302 | dev_uc_add(dev, vlandev->dev_addr); | 302 | dev_uc_add(dev, vlandev->dev_addr); |
| 303 | 303 | ||
| 304 | memcpy(vlan->real_dev_addr, dev->dev_addr, ETH_ALEN); | 304 | ether_addr_copy(vlan->real_dev_addr, dev->dev_addr); |
| 305 | } | 305 | } |
| 306 | 306 | ||
| 307 | static void vlan_transfer_features(struct net_device *dev, | 307 | static void vlan_transfer_features(struct net_device *dev, |
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index 47c908f1f626..de51c48c4393 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c | |||
| @@ -61,7 +61,7 @@ static int vlan_dev_rebuild_header(struct sk_buff *skb) | |||
| 61 | pr_debug("%s: unable to resolve type %X addresses\n", | 61 | pr_debug("%s: unable to resolve type %X addresses\n", |
| 62 | dev->name, ntohs(veth->h_vlan_encapsulated_proto)); | 62 | dev->name, ntohs(veth->h_vlan_encapsulated_proto)); |
| 63 | 63 | ||
| 64 | memcpy(veth->h_source, dev->dev_addr, ETH_ALEN); | 64 | ether_addr_copy(veth->h_source, dev->dev_addr); |
| 65 | break; | 65 | break; |
| 66 | } | 66 | } |
| 67 | 67 | ||
| @@ -303,7 +303,7 @@ static int vlan_dev_open(struct net_device *dev) | |||
| 303 | goto clear_allmulti; | 303 | goto clear_allmulti; |
| 304 | } | 304 | } |
| 305 | 305 | ||
| 306 | memcpy(vlan->real_dev_addr, real_dev->dev_addr, ETH_ALEN); | 306 | ether_addr_copy(vlan->real_dev_addr, real_dev->dev_addr); |
| 307 | 307 | ||
| 308 | if (vlan->flags & VLAN_FLAG_GVRP) | 308 | if (vlan->flags & VLAN_FLAG_GVRP) |
| 309 | vlan_gvrp_request_join(dev); | 309 | vlan_gvrp_request_join(dev); |
| @@ -367,7 +367,7 @@ static int vlan_dev_set_mac_address(struct net_device *dev, void *p) | |||
| 367 | dev_uc_del(real_dev, dev->dev_addr); | 367 | dev_uc_del(real_dev, dev->dev_addr); |
| 368 | 368 | ||
| 369 | out: | 369 | out: |
| 370 | memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN); | 370 | ether_addr_copy(dev->dev_addr, addr->sa_data); |
| 371 | return 0; | 371 | return 0; |
| 372 | } | 372 | } |
| 373 | 373 | ||
diff --git a/net/9p/client.c b/net/9p/client.c index ee8fd6bd4035..a5e4d2dcb03e 100644 --- a/net/9p/client.c +++ b/net/9p/client.c | |||
| @@ -1012,9 +1012,6 @@ struct p9_client *p9_client_create(const char *dev_name, char *options) | |||
| 1012 | goto destroy_tagpool; | 1012 | goto destroy_tagpool; |
| 1013 | 1013 | ||
| 1014 | if (!clnt->trans_mod) | 1014 | if (!clnt->trans_mod) |
| 1015 | clnt->trans_mod = v9fs_get_trans_by_name("virtio"); | ||
| 1016 | |||
| 1017 | if (!clnt->trans_mod) | ||
| 1018 | clnt->trans_mod = v9fs_get_default_trans(); | 1015 | clnt->trans_mod = v9fs_get_default_trans(); |
| 1019 | 1016 | ||
| 1020 | if (clnt->trans_mod == NULL) { | 1017 | if (clnt->trans_mod == NULL) { |
diff --git a/net/9p/trans_fd.c b/net/9p/trans_fd.c index 9321a7763067..b7bd7f2961bf 100644 --- a/net/9p/trans_fd.c +++ b/net/9p/trans_fd.c | |||
| @@ -1048,7 +1048,7 @@ p9_fd_create(struct p9_client *client, const char *addr, char *args) | |||
| 1048 | static struct p9_trans_module p9_tcp_trans = { | 1048 | static struct p9_trans_module p9_tcp_trans = { |
| 1049 | .name = "tcp", | 1049 | .name = "tcp", |
| 1050 | .maxsize = MAX_SOCK_BUF, | 1050 | .maxsize = MAX_SOCK_BUF, |
| 1051 | .def = 1, | 1051 | .def = 0, |
| 1052 | .create = p9_fd_create_tcp, | 1052 | .create = p9_fd_create_tcp, |
| 1053 | .close = p9_fd_close, | 1053 | .close = p9_fd_close, |
| 1054 | .request = p9_fd_request, | 1054 | .request = p9_fd_request, |
diff --git a/net/9p/trans_virtio.c b/net/9p/trans_virtio.c index 9c5a1aa34d12..cd1e1ede73a4 100644 --- a/net/9p/trans_virtio.c +++ b/net/9p/trans_virtio.c | |||
| @@ -698,7 +698,7 @@ static struct p9_trans_module p9_virtio_trans = { | |||
| 698 | * page in zero copy. | 698 | * page in zero copy. |
| 699 | */ | 699 | */ |
| 700 | .maxsize = PAGE_SIZE * (VIRTQUEUE_NUM - 3), | 700 | .maxsize = PAGE_SIZE * (VIRTQUEUE_NUM - 3), |
| 701 | .def = 0, | 701 | .def = 1, |
| 702 | .owner = THIS_MODULE, | 702 | .owner = THIS_MODULE, |
| 703 | }; | 703 | }; |
| 704 | 704 | ||
diff --git a/net/Kconfig b/net/Kconfig index d334678c0bd8..e411046a62e3 100644 --- a/net/Kconfig +++ b/net/Kconfig | |||
| @@ -238,12 +238,19 @@ config XPS | |||
| 238 | depends on SMP | 238 | depends on SMP |
| 239 | default y | 239 | default y |
| 240 | 240 | ||
| 241 | config NETPRIO_CGROUP | 241 | config CGROUP_NET_PRIO |
| 242 | tristate "Network priority cgroup" | 242 | tristate "Network priority cgroup" |
| 243 | depends on CGROUPS | 243 | depends on CGROUPS |
| 244 | ---help--- | 244 | ---help--- |
| 245 | Cgroup subsystem for use in assigning processes to network priorities on | 245 | Cgroup subsystem for use in assigning processes to network priorities on |
| 246 | a per-interface basis | 246 | a per-interface basis. |
| 247 | |||
| 248 | config CGROUP_NET_CLASSID | ||
| 249 | boolean "Network classid cgroup" | ||
| 250 | depends on CGROUPS | ||
| 251 | ---help--- | ||
| 252 | Cgroup subsystem for use as general purpose socket classid marker that is | ||
| 253 | being used in cls_cgroup and for netfilter matching. | ||
| 247 | 254 | ||
| 248 | config NET_RX_BUSY_POLL | 255 | config NET_RX_BUSY_POLL |
| 249 | boolean | 256 | boolean |
diff --git a/net/Makefile b/net/Makefile index 8fa2f91517f1..cbbbe6d657ca 100644 --- a/net/Makefile +++ b/net/Makefile | |||
| @@ -57,7 +57,7 @@ obj-$(CONFIG_CAIF) += caif/ | |||
| 57 | ifneq ($(CONFIG_DCB),) | 57 | ifneq ($(CONFIG_DCB),) |
| 58 | obj-y += dcb/ | 58 | obj-y += dcb/ |
| 59 | endif | 59 | endif |
| 60 | obj-$(CONFIG_IEEE802154) += ieee802154/ | 60 | obj-y += ieee802154/ |
| 61 | obj-$(CONFIG_MAC802154) += mac802154/ | 61 | obj-$(CONFIG_MAC802154) += mac802154/ |
| 62 | 62 | ||
| 63 | ifeq ($(CONFIG_NET),y) | 63 | ifeq ($(CONFIG_NET),y) |
diff --git a/net/appletalk/aarp.c b/net/appletalk/aarp.c index 690356fa52b9..d27b86dfb0e9 100644 --- a/net/appletalk/aarp.c +++ b/net/appletalk/aarp.c | |||
| @@ -40,6 +40,7 @@ | |||
| 40 | #include <linux/proc_fs.h> | 40 | #include <linux/proc_fs.h> |
| 41 | #include <linux/seq_file.h> | 41 | #include <linux/seq_file.h> |
| 42 | #include <linux/export.h> | 42 | #include <linux/export.h> |
| 43 | #include <linux/etherdevice.h> | ||
| 43 | 44 | ||
| 44 | int sysctl_aarp_expiry_time = AARP_EXPIRY_TIME; | 45 | int sysctl_aarp_expiry_time = AARP_EXPIRY_TIME; |
| 45 | int sysctl_aarp_tick_time = AARP_TICK_TIME; | 46 | int sysctl_aarp_tick_time = AARP_TICK_TIME; |
| @@ -67,7 +68,7 @@ struct aarp_entry { | |||
| 67 | unsigned long expires_at; | 68 | unsigned long expires_at; |
| 68 | struct atalk_addr target_addr; | 69 | struct atalk_addr target_addr; |
| 69 | struct net_device *dev; | 70 | struct net_device *dev; |
| 70 | char hwaddr[6]; | 71 | char hwaddr[ETH_ALEN]; |
| 71 | unsigned short xmit_count; | 72 | unsigned short xmit_count; |
| 72 | struct aarp_entry *next; | 73 | struct aarp_entry *next; |
| 73 | }; | 74 | }; |
| @@ -134,7 +135,7 @@ static void __aarp_send_query(struct aarp_entry *a) | |||
| 134 | eah->pa_len = AARP_PA_ALEN; | 135 | eah->pa_len = AARP_PA_ALEN; |
| 135 | eah->function = htons(AARP_REQUEST); | 136 | eah->function = htons(AARP_REQUEST); |
| 136 | 137 | ||
| 137 | memcpy(eah->hw_src, dev->dev_addr, ETH_ALEN); | 138 | ether_addr_copy(eah->hw_src, dev->dev_addr); |
| 138 | 139 | ||
| 139 | eah->pa_src_zero = 0; | 140 | eah->pa_src_zero = 0; |
| 140 | eah->pa_src_net = sat->s_net; | 141 | eah->pa_src_net = sat->s_net; |
| @@ -181,7 +182,7 @@ static void aarp_send_reply(struct net_device *dev, struct atalk_addr *us, | |||
| 181 | eah->pa_len = AARP_PA_ALEN; | 182 | eah->pa_len = AARP_PA_ALEN; |
| 182 | eah->function = htons(AARP_REPLY); | 183 | eah->function = htons(AARP_REPLY); |
| 183 | 184 | ||
| 184 | memcpy(eah->hw_src, dev->dev_addr, ETH_ALEN); | 185 | ether_addr_copy(eah->hw_src, dev->dev_addr); |
| 185 | 186 | ||
| 186 | eah->pa_src_zero = 0; | 187 | eah->pa_src_zero = 0; |
| 187 | eah->pa_src_net = us->s_net; | 188 | eah->pa_src_net = us->s_net; |
| @@ -190,7 +191,7 @@ static void aarp_send_reply(struct net_device *dev, struct atalk_addr *us, | |||
| 190 | if (!sha) | 191 | if (!sha) |
| 191 | memset(eah->hw_dst, '\0', ETH_ALEN); | 192 | memset(eah->hw_dst, '\0', ETH_ALEN); |
| 192 | else | 193 | else |
| 193 | memcpy(eah->hw_dst, sha, ETH_ALEN); | 194 | ether_addr_copy(eah->hw_dst, sha); |
| 194 | 195 | ||
| 195 | eah->pa_dst_zero = 0; | 196 | eah->pa_dst_zero = 0; |
| 196 | eah->pa_dst_net = them->s_net; | 197 | eah->pa_dst_net = them->s_net; |
| @@ -232,7 +233,7 @@ static void aarp_send_probe(struct net_device *dev, struct atalk_addr *us) | |||
| 232 | eah->pa_len = AARP_PA_ALEN; | 233 | eah->pa_len = AARP_PA_ALEN; |
| 233 | eah->function = htons(AARP_PROBE); | 234 | eah->function = htons(AARP_PROBE); |
| 234 | 235 | ||
| 235 | memcpy(eah->hw_src, dev->dev_addr, ETH_ALEN); | 236 | ether_addr_copy(eah->hw_src, dev->dev_addr); |
| 236 | 237 | ||
| 237 | eah->pa_src_zero = 0; | 238 | eah->pa_src_zero = 0; |
| 238 | eah->pa_src_net = us->s_net; | 239 | eah->pa_src_net = us->s_net; |
| @@ -790,7 +791,7 @@ static int aarp_rcv(struct sk_buff *skb, struct net_device *dev, | |||
| 790 | break; | 791 | break; |
| 791 | 792 | ||
| 792 | /* We can fill one in - this is good. */ | 793 | /* We can fill one in - this is good. */ |
| 793 | memcpy(a->hwaddr, ea->hw_src, ETH_ALEN); | 794 | ether_addr_copy(a->hwaddr, ea->hw_src); |
| 794 | __aarp_resolved(&unresolved[hash], a, hash); | 795 | __aarp_resolved(&unresolved[hash], a, hash); |
| 795 | if (!unresolved_count) | 796 | if (!unresolved_count) |
| 796 | mod_timer(&aarp_timer, | 797 | mod_timer(&aarp_timer, |
diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c index 7d424ac6e760..02806c6b2ff3 100644 --- a/net/appletalk/ddp.c +++ b/net/appletalk/ddp.c | |||
| @@ -1566,7 +1566,7 @@ static int atalk_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr | |||
| 1566 | { | 1566 | { |
| 1567 | struct sock *sk = sock->sk; | 1567 | struct sock *sk = sock->sk; |
| 1568 | struct atalk_sock *at = at_sk(sk); | 1568 | struct atalk_sock *at = at_sk(sk); |
| 1569 | struct sockaddr_at *usat = (struct sockaddr_at *)msg->msg_name; | 1569 | DECLARE_SOCKADDR(struct sockaddr_at *, usat, msg->msg_name); |
| 1570 | int flags = msg->msg_flags; | 1570 | int flags = msg->msg_flags; |
| 1571 | int loopback = 0; | 1571 | int loopback = 0; |
| 1572 | struct sockaddr_at local_satalk, gsat; | 1572 | struct sockaddr_at local_satalk, gsat; |
| @@ -1764,7 +1764,7 @@ static int atalk_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr | |||
| 1764 | err = skb_copy_datagram_iovec(skb, offset, msg->msg_iov, copied); | 1764 | err = skb_copy_datagram_iovec(skb, offset, msg->msg_iov, copied); |
| 1765 | 1765 | ||
| 1766 | if (!err && msg->msg_name) { | 1766 | if (!err && msg->msg_name) { |
| 1767 | struct sockaddr_at *sat = msg->msg_name; | 1767 | DECLARE_SOCKADDR(struct sockaddr_at *, sat, msg->msg_name); |
| 1768 | sat->sat_family = AF_APPLETALK; | 1768 | sat->sat_family = AF_APPLETALK; |
| 1769 | sat->sat_port = ddp->deh_sport; | 1769 | sat->sat_port = ddp->deh_sport; |
| 1770 | sat->sat_addr.s_node = ddp->deh_snode; | 1770 | sat->sat_addr.s_node = ddp->deh_snode; |
diff --git a/net/atm/lec.c b/net/atm/lec.c index f23916be18fb..5a2f602d07e1 100644 --- a/net/atm/lec.c +++ b/net/atm/lec.c | |||
| @@ -521,7 +521,7 @@ send_to_lecd(struct lec_priv *priv, atmlec_msg_type type, | |||
| 521 | if (data != NULL) | 521 | if (data != NULL) |
| 522 | mesg->sizeoftlvs = data->len; | 522 | mesg->sizeoftlvs = data->len; |
| 523 | if (mac_addr) | 523 | if (mac_addr) |
| 524 | memcpy(&mesg->content.normal.mac_addr, mac_addr, ETH_ALEN); | 524 | ether_addr_copy(mesg->content.normal.mac_addr, mac_addr); |
| 525 | else | 525 | else |
| 526 | mesg->content.normal.targetless_le_arp = 1; | 526 | mesg->content.normal.targetless_le_arp = 1; |
| 527 | if (atm_addr) | 527 | if (atm_addr) |
| @@ -1565,7 +1565,7 @@ static struct lec_arp_table *make_entry(struct lec_priv *priv, | |||
| 1565 | pr_info("LEC: Arp entry kmalloc failed\n"); | 1565 | pr_info("LEC: Arp entry kmalloc failed\n"); |
| 1566 | return NULL; | 1566 | return NULL; |
| 1567 | } | 1567 | } |
| 1568 | memcpy(to_return->mac_addr, mac_addr, ETH_ALEN); | 1568 | ether_addr_copy(to_return->mac_addr, mac_addr); |
| 1569 | INIT_HLIST_NODE(&to_return->next); | 1569 | INIT_HLIST_NODE(&to_return->next); |
| 1570 | setup_timer(&to_return->timer, lec_arp_expire_arp, | 1570 | setup_timer(&to_return->timer, lec_arp_expire_arp, |
| 1571 | (unsigned long)to_return); | 1571 | (unsigned long)to_return); |
| @@ -1887,7 +1887,8 @@ lec_arp_update(struct lec_priv *priv, const unsigned char *mac_addr, | |||
| 1887 | entry = tmp; | 1887 | entry = tmp; |
| 1888 | } else { | 1888 | } else { |
| 1889 | entry->status = ESI_FORWARD_DIRECT; | 1889 | entry->status = ESI_FORWARD_DIRECT; |
| 1890 | memcpy(entry->mac_addr, mac_addr, ETH_ALEN); | 1890 | ether_addr_copy(entry->mac_addr, |
| 1891 | mac_addr); | ||
| 1891 | entry->last_used = jiffies; | 1892 | entry->last_used = jiffies; |
| 1892 | lec_arp_add(priv, entry); | 1893 | lec_arp_add(priv, entry); |
| 1893 | } | 1894 | } |
| @@ -2263,7 +2264,7 @@ lec_arp_check_empties(struct lec_priv *priv, | |||
| 2263 | &priv->lec_arp_empty_ones, next) { | 2264 | &priv->lec_arp_empty_ones, next) { |
| 2264 | if (vcc == entry->vcc) { | 2265 | if (vcc == entry->vcc) { |
| 2265 | del_timer(&entry->timer); | 2266 | del_timer(&entry->timer); |
| 2266 | memcpy(entry->mac_addr, src, ETH_ALEN); | 2267 | ether_addr_copy(entry->mac_addr, src); |
| 2267 | entry->status = ESI_FORWARD_DIRECT; | 2268 | entry->status = ESI_FORWARD_DIRECT; |
| 2268 | entry->last_used = jiffies; | 2269 | entry->last_used = jiffies; |
| 2269 | /* We might have got an entry */ | 2270 | /* We might have got an entry */ |
diff --git a/net/atm/mpc.c b/net/atm/mpc.c index 3af12755cd04..b71ff6b234f2 100644 --- a/net/atm/mpc.c +++ b/net/atm/mpc.c | |||
| @@ -478,7 +478,7 @@ static const uint8_t *copy_macs(struct mpoa_client *mpc, | |||
| 478 | return NULL; | 478 | return NULL; |
| 479 | } | 479 | } |
| 480 | } | 480 | } |
| 481 | memcpy(mpc->mps_macs, router_mac, ETH_ALEN); | 481 | ether_addr_copy(mpc->mps_macs, router_mac); |
| 482 | tlvs += 20; if (device_type == MPS_AND_MPC) tlvs += 20; | 482 | tlvs += 20; if (device_type == MPS_AND_MPC) tlvs += 20; |
| 483 | if (mps_macs > 0) | 483 | if (mps_macs > 0) |
| 484 | memcpy(mpc->mps_macs, tlvs, mps_macs*ETH_ALEN); | 484 | memcpy(mpc->mps_macs, tlvs, mps_macs*ETH_ALEN); |
diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c index 7bb1605bdfd9..c35c3f48fc0f 100644 --- a/net/ax25/af_ax25.c +++ b/net/ax25/af_ax25.c | |||
| @@ -1435,7 +1435,7 @@ out: | |||
| 1435 | static int ax25_sendmsg(struct kiocb *iocb, struct socket *sock, | 1435 | static int ax25_sendmsg(struct kiocb *iocb, struct socket *sock, |
| 1436 | struct msghdr *msg, size_t len) | 1436 | struct msghdr *msg, size_t len) |
| 1437 | { | 1437 | { |
| 1438 | struct sockaddr_ax25 *usax = (struct sockaddr_ax25 *)msg->msg_name; | 1438 | DECLARE_SOCKADDR(struct sockaddr_ax25 *, usax, msg->msg_name); |
| 1439 | struct sock *sk = sock->sk; | 1439 | struct sock *sk = sock->sk; |
| 1440 | struct sockaddr_ax25 sax; | 1440 | struct sockaddr_ax25 sax; |
| 1441 | struct sk_buff *skb; | 1441 | struct sk_buff *skb; |
| @@ -1640,7 +1640,7 @@ static int ax25_recvmsg(struct kiocb *iocb, struct socket *sock, | |||
| 1640 | ax25_digi digi; | 1640 | ax25_digi digi; |
| 1641 | ax25_address src; | 1641 | ax25_address src; |
| 1642 | const unsigned char *mac = skb_mac_header(skb); | 1642 | const unsigned char *mac = skb_mac_header(skb); |
| 1643 | struct sockaddr_ax25 *sax = msg->msg_name; | 1643 | DECLARE_SOCKADDR(struct sockaddr_ax25 *, sax, msg->msg_name); |
| 1644 | 1644 | ||
| 1645 | memset(sax, 0, sizeof(struct full_sockaddr_ax25)); | 1645 | memset(sax, 0, sizeof(struct full_sockaddr_ax25)); |
| 1646 | ax25_addr_parse(mac + 1, skb->data - mac - 1, &src, NULL, | 1646 | ax25_addr_parse(mac + 1, skb->data - mac - 1, &src, NULL, |
diff --git a/net/batman-adv/Makefile b/net/batman-adv/Makefile index 4f4aabbd8eab..42df18f877e9 100644 --- a/net/batman-adv/Makefile +++ b/net/batman-adv/Makefile | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | # | 1 | # |
| 2 | # Copyright (C) 2007-2013 B.A.T.M.A.N. contributors: | 2 | # Copyright (C) 2007-2014 B.A.T.M.A.N. contributors: |
| 3 | # | 3 | # |
| 4 | # Marek Lindner, Simon Wunderlich | 4 | # Marek Lindner, Simon Wunderlich |
| 5 | # | 5 | # |
| @@ -13,9 +13,7 @@ | |||
| 13 | # General Public License for more details. | 13 | # General Public License for more details. |
| 14 | # | 14 | # |
| 15 | # You should have received a copy of the GNU General Public License | 15 | # You should have received a copy of the GNU General Public License |
| 16 | # along with this program; if not, write to the Free Software | 16 | # along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 17 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 18 | # 02110-1301, USA | ||
| 19 | # | 17 | # |
| 20 | 18 | ||
| 21 | obj-$(CONFIG_BATMAN_ADV) += batman-adv.o | 19 | obj-$(CONFIG_BATMAN_ADV) += batman-adv.o |
diff --git a/net/batman-adv/bat_algo.h b/net/batman-adv/bat_algo.h index a4808c29ea3d..4e49666f8c65 100644 --- a/net/batman-adv/bat_algo.h +++ b/net/batman-adv/bat_algo.h | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* Copyright (C) 2011-2013 B.A.T.M.A.N. contributors: | 1 | /* Copyright (C) 2011-2014 B.A.T.M.A.N. contributors: |
| 2 | * | 2 | * |
| 3 | * Marek Lindner | 3 | * Marek Lindner |
| 4 | * | 4 | * |
| @@ -12,9 +12,7 @@ | |||
| 12 | * General Public License for more details. | 12 | * General Public License for more details. |
| 13 | * | 13 | * |
| 14 | * You should have received a copy of the GNU General Public License | 14 | * You should have received a copy of the GNU General Public License |
| 15 | * along with this program; if not, write to the Free Software | 15 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 17 | * 02110-1301, USA | ||
| 18 | */ | 16 | */ |
| 19 | 17 | ||
| 20 | #ifndef _NET_BATMAN_ADV_BAT_ALGO_H_ | 18 | #ifndef _NET_BATMAN_ADV_BAT_ALGO_H_ |
diff --git a/net/batman-adv/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c index b9c8a6eedf45..512159bf607f 100644 --- a/net/batman-adv/bat_iv_ogm.c +++ b/net/batman-adv/bat_iv_ogm.c | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors: | 1 | /* Copyright (C) 2007-2014 B.A.T.M.A.N. contributors: |
| 2 | * | 2 | * |
| 3 | * Marek Lindner, Simon Wunderlich | 3 | * Marek Lindner, Simon Wunderlich |
| 4 | * | 4 | * |
| @@ -12,9 +12,7 @@ | |||
| 12 | * General Public License for more details. | 12 | * General Public License for more details. |
| 13 | * | 13 | * |
| 14 | * You should have received a copy of the GNU General Public License | 14 | * You should have received a copy of the GNU General Public License |
| 15 | * along with this program; if not, write to the Free Software | 15 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 17 | * 02110-1301, USA | ||
| 18 | */ | 16 | */ |
| 19 | 17 | ||
| 20 | #include "main.h" | 18 | #include "main.h" |
| @@ -274,7 +272,14 @@ batadv_iv_ogm_neigh_new(struct batadv_hard_iface *hard_iface, | |||
| 274 | if (!neigh_node) | 272 | if (!neigh_node) |
| 275 | goto out; | 273 | goto out; |
| 276 | 274 | ||
| 277 | spin_lock_init(&neigh_node->bat_iv.lq_update_lock); | 275 | if (!atomic_inc_not_zero(&hard_iface->refcount)) { |
| 276 | kfree(neigh_node); | ||
| 277 | neigh_node = NULL; | ||
| 278 | goto out; | ||
| 279 | } | ||
| 280 | |||
| 281 | neigh_node->orig_node = orig_neigh; | ||
| 282 | neigh_node->if_incoming = hard_iface; | ||
| 278 | 283 | ||
| 279 | batadv_dbg(BATADV_DBG_BATMAN, bat_priv, | 284 | batadv_dbg(BATADV_DBG_BATMAN, bat_priv, |
| 280 | "Creating new neighbor %pM for orig_node %pM on interface %s\n", | 285 | "Creating new neighbor %pM for orig_node %pM on interface %s\n", |
| @@ -461,17 +466,9 @@ static void batadv_iv_ogm_send_to_if(struct batadv_forw_packet *forw_packet, | |||
| 461 | /* send a batman ogm packet */ | 466 | /* send a batman ogm packet */ |
| 462 | static void batadv_iv_ogm_emit(struct batadv_forw_packet *forw_packet) | 467 | static void batadv_iv_ogm_emit(struct batadv_forw_packet *forw_packet) |
| 463 | { | 468 | { |
| 464 | struct batadv_hard_iface *hard_iface; | ||
| 465 | struct net_device *soft_iface; | 469 | struct net_device *soft_iface; |
| 466 | struct batadv_priv *bat_priv; | 470 | struct batadv_priv *bat_priv; |
| 467 | struct batadv_hard_iface *primary_if = NULL; | 471 | struct batadv_hard_iface *primary_if = NULL; |
| 468 | struct batadv_ogm_packet *batadv_ogm_packet; | ||
| 469 | unsigned char directlink; | ||
| 470 | uint8_t *packet_pos; | ||
| 471 | |||
| 472 | packet_pos = forw_packet->skb->data; | ||
| 473 | batadv_ogm_packet = (struct batadv_ogm_packet *)packet_pos; | ||
| 474 | directlink = (batadv_ogm_packet->flags & BATADV_DIRECTLINK ? 1 : 0); | ||
| 475 | 472 | ||
| 476 | if (!forw_packet->if_incoming) { | 473 | if (!forw_packet->if_incoming) { |
| 477 | pr_err("Error - can't forward packet: incoming iface not specified\n"); | 474 | pr_err("Error - can't forward packet: incoming iface not specified\n"); |
| @@ -481,59 +478,48 @@ static void batadv_iv_ogm_emit(struct batadv_forw_packet *forw_packet) | |||
| 481 | soft_iface = forw_packet->if_incoming->soft_iface; | 478 | soft_iface = forw_packet->if_incoming->soft_iface; |
| 482 | bat_priv = netdev_priv(soft_iface); | 479 | bat_priv = netdev_priv(soft_iface); |
| 483 | 480 | ||
| 484 | if (forw_packet->if_incoming->if_status != BATADV_IF_ACTIVE) | 481 | if (WARN_ON(!forw_packet->if_outgoing)) |
| 485 | goto out; | 482 | goto out; |
| 486 | 483 | ||
| 487 | primary_if = batadv_primary_if_get_selected(bat_priv); | 484 | if (WARN_ON(forw_packet->if_outgoing->soft_iface != soft_iface)) |
| 488 | if (!primary_if) | ||
| 489 | goto out; | 485 | goto out; |
| 490 | 486 | ||
| 491 | /* multihomed peer assumed | 487 | if (forw_packet->if_incoming->if_status != BATADV_IF_ACTIVE) |
| 492 | * non-primary OGMs are only broadcasted on their interface | ||
| 493 | */ | ||
| 494 | if ((directlink && (batadv_ogm_packet->ttl == 1)) || | ||
| 495 | (forw_packet->own && (forw_packet->if_incoming != primary_if))) { | ||
| 496 | /* FIXME: what about aggregated packets ? */ | ||
| 497 | batadv_dbg(BATADV_DBG_BATMAN, bat_priv, | ||
| 498 | "%s packet (originator %pM, seqno %u, TTL %d) on interface %s [%pM]\n", | ||
| 499 | (forw_packet->own ? "Sending own" : "Forwarding"), | ||
| 500 | batadv_ogm_packet->orig, | ||
| 501 | ntohl(batadv_ogm_packet->seqno), | ||
| 502 | batadv_ogm_packet->ttl, | ||
| 503 | forw_packet->if_incoming->net_dev->name, | ||
| 504 | forw_packet->if_incoming->net_dev->dev_addr); | ||
| 505 | |||
| 506 | /* skb is only used once and than forw_packet is free'd */ | ||
| 507 | batadv_send_skb_packet(forw_packet->skb, | ||
| 508 | forw_packet->if_incoming, | ||
| 509 | batadv_broadcast_addr); | ||
| 510 | forw_packet->skb = NULL; | ||
| 511 | |||
| 512 | goto out; | 488 | goto out; |
| 513 | } | ||
| 514 | 489 | ||
| 515 | /* broadcast on every interface */ | 490 | primary_if = batadv_primary_if_get_selected(bat_priv); |
| 516 | rcu_read_lock(); | 491 | if (!primary_if) |
| 517 | list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) { | 492 | goto out; |
| 518 | if (hard_iface->soft_iface != soft_iface) | ||
| 519 | continue; | ||
| 520 | 493 | ||
| 521 | batadv_iv_ogm_send_to_if(forw_packet, hard_iface); | 494 | /* only for one specific outgoing interface */ |
| 522 | } | 495 | batadv_iv_ogm_send_to_if(forw_packet, forw_packet->if_outgoing); |
| 523 | rcu_read_unlock(); | ||
| 524 | 496 | ||
| 525 | out: | 497 | out: |
| 526 | if (primary_if) | 498 | if (primary_if) |
| 527 | batadv_hardif_free_ref(primary_if); | 499 | batadv_hardif_free_ref(primary_if); |
| 528 | } | 500 | } |
| 529 | 501 | ||
| 530 | /* return true if new_packet can be aggregated with forw_packet */ | 502 | /** |
| 503 | * batadv_iv_ogm_can_aggregate - find out if an OGM can be aggregated on an | ||
| 504 | * existing forward packet | ||
| 505 | * @new_bat_ogm_packet: OGM packet to be aggregated | ||
| 506 | * @bat_priv: the bat priv with all the soft interface information | ||
| 507 | * @packet_len: (total) length of the OGM | ||
| 508 | * @send_time: timestamp (jiffies) when the packet is to be sent | ||
| 509 | * @direktlink: true if this is a direct link packet | ||
| 510 | * @if_incoming: interface where the packet was received | ||
| 511 | * @if_outgoing: interface for which the retransmission should be considered | ||
| 512 | * @forw_packet: the forwarded packet which should be checked | ||
| 513 | * | ||
| 514 | * Returns true if new_packet can be aggregated with forw_packet | ||
| 515 | */ | ||
| 531 | static bool | 516 | static bool |
| 532 | batadv_iv_ogm_can_aggregate(const struct batadv_ogm_packet *new_bat_ogm_packet, | 517 | batadv_iv_ogm_can_aggregate(const struct batadv_ogm_packet *new_bat_ogm_packet, |
| 533 | struct batadv_priv *bat_priv, | 518 | struct batadv_priv *bat_priv, |
| 534 | int packet_len, unsigned long send_time, | 519 | int packet_len, unsigned long send_time, |
| 535 | bool directlink, | 520 | bool directlink, |
| 536 | const struct batadv_hard_iface *if_incoming, | 521 | const struct batadv_hard_iface *if_incoming, |
| 522 | const struct batadv_hard_iface *if_outgoing, | ||
| 537 | const struct batadv_forw_packet *forw_packet) | 523 | const struct batadv_forw_packet *forw_packet) |
| 538 | { | 524 | { |
| 539 | struct batadv_ogm_packet *batadv_ogm_packet; | 525 | struct batadv_ogm_packet *batadv_ogm_packet; |
| @@ -567,6 +553,10 @@ batadv_iv_ogm_can_aggregate(const struct batadv_ogm_packet *new_bat_ogm_packet, | |||
| 567 | if (!primary_if) | 553 | if (!primary_if) |
| 568 | goto out; | 554 | goto out; |
| 569 | 555 | ||
| 556 | /* packet is not leaving on the same interface. */ | ||
| 557 | if (forw_packet->if_outgoing != if_outgoing) | ||
| 558 | goto out; | ||
| 559 | |||
| 570 | /* packets without direct link flag and high TTL | 560 | /* packets without direct link flag and high TTL |
| 571 | * are flooded through the net | 561 | * are flooded through the net |
| 572 | */ | 562 | */ |
| @@ -608,11 +598,22 @@ out: | |||
| 608 | return res; | 598 | return res; |
| 609 | } | 599 | } |
| 610 | 600 | ||
| 611 | /* create a new aggregated packet and add this packet to it */ | 601 | /** |
| 602 | * batadv_iv_ogm_aggregate_new - create a new aggregated packet and add this | ||
| 603 | * packet to it. | ||
| 604 | * @packet_buff: pointer to the OGM | ||
| 605 | * @packet_len: (total) length of the OGM | ||
| 606 | * @send_time: timestamp (jiffies) when the packet is to be sent | ||
| 607 | * @direct_link: whether this OGM has direct link status | ||
| 608 | * @if_incoming: interface where the packet was received | ||
| 609 | * @if_outgoing: interface for which the retransmission should be considered | ||
| 610 | * @own_packet: true if it is a self-generated ogm | ||
| 611 | */ | ||
| 612 | static void batadv_iv_ogm_aggregate_new(const unsigned char *packet_buff, | 612 | static void batadv_iv_ogm_aggregate_new(const unsigned char *packet_buff, |
| 613 | int packet_len, unsigned long send_time, | 613 | int packet_len, unsigned long send_time, |
| 614 | bool direct_link, | 614 | bool direct_link, |
| 615 | struct batadv_hard_iface *if_incoming, | 615 | struct batadv_hard_iface *if_incoming, |
| 616 | struct batadv_hard_iface *if_outgoing, | ||
| 616 | int own_packet) | 617 | int own_packet) |
| 617 | { | 618 | { |
| 618 | struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface); | 619 | struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface); |
| @@ -623,6 +624,9 @@ static void batadv_iv_ogm_aggregate_new(const unsigned char *packet_buff, | |||
| 623 | if (!atomic_inc_not_zero(&if_incoming->refcount)) | 624 | if (!atomic_inc_not_zero(&if_incoming->refcount)) |
| 624 | return; | 625 | return; |
| 625 | 626 | ||
| 627 | if (!atomic_inc_not_zero(&if_outgoing->refcount)) | ||
| 628 | goto out_free_incoming; | ||
| 629 | |||
| 626 | /* own packet should always be scheduled */ | 630 | /* own packet should always be scheduled */ |
| 627 | if (!own_packet) { | 631 | if (!own_packet) { |
| 628 | if (!batadv_atomic_dec_not_zero(&bat_priv->batman_queue_left)) { | 632 | if (!batadv_atomic_dec_not_zero(&bat_priv->batman_queue_left)) { |
| @@ -663,6 +667,7 @@ static void batadv_iv_ogm_aggregate_new(const unsigned char *packet_buff, | |||
| 663 | 667 | ||
| 664 | forw_packet_aggr->own = own_packet; | 668 | forw_packet_aggr->own = own_packet; |
| 665 | forw_packet_aggr->if_incoming = if_incoming; | 669 | forw_packet_aggr->if_incoming = if_incoming; |
| 670 | forw_packet_aggr->if_outgoing = if_outgoing; | ||
| 666 | forw_packet_aggr->num_packets = 0; | 671 | forw_packet_aggr->num_packets = 0; |
| 667 | forw_packet_aggr->direct_link_flags = BATADV_NO_FLAGS; | 672 | forw_packet_aggr->direct_link_flags = BATADV_NO_FLAGS; |
| 668 | forw_packet_aggr->send_time = send_time; | 673 | forw_packet_aggr->send_time = send_time; |
| @@ -685,6 +690,8 @@ static void batadv_iv_ogm_aggregate_new(const unsigned char *packet_buff, | |||
| 685 | 690 | ||
| 686 | return; | 691 | return; |
| 687 | out: | 692 | out: |
| 693 | batadv_hardif_free_ref(if_outgoing); | ||
| 694 | out_free_incoming: | ||
| 688 | batadv_hardif_free_ref(if_incoming); | 695 | batadv_hardif_free_ref(if_incoming); |
| 689 | } | 696 | } |
| 690 | 697 | ||
| @@ -708,10 +715,21 @@ static void batadv_iv_ogm_aggregate(struct batadv_forw_packet *forw_packet_aggr, | |||
| 708 | } | 715 | } |
| 709 | } | 716 | } |
| 710 | 717 | ||
| 718 | /** | ||
| 719 | * batadv_iv_ogm_queue_add - queue up an OGM for transmission | ||
| 720 | * @bat_priv: the bat priv with all the soft interface information | ||
| 721 | * @packet_buff: pointer to the OGM | ||
| 722 | * @packet_len: (total) length of the OGM | ||
| 723 | * @if_incoming: interface where the packet was received | ||
| 724 | * @if_outgoing: interface for which the retransmission should be considered | ||
| 725 | * @own_packet: true if it is a self-generated ogm | ||
| 726 | * @send_time: timestamp (jiffies) when the packet is to be sent | ||
| 727 | */ | ||
| 711 | static void batadv_iv_ogm_queue_add(struct batadv_priv *bat_priv, | 728 | static void batadv_iv_ogm_queue_add(struct batadv_priv *bat_priv, |
| 712 | unsigned char *packet_buff, | 729 | unsigned char *packet_buff, |
| 713 | int packet_len, | 730 | int packet_len, |
| 714 | struct batadv_hard_iface *if_incoming, | 731 | struct batadv_hard_iface *if_incoming, |
| 732 | struct batadv_hard_iface *if_outgoing, | ||
| 715 | int own_packet, unsigned long send_time) | 733 | int own_packet, unsigned long send_time) |
| 716 | { | 734 | { |
| 717 | /* _aggr -> pointer to the packet we want to aggregate with | 735 | /* _aggr -> pointer to the packet we want to aggregate with |
| @@ -737,6 +755,7 @@ static void batadv_iv_ogm_queue_add(struct batadv_priv *bat_priv, | |||
| 737 | bat_priv, packet_len, | 755 | bat_priv, packet_len, |
| 738 | send_time, direct_link, | 756 | send_time, direct_link, |
| 739 | if_incoming, | 757 | if_incoming, |
| 758 | if_outgoing, | ||
| 740 | forw_packet_pos)) { | 759 | forw_packet_pos)) { |
| 741 | forw_packet_aggr = forw_packet_pos; | 760 | forw_packet_aggr = forw_packet_pos; |
| 742 | break; | 761 | break; |
| @@ -760,7 +779,8 @@ static void batadv_iv_ogm_queue_add(struct batadv_priv *bat_priv, | |||
| 760 | 779 | ||
| 761 | batadv_iv_ogm_aggregate_new(packet_buff, packet_len, | 780 | batadv_iv_ogm_aggregate_new(packet_buff, packet_len, |
| 762 | send_time, direct_link, | 781 | send_time, direct_link, |
| 763 | if_incoming, own_packet); | 782 | if_incoming, if_outgoing, |
| 783 | own_packet); | ||
| 764 | } else { | 784 | } else { |
| 765 | batadv_iv_ogm_aggregate(forw_packet_aggr, packet_buff, | 785 | batadv_iv_ogm_aggregate(forw_packet_aggr, packet_buff, |
| 766 | packet_len, direct_link); | 786 | packet_len, direct_link); |
| @@ -773,7 +793,8 @@ static void batadv_iv_ogm_forward(struct batadv_orig_node *orig_node, | |||
| 773 | struct batadv_ogm_packet *batadv_ogm_packet, | 793 | struct batadv_ogm_packet *batadv_ogm_packet, |
| 774 | bool is_single_hop_neigh, | 794 | bool is_single_hop_neigh, |
| 775 | bool is_from_best_next_hop, | 795 | bool is_from_best_next_hop, |
| 776 | struct batadv_hard_iface *if_incoming) | 796 | struct batadv_hard_iface *if_incoming, |
| 797 | struct batadv_hard_iface *if_outgoing) | ||
| 777 | { | 798 | { |
| 778 | struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface); | 799 | struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface); |
| 779 | uint16_t tvlv_len; | 800 | uint16_t tvlv_len; |
| @@ -818,7 +839,8 @@ static void batadv_iv_ogm_forward(struct batadv_orig_node *orig_node, | |||
| 818 | 839 | ||
| 819 | batadv_iv_ogm_queue_add(bat_priv, (unsigned char *)batadv_ogm_packet, | 840 | batadv_iv_ogm_queue_add(bat_priv, (unsigned char *)batadv_ogm_packet, |
| 820 | BATADV_OGM_HLEN + tvlv_len, | 841 | BATADV_OGM_HLEN + tvlv_len, |
| 821 | if_incoming, 0, batadv_iv_ogm_fwd_send_time()); | 842 | if_incoming, if_outgoing, 0, |
| 843 | batadv_iv_ogm_fwd_send_time()); | ||
| 822 | } | 844 | } |
| 823 | 845 | ||
| 824 | /** | 846 | /** |
| @@ -863,10 +885,11 @@ static void batadv_iv_ogm_schedule(struct batadv_hard_iface *hard_iface) | |||
| 863 | struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface); | 885 | struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface); |
| 864 | unsigned char **ogm_buff = &hard_iface->bat_iv.ogm_buff; | 886 | unsigned char **ogm_buff = &hard_iface->bat_iv.ogm_buff; |
| 865 | struct batadv_ogm_packet *batadv_ogm_packet; | 887 | struct batadv_ogm_packet *batadv_ogm_packet; |
| 866 | struct batadv_hard_iface *primary_if; | 888 | struct batadv_hard_iface *primary_if, *tmp_hard_iface; |
| 867 | int *ogm_buff_len = &hard_iface->bat_iv.ogm_buff_len; | 889 | int *ogm_buff_len = &hard_iface->bat_iv.ogm_buff_len; |
| 868 | uint32_t seqno; | 890 | uint32_t seqno; |
| 869 | uint16_t tvlv_len = 0; | 891 | uint16_t tvlv_len = 0; |
| 892 | unsigned long send_time; | ||
| 870 | 893 | ||
| 871 | primary_if = batadv_primary_if_get_selected(bat_priv); | 894 | primary_if = batadv_primary_if_get_selected(bat_priv); |
| 872 | 895 | ||
| @@ -889,23 +912,60 @@ static void batadv_iv_ogm_schedule(struct batadv_hard_iface *hard_iface) | |||
| 889 | atomic_inc(&hard_iface->bat_iv.ogm_seqno); | 912 | atomic_inc(&hard_iface->bat_iv.ogm_seqno); |
| 890 | 913 | ||
| 891 | batadv_iv_ogm_slide_own_bcast_window(hard_iface); | 914 | batadv_iv_ogm_slide_own_bcast_window(hard_iface); |
| 892 | batadv_iv_ogm_queue_add(bat_priv, hard_iface->bat_iv.ogm_buff, | ||
| 893 | hard_iface->bat_iv.ogm_buff_len, hard_iface, 1, | ||
| 894 | batadv_iv_ogm_emit_send_time(bat_priv)); | ||
| 895 | 915 | ||
| 916 | send_time = batadv_iv_ogm_emit_send_time(bat_priv); | ||
| 917 | |||
| 918 | if (hard_iface != primary_if) { | ||
| 919 | /* OGMs from secondary interfaces are only scheduled on their | ||
| 920 | * respective interfaces. | ||
| 921 | */ | ||
| 922 | batadv_iv_ogm_queue_add(bat_priv, *ogm_buff, *ogm_buff_len, | ||
| 923 | hard_iface, hard_iface, 1, send_time); | ||
| 924 | goto out; | ||
| 925 | } | ||
| 926 | |||
| 927 | /* OGMs from primary interfaces are scheduled on all | ||
| 928 | * interfaces. | ||
| 929 | */ | ||
| 930 | rcu_read_lock(); | ||
| 931 | list_for_each_entry_rcu(tmp_hard_iface, &batadv_hardif_list, list) { | ||
| 932 | if (tmp_hard_iface->soft_iface != hard_iface->soft_iface) | ||
| 933 | continue; | ||
| 934 | batadv_iv_ogm_queue_add(bat_priv, *ogm_buff, | ||
| 935 | *ogm_buff_len, hard_iface, | ||
| 936 | tmp_hard_iface, 1, send_time); | ||
| 937 | } | ||
| 938 | rcu_read_unlock(); | ||
| 939 | |||
| 940 | out: | ||
| 896 | if (primary_if) | 941 | if (primary_if) |
| 897 | batadv_hardif_free_ref(primary_if); | 942 | batadv_hardif_free_ref(primary_if); |
| 898 | } | 943 | } |
| 899 | 944 | ||
| 945 | /** | ||
| 946 | * batadv_iv_ogm_orig_update - use OGM to update corresponding data in an | ||
| 947 | * originator | ||
| 948 | * @bat_priv: the bat priv with all the soft interface information | ||
| 949 | * @orig_node: the orig node who originally emitted the ogm packet | ||
| 950 | * @orig_ifinfo: ifinfo for the outgoing interface of the orig_node | ||
| 951 | * @ethhdr: Ethernet header of the OGM | ||
| 952 | * @batadv_ogm_packet: the ogm packet | ||
| 953 | * @if_incoming: interface where the packet was received | ||
| 954 | * @if_outgoing: interface for which the retransmission should be considered | ||
| 955 | * @dup_status: the duplicate status of this ogm packet. | ||
| 956 | */ | ||
| 900 | static void | 957 | static void |
| 901 | batadv_iv_ogm_orig_update(struct batadv_priv *bat_priv, | 958 | batadv_iv_ogm_orig_update(struct batadv_priv *bat_priv, |
| 902 | struct batadv_orig_node *orig_node, | 959 | struct batadv_orig_node *orig_node, |
| 960 | struct batadv_orig_ifinfo *orig_ifinfo, | ||
| 903 | const struct ethhdr *ethhdr, | 961 | const struct ethhdr *ethhdr, |
| 904 | const struct batadv_ogm_packet *batadv_ogm_packet, | 962 | const struct batadv_ogm_packet *batadv_ogm_packet, |
| 905 | struct batadv_hard_iface *if_incoming, | 963 | struct batadv_hard_iface *if_incoming, |
| 906 | const unsigned char *tt_buff, | 964 | struct batadv_hard_iface *if_outgoing, |
| 907 | enum batadv_dup_status dup_status) | 965 | enum batadv_dup_status dup_status) |
| 908 | { | 966 | { |
| 967 | struct batadv_neigh_ifinfo *neigh_ifinfo = NULL; | ||
| 968 | struct batadv_neigh_ifinfo *router_ifinfo = NULL; | ||
| 909 | struct batadv_neigh_node *neigh_node = NULL, *tmp_neigh_node = NULL; | 969 | struct batadv_neigh_node *neigh_node = NULL, *tmp_neigh_node = NULL; |
| 910 | struct batadv_neigh_node *router = NULL; | 970 | struct batadv_neigh_node *router = NULL; |
| 911 | struct batadv_orig_node *orig_node_tmp; | 971 | struct batadv_orig_node *orig_node_tmp; |
| @@ -933,12 +993,21 @@ batadv_iv_ogm_orig_update(struct batadv_priv *bat_priv, | |||
| 933 | if (dup_status != BATADV_NO_DUP) | 993 | if (dup_status != BATADV_NO_DUP) |
| 934 | continue; | 994 | continue; |
| 935 | 995 | ||
| 936 | spin_lock_bh(&tmp_neigh_node->bat_iv.lq_update_lock); | 996 | /* only update the entry for this outgoing interface */ |
| 937 | batadv_ring_buffer_set(tmp_neigh_node->bat_iv.tq_recv, | 997 | neigh_ifinfo = batadv_neigh_ifinfo_get(tmp_neigh_node, |
| 938 | &tmp_neigh_node->bat_iv.tq_index, 0); | 998 | if_outgoing); |
| 939 | tq_avg = batadv_ring_buffer_avg(tmp_neigh_node->bat_iv.tq_recv); | 999 | if (!neigh_ifinfo) |
| 940 | tmp_neigh_node->bat_iv.tq_avg = tq_avg; | 1000 | continue; |
| 941 | spin_unlock_bh(&tmp_neigh_node->bat_iv.lq_update_lock); | 1001 | |
| 1002 | spin_lock_bh(&tmp_neigh_node->ifinfo_lock); | ||
| 1003 | batadv_ring_buffer_set(neigh_ifinfo->bat_iv.tq_recv, | ||
| 1004 | &neigh_ifinfo->bat_iv.tq_index, 0); | ||
| 1005 | tq_avg = batadv_ring_buffer_avg(neigh_ifinfo->bat_iv.tq_recv); | ||
| 1006 | neigh_ifinfo->bat_iv.tq_avg = tq_avg; | ||
| 1007 | spin_unlock_bh(&tmp_neigh_node->ifinfo_lock); | ||
| 1008 | |||
| 1009 | batadv_neigh_ifinfo_free_ref(neigh_ifinfo); | ||
| 1010 | neigh_ifinfo = NULL; | ||
| 942 | } | 1011 | } |
| 943 | 1012 | ||
| 944 | if (!neigh_node) { | 1013 | if (!neigh_node) { |
| @@ -960,39 +1029,49 @@ batadv_iv_ogm_orig_update(struct batadv_priv *bat_priv, | |||
| 960 | "Updating existing last-hop neighbor of originator\n"); | 1029 | "Updating existing last-hop neighbor of originator\n"); |
| 961 | 1030 | ||
| 962 | rcu_read_unlock(); | 1031 | rcu_read_unlock(); |
| 1032 | neigh_ifinfo = batadv_neigh_ifinfo_new(neigh_node, if_outgoing); | ||
| 1033 | if (!neigh_ifinfo) | ||
| 1034 | goto out; | ||
| 963 | 1035 | ||
| 964 | neigh_node->last_seen = jiffies; | 1036 | neigh_node->last_seen = jiffies; |
| 965 | 1037 | ||
| 966 | spin_lock_bh(&neigh_node->bat_iv.lq_update_lock); | 1038 | spin_lock_bh(&neigh_node->ifinfo_lock); |
| 967 | batadv_ring_buffer_set(neigh_node->bat_iv.tq_recv, | 1039 | batadv_ring_buffer_set(neigh_ifinfo->bat_iv.tq_recv, |
| 968 | &neigh_node->bat_iv.tq_index, | 1040 | &neigh_ifinfo->bat_iv.tq_index, |
| 969 | batadv_ogm_packet->tq); | 1041 | batadv_ogm_packet->tq); |
| 970 | tq_avg = batadv_ring_buffer_avg(neigh_node->bat_iv.tq_recv); | 1042 | tq_avg = batadv_ring_buffer_avg(neigh_ifinfo->bat_iv.tq_recv); |
| 971 | neigh_node->bat_iv.tq_avg = tq_avg; | 1043 | neigh_ifinfo->bat_iv.tq_avg = tq_avg; |
| 972 | spin_unlock_bh(&neigh_node->bat_iv.lq_update_lock); | 1044 | spin_unlock_bh(&neigh_node->ifinfo_lock); |
| 973 | 1045 | ||
| 974 | if (dup_status == BATADV_NO_DUP) { | 1046 | if (dup_status == BATADV_NO_DUP) { |
| 975 | orig_node->last_ttl = batadv_ogm_packet->ttl; | 1047 | orig_ifinfo->last_ttl = batadv_ogm_packet->ttl; |
| 976 | neigh_node->last_ttl = batadv_ogm_packet->ttl; | 1048 | neigh_ifinfo->last_ttl = batadv_ogm_packet->ttl; |
| 977 | } | 1049 | } |
| 978 | 1050 | ||
| 979 | batadv_bonding_candidate_add(bat_priv, orig_node, neigh_node); | ||
| 980 | |||
| 981 | /* if this neighbor already is our next hop there is nothing | 1051 | /* if this neighbor already is our next hop there is nothing |
| 982 | * to change | 1052 | * to change |
| 983 | */ | 1053 | */ |
| 984 | router = batadv_orig_node_get_router(orig_node); | 1054 | router = batadv_orig_router_get(orig_node, if_outgoing); |
| 985 | if (router == neigh_node) | 1055 | if (router == neigh_node) |
| 986 | goto out; | 1056 | goto out; |
| 987 | 1057 | ||
| 988 | /* if this neighbor does not offer a better TQ we won't consider it */ | 1058 | if (router) { |
| 989 | if (router && (router->bat_iv.tq_avg > neigh_node->bat_iv.tq_avg)) | 1059 | router_ifinfo = batadv_neigh_ifinfo_get(router, if_outgoing); |
| 990 | goto out; | 1060 | if (!router_ifinfo) |
| 1061 | goto out; | ||
| 1062 | |||
| 1063 | /* if this neighbor does not offer a better TQ we won't | ||
| 1064 | * consider it | ||
| 1065 | */ | ||
| 1066 | if (router_ifinfo->bat_iv.tq_avg > neigh_ifinfo->bat_iv.tq_avg) | ||
| 1067 | goto out; | ||
| 1068 | } | ||
| 991 | 1069 | ||
| 992 | /* if the TQ is the same and the link not more symmetric we | 1070 | /* if the TQ is the same and the link not more symmetric we |
| 993 | * won't consider it either | 1071 | * won't consider it either |
| 994 | */ | 1072 | */ |
| 995 | if (router && (neigh_node->bat_iv.tq_avg == router->bat_iv.tq_avg)) { | 1073 | if (router_ifinfo && |
| 1074 | (neigh_ifinfo->bat_iv.tq_avg == router_ifinfo->bat_iv.tq_avg)) { | ||
| 996 | orig_node_tmp = router->orig_node; | 1075 | orig_node_tmp = router->orig_node; |
| 997 | spin_lock_bh(&orig_node_tmp->bat_iv.ogm_cnt_lock); | 1076 | spin_lock_bh(&orig_node_tmp->bat_iv.ogm_cnt_lock); |
| 998 | if_num = router->if_incoming->if_num; | 1077 | if_num = router->if_incoming->if_num; |
| @@ -1009,7 +1088,7 @@ batadv_iv_ogm_orig_update(struct batadv_priv *bat_priv, | |||
| 1009 | goto out; | 1088 | goto out; |
| 1010 | } | 1089 | } |
| 1011 | 1090 | ||
| 1012 | batadv_update_route(bat_priv, orig_node, neigh_node); | 1091 | batadv_update_route(bat_priv, orig_node, if_outgoing, neigh_node); |
| 1013 | goto out; | 1092 | goto out; |
| 1014 | 1093 | ||
| 1015 | unlock: | 1094 | unlock: |
| @@ -1019,20 +1098,37 @@ out: | |||
| 1019 | batadv_neigh_node_free_ref(neigh_node); | 1098 | batadv_neigh_node_free_ref(neigh_node); |
| 1020 | if (router) | 1099 | if (router) |
| 1021 | batadv_neigh_node_free_ref(router); | 1100 | batadv_neigh_node_free_ref(router); |
| 1101 | if (neigh_ifinfo) | ||
| 1102 | batadv_neigh_ifinfo_free_ref(neigh_ifinfo); | ||
| 1103 | if (router_ifinfo) | ||
| 1104 | batadv_neigh_ifinfo_free_ref(router_ifinfo); | ||
| 1022 | } | 1105 | } |
| 1023 | 1106 | ||
| 1107 | /** | ||
| 1108 | * batadv_iv_ogm_calc_tq - calculate tq for current received ogm packet | ||
| 1109 | * @orig_node: the orig node who originally emitted the ogm packet | ||
| 1110 | * @orig_neigh_node: the orig node struct of the neighbor who sent the packet | ||
| 1111 | * @batadv_ogm_packet: the ogm packet | ||
| 1112 | * @if_incoming: interface where the packet was received | ||
| 1113 | * @if_outgoing: interface for which the retransmission should be considered | ||
| 1114 | * | ||
| 1115 | * Returns 1 if the link can be considered bidirectional, 0 otherwise | ||
| 1116 | */ | ||
| 1024 | static int batadv_iv_ogm_calc_tq(struct batadv_orig_node *orig_node, | 1117 | static int batadv_iv_ogm_calc_tq(struct batadv_orig_node *orig_node, |
| 1025 | struct batadv_orig_node *orig_neigh_node, | 1118 | struct batadv_orig_node *orig_neigh_node, |
| 1026 | struct batadv_ogm_packet *batadv_ogm_packet, | 1119 | struct batadv_ogm_packet *batadv_ogm_packet, |
| 1027 | struct batadv_hard_iface *if_incoming) | 1120 | struct batadv_hard_iface *if_incoming, |
| 1121 | struct batadv_hard_iface *if_outgoing) | ||
| 1028 | { | 1122 | { |
| 1029 | struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface); | 1123 | struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface); |
| 1030 | struct batadv_neigh_node *neigh_node = NULL, *tmp_neigh_node; | 1124 | struct batadv_neigh_node *neigh_node = NULL, *tmp_neigh_node; |
| 1125 | struct batadv_neigh_ifinfo *neigh_ifinfo; | ||
| 1031 | uint8_t total_count; | 1126 | uint8_t total_count; |
| 1032 | uint8_t orig_eq_count, neigh_rq_count, neigh_rq_inv, tq_own; | 1127 | uint8_t orig_eq_count, neigh_rq_count, neigh_rq_inv, tq_own; |
| 1033 | unsigned int neigh_rq_inv_cube, neigh_rq_max_cube; | 1128 | unsigned int neigh_rq_inv_cube, neigh_rq_max_cube; |
| 1034 | int tq_asym_penalty, inv_asym_penalty, if_num, ret = 0; | 1129 | int tq_asym_penalty, inv_asym_penalty, if_num, ret = 0; |
| 1035 | unsigned int combined_tq; | 1130 | unsigned int combined_tq; |
| 1131 | int tq_iface_penalty; | ||
| 1036 | 1132 | ||
| 1037 | /* find corresponding one hop neighbor */ | 1133 | /* find corresponding one hop neighbor */ |
| 1038 | rcu_read_lock(); | 1134 | rcu_read_lock(); |
| @@ -1072,7 +1168,13 @@ static int batadv_iv_ogm_calc_tq(struct batadv_orig_node *orig_node, | |||
| 1072 | spin_lock_bh(&orig_node->bat_iv.ogm_cnt_lock); | 1168 | spin_lock_bh(&orig_node->bat_iv.ogm_cnt_lock); |
| 1073 | if_num = if_incoming->if_num; | 1169 | if_num = if_incoming->if_num; |
| 1074 | orig_eq_count = orig_neigh_node->bat_iv.bcast_own_sum[if_num]; | 1170 | orig_eq_count = orig_neigh_node->bat_iv.bcast_own_sum[if_num]; |
| 1075 | neigh_rq_count = neigh_node->bat_iv.real_packet_count; | 1171 | neigh_ifinfo = batadv_neigh_ifinfo_new(neigh_node, if_outgoing); |
| 1172 | if (neigh_ifinfo) { | ||
| 1173 | neigh_rq_count = neigh_ifinfo->bat_iv.real_packet_count; | ||
| 1174 | batadv_neigh_ifinfo_free_ref(neigh_ifinfo); | ||
| 1175 | } else { | ||
| 1176 | neigh_rq_count = 0; | ||
| 1177 | } | ||
| 1076 | spin_unlock_bh(&orig_node->bat_iv.ogm_cnt_lock); | 1178 | spin_unlock_bh(&orig_node->bat_iv.ogm_cnt_lock); |
| 1077 | 1179 | ||
| 1078 | /* pay attention to not get a value bigger than 100 % */ | 1180 | /* pay attention to not get a value bigger than 100 % */ |
| @@ -1108,15 +1210,31 @@ static int batadv_iv_ogm_calc_tq(struct batadv_orig_node *orig_node, | |||
| 1108 | inv_asym_penalty /= neigh_rq_max_cube; | 1210 | inv_asym_penalty /= neigh_rq_max_cube; |
| 1109 | tq_asym_penalty = BATADV_TQ_MAX_VALUE - inv_asym_penalty; | 1211 | tq_asym_penalty = BATADV_TQ_MAX_VALUE - inv_asym_penalty; |
| 1110 | 1212 | ||
| 1111 | combined_tq = batadv_ogm_packet->tq * tq_own * tq_asym_penalty; | 1213 | /* penalize if the OGM is forwarded on the same interface. WiFi |
| 1112 | combined_tq /= BATADV_TQ_MAX_VALUE * BATADV_TQ_MAX_VALUE; | 1214 | * interfaces and other half duplex devices suffer from throughput |
| 1215 | * drops as they can't send and receive at the same time. | ||
| 1216 | */ | ||
| 1217 | tq_iface_penalty = BATADV_TQ_MAX_VALUE; | ||
| 1218 | if (if_outgoing && (if_incoming == if_outgoing) && | ||
| 1219 | batadv_is_wifi_netdev(if_outgoing->net_dev)) | ||
| 1220 | tq_iface_penalty = batadv_hop_penalty(BATADV_TQ_MAX_VALUE, | ||
| 1221 | bat_priv); | ||
| 1222 | |||
| 1223 | combined_tq = batadv_ogm_packet->tq * | ||
| 1224 | tq_own * | ||
| 1225 | tq_asym_penalty * | ||
| 1226 | tq_iface_penalty; | ||
| 1227 | combined_tq /= BATADV_TQ_MAX_VALUE * | ||
| 1228 | BATADV_TQ_MAX_VALUE * | ||
| 1229 | BATADV_TQ_MAX_VALUE; | ||
| 1113 | batadv_ogm_packet->tq = combined_tq; | 1230 | batadv_ogm_packet->tq = combined_tq; |
| 1114 | 1231 | ||
| 1115 | batadv_dbg(BATADV_DBG_BATMAN, bat_priv, | 1232 | batadv_dbg(BATADV_DBG_BATMAN, bat_priv, |
| 1116 | "bidirectional: orig = %-15pM neigh = %-15pM => own_bcast = %2i, real recv = %2i, local tq: %3i, asym_penalty: %3i, total tq: %3i\n", | 1233 | "bidirectional: orig = %-15pM neigh = %-15pM => own_bcast = %2i, real recv = %2i, local tq: %3i, asym_penalty: %3i, iface_penalty: %3i, total tq: %3i, if_incoming = %s, if_outgoing = %s\n", |
| 1117 | orig_node->orig, orig_neigh_node->orig, total_count, | 1234 | orig_node->orig, orig_neigh_node->orig, total_count, |
| 1118 | neigh_rq_count, tq_own, | 1235 | neigh_rq_count, tq_own, tq_asym_penalty, tq_iface_penalty, |
| 1119 | tq_asym_penalty, batadv_ogm_packet->tq); | 1236 | batadv_ogm_packet->tq, if_incoming->net_dev->name, |
| 1237 | if_outgoing ? if_outgoing->net_dev->name : "DEFAULT"); | ||
| 1120 | 1238 | ||
| 1121 | /* if link has the minimum required transmission quality | 1239 | /* if link has the minimum required transmission quality |
| 1122 | * consider it bidirectional | 1240 | * consider it bidirectional |
| @@ -1136,17 +1254,21 @@ out: | |||
| 1136 | * @ethhdr: ethernet header of the packet | 1254 | * @ethhdr: ethernet header of the packet |
| 1137 | * @batadv_ogm_packet: OGM packet to be considered | 1255 | * @batadv_ogm_packet: OGM packet to be considered |
| 1138 | * @if_incoming: interface on which the OGM packet was received | 1256 | * @if_incoming: interface on which the OGM packet was received |
| 1257 | * @if_outgoing: interface for which the retransmission should be considered | ||
| 1139 | * | 1258 | * |
| 1140 | * Returns duplicate status as enum batadv_dup_status | 1259 | * Returns duplicate status as enum batadv_dup_status |
| 1141 | */ | 1260 | */ |
| 1142 | static enum batadv_dup_status | 1261 | static enum batadv_dup_status |
| 1143 | batadv_iv_ogm_update_seqnos(const struct ethhdr *ethhdr, | 1262 | batadv_iv_ogm_update_seqnos(const struct ethhdr *ethhdr, |
| 1144 | const struct batadv_ogm_packet *batadv_ogm_packet, | 1263 | const struct batadv_ogm_packet *batadv_ogm_packet, |
| 1145 | const struct batadv_hard_iface *if_incoming) | 1264 | const struct batadv_hard_iface *if_incoming, |
| 1265 | struct batadv_hard_iface *if_outgoing) | ||
| 1146 | { | 1266 | { |
| 1147 | struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface); | 1267 | struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface); |
| 1148 | struct batadv_orig_node *orig_node; | 1268 | struct batadv_orig_node *orig_node; |
| 1149 | struct batadv_neigh_node *tmp_neigh_node; | 1269 | struct batadv_orig_ifinfo *orig_ifinfo = NULL; |
| 1270 | struct batadv_neigh_node *neigh_node; | ||
| 1271 | struct batadv_neigh_ifinfo *neigh_ifinfo; | ||
| 1150 | int is_dup; | 1272 | int is_dup; |
| 1151 | int32_t seq_diff; | 1273 | int32_t seq_diff; |
| 1152 | int need_update = 0; | 1274 | int need_update = 0; |
| @@ -1161,27 +1283,37 @@ batadv_iv_ogm_update_seqnos(const struct ethhdr *ethhdr, | |||
| 1161 | if (!orig_node) | 1283 | if (!orig_node) |
| 1162 | return BATADV_NO_DUP; | 1284 | return BATADV_NO_DUP; |
| 1163 | 1285 | ||
| 1286 | orig_ifinfo = batadv_orig_ifinfo_new(orig_node, if_outgoing); | ||
| 1287 | if (WARN_ON(!orig_ifinfo)) { | ||
| 1288 | batadv_orig_node_free_ref(orig_node); | ||
| 1289 | return 0; | ||
| 1290 | } | ||
| 1291 | |||
| 1164 | spin_lock_bh(&orig_node->bat_iv.ogm_cnt_lock); | 1292 | spin_lock_bh(&orig_node->bat_iv.ogm_cnt_lock); |
| 1165 | seq_diff = seqno - orig_node->last_real_seqno; | 1293 | seq_diff = seqno - orig_ifinfo->last_real_seqno; |
| 1166 | 1294 | ||
| 1167 | /* signalize caller that the packet is to be dropped. */ | 1295 | /* signalize caller that the packet is to be dropped. */ |
| 1168 | if (!hlist_empty(&orig_node->neigh_list) && | 1296 | if (!hlist_empty(&orig_node->neigh_list) && |
| 1169 | batadv_window_protected(bat_priv, seq_diff, | 1297 | batadv_window_protected(bat_priv, seq_diff, |
| 1170 | &orig_node->batman_seqno_reset)) { | 1298 | &orig_ifinfo->batman_seqno_reset)) { |
| 1171 | ret = BATADV_PROTECTED; | 1299 | ret = BATADV_PROTECTED; |
| 1172 | goto out; | 1300 | goto out; |
| 1173 | } | 1301 | } |
| 1174 | 1302 | ||
| 1175 | rcu_read_lock(); | 1303 | rcu_read_lock(); |
| 1176 | hlist_for_each_entry_rcu(tmp_neigh_node, | 1304 | hlist_for_each_entry_rcu(neigh_node, &orig_node->neigh_list, list) { |
| 1177 | &orig_node->neigh_list, list) { | 1305 | neigh_ifinfo = batadv_neigh_ifinfo_new(neigh_node, |
| 1178 | neigh_addr = tmp_neigh_node->addr; | 1306 | if_outgoing); |
| 1179 | is_dup = batadv_test_bit(tmp_neigh_node->bat_iv.real_bits, | 1307 | if (!neigh_ifinfo) |
| 1180 | orig_node->last_real_seqno, | 1308 | continue; |
| 1309 | |||
| 1310 | neigh_addr = neigh_node->addr; | ||
| 1311 | is_dup = batadv_test_bit(neigh_ifinfo->bat_iv.real_bits, | ||
| 1312 | orig_ifinfo->last_real_seqno, | ||
| 1181 | seqno); | 1313 | seqno); |
| 1182 | 1314 | ||
| 1183 | if (batadv_compare_eth(neigh_addr, ethhdr->h_source) && | 1315 | if (batadv_compare_eth(neigh_addr, ethhdr->h_source) && |
| 1184 | tmp_neigh_node->if_incoming == if_incoming) { | 1316 | neigh_node->if_incoming == if_incoming) { |
| 1185 | set_mark = 1; | 1317 | set_mark = 1; |
| 1186 | if (is_dup) | 1318 | if (is_dup) |
| 1187 | ret = BATADV_NEIGH_DUP; | 1319 | ret = BATADV_NEIGH_DUP; |
| @@ -1192,173 +1324,78 @@ batadv_iv_ogm_update_seqnos(const struct ethhdr *ethhdr, | |||
| 1192 | } | 1324 | } |
| 1193 | 1325 | ||
| 1194 | /* if the window moved, set the update flag. */ | 1326 | /* if the window moved, set the update flag. */ |
| 1195 | bitmap = tmp_neigh_node->bat_iv.real_bits; | 1327 | bitmap = neigh_ifinfo->bat_iv.real_bits; |
| 1196 | need_update |= batadv_bit_get_packet(bat_priv, bitmap, | 1328 | need_update |= batadv_bit_get_packet(bat_priv, bitmap, |
| 1197 | seq_diff, set_mark); | 1329 | seq_diff, set_mark); |
| 1198 | 1330 | ||
| 1199 | packet_count = bitmap_weight(tmp_neigh_node->bat_iv.real_bits, | 1331 | packet_count = bitmap_weight(bitmap, |
| 1200 | BATADV_TQ_LOCAL_WINDOW_SIZE); | 1332 | BATADV_TQ_LOCAL_WINDOW_SIZE); |
| 1201 | tmp_neigh_node->bat_iv.real_packet_count = packet_count; | 1333 | neigh_ifinfo->bat_iv.real_packet_count = packet_count; |
| 1334 | batadv_neigh_ifinfo_free_ref(neigh_ifinfo); | ||
| 1202 | } | 1335 | } |
| 1203 | rcu_read_unlock(); | 1336 | rcu_read_unlock(); |
| 1204 | 1337 | ||
| 1205 | if (need_update) { | 1338 | if (need_update) { |
| 1206 | batadv_dbg(BATADV_DBG_BATMAN, bat_priv, | 1339 | batadv_dbg(BATADV_DBG_BATMAN, bat_priv, |
| 1207 | "updating last_seqno: old %u, new %u\n", | 1340 | "%s updating last_seqno: old %u, new %u\n", |
| 1208 | orig_node->last_real_seqno, seqno); | 1341 | if_outgoing ? if_outgoing->net_dev->name : "DEFAULT", |
| 1209 | orig_node->last_real_seqno = seqno; | 1342 | orig_ifinfo->last_real_seqno, seqno); |
| 1343 | orig_ifinfo->last_real_seqno = seqno; | ||
| 1210 | } | 1344 | } |
| 1211 | 1345 | ||
| 1212 | out: | 1346 | out: |
| 1213 | spin_unlock_bh(&orig_node->bat_iv.ogm_cnt_lock); | 1347 | spin_unlock_bh(&orig_node->bat_iv.ogm_cnt_lock); |
| 1214 | batadv_orig_node_free_ref(orig_node); | 1348 | batadv_orig_node_free_ref(orig_node); |
| 1349 | if (orig_ifinfo) | ||
| 1350 | batadv_orig_ifinfo_free_ref(orig_ifinfo); | ||
| 1215 | return ret; | 1351 | return ret; |
| 1216 | } | 1352 | } |
| 1217 | 1353 | ||
| 1218 | static void batadv_iv_ogm_process(const struct ethhdr *ethhdr, | 1354 | |
| 1219 | struct batadv_ogm_packet *batadv_ogm_packet, | 1355 | /** |
| 1220 | const unsigned char *tt_buff, | 1356 | * batadv_iv_ogm_process_per_outif - process a batman iv OGM for an outgoing if |
| 1221 | struct batadv_hard_iface *if_incoming) | 1357 | * @skb: the skb containing the OGM |
| 1358 | * @orig_node: the (cached) orig node for the originator of this OGM | ||
| 1359 | * @if_incoming: the interface where this packet was received | ||
| 1360 | * @if_outgoing: the interface for which the packet should be considered | ||
| 1361 | */ | ||
| 1362 | static void | ||
| 1363 | batadv_iv_ogm_process_per_outif(const struct sk_buff *skb, int ogm_offset, | ||
| 1364 | struct batadv_orig_node *orig_node, | ||
| 1365 | struct batadv_hard_iface *if_incoming, | ||
| 1366 | struct batadv_hard_iface *if_outgoing) | ||
| 1222 | { | 1367 | { |
| 1223 | struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface); | 1368 | struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface); |
| 1224 | struct batadv_hard_iface *hard_iface; | ||
| 1225 | struct batadv_orig_node *orig_neigh_node, *orig_node, *orig_node_tmp; | ||
| 1226 | struct batadv_neigh_node *router = NULL, *router_router = NULL; | 1369 | struct batadv_neigh_node *router = NULL, *router_router = NULL; |
| 1370 | struct batadv_orig_node *orig_neigh_node; | ||
| 1371 | struct batadv_orig_ifinfo *orig_ifinfo; | ||
| 1227 | struct batadv_neigh_node *orig_neigh_router = NULL; | 1372 | struct batadv_neigh_node *orig_neigh_router = NULL; |
| 1228 | int has_directlink_flag; | 1373 | struct batadv_neigh_ifinfo *router_ifinfo = NULL; |
| 1229 | int is_my_addr = 0, is_my_orig = 0, is_my_oldorig = 0; | 1374 | struct batadv_ogm_packet *ogm_packet; |
| 1230 | int is_bidirect; | ||
| 1231 | bool is_single_hop_neigh = false; | ||
| 1232 | bool is_from_best_next_hop = false; | ||
| 1233 | int sameseq, similar_ttl; | ||
| 1234 | enum batadv_dup_status dup_status; | 1375 | enum batadv_dup_status dup_status; |
| 1235 | uint32_t if_incoming_seqno; | 1376 | bool is_from_best_next_hop = false; |
| 1377 | bool is_single_hop_neigh = false; | ||
| 1378 | bool sameseq, similar_ttl; | ||
| 1379 | struct sk_buff *skb_priv; | ||
| 1380 | struct ethhdr *ethhdr; | ||
| 1236 | uint8_t *prev_sender; | 1381 | uint8_t *prev_sender; |
| 1382 | int is_bidirect; | ||
| 1237 | 1383 | ||
| 1238 | /* Silently drop when the batman packet is actually not a | 1384 | /* create a private copy of the skb, as some functions change tq value |
| 1239 | * correct packet. | 1385 | * and/or flags. |
| 1240 | * | ||
| 1241 | * This might happen if a packet is padded (e.g. Ethernet has a | ||
| 1242 | * minimum frame length of 64 byte) and the aggregation interprets | ||
| 1243 | * it as an additional length. | ||
| 1244 | * | ||
| 1245 | * TODO: A more sane solution would be to have a bit in the | ||
| 1246 | * batadv_ogm_packet to detect whether the packet is the last | ||
| 1247 | * packet in an aggregation. Here we expect that the padding | ||
| 1248 | * is always zero (or not 0x01) | ||
| 1249 | */ | 1386 | */ |
| 1250 | if (batadv_ogm_packet->packet_type != BATADV_IV_OGM) | 1387 | skb_priv = skb_copy(skb, GFP_ATOMIC); |
| 1388 | if (!skb_priv) | ||
| 1251 | return; | 1389 | return; |
| 1252 | 1390 | ||
| 1253 | /* could be changed by schedule_own_packet() */ | 1391 | ethhdr = eth_hdr(skb_priv); |
| 1254 | if_incoming_seqno = atomic_read(&if_incoming->bat_iv.ogm_seqno); | 1392 | ogm_packet = (struct batadv_ogm_packet *)(skb_priv->data + ogm_offset); |
| 1255 | |||
| 1256 | if (batadv_ogm_packet->flags & BATADV_DIRECTLINK) | ||
| 1257 | has_directlink_flag = 1; | ||
| 1258 | else | ||
| 1259 | has_directlink_flag = 0; | ||
| 1260 | 1393 | ||
| 1261 | if (batadv_compare_eth(ethhdr->h_source, batadv_ogm_packet->orig)) | 1394 | dup_status = batadv_iv_ogm_update_seqnos(ethhdr, ogm_packet, |
| 1395 | if_incoming, if_outgoing); | ||
| 1396 | if (batadv_compare_eth(ethhdr->h_source, ogm_packet->orig)) | ||
| 1262 | is_single_hop_neigh = true; | 1397 | is_single_hop_neigh = true; |
| 1263 | 1398 | ||
| 1264 | batadv_dbg(BATADV_DBG_BATMAN, bat_priv, | ||
| 1265 | "Received BATMAN packet via NB: %pM, IF: %s [%pM] (from OG: %pM, via prev OG: %pM, seqno %u, tq %d, TTL %d, V %d, IDF %d)\n", | ||
| 1266 | ethhdr->h_source, if_incoming->net_dev->name, | ||
| 1267 | if_incoming->net_dev->dev_addr, batadv_ogm_packet->orig, | ||
| 1268 | batadv_ogm_packet->prev_sender, | ||
| 1269 | ntohl(batadv_ogm_packet->seqno), batadv_ogm_packet->tq, | ||
| 1270 | batadv_ogm_packet->ttl, | ||
| 1271 | batadv_ogm_packet->version, has_directlink_flag); | ||
| 1272 | |||
| 1273 | rcu_read_lock(); | ||
| 1274 | list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) { | ||
| 1275 | if (hard_iface->if_status != BATADV_IF_ACTIVE) | ||
| 1276 | continue; | ||
| 1277 | |||
| 1278 | if (hard_iface->soft_iface != if_incoming->soft_iface) | ||
| 1279 | continue; | ||
| 1280 | |||
| 1281 | if (batadv_compare_eth(ethhdr->h_source, | ||
| 1282 | hard_iface->net_dev->dev_addr)) | ||
| 1283 | is_my_addr = 1; | ||
| 1284 | |||
| 1285 | if (batadv_compare_eth(batadv_ogm_packet->orig, | ||
| 1286 | hard_iface->net_dev->dev_addr)) | ||
| 1287 | is_my_orig = 1; | ||
| 1288 | |||
| 1289 | if (batadv_compare_eth(batadv_ogm_packet->prev_sender, | ||
| 1290 | hard_iface->net_dev->dev_addr)) | ||
| 1291 | is_my_oldorig = 1; | ||
| 1292 | } | ||
| 1293 | rcu_read_unlock(); | ||
| 1294 | |||
| 1295 | if (is_my_addr) { | ||
| 1296 | batadv_dbg(BATADV_DBG_BATMAN, bat_priv, | ||
| 1297 | "Drop packet: received my own broadcast (sender: %pM)\n", | ||
| 1298 | ethhdr->h_source); | ||
| 1299 | return; | ||
| 1300 | } | ||
| 1301 | |||
| 1302 | if (is_my_orig) { | ||
| 1303 | unsigned long *word; | ||
| 1304 | int offset; | ||
| 1305 | int32_t bit_pos; | ||
| 1306 | int16_t if_num; | ||
| 1307 | uint8_t *weight; | ||
| 1308 | |||
| 1309 | orig_neigh_node = batadv_iv_ogm_orig_get(bat_priv, | ||
| 1310 | ethhdr->h_source); | ||
| 1311 | if (!orig_neigh_node) | ||
| 1312 | return; | ||
| 1313 | |||
| 1314 | /* neighbor has to indicate direct link and it has to | ||
| 1315 | * come via the corresponding interface | ||
| 1316 | * save packet seqno for bidirectional check | ||
| 1317 | */ | ||
| 1318 | if (has_directlink_flag && | ||
| 1319 | batadv_compare_eth(if_incoming->net_dev->dev_addr, | ||
| 1320 | batadv_ogm_packet->orig)) { | ||
| 1321 | if_num = if_incoming->if_num; | ||
| 1322 | offset = if_num * BATADV_NUM_WORDS; | ||
| 1323 | |||
| 1324 | spin_lock_bh(&orig_neigh_node->bat_iv.ogm_cnt_lock); | ||
| 1325 | word = &(orig_neigh_node->bat_iv.bcast_own[offset]); | ||
| 1326 | bit_pos = if_incoming_seqno - 2; | ||
| 1327 | bit_pos -= ntohl(batadv_ogm_packet->seqno); | ||
| 1328 | batadv_set_bit(word, bit_pos); | ||
| 1329 | weight = &orig_neigh_node->bat_iv.bcast_own_sum[if_num]; | ||
| 1330 | *weight = bitmap_weight(word, | ||
| 1331 | BATADV_TQ_LOCAL_WINDOW_SIZE); | ||
| 1332 | spin_unlock_bh(&orig_neigh_node->bat_iv.ogm_cnt_lock); | ||
| 1333 | } | ||
| 1334 | |||
| 1335 | batadv_dbg(BATADV_DBG_BATMAN, bat_priv, | ||
| 1336 | "Drop packet: originator packet from myself (via neighbor)\n"); | ||
| 1337 | batadv_orig_node_free_ref(orig_neigh_node); | ||
| 1338 | return; | ||
| 1339 | } | ||
| 1340 | |||
| 1341 | if (is_my_oldorig) { | ||
| 1342 | batadv_dbg(BATADV_DBG_BATMAN, bat_priv, | ||
| 1343 | "Drop packet: ignoring all rebroadcast echos (sender: %pM)\n", | ||
| 1344 | ethhdr->h_source); | ||
| 1345 | return; | ||
| 1346 | } | ||
| 1347 | |||
| 1348 | if (batadv_ogm_packet->flags & BATADV_NOT_BEST_NEXT_HOP) { | ||
| 1349 | batadv_dbg(BATADV_DBG_BATMAN, bat_priv, | ||
| 1350 | "Drop packet: ignoring all packets not forwarded from the best next hop (sender: %pM)\n", | ||
| 1351 | ethhdr->h_source); | ||
| 1352 | return; | ||
| 1353 | } | ||
| 1354 | |||
| 1355 | orig_node = batadv_iv_ogm_orig_get(bat_priv, batadv_ogm_packet->orig); | ||
| 1356 | if (!orig_node) | ||
| 1357 | return; | ||
| 1358 | |||
| 1359 | dup_status = batadv_iv_ogm_update_seqnos(ethhdr, batadv_ogm_packet, | ||
| 1360 | if_incoming); | ||
| 1361 | |||
| 1362 | if (dup_status == BATADV_PROTECTED) { | 1399 | if (dup_status == BATADV_PROTECTED) { |
| 1363 | batadv_dbg(BATADV_DBG_BATMAN, bat_priv, | 1400 | batadv_dbg(BATADV_DBG_BATMAN, bat_priv, |
| 1364 | "Drop packet: packet within seqno protection time (sender: %pM)\n", | 1401 | "Drop packet: packet within seqno protection time (sender: %pM)\n", |
| @@ -1366,27 +1403,28 @@ static void batadv_iv_ogm_process(const struct ethhdr *ethhdr, | |||
| 1366 | goto out; | 1403 | goto out; |
| 1367 | } | 1404 | } |
| 1368 | 1405 | ||
| 1369 | if (batadv_ogm_packet->tq == 0) { | 1406 | if (ogm_packet->tq == 0) { |
| 1370 | batadv_dbg(BATADV_DBG_BATMAN, bat_priv, | 1407 | batadv_dbg(BATADV_DBG_BATMAN, bat_priv, |
| 1371 | "Drop packet: originator packet with tq equal 0\n"); | 1408 | "Drop packet: originator packet with tq equal 0\n"); |
| 1372 | goto out; | 1409 | goto out; |
| 1373 | } | 1410 | } |
| 1374 | 1411 | ||
| 1375 | router = batadv_orig_node_get_router(orig_node); | 1412 | router = batadv_orig_router_get(orig_node, if_outgoing); |
| 1376 | if (router) { | 1413 | if (router) { |
| 1377 | orig_node_tmp = router->orig_node; | 1414 | router_router = batadv_orig_router_get(router->orig_node, |
| 1378 | router_router = batadv_orig_node_get_router(orig_node_tmp); | 1415 | if_outgoing); |
| 1416 | router_ifinfo = batadv_neigh_ifinfo_get(router, if_outgoing); | ||
| 1379 | } | 1417 | } |
| 1380 | 1418 | ||
| 1381 | if ((router && router->bat_iv.tq_avg != 0) && | 1419 | if ((router_ifinfo && router_ifinfo->bat_iv.tq_avg != 0) && |
| 1382 | (batadv_compare_eth(router->addr, ethhdr->h_source))) | 1420 | (batadv_compare_eth(router->addr, ethhdr->h_source))) |
| 1383 | is_from_best_next_hop = true; | 1421 | is_from_best_next_hop = true; |
| 1384 | 1422 | ||
| 1385 | prev_sender = batadv_ogm_packet->prev_sender; | 1423 | prev_sender = ogm_packet->prev_sender; |
| 1386 | /* avoid temporary routing loops */ | 1424 | /* avoid temporary routing loops */ |
| 1387 | if (router && router_router && | 1425 | if (router && router_router && |
| 1388 | (batadv_compare_eth(router->addr, prev_sender)) && | 1426 | (batadv_compare_eth(router->addr, prev_sender)) && |
| 1389 | !(batadv_compare_eth(batadv_ogm_packet->orig, prev_sender)) && | 1427 | !(batadv_compare_eth(ogm_packet->orig, prev_sender)) && |
| 1390 | (batadv_compare_eth(router->addr, router_router->addr))) { | 1428 | (batadv_compare_eth(router->addr, router_router->addr))) { |
| 1391 | batadv_dbg(BATADV_DBG_BATMAN, bat_priv, | 1429 | batadv_dbg(BATADV_DBG_BATMAN, bat_priv, |
| 1392 | "Drop packet: ignoring all rebroadcast packets that may make me loop (sender: %pM)\n", | 1430 | "Drop packet: ignoring all rebroadcast packets that may make me loop (sender: %pM)\n", |
| @@ -1394,7 +1432,8 @@ static void batadv_iv_ogm_process(const struct ethhdr *ethhdr, | |||
| 1394 | goto out; | 1432 | goto out; |
| 1395 | } | 1433 | } |
| 1396 | 1434 | ||
| 1397 | batadv_tvlv_ogm_receive(bat_priv, batadv_ogm_packet, orig_node); | 1435 | if (if_outgoing == BATADV_IF_DEFAULT) |
| 1436 | batadv_tvlv_ogm_receive(bat_priv, ogm_packet, orig_node); | ||
| 1398 | 1437 | ||
| 1399 | /* if sender is a direct neighbor the sender mac equals | 1438 | /* if sender is a direct neighbor the sender mac equals |
| 1400 | * originator mac | 1439 | * originator mac |
| @@ -1410,9 +1449,10 @@ static void batadv_iv_ogm_process(const struct ethhdr *ethhdr, | |||
| 1410 | 1449 | ||
| 1411 | /* Update nc_nodes of the originator */ | 1450 | /* Update nc_nodes of the originator */ |
| 1412 | batadv_nc_update_nc_node(bat_priv, orig_node, orig_neigh_node, | 1451 | batadv_nc_update_nc_node(bat_priv, orig_node, orig_neigh_node, |
| 1413 | batadv_ogm_packet, is_single_hop_neigh); | 1452 | ogm_packet, is_single_hop_neigh); |
| 1414 | 1453 | ||
| 1415 | orig_neigh_router = batadv_orig_node_get_router(orig_neigh_node); | 1454 | orig_neigh_router = batadv_orig_router_get(orig_neigh_node, |
| 1455 | if_outgoing); | ||
| 1416 | 1456 | ||
| 1417 | /* drop packet if sender is not a direct neighbor and if we | 1457 | /* drop packet if sender is not a direct neighbor and if we |
| 1418 | * don't route towards it | 1458 | * don't route towards it |
| @@ -1424,28 +1464,48 @@ static void batadv_iv_ogm_process(const struct ethhdr *ethhdr, | |||
| 1424 | } | 1464 | } |
| 1425 | 1465 | ||
| 1426 | is_bidirect = batadv_iv_ogm_calc_tq(orig_node, orig_neigh_node, | 1466 | is_bidirect = batadv_iv_ogm_calc_tq(orig_node, orig_neigh_node, |
| 1427 | batadv_ogm_packet, if_incoming); | 1467 | ogm_packet, if_incoming, |
| 1428 | 1468 | if_outgoing); | |
| 1429 | batadv_bonding_save_primary(orig_node, orig_neigh_node, | ||
| 1430 | batadv_ogm_packet); | ||
| 1431 | 1469 | ||
| 1432 | /* update ranking if it is not a duplicate or has the same | 1470 | /* update ranking if it is not a duplicate or has the same |
| 1433 | * seqno and similar ttl as the non-duplicate | 1471 | * seqno and similar ttl as the non-duplicate |
| 1434 | */ | 1472 | */ |
| 1435 | sameseq = orig_node->last_real_seqno == ntohl(batadv_ogm_packet->seqno); | 1473 | orig_ifinfo = batadv_orig_ifinfo_new(orig_node, if_outgoing); |
| 1436 | similar_ttl = orig_node->last_ttl - 3 <= batadv_ogm_packet->ttl; | 1474 | if (!orig_ifinfo) |
| 1475 | goto out_neigh; | ||
| 1476 | |||
| 1477 | sameseq = orig_ifinfo->last_real_seqno == ntohl(ogm_packet->seqno); | ||
| 1478 | similar_ttl = (orig_ifinfo->last_ttl - 3) <= ogm_packet->ttl; | ||
| 1479 | |||
| 1437 | if (is_bidirect && ((dup_status == BATADV_NO_DUP) || | 1480 | if (is_bidirect && ((dup_status == BATADV_NO_DUP) || |
| 1438 | (sameseq && similar_ttl))) | 1481 | (sameseq && similar_ttl))) { |
| 1439 | batadv_iv_ogm_orig_update(bat_priv, orig_node, ethhdr, | 1482 | batadv_iv_ogm_orig_update(bat_priv, orig_node, |
| 1440 | batadv_ogm_packet, if_incoming, | 1483 | orig_ifinfo, ethhdr, |
| 1441 | tt_buff, dup_status); | 1484 | ogm_packet, if_incoming, |
| 1485 | if_outgoing, dup_status); | ||
| 1486 | } | ||
| 1487 | batadv_orig_ifinfo_free_ref(orig_ifinfo); | ||
| 1488 | |||
| 1489 | /* only forward for specific interface, not for the default one. */ | ||
| 1490 | if (if_outgoing == BATADV_IF_DEFAULT) | ||
| 1491 | goto out_neigh; | ||
| 1442 | 1492 | ||
| 1443 | /* is single hop (direct) neighbor */ | 1493 | /* is single hop (direct) neighbor */ |
| 1444 | if (is_single_hop_neigh) { | 1494 | if (is_single_hop_neigh) { |
| 1495 | /* OGMs from secondary interfaces should only scheduled once | ||
| 1496 | * per interface where it has been received, not multiple times | ||
| 1497 | */ | ||
| 1498 | if ((ogm_packet->ttl <= 2) && | ||
| 1499 | (if_incoming != if_outgoing)) { | ||
| 1500 | batadv_dbg(BATADV_DBG_BATMAN, bat_priv, | ||
| 1501 | "Drop packet: OGM from secondary interface and wrong outgoing interface\n"); | ||
| 1502 | goto out_neigh; | ||
| 1503 | } | ||
| 1445 | /* mark direct link on incoming interface */ | 1504 | /* mark direct link on incoming interface */ |
| 1446 | batadv_iv_ogm_forward(orig_node, ethhdr, batadv_ogm_packet, | 1505 | batadv_iv_ogm_forward(orig_node, ethhdr, ogm_packet, |
| 1447 | is_single_hop_neigh, | 1506 | is_single_hop_neigh, |
| 1448 | is_from_best_next_hop, if_incoming); | 1507 | is_from_best_next_hop, if_incoming, |
| 1508 | if_outgoing); | ||
| 1449 | 1509 | ||
| 1450 | batadv_dbg(BATADV_DBG_BATMAN, bat_priv, | 1510 | batadv_dbg(BATADV_DBG_BATMAN, bat_priv, |
| 1451 | "Forwarding packet: rebroadcast neighbor packet with direct link flag\n"); | 1511 | "Forwarding packet: rebroadcast neighbor packet with direct link flag\n"); |
| @@ -1467,9 +1527,9 @@ static void batadv_iv_ogm_process(const struct ethhdr *ethhdr, | |||
| 1467 | 1527 | ||
| 1468 | batadv_dbg(BATADV_DBG_BATMAN, bat_priv, | 1528 | batadv_dbg(BATADV_DBG_BATMAN, bat_priv, |
| 1469 | "Forwarding packet: rebroadcast originator packet\n"); | 1529 | "Forwarding packet: rebroadcast originator packet\n"); |
| 1470 | batadv_iv_ogm_forward(orig_node, ethhdr, batadv_ogm_packet, | 1530 | batadv_iv_ogm_forward(orig_node, ethhdr, ogm_packet, |
| 1471 | is_single_hop_neigh, is_from_best_next_hop, | 1531 | is_single_hop_neigh, is_from_best_next_hop, |
| 1472 | if_incoming); | 1532 | if_incoming, if_outgoing); |
| 1473 | 1533 | ||
| 1474 | out_neigh: | 1534 | out_neigh: |
| 1475 | if ((orig_neigh_node) && (!is_single_hop_neigh)) | 1535 | if ((orig_neigh_node) && (!is_single_hop_neigh)) |
| @@ -1482,6 +1542,165 @@ out: | |||
| 1482 | if (orig_neigh_router) | 1542 | if (orig_neigh_router) |
| 1483 | batadv_neigh_node_free_ref(orig_neigh_router); | 1543 | batadv_neigh_node_free_ref(orig_neigh_router); |
| 1484 | 1544 | ||
| 1545 | kfree_skb(skb_priv); | ||
| 1546 | } | ||
| 1547 | |||
| 1548 | /** | ||
| 1549 | * batadv_iv_ogm_process - process an incoming batman iv OGM | ||
| 1550 | * @skb: the skb containing the OGM | ||
| 1551 | * @ogm_offset: offset to the OGM which should be processed (for aggregates) | ||
| 1552 | * @if_incoming: the interface where this packet was receved | ||
| 1553 | */ | ||
| 1554 | static void batadv_iv_ogm_process(const struct sk_buff *skb, int ogm_offset, | ||
| 1555 | struct batadv_hard_iface *if_incoming) | ||
| 1556 | { | ||
| 1557 | struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface); | ||
| 1558 | struct batadv_orig_node *orig_neigh_node, *orig_node; | ||
| 1559 | struct batadv_hard_iface *hard_iface; | ||
| 1560 | struct batadv_ogm_packet *ogm_packet; | ||
| 1561 | uint32_t if_incoming_seqno; | ||
| 1562 | bool has_directlink_flag; | ||
| 1563 | struct ethhdr *ethhdr; | ||
| 1564 | bool is_my_oldorig = false; | ||
| 1565 | bool is_my_addr = false; | ||
| 1566 | bool is_my_orig = false; | ||
| 1567 | |||
| 1568 | ogm_packet = (struct batadv_ogm_packet *)(skb->data + ogm_offset); | ||
| 1569 | ethhdr = eth_hdr(skb); | ||
| 1570 | |||
| 1571 | /* Silently drop when the batman packet is actually not a | ||
| 1572 | * correct packet. | ||
| 1573 | * | ||
| 1574 | * This might happen if a packet is padded (e.g. Ethernet has a | ||
| 1575 | * minimum frame length of 64 byte) and the aggregation interprets | ||
| 1576 | * it as an additional length. | ||
| 1577 | * | ||
| 1578 | * TODO: A more sane solution would be to have a bit in the | ||
| 1579 | * batadv_ogm_packet to detect whether the packet is the last | ||
| 1580 | * packet in an aggregation. Here we expect that the padding | ||
| 1581 | * is always zero (or not 0x01) | ||
| 1582 | */ | ||
| 1583 | if (ogm_packet->packet_type != BATADV_IV_OGM) | ||
| 1584 | return; | ||
| 1585 | |||
| 1586 | /* could be changed by schedule_own_packet() */ | ||
| 1587 | if_incoming_seqno = atomic_read(&if_incoming->bat_iv.ogm_seqno); | ||
| 1588 | |||
| 1589 | if (ogm_packet->flags & BATADV_DIRECTLINK) | ||
| 1590 | has_directlink_flag = true; | ||
| 1591 | else | ||
| 1592 | has_directlink_flag = false; | ||
| 1593 | |||
| 1594 | batadv_dbg(BATADV_DBG_BATMAN, bat_priv, | ||
| 1595 | "Received BATMAN packet via NB: %pM, IF: %s [%pM] (from OG: %pM, via prev OG: %pM, seqno %u, tq %d, TTL %d, V %d, IDF %d)\n", | ||
| 1596 | ethhdr->h_source, if_incoming->net_dev->name, | ||
| 1597 | if_incoming->net_dev->dev_addr, ogm_packet->orig, | ||
| 1598 | ogm_packet->prev_sender, ntohl(ogm_packet->seqno), | ||
| 1599 | ogm_packet->tq, ogm_packet->ttl, | ||
| 1600 | ogm_packet->version, has_directlink_flag); | ||
| 1601 | |||
| 1602 | rcu_read_lock(); | ||
| 1603 | list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) { | ||
| 1604 | if (hard_iface->if_status != BATADV_IF_ACTIVE) | ||
| 1605 | continue; | ||
| 1606 | |||
| 1607 | if (hard_iface->soft_iface != if_incoming->soft_iface) | ||
| 1608 | continue; | ||
| 1609 | |||
| 1610 | if (batadv_compare_eth(ethhdr->h_source, | ||
| 1611 | hard_iface->net_dev->dev_addr)) | ||
| 1612 | is_my_addr = true; | ||
| 1613 | |||
| 1614 | if (batadv_compare_eth(ogm_packet->orig, | ||
| 1615 | hard_iface->net_dev->dev_addr)) | ||
| 1616 | is_my_orig = true; | ||
| 1617 | |||
| 1618 | if (batadv_compare_eth(ogm_packet->prev_sender, | ||
| 1619 | hard_iface->net_dev->dev_addr)) | ||
| 1620 | is_my_oldorig = true; | ||
| 1621 | } | ||
| 1622 | rcu_read_unlock(); | ||
| 1623 | |||
| 1624 | if (is_my_addr) { | ||
| 1625 | batadv_dbg(BATADV_DBG_BATMAN, bat_priv, | ||
| 1626 | "Drop packet: received my own broadcast (sender: %pM)\n", | ||
| 1627 | ethhdr->h_source); | ||
| 1628 | return; | ||
| 1629 | } | ||
| 1630 | |||
| 1631 | if (is_my_orig) { | ||
| 1632 | unsigned long *word; | ||
| 1633 | int offset; | ||
| 1634 | int32_t bit_pos; | ||
| 1635 | int16_t if_num; | ||
| 1636 | uint8_t *weight; | ||
| 1637 | |||
| 1638 | orig_neigh_node = batadv_iv_ogm_orig_get(bat_priv, | ||
| 1639 | ethhdr->h_source); | ||
| 1640 | if (!orig_neigh_node) | ||
| 1641 | return; | ||
| 1642 | |||
| 1643 | /* neighbor has to indicate direct link and it has to | ||
| 1644 | * come via the corresponding interface | ||
| 1645 | * save packet seqno for bidirectional check | ||
| 1646 | */ | ||
| 1647 | if (has_directlink_flag && | ||
| 1648 | batadv_compare_eth(if_incoming->net_dev->dev_addr, | ||
| 1649 | ogm_packet->orig)) { | ||
| 1650 | if_num = if_incoming->if_num; | ||
| 1651 | offset = if_num * BATADV_NUM_WORDS; | ||
| 1652 | |||
| 1653 | spin_lock_bh(&orig_neigh_node->bat_iv.ogm_cnt_lock); | ||
| 1654 | word = &(orig_neigh_node->bat_iv.bcast_own[offset]); | ||
| 1655 | bit_pos = if_incoming_seqno - 2; | ||
| 1656 | bit_pos -= ntohl(ogm_packet->seqno); | ||
| 1657 | batadv_set_bit(word, bit_pos); | ||
| 1658 | weight = &orig_neigh_node->bat_iv.bcast_own_sum[if_num]; | ||
| 1659 | *weight = bitmap_weight(word, | ||
| 1660 | BATADV_TQ_LOCAL_WINDOW_SIZE); | ||
| 1661 | spin_unlock_bh(&orig_neigh_node->bat_iv.ogm_cnt_lock); | ||
| 1662 | } | ||
| 1663 | |||
| 1664 | batadv_dbg(BATADV_DBG_BATMAN, bat_priv, | ||
| 1665 | "Drop packet: originator packet from myself (via neighbor)\n"); | ||
| 1666 | batadv_orig_node_free_ref(orig_neigh_node); | ||
| 1667 | return; | ||
| 1668 | } | ||
| 1669 | |||
| 1670 | if (is_my_oldorig) { | ||
| 1671 | batadv_dbg(BATADV_DBG_BATMAN, bat_priv, | ||
| 1672 | "Drop packet: ignoring all rebroadcast echos (sender: %pM)\n", | ||
| 1673 | ethhdr->h_source); | ||
| 1674 | return; | ||
| 1675 | } | ||
| 1676 | |||
| 1677 | if (ogm_packet->flags & BATADV_NOT_BEST_NEXT_HOP) { | ||
| 1678 | batadv_dbg(BATADV_DBG_BATMAN, bat_priv, | ||
| 1679 | "Drop packet: ignoring all packets not forwarded from the best next hop (sender: %pM)\n", | ||
| 1680 | ethhdr->h_source); | ||
| 1681 | return; | ||
| 1682 | } | ||
| 1683 | |||
| 1684 | orig_node = batadv_iv_ogm_orig_get(bat_priv, ogm_packet->orig); | ||
| 1685 | if (!orig_node) | ||
| 1686 | return; | ||
| 1687 | |||
| 1688 | batadv_iv_ogm_process_per_outif(skb, ogm_offset, orig_node, | ||
| 1689 | if_incoming, BATADV_IF_DEFAULT); | ||
| 1690 | |||
| 1691 | rcu_read_lock(); | ||
| 1692 | list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) { | ||
| 1693 | if (hard_iface->if_status != BATADV_IF_ACTIVE) | ||
| 1694 | continue; | ||
| 1695 | |||
| 1696 | if (hard_iface->soft_iface != bat_priv->soft_iface) | ||
| 1697 | continue; | ||
| 1698 | |||
| 1699 | batadv_iv_ogm_process_per_outif(skb, ogm_offset, orig_node, | ||
| 1700 | if_incoming, hard_iface); | ||
| 1701 | } | ||
| 1702 | rcu_read_unlock(); | ||
| 1703 | |||
| 1485 | batadv_orig_node_free_ref(orig_node); | 1704 | batadv_orig_node_free_ref(orig_node); |
| 1486 | } | 1705 | } |
| 1487 | 1706 | ||
| @@ -1489,11 +1708,9 @@ static int batadv_iv_ogm_receive(struct sk_buff *skb, | |||
| 1489 | struct batadv_hard_iface *if_incoming) | 1708 | struct batadv_hard_iface *if_incoming) |
| 1490 | { | 1709 | { |
| 1491 | struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface); | 1710 | struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface); |
| 1492 | struct batadv_ogm_packet *batadv_ogm_packet; | 1711 | struct batadv_ogm_packet *ogm_packet; |
| 1493 | struct ethhdr *ethhdr; | ||
| 1494 | int buff_pos = 0, packet_len; | ||
| 1495 | unsigned char *tvlv_buff, *packet_buff; | ||
| 1496 | uint8_t *packet_pos; | 1712 | uint8_t *packet_pos; |
| 1713 | int ogm_offset; | ||
| 1497 | bool ret; | 1714 | bool ret; |
| 1498 | 1715 | ||
| 1499 | ret = batadv_check_management_packet(skb, if_incoming, BATADV_OGM_HLEN); | 1716 | ret = batadv_check_management_packet(skb, if_incoming, BATADV_OGM_HLEN); |
| @@ -1510,24 +1727,19 @@ static int batadv_iv_ogm_receive(struct sk_buff *skb, | |||
| 1510 | batadv_add_counter(bat_priv, BATADV_CNT_MGMT_RX_BYTES, | 1727 | batadv_add_counter(bat_priv, BATADV_CNT_MGMT_RX_BYTES, |
| 1511 | skb->len + ETH_HLEN); | 1728 | skb->len + ETH_HLEN); |
| 1512 | 1729 | ||
| 1513 | packet_len = skb_headlen(skb); | 1730 | ogm_offset = 0; |
| 1514 | ethhdr = eth_hdr(skb); | 1731 | ogm_packet = (struct batadv_ogm_packet *)skb->data; |
| 1515 | packet_buff = skb->data; | ||
| 1516 | batadv_ogm_packet = (struct batadv_ogm_packet *)packet_buff; | ||
| 1517 | 1732 | ||
| 1518 | /* unpack the aggregated packets and process them one by one */ | 1733 | /* unpack the aggregated packets and process them one by one */ |
| 1519 | while (batadv_iv_ogm_aggr_packet(buff_pos, packet_len, | 1734 | while (batadv_iv_ogm_aggr_packet(ogm_offset, skb_headlen(skb), |
| 1520 | batadv_ogm_packet->tvlv_len)) { | 1735 | ogm_packet->tvlv_len)) { |
| 1521 | tvlv_buff = packet_buff + buff_pos + BATADV_OGM_HLEN; | 1736 | batadv_iv_ogm_process(skb, ogm_offset, if_incoming); |
| 1522 | |||
| 1523 | batadv_iv_ogm_process(ethhdr, batadv_ogm_packet, | ||
| 1524 | tvlv_buff, if_incoming); | ||
| 1525 | 1737 | ||
| 1526 | buff_pos += BATADV_OGM_HLEN; | 1738 | ogm_offset += BATADV_OGM_HLEN; |
| 1527 | buff_pos += ntohs(batadv_ogm_packet->tvlv_len); | 1739 | ogm_offset += ntohs(ogm_packet->tvlv_len); |
| 1528 | 1740 | ||
| 1529 | packet_pos = packet_buff + buff_pos; | 1741 | packet_pos = skb->data + ogm_offset; |
| 1530 | batadv_ogm_packet = (struct batadv_ogm_packet *)packet_pos; | 1742 | ogm_packet = (struct batadv_ogm_packet *)packet_pos; |
| 1531 | } | 1743 | } |
| 1532 | 1744 | ||
| 1533 | kfree_skb(skb); | 1745 | kfree_skb(skb); |
| @@ -1535,17 +1747,49 @@ static int batadv_iv_ogm_receive(struct sk_buff *skb, | |||
| 1535 | } | 1747 | } |
| 1536 | 1748 | ||
| 1537 | /** | 1749 | /** |
| 1750 | * batadv_iv_ogm_orig_print_neigh - print neighbors for the originator table | ||
| 1751 | * @orig_node: the orig_node for which the neighbors are printed | ||
| 1752 | * @if_outgoing: outgoing interface for these entries | ||
| 1753 | * @seq: debugfs table seq_file struct | ||
| 1754 | * | ||
| 1755 | * Must be called while holding an rcu lock. | ||
| 1756 | */ | ||
| 1757 | static void | ||
| 1758 | batadv_iv_ogm_orig_print_neigh(struct batadv_orig_node *orig_node, | ||
| 1759 | struct batadv_hard_iface *if_outgoing, | ||
| 1760 | struct seq_file *seq) | ||
| 1761 | { | ||
| 1762 | struct batadv_neigh_node *neigh_node; | ||
| 1763 | struct batadv_neigh_ifinfo *n_ifinfo; | ||
| 1764 | |||
| 1765 | hlist_for_each_entry_rcu(neigh_node, &orig_node->neigh_list, list) { | ||
| 1766 | n_ifinfo = batadv_neigh_ifinfo_get(neigh_node, if_outgoing); | ||
| 1767 | if (!n_ifinfo) | ||
| 1768 | continue; | ||
| 1769 | |||
| 1770 | seq_printf(seq, " %pM (%3i)", | ||
| 1771 | neigh_node->addr, | ||
| 1772 | n_ifinfo->bat_iv.tq_avg); | ||
| 1773 | |||
| 1774 | batadv_neigh_ifinfo_free_ref(n_ifinfo); | ||
| 1775 | } | ||
| 1776 | } | ||
| 1777 | |||
| 1778 | /** | ||
| 1538 | * batadv_iv_ogm_orig_print - print the originator table | 1779 | * batadv_iv_ogm_orig_print - print the originator table |
| 1539 | * @bat_priv: the bat priv with all the soft interface information | 1780 | * @bat_priv: the bat priv with all the soft interface information |
| 1540 | * @seq: debugfs table seq_file struct | 1781 | * @seq: debugfs table seq_file struct |
| 1782 | * @if_outgoing: the outgoing interface for which this should be printed | ||
| 1541 | */ | 1783 | */ |
| 1542 | static void batadv_iv_ogm_orig_print(struct batadv_priv *bat_priv, | 1784 | static void batadv_iv_ogm_orig_print(struct batadv_priv *bat_priv, |
| 1543 | struct seq_file *seq) | 1785 | struct seq_file *seq, |
| 1786 | struct batadv_hard_iface *if_outgoing) | ||
| 1544 | { | 1787 | { |
| 1545 | struct batadv_neigh_node *neigh_node, *neigh_node_tmp; | 1788 | struct batadv_neigh_node *neigh_node; |
| 1546 | struct batadv_hashtable *hash = bat_priv->orig_hash; | 1789 | struct batadv_hashtable *hash = bat_priv->orig_hash; |
| 1547 | int last_seen_msecs, last_seen_secs; | 1790 | int last_seen_msecs, last_seen_secs; |
| 1548 | struct batadv_orig_node *orig_node; | 1791 | struct batadv_orig_node *orig_node; |
| 1792 | struct batadv_neigh_ifinfo *n_ifinfo; | ||
| 1549 | unsigned long last_seen_jiffies; | 1793 | unsigned long last_seen_jiffies; |
| 1550 | struct hlist_head *head; | 1794 | struct hlist_head *head; |
| 1551 | int batman_count = 0; | 1795 | int batman_count = 0; |
| @@ -1560,11 +1804,17 @@ static void batadv_iv_ogm_orig_print(struct batadv_priv *bat_priv, | |||
| 1560 | 1804 | ||
| 1561 | rcu_read_lock(); | 1805 | rcu_read_lock(); |
| 1562 | hlist_for_each_entry_rcu(orig_node, head, hash_entry) { | 1806 | hlist_for_each_entry_rcu(orig_node, head, hash_entry) { |
| 1563 | neigh_node = batadv_orig_node_get_router(orig_node); | 1807 | neigh_node = batadv_orig_router_get(orig_node, |
| 1808 | if_outgoing); | ||
| 1564 | if (!neigh_node) | 1809 | if (!neigh_node) |
| 1565 | continue; | 1810 | continue; |
| 1566 | 1811 | ||
| 1567 | if (neigh_node->bat_iv.tq_avg == 0) | 1812 | n_ifinfo = batadv_neigh_ifinfo_get(neigh_node, |
| 1813 | if_outgoing); | ||
| 1814 | if (!n_ifinfo) | ||
| 1815 | goto next; | ||
| 1816 | |||
| 1817 | if (n_ifinfo->bat_iv.tq_avg == 0) | ||
| 1568 | goto next; | 1818 | goto next; |
| 1569 | 1819 | ||
| 1570 | last_seen_jiffies = jiffies - orig_node->last_seen; | 1820 | last_seen_jiffies = jiffies - orig_node->last_seen; |
| @@ -1574,22 +1824,19 @@ static void batadv_iv_ogm_orig_print(struct batadv_priv *bat_priv, | |||
| 1574 | 1824 | ||
| 1575 | seq_printf(seq, "%pM %4i.%03is (%3i) %pM [%10s]:", | 1825 | seq_printf(seq, "%pM %4i.%03is (%3i) %pM [%10s]:", |
| 1576 | orig_node->orig, last_seen_secs, | 1826 | orig_node->orig, last_seen_secs, |
| 1577 | last_seen_msecs, neigh_node->bat_iv.tq_avg, | 1827 | last_seen_msecs, n_ifinfo->bat_iv.tq_avg, |
| 1578 | neigh_node->addr, | 1828 | neigh_node->addr, |
| 1579 | neigh_node->if_incoming->net_dev->name); | 1829 | neigh_node->if_incoming->net_dev->name); |
| 1580 | 1830 | ||
| 1581 | hlist_for_each_entry_rcu(neigh_node_tmp, | 1831 | batadv_iv_ogm_orig_print_neigh(orig_node, if_outgoing, |
| 1582 | &orig_node->neigh_list, list) { | 1832 | seq); |
| 1583 | seq_printf(seq, " %pM (%3i)", | ||
| 1584 | neigh_node_tmp->addr, | ||
| 1585 | neigh_node_tmp->bat_iv.tq_avg); | ||
| 1586 | } | ||
| 1587 | |||
| 1588 | seq_puts(seq, "\n"); | 1833 | seq_puts(seq, "\n"); |
| 1589 | batman_count++; | 1834 | batman_count++; |
| 1590 | 1835 | ||
| 1591 | next: | 1836 | next: |
| 1592 | batadv_neigh_node_free_ref(neigh_node); | 1837 | batadv_neigh_node_free_ref(neigh_node); |
| 1838 | if (n_ifinfo) | ||
| 1839 | batadv_neigh_ifinfo_free_ref(n_ifinfo); | ||
| 1593 | } | 1840 | } |
| 1594 | rcu_read_unlock(); | 1841 | rcu_read_unlock(); |
| 1595 | } | 1842 | } |
| @@ -1601,37 +1848,84 @@ next: | |||
| 1601 | /** | 1848 | /** |
| 1602 | * batadv_iv_ogm_neigh_cmp - compare the metrics of two neighbors | 1849 | * batadv_iv_ogm_neigh_cmp - compare the metrics of two neighbors |
| 1603 | * @neigh1: the first neighbor object of the comparison | 1850 | * @neigh1: the first neighbor object of the comparison |
| 1851 | * @if_outgoing1: outgoing interface for the first neighbor | ||
| 1604 | * @neigh2: the second neighbor object of the comparison | 1852 | * @neigh2: the second neighbor object of the comparison |
| 1853 | * @if_outgoing2: outgoing interface for the second neighbor | ||
| 1605 | * | 1854 | * |
| 1606 | * Returns a value less, equal to or greater than 0 if the metric via neigh1 is | 1855 | * Returns a value less, equal to or greater than 0 if the metric via neigh1 is |
| 1607 | * lower, the same as or higher than the metric via neigh2 | 1856 | * lower, the same as or higher than the metric via neigh2 |
| 1608 | */ | 1857 | */ |
| 1609 | static int batadv_iv_ogm_neigh_cmp(struct batadv_neigh_node *neigh1, | 1858 | static int batadv_iv_ogm_neigh_cmp(struct batadv_neigh_node *neigh1, |
| 1610 | struct batadv_neigh_node *neigh2) | 1859 | struct batadv_hard_iface *if_outgoing1, |
| 1860 | struct batadv_neigh_node *neigh2, | ||
| 1861 | struct batadv_hard_iface *if_outgoing2) | ||
| 1611 | { | 1862 | { |
| 1863 | struct batadv_neigh_ifinfo *neigh1_ifinfo, *neigh2_ifinfo; | ||
| 1612 | uint8_t tq1, tq2; | 1864 | uint8_t tq1, tq2; |
| 1865 | int diff; | ||
| 1866 | |||
| 1867 | neigh1_ifinfo = batadv_neigh_ifinfo_get(neigh1, if_outgoing1); | ||
| 1868 | neigh2_ifinfo = batadv_neigh_ifinfo_get(neigh2, if_outgoing2); | ||
| 1869 | |||
| 1870 | if (!neigh1_ifinfo || !neigh2_ifinfo) { | ||
| 1871 | diff = 0; | ||
| 1872 | goto out; | ||
| 1873 | } | ||
| 1874 | |||
| 1875 | tq1 = neigh1_ifinfo->bat_iv.tq_avg; | ||
| 1876 | tq2 = neigh2_ifinfo->bat_iv.tq_avg; | ||
| 1877 | diff = tq1 - tq2; | ||
| 1613 | 1878 | ||
| 1614 | tq1 = neigh1->bat_iv.tq_avg; | 1879 | out: |
| 1615 | tq2 = neigh2->bat_iv.tq_avg; | 1880 | if (neigh1_ifinfo) |
| 1881 | batadv_neigh_ifinfo_free_ref(neigh1_ifinfo); | ||
| 1882 | if (neigh2_ifinfo) | ||
| 1883 | batadv_neigh_ifinfo_free_ref(neigh2_ifinfo); | ||
| 1616 | 1884 | ||
| 1617 | return tq1 - tq2; | 1885 | return diff; |
| 1618 | } | 1886 | } |
| 1619 | 1887 | ||
| 1620 | /** | 1888 | /** |
| 1621 | * batadv_iv_ogm_neigh_is_eob - check if neigh1 is equally good or better than | 1889 | * batadv_iv_ogm_neigh_is_eob - check if neigh1 is equally good or better than |
| 1622 | * neigh2 from the metric prospective | 1890 | * neigh2 from the metric prospective |
| 1623 | * @neigh1: the first neighbor object of the comparison | 1891 | * @neigh1: the first neighbor object of the comparison |
| 1892 | * @if_outgoing: outgoing interface for the first neighbor | ||
| 1624 | * @neigh2: the second neighbor object of the comparison | 1893 | * @neigh2: the second neighbor object of the comparison |
| 1625 | * | 1894 | * @if_outgoing2: outgoing interface for the second neighbor |
| 1626 | * Returns true if the metric via neigh1 is equally good or better than the | 1895 | |
| 1627 | * metric via neigh2, false otherwise. | 1896 | * Returns true if the metric via neigh1 is equally good or better than |
| 1897 | * the metric via neigh2, false otherwise. | ||
| 1628 | */ | 1898 | */ |
| 1629 | static bool batadv_iv_ogm_neigh_is_eob(struct batadv_neigh_node *neigh1, | 1899 | static bool |
| 1630 | struct batadv_neigh_node *neigh2) | 1900 | batadv_iv_ogm_neigh_is_eob(struct batadv_neigh_node *neigh1, |
| 1901 | struct batadv_hard_iface *if_outgoing1, | ||
| 1902 | struct batadv_neigh_node *neigh2, | ||
| 1903 | struct batadv_hard_iface *if_outgoing2) | ||
| 1631 | { | 1904 | { |
| 1632 | int diff = batadv_iv_ogm_neigh_cmp(neigh1, neigh2); | 1905 | struct batadv_neigh_ifinfo *neigh1_ifinfo, *neigh2_ifinfo; |
| 1906 | uint8_t tq1, tq2; | ||
| 1907 | bool ret; | ||
| 1633 | 1908 | ||
| 1634 | return diff > -BATADV_TQ_SIMILARITY_THRESHOLD; | 1909 | neigh1_ifinfo = batadv_neigh_ifinfo_get(neigh1, if_outgoing1); |
| 1910 | neigh2_ifinfo = batadv_neigh_ifinfo_get(neigh2, if_outgoing2); | ||
| 1911 | |||
| 1912 | /* we can't say that the metric is better */ | ||
| 1913 | if (!neigh1_ifinfo || !neigh2_ifinfo) { | ||
| 1914 | ret = false; | ||
| 1915 | goto out; | ||
| 1916 | } | ||
| 1917 | |||
| 1918 | tq1 = neigh1_ifinfo->bat_iv.tq_avg; | ||
| 1919 | tq2 = neigh2_ifinfo->bat_iv.tq_avg; | ||
| 1920 | ret = (tq1 - tq2) > -BATADV_TQ_SIMILARITY_THRESHOLD; | ||
| 1921 | |||
| 1922 | out: | ||
| 1923 | if (neigh1_ifinfo) | ||
| 1924 | batadv_neigh_ifinfo_free_ref(neigh1_ifinfo); | ||
| 1925 | if (neigh2_ifinfo) | ||
| 1926 | batadv_neigh_ifinfo_free_ref(neigh2_ifinfo); | ||
| 1927 | |||
| 1928 | return ret; | ||
| 1635 | } | 1929 | } |
| 1636 | 1930 | ||
| 1637 | static struct batadv_algo_ops batadv_batman_iv __read_mostly = { | 1931 | static struct batadv_algo_ops batadv_batman_iv __read_mostly = { |
diff --git a/net/batman-adv/bitarray.c b/net/batman-adv/bitarray.c index 973982414d58..9586750022f5 100644 --- a/net/batman-adv/bitarray.c +++ b/net/batman-adv/bitarray.c | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* Copyright (C) 2006-2013 B.A.T.M.A.N. contributors: | 1 | /* Copyright (C) 2006-2014 B.A.T.M.A.N. contributors: |
| 2 | * | 2 | * |
| 3 | * Simon Wunderlich, Marek Lindner | 3 | * Simon Wunderlich, Marek Lindner |
| 4 | * | 4 | * |
| @@ -12,9 +12,7 @@ | |||
| 12 | * General Public License for more details. | 12 | * General Public License for more details. |
| 13 | * | 13 | * |
| 14 | * You should have received a copy of the GNU General Public License | 14 | * You should have received a copy of the GNU General Public License |
| 15 | * along with this program; if not, write to the Free Software | 15 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 17 | * 02110-1301, USA | ||
| 18 | */ | 16 | */ |
| 19 | 17 | ||
| 20 | #include "main.h" | 18 | #include "main.h" |
diff --git a/net/batman-adv/bitarray.h b/net/batman-adv/bitarray.h index a81b9322e382..cc2407351d36 100644 --- a/net/batman-adv/bitarray.h +++ b/net/batman-adv/bitarray.h | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* Copyright (C) 2006-2013 B.A.T.M.A.N. contributors: | 1 | /* Copyright (C) 2006-2014 B.A.T.M.A.N. contributors: |
| 2 | * | 2 | * |
| 3 | * Simon Wunderlich, Marek Lindner | 3 | * Simon Wunderlich, Marek Lindner |
| 4 | * | 4 | * |
| @@ -12,9 +12,7 @@ | |||
| 12 | * General Public License for more details. | 12 | * General Public License for more details. |
| 13 | * | 13 | * |
| 14 | * You should have received a copy of the GNU General Public License | 14 | * You should have received a copy of the GNU General Public License |
| 15 | * along with this program; if not, write to the Free Software | 15 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 17 | * 02110-1301, USA | ||
| 18 | */ | 16 | */ |
| 19 | 17 | ||
| 20 | #ifndef _NET_BATMAN_ADV_BITARRAY_H_ | 18 | #ifndef _NET_BATMAN_ADV_BITARRAY_H_ |
diff --git a/net/batman-adv/bridge_loop_avoidance.c b/net/batman-adv/bridge_loop_avoidance.c index 28eb5e6d0a02..05f0712be5e7 100644 --- a/net/batman-adv/bridge_loop_avoidance.c +++ b/net/batman-adv/bridge_loop_avoidance.c | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* Copyright (C) 2011-2013 B.A.T.M.A.N. contributors: | 1 | /* Copyright (C) 2011-2014 B.A.T.M.A.N. contributors: |
| 2 | * | 2 | * |
| 3 | * Simon Wunderlich | 3 | * Simon Wunderlich |
| 4 | * | 4 | * |
| @@ -12,9 +12,7 @@ | |||
| 12 | * General Public License for more details. | 12 | * General Public License for more details. |
| 13 | * | 13 | * |
| 14 | * You should have received a copy of the GNU General Public License | 14 | * You should have received a copy of the GNU General Public License |
| 15 | * along with this program; if not, write to the Free Software | 15 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 17 | * 02110-1301, USA | ||
| 18 | */ | 16 | */ |
| 19 | 17 | ||
| 20 | #include "main.h" | 18 | #include "main.h" |
| @@ -132,7 +130,9 @@ static void batadv_claim_free_ref(struct batadv_bla_claim *claim) | |||
| 132 | call_rcu(&claim->rcu, batadv_claim_free_rcu); | 130 | call_rcu(&claim->rcu, batadv_claim_free_rcu); |
| 133 | } | 131 | } |
| 134 | 132 | ||
| 135 | /* @bat_priv: the bat priv with all the soft interface information | 133 | /** |
| 134 | * batadv_claim_hash_find | ||
| 135 | * @bat_priv: the bat priv with all the soft interface information | ||
| 136 | * @data: search data (may be local/static data) | 136 | * @data: search data (may be local/static data) |
| 137 | * | 137 | * |
| 138 | * looks for a claim in the hash, and returns it if found | 138 | * looks for a claim in the hash, and returns it if found |
| @@ -451,7 +451,9 @@ batadv_bla_update_own_backbone_gw(struct batadv_priv *bat_priv, | |||
| 451 | batadv_backbone_gw_free_ref(backbone_gw); | 451 | batadv_backbone_gw_free_ref(backbone_gw); |
| 452 | } | 452 | } |
| 453 | 453 | ||
| 454 | /* @bat_priv: the bat priv with all the soft interface information | 454 | /** |
| 455 | * batadv_bla_answer_request - answer a bla request by sending own claims | ||
| 456 | * @bat_priv: the bat priv with all the soft interface information | ||
| 455 | * @vid: the vid where the request came on | 457 | * @vid: the vid where the request came on |
| 456 | * | 458 | * |
| 457 | * Repeat all of our own claims, and finally send an ANNOUNCE frame | 459 | * Repeat all of our own claims, and finally send an ANNOUNCE frame |
| @@ -497,7 +499,9 @@ static void batadv_bla_answer_request(struct batadv_priv *bat_priv, | |||
| 497 | batadv_backbone_gw_free_ref(backbone_gw); | 499 | batadv_backbone_gw_free_ref(backbone_gw); |
| 498 | } | 500 | } |
| 499 | 501 | ||
| 500 | /* @backbone_gw: the backbone gateway from whom we are out of sync | 502 | /** |
| 503 | * batadv_bla_send_request - send a request to repeat claims | ||
| 504 | * @backbone_gw: the backbone gateway from whom we are out of sync | ||
| 501 | * | 505 | * |
| 502 | * When the crc is wrong, ask the backbone gateway for a full table update. | 506 | * When the crc is wrong, ask the backbone gateway for a full table update. |
| 503 | * After the request, it will repeat all of his own claims and finally | 507 | * After the request, it will repeat all of his own claims and finally |
| @@ -522,7 +526,9 @@ static void batadv_bla_send_request(struct batadv_bla_backbone_gw *backbone_gw) | |||
| 522 | } | 526 | } |
| 523 | } | 527 | } |
| 524 | 528 | ||
| 525 | /* @bat_priv: the bat priv with all the soft interface information | 529 | /** |
| 530 | * batadv_bla_send_announce | ||
| 531 | * @bat_priv: the bat priv with all the soft interface information | ||
| 526 | * @backbone_gw: our backbone gateway which should be announced | 532 | * @backbone_gw: our backbone gateway which should be announced |
| 527 | * | 533 | * |
| 528 | * This function sends an announcement. It is called from multiple | 534 | * This function sends an announcement. It is called from multiple |
| @@ -846,7 +852,9 @@ static int batadv_check_claim_group(struct batadv_priv *bat_priv, | |||
| 846 | } | 852 | } |
| 847 | 853 | ||
| 848 | 854 | ||
| 849 | /* @bat_priv: the bat priv with all the soft interface information | 855 | /** |
| 856 | * batadv_bla_process_claim | ||
| 857 | * @bat_priv: the bat priv with all the soft interface information | ||
| 850 | * @skb: the frame to be checked | 858 | * @skb: the frame to be checked |
| 851 | * | 859 | * |
| 852 | * Check if this is a claim frame, and process it accordingly. | 860 | * Check if this is a claim frame, and process it accordingly. |
| @@ -1313,7 +1321,9 @@ out: | |||
| 1313 | 1321 | ||
| 1314 | 1322 | ||
| 1315 | 1323 | ||
| 1316 | /* @bat_priv: the bat priv with all the soft interface information | 1324 | /** |
| 1325 | * batadv_bla_is_backbone_gw_orig | ||
| 1326 | * @bat_priv: the bat priv with all the soft interface information | ||
| 1317 | * @orig: originator mac address | 1327 | * @orig: originator mac address |
| 1318 | * @vid: VLAN identifier | 1328 | * @vid: VLAN identifier |
| 1319 | * | 1329 | * |
diff --git a/net/batman-adv/bridge_loop_avoidance.h b/net/batman-adv/bridge_loop_avoidance.h index da173e760e77..43c985d92c3e 100644 --- a/net/batman-adv/bridge_loop_avoidance.h +++ b/net/batman-adv/bridge_loop_avoidance.h | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* Copyright (C) 2011-2013 B.A.T.M.A.N. contributors: | 1 | /* Copyright (C) 2011-2014 B.A.T.M.A.N. contributors: |
| 2 | * | 2 | * |
| 3 | * Simon Wunderlich | 3 | * Simon Wunderlich |
| 4 | * | 4 | * |
| @@ -12,9 +12,7 @@ | |||
| 12 | * General Public License for more details. | 12 | * General Public License for more details. |
| 13 | * | 13 | * |
| 14 | * You should have received a copy of the GNU General Public License | 14 | * You should have received a copy of the GNU General Public License |
| 15 | * along with this program; if not, write to the Free Software | 15 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 17 | * 02110-1301, USA | ||
| 18 | */ | 16 | */ |
| 19 | 17 | ||
| 20 | #ifndef _NET_BATMAN_ADV_BLA_H_ | 18 | #ifndef _NET_BATMAN_ADV_BLA_H_ |
diff --git a/net/batman-adv/debugfs.c b/net/batman-adv/debugfs.c index 049a7a2ac5b6..b758881be108 100644 --- a/net/batman-adv/debugfs.c +++ b/net/batman-adv/debugfs.c | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* Copyright (C) 2010-2013 B.A.T.M.A.N. contributors: | 1 | /* Copyright (C) 2010-2014 B.A.T.M.A.N. contributors: |
| 2 | * | 2 | * |
| 3 | * Marek Lindner | 3 | * Marek Lindner |
| 4 | * | 4 | * |
| @@ -12,9 +12,7 @@ | |||
| 12 | * General Public License for more details. | 12 | * General Public License for more details. |
| 13 | * | 13 | * |
| 14 | * You should have received a copy of the GNU General Public License | 14 | * You should have received a copy of the GNU General Public License |
| 15 | * along with this program; if not, write to the Free Software | 15 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 17 | * 02110-1301, USA | ||
| 18 | */ | 16 | */ |
| 19 | 17 | ||
| 20 | #include "main.h" | 18 | #include "main.h" |
| @@ -250,6 +248,19 @@ static int batadv_originators_open(struct inode *inode, struct file *file) | |||
| 250 | return single_open(file, batadv_orig_seq_print_text, net_dev); | 248 | return single_open(file, batadv_orig_seq_print_text, net_dev); |
| 251 | } | 249 | } |
| 252 | 250 | ||
| 251 | /** | ||
| 252 | * batadv_originators_hardif_open - handles debugfs output for the | ||
| 253 | * originator table of an hard interface | ||
| 254 | * @inode: inode pointer to debugfs file | ||
| 255 | * @file: pointer to the seq_file | ||
| 256 | */ | ||
| 257 | static int batadv_originators_hardif_open(struct inode *inode, | ||
| 258 | struct file *file) | ||
| 259 | { | ||
| 260 | struct net_device *net_dev = (struct net_device *)inode->i_private; | ||
| 261 | return single_open(file, batadv_orig_hardif_seq_print_text, net_dev); | ||
| 262 | } | ||
| 263 | |||
| 253 | static int batadv_gateways_open(struct inode *inode, struct file *file) | 264 | static int batadv_gateways_open(struct inode *inode, struct file *file) |
| 254 | { | 265 | { |
| 255 | struct net_device *net_dev = (struct net_device *)inode->i_private; | 266 | struct net_device *net_dev = (struct net_device *)inode->i_private; |
| @@ -371,6 +382,28 @@ static struct batadv_debuginfo *batadv_mesh_debuginfos[] = { | |||
| 371 | NULL, | 382 | NULL, |
| 372 | }; | 383 | }; |
| 373 | 384 | ||
| 385 | #define BATADV_HARDIF_DEBUGINFO(_name, _mode, _open) \ | ||
| 386 | struct batadv_debuginfo batadv_hardif_debuginfo_##_name = { \ | ||
| 387 | .attr = { \ | ||
| 388 | .name = __stringify(_name), \ | ||
| 389 | .mode = _mode, \ | ||
| 390 | }, \ | ||
| 391 | .fops = { \ | ||
| 392 | .owner = THIS_MODULE, \ | ||
| 393 | .open = _open, \ | ||
| 394 | .read = seq_read, \ | ||
| 395 | .llseek = seq_lseek, \ | ||
| 396 | .release = single_release, \ | ||
| 397 | }, \ | ||
| 398 | }; | ||
| 399 | static BATADV_HARDIF_DEBUGINFO(originators, S_IRUGO, | ||
| 400 | batadv_originators_hardif_open); | ||
| 401 | |||
| 402 | static struct batadv_debuginfo *batadv_hardif_debuginfos[] = { | ||
| 403 | &batadv_hardif_debuginfo_originators, | ||
| 404 | NULL, | ||
| 405 | }; | ||
| 406 | |||
| 374 | void batadv_debugfs_init(void) | 407 | void batadv_debugfs_init(void) |
| 375 | { | 408 | { |
| 376 | struct batadv_debuginfo **bat_debug; | 409 | struct batadv_debuginfo **bat_debug; |
| @@ -398,6 +431,7 @@ void batadv_debugfs_init(void) | |||
| 398 | return; | 431 | return; |
| 399 | err: | 432 | err: |
| 400 | debugfs_remove_recursive(batadv_debugfs); | 433 | debugfs_remove_recursive(batadv_debugfs); |
| 434 | batadv_debugfs = NULL; | ||
| 401 | } | 435 | } |
| 402 | 436 | ||
| 403 | void batadv_debugfs_destroy(void) | 437 | void batadv_debugfs_destroy(void) |
| @@ -406,6 +440,59 @@ void batadv_debugfs_destroy(void) | |||
| 406 | batadv_debugfs = NULL; | 440 | batadv_debugfs = NULL; |
| 407 | } | 441 | } |
| 408 | 442 | ||
| 443 | /** | ||
| 444 | * batadv_debugfs_add_hardif - creates the base directory for a hard interface | ||
| 445 | * in debugfs. | ||
| 446 | * @hard_iface: hard interface which should be added. | ||
| 447 | */ | ||
| 448 | int batadv_debugfs_add_hardif(struct batadv_hard_iface *hard_iface) | ||
| 449 | { | ||
| 450 | struct batadv_debuginfo **bat_debug; | ||
| 451 | struct dentry *file; | ||
| 452 | |||
| 453 | if (!batadv_debugfs) | ||
| 454 | goto out; | ||
| 455 | |||
| 456 | hard_iface->debug_dir = debugfs_create_dir(hard_iface->net_dev->name, | ||
| 457 | batadv_debugfs); | ||
| 458 | if (!hard_iface->debug_dir) | ||
| 459 | goto out; | ||
| 460 | |||
| 461 | for (bat_debug = batadv_hardif_debuginfos; *bat_debug; ++bat_debug) { | ||
| 462 | file = debugfs_create_file(((*bat_debug)->attr).name, | ||
| 463 | S_IFREG | ((*bat_debug)->attr).mode, | ||
| 464 | hard_iface->debug_dir, | ||
| 465 | hard_iface->net_dev, | ||
| 466 | &(*bat_debug)->fops); | ||
| 467 | if (!file) | ||
| 468 | goto rem_attr; | ||
| 469 | } | ||
| 470 | |||
| 471 | return 0; | ||
| 472 | rem_attr: | ||
| 473 | debugfs_remove_recursive(hard_iface->debug_dir); | ||
| 474 | hard_iface->debug_dir = NULL; | ||
| 475 | out: | ||
| 476 | #ifdef CONFIG_DEBUG_FS | ||
| 477 | return -ENOMEM; | ||
| 478 | #else | ||
| 479 | return 0; | ||
| 480 | #endif /* CONFIG_DEBUG_FS */ | ||
| 481 | } | ||
| 482 | |||
| 483 | /** | ||
| 484 | * batadv_debugfs_del_hardif - delete the base directory for a hard interface | ||
| 485 | * in debugfs. | ||
| 486 | * @hard_iface: hard interface which is deleted. | ||
| 487 | */ | ||
| 488 | void batadv_debugfs_del_hardif(struct batadv_hard_iface *hard_iface) | ||
| 489 | { | ||
| 490 | if (batadv_debugfs) { | ||
| 491 | debugfs_remove_recursive(hard_iface->debug_dir); | ||
| 492 | hard_iface->debug_dir = NULL; | ||
| 493 | } | ||
| 494 | } | ||
| 495 | |||
| 409 | int batadv_debugfs_add_meshif(struct net_device *dev) | 496 | int batadv_debugfs_add_meshif(struct net_device *dev) |
| 410 | { | 497 | { |
| 411 | struct batadv_priv *bat_priv = netdev_priv(dev); | 498 | struct batadv_priv *bat_priv = netdev_priv(dev); |
diff --git a/net/batman-adv/debugfs.h b/net/batman-adv/debugfs.h index f8c3849edff4..37c4d6ddd04d 100644 --- a/net/batman-adv/debugfs.h +++ b/net/batman-adv/debugfs.h | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* Copyright (C) 2010-2013 B.A.T.M.A.N. contributors: | 1 | /* Copyright (C) 2010-2014 B.A.T.M.A.N. contributors: |
| 2 | * | 2 | * |
| 3 | * Marek Lindner | 3 | * Marek Lindner |
| 4 | * | 4 | * |
| @@ -12,9 +12,7 @@ | |||
| 12 | * General Public License for more details. | 12 | * General Public License for more details. |
| 13 | * | 13 | * |
| 14 | * You should have received a copy of the GNU General Public License | 14 | * You should have received a copy of the GNU General Public License |
| 15 | * along with this program; if not, write to the Free Software | 15 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 17 | * 02110-1301, USA | ||
| 18 | */ | 16 | */ |
| 19 | 17 | ||
| 20 | #ifndef _NET_BATMAN_ADV_DEBUGFS_H_ | 18 | #ifndef _NET_BATMAN_ADV_DEBUGFS_H_ |
| @@ -26,5 +24,7 @@ void batadv_debugfs_init(void); | |||
| 26 | void batadv_debugfs_destroy(void); | 24 | void batadv_debugfs_destroy(void); |
| 27 | int batadv_debugfs_add_meshif(struct net_device *dev); | 25 | int batadv_debugfs_add_meshif(struct net_device *dev); |
| 28 | void batadv_debugfs_del_meshif(struct net_device *dev); | 26 | void batadv_debugfs_del_meshif(struct net_device *dev); |
| 27 | int batadv_debugfs_add_hardif(struct batadv_hard_iface *hard_iface); | ||
| 28 | void batadv_debugfs_del_hardif(struct batadv_hard_iface *hard_iface); | ||
| 29 | 29 | ||
| 30 | #endif /* _NET_BATMAN_ADV_DEBUGFS_H_ */ | 30 | #endif /* _NET_BATMAN_ADV_DEBUGFS_H_ */ |
diff --git a/net/batman-adv/distributed-arp-table.c b/net/batman-adv/distributed-arp-table.c index b316a4cb6f14..edee50411892 100644 --- a/net/batman-adv/distributed-arp-table.c +++ b/net/batman-adv/distributed-arp-table.c | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* Copyright (C) 2011-2013 B.A.T.M.A.N. contributors: | 1 | /* Copyright (C) 2011-2014 B.A.T.M.A.N. contributors: |
| 2 | * | 2 | * |
| 3 | * Antonio Quartulli | 3 | * Antonio Quartulli |
| 4 | * | 4 | * |
| @@ -12,9 +12,7 @@ | |||
| 12 | * General Public License for more details. | 12 | * General Public License for more details. |
| 13 | * | 13 | * |
| 14 | * You should have received a copy of the GNU General Public License | 14 | * You should have received a copy of the GNU General Public License |
| 15 | * along with this program; if not, write to the Free Software | 15 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 17 | * 02110-1301, USA | ||
| 18 | */ | 16 | */ |
| 19 | 17 | ||
| 20 | #include <linux/if_ether.h> | 18 | #include <linux/if_ether.h> |
| @@ -141,7 +139,7 @@ static int batadv_compare_dat(const struct hlist_node *node, const void *data2) | |||
| 141 | const void *data1 = container_of(node, struct batadv_dat_entry, | 139 | const void *data1 = container_of(node, struct batadv_dat_entry, |
| 142 | hash_entry); | 140 | hash_entry); |
| 143 | 141 | ||
| 144 | return (memcmp(data1, data2, sizeof(__be32)) == 0 ? 1 : 0); | 142 | return memcmp(data1, data2, sizeof(__be32)) == 0 ? 1 : 0; |
| 145 | } | 143 | } |
| 146 | 144 | ||
| 147 | /** | 145 | /** |
| @@ -591,7 +589,8 @@ static bool batadv_dat_send_data(struct batadv_priv *bat_priv, | |||
| 591 | if (cand[i].type == BATADV_DAT_CANDIDATE_NOT_FOUND) | 589 | if (cand[i].type == BATADV_DAT_CANDIDATE_NOT_FOUND) |
| 592 | continue; | 590 | continue; |
| 593 | 591 | ||
| 594 | neigh_node = batadv_orig_node_get_router(cand[i].orig_node); | 592 | neigh_node = batadv_orig_router_get(cand[i].orig_node, |
| 593 | BATADV_IF_DEFAULT); | ||
| 595 | if (!neigh_node) | 594 | if (!neigh_node) |
| 596 | goto free_orig; | 595 | goto free_orig; |
| 597 | 596 | ||
| @@ -1039,9 +1038,9 @@ bool batadv_dat_snoop_incoming_arp_request(struct batadv_priv *bat_priv, | |||
| 1039 | if (hdr_size == sizeof(struct batadv_unicast_4addr_packet)) | 1038 | if (hdr_size == sizeof(struct batadv_unicast_4addr_packet)) |
| 1040 | err = batadv_send_skb_via_tt_4addr(bat_priv, skb_new, | 1039 | err = batadv_send_skb_via_tt_4addr(bat_priv, skb_new, |
| 1041 | BATADV_P_DAT_CACHE_REPLY, | 1040 | BATADV_P_DAT_CACHE_REPLY, |
| 1042 | vid); | 1041 | NULL, vid); |
| 1043 | else | 1042 | else |
| 1044 | err = batadv_send_skb_via_tt(bat_priv, skb_new, vid); | 1043 | err = batadv_send_skb_via_tt(bat_priv, skb_new, NULL, vid); |
| 1045 | 1044 | ||
| 1046 | if (err != NET_XMIT_DROP) { | 1045 | if (err != NET_XMIT_DROP) { |
| 1047 | batadv_inc_counter(bat_priv, BATADV_CNT_DAT_CACHED_REPLY_TX); | 1046 | batadv_inc_counter(bat_priv, BATADV_CNT_DAT_CACHED_REPLY_TX); |
diff --git a/net/batman-adv/distributed-arp-table.h b/net/batman-adv/distributed-arp-table.h index 60d853beb8d8..ac9be9b67a25 100644 --- a/net/batman-adv/distributed-arp-table.h +++ b/net/batman-adv/distributed-arp-table.h | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* Copyright (C) 2011-2013 B.A.T.M.A.N. contributors: | 1 | /* Copyright (C) 2011-2014 B.A.T.M.A.N. contributors: |
| 2 | * | 2 | * |
| 3 | * Antonio Quartulli | 3 | * Antonio Quartulli |
| 4 | * | 4 | * |
| @@ -12,13 +12,11 @@ | |||
| 12 | * General Public License for more details. | 12 | * General Public License for more details. |
| 13 | * | 13 | * |
| 14 | * You should have received a copy of the GNU General Public License | 14 | * You should have received a copy of the GNU General Public License |
| 15 | * along with this program; if not, write to the Free Software | 15 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 17 | * 02110-1301, USA | ||
| 18 | */ | 16 | */ |
| 19 | 17 | ||
| 20 | #ifndef _NET_BATMAN_ADV_ARP_H_ | 18 | #ifndef _NET_BATMAN_ADV_DISTRIBUTED_ARP_TABLE_H_ |
| 21 | #define _NET_BATMAN_ADV_ARP_H_ | 19 | #define _NET_BATMAN_ADV_DISTRIBUTED_ARP_TABLE_H_ |
| 22 | 20 | ||
| 23 | #ifdef CONFIG_BATMAN_ADV_DAT | 21 | #ifdef CONFIG_BATMAN_ADV_DAT |
| 24 | 22 | ||
| @@ -169,4 +167,4 @@ static inline void batadv_dat_inc_counter(struct batadv_priv *bat_priv, | |||
| 169 | 167 | ||
| 170 | #endif /* CONFIG_BATMAN_ADV_DAT */ | 168 | #endif /* CONFIG_BATMAN_ADV_DAT */ |
| 171 | 169 | ||
| 172 | #endif /* _NET_BATMAN_ADV_ARP_H_ */ | 170 | #endif /* _NET_BATMAN_ADV_DISTRIBUTED_ARP_TABLE_H_ */ |
diff --git a/net/batman-adv/fragmentation.c b/net/batman-adv/fragmentation.c index 6ddb6145ffb5..88df9b1d552d 100644 --- a/net/batman-adv/fragmentation.c +++ b/net/batman-adv/fragmentation.c | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* Copyright (C) 2013 B.A.T.M.A.N. contributors: | 1 | /* Copyright (C) 2013-2014 B.A.T.M.A.N. contributors: |
| 2 | * | 2 | * |
| 3 | * Martin Hundebøll <martin@hundeboll.net> | 3 | * Martin Hundebøll <martin@hundeboll.net> |
| 4 | * | 4 | * |
| @@ -12,9 +12,7 @@ | |||
| 12 | * General Public License for more details. | 12 | * General Public License for more details. |
| 13 | * | 13 | * |
| 14 | * You should have received a copy of the GNU General Public License | 14 | * You should have received a copy of the GNU General Public License |
| 15 | * along with this program; if not, write to the Free Software | 15 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 17 | * 02110-1301, USA | ||
| 18 | */ | 16 | */ |
| 19 | 17 | ||
| 20 | #include "main.h" | 18 | #include "main.h" |
diff --git a/net/batman-adv/fragmentation.h b/net/batman-adv/fragmentation.h index ca029e2676e7..5d7a0e66a22b 100644 --- a/net/batman-adv/fragmentation.h +++ b/net/batman-adv/fragmentation.h | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* Copyright (C) 2013 B.A.T.M.A.N. contributors: | 1 | /* Copyright (C) 2013-2014 B.A.T.M.A.N. contributors: |
| 2 | * | 2 | * |
| 3 | * Martin Hundebøll <martin@hundeboll.net> | 3 | * Martin Hundebøll <martin@hundeboll.net> |
| 4 | * | 4 | * |
| @@ -12,9 +12,7 @@ | |||
| 12 | * General Public License for more details. | 12 | * General Public License for more details. |
| 13 | * | 13 | * |
| 14 | * You should have received a copy of the GNU General Public License | 14 | * You should have received a copy of the GNU General Public License |
| 15 | * along with this program; if not, write to the Free Software | 15 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 17 | * 02110-1301, USA | ||
| 18 | */ | 16 | */ |
| 19 | 17 | ||
| 20 | #ifndef _NET_BATMAN_ADV_FRAGMENTATION_H_ | 18 | #ifndef _NET_BATMAN_ADV_FRAGMENTATION_H_ |
diff --git a/net/batman-adv/gateway_client.c b/net/batman-adv/gateway_client.c index 2449afaa7638..55cf2260d295 100644 --- a/net/batman-adv/gateway_client.c +++ b/net/batman-adv/gateway_client.c | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* Copyright (C) 2009-2013 B.A.T.M.A.N. contributors: | 1 | /* Copyright (C) 2009-2014 B.A.T.M.A.N. contributors: |
| 2 | * | 2 | * |
| 3 | * Marek Lindner | 3 | * Marek Lindner |
| 4 | * | 4 | * |
| @@ -12,9 +12,7 @@ | |||
| 12 | * General Public License for more details. | 12 | * General Public License for more details. |
| 13 | * | 13 | * |
| 14 | * You should have received a copy of the GNU General Public License | 14 | * You should have received a copy of the GNU General Public License |
| 15 | * along with this program; if not, write to the Free Software | 15 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 17 | * 02110-1301, USA | ||
| 18 | */ | 16 | */ |
| 19 | 17 | ||
| 20 | #include "main.h" | 18 | #include "main.h" |
| @@ -30,11 +28,17 @@ | |||
| 30 | #include <linux/udp.h> | 28 | #include <linux/udp.h> |
| 31 | #include <linux/if_vlan.h> | 29 | #include <linux/if_vlan.h> |
| 32 | 30 | ||
| 33 | /* This is the offset of the options field in a dhcp packet starting at | 31 | /* These are the offsets of the "hw type" and "hw address length" in the dhcp |
| 34 | * the beginning of the dhcp header | 32 | * packet starting at the beginning of the dhcp header |
| 35 | */ | 33 | */ |
| 36 | #define BATADV_DHCP_OPTIONS_OFFSET 240 | 34 | #define BATADV_DHCP_HTYPE_OFFSET 1 |
| 37 | #define BATADV_DHCP_REQUEST 3 | 35 | #define BATADV_DHCP_HLEN_OFFSET 2 |
| 36 | /* Value of htype representing Ethernet */ | ||
| 37 | #define BATADV_DHCP_HTYPE_ETHERNET 0x01 | ||
| 38 | /* This is the offset of the "chaddr" field in the dhcp packet starting at the | ||
| 39 | * beginning of the dhcp header | ||
| 40 | */ | ||
| 41 | #define BATADV_DHCP_CHADDR_OFFSET 28 | ||
| 38 | 42 | ||
| 39 | static void batadv_gw_node_free_ref(struct batadv_gw_node *gw_node) | 43 | static void batadv_gw_node_free_ref(struct batadv_gw_node *gw_node) |
| 40 | { | 44 | { |
| @@ -105,7 +109,18 @@ static void batadv_gw_select(struct batadv_priv *bat_priv, | |||
| 105 | spin_unlock_bh(&bat_priv->gw.list_lock); | 109 | spin_unlock_bh(&bat_priv->gw.list_lock); |
| 106 | } | 110 | } |
| 107 | 111 | ||
| 108 | void batadv_gw_deselect(struct batadv_priv *bat_priv) | 112 | /** |
| 113 | * batadv_gw_reselect - force a gateway reselection | ||
| 114 | * @bat_priv: the bat priv with all the soft interface information | ||
| 115 | * | ||
| 116 | * Set a flag to remind the GW component to perform a new gateway reselection. | ||
| 117 | * However this function does not ensure that the current gateway is going to be | ||
| 118 | * deselected. The reselection mechanism may elect the same gateway once again. | ||
| 119 | * | ||
| 120 | * This means that invoking batadv_gw_reselect() does not guarantee a gateway | ||
| 121 | * change and therefore a uevent is not necessarily expected. | ||
| 122 | */ | ||
| 123 | void batadv_gw_reselect(struct batadv_priv *bat_priv) | ||
| 109 | { | 124 | { |
| 110 | atomic_set(&bat_priv->gw.reselect, 1); | 125 | atomic_set(&bat_priv->gw.reselect, 1); |
| 111 | } | 126 | } |
| @@ -114,6 +129,7 @@ static struct batadv_gw_node * | |||
| 114 | batadv_gw_get_best_gw_node(struct batadv_priv *bat_priv) | 129 | batadv_gw_get_best_gw_node(struct batadv_priv *bat_priv) |
| 115 | { | 130 | { |
| 116 | struct batadv_neigh_node *router; | 131 | struct batadv_neigh_node *router; |
| 132 | struct batadv_neigh_ifinfo *router_ifinfo; | ||
| 117 | struct batadv_gw_node *gw_node, *curr_gw = NULL; | 133 | struct batadv_gw_node *gw_node, *curr_gw = NULL; |
| 118 | uint32_t max_gw_factor = 0, tmp_gw_factor = 0; | 134 | uint32_t max_gw_factor = 0, tmp_gw_factor = 0; |
| 119 | uint32_t gw_divisor; | 135 | uint32_t gw_divisor; |
| @@ -130,14 +146,19 @@ batadv_gw_get_best_gw_node(struct batadv_priv *bat_priv) | |||
| 130 | continue; | 146 | continue; |
| 131 | 147 | ||
| 132 | orig_node = gw_node->orig_node; | 148 | orig_node = gw_node->orig_node; |
| 133 | router = batadv_orig_node_get_router(orig_node); | 149 | router = batadv_orig_router_get(orig_node, BATADV_IF_DEFAULT); |
| 134 | if (!router) | 150 | if (!router) |
| 135 | continue; | 151 | continue; |
| 136 | 152 | ||
| 153 | router_ifinfo = batadv_neigh_ifinfo_get(router, | ||
| 154 | BATADV_IF_DEFAULT); | ||
| 155 | if (!router_ifinfo) | ||
| 156 | goto next; | ||
| 157 | |||
| 137 | if (!atomic_inc_not_zero(&gw_node->refcount)) | 158 | if (!atomic_inc_not_zero(&gw_node->refcount)) |
| 138 | goto next; | 159 | goto next; |
| 139 | 160 | ||
| 140 | tq_avg = router->bat_iv.tq_avg; | 161 | tq_avg = router_ifinfo->bat_iv.tq_avg; |
| 141 | 162 | ||
| 142 | switch (atomic_read(&bat_priv->gw_sel_class)) { | 163 | switch (atomic_read(&bat_priv->gw_sel_class)) { |
| 143 | case 1: /* fast connection */ | 164 | case 1: /* fast connection */ |
| @@ -182,6 +203,8 @@ batadv_gw_get_best_gw_node(struct batadv_priv *bat_priv) | |||
| 182 | 203 | ||
| 183 | next: | 204 | next: |
| 184 | batadv_neigh_node_free_ref(router); | 205 | batadv_neigh_node_free_ref(router); |
| 206 | if (router_ifinfo) | ||
| 207 | batadv_neigh_ifinfo_free_ref(router_ifinfo); | ||
| 185 | } | 208 | } |
| 186 | rcu_read_unlock(); | 209 | rcu_read_unlock(); |
| 187 | 210 | ||
| @@ -207,6 +230,11 @@ void batadv_gw_check_client_stop(struct batadv_priv *bat_priv) | |||
| 207 | if (!curr_gw) | 230 | if (!curr_gw) |
| 208 | return; | 231 | return; |
| 209 | 232 | ||
| 233 | /* deselect the current gateway so that next time that client mode is | ||
| 234 | * enabled a proper GW_ADD event can be sent | ||
| 235 | */ | ||
| 236 | batadv_gw_select(bat_priv, NULL); | ||
| 237 | |||
| 210 | /* if batman-adv is switching the gw client mode off and a gateway was | 238 | /* if batman-adv is switching the gw client mode off and a gateway was |
| 211 | * already selected, send a DEL uevent | 239 | * already selected, send a DEL uevent |
| 212 | */ | 240 | */ |
| @@ -219,6 +247,7 @@ void batadv_gw_election(struct batadv_priv *bat_priv) | |||
| 219 | { | 247 | { |
| 220 | struct batadv_gw_node *curr_gw = NULL, *next_gw = NULL; | 248 | struct batadv_gw_node *curr_gw = NULL, *next_gw = NULL; |
| 221 | struct batadv_neigh_node *router = NULL; | 249 | struct batadv_neigh_node *router = NULL; |
| 250 | struct batadv_neigh_ifinfo *router_ifinfo = NULL; | ||
| 222 | char gw_addr[18] = { '\0' }; | 251 | char gw_addr[18] = { '\0' }; |
| 223 | 252 | ||
| 224 | if (atomic_read(&bat_priv->gw_mode) != BATADV_GW_MODE_CLIENT) | 253 | if (atomic_read(&bat_priv->gw_mode) != BATADV_GW_MODE_CLIENT) |
| @@ -237,9 +266,17 @@ void batadv_gw_election(struct batadv_priv *bat_priv) | |||
| 237 | if (next_gw) { | 266 | if (next_gw) { |
| 238 | sprintf(gw_addr, "%pM", next_gw->orig_node->orig); | 267 | sprintf(gw_addr, "%pM", next_gw->orig_node->orig); |
| 239 | 268 | ||
| 240 | router = batadv_orig_node_get_router(next_gw->orig_node); | 269 | router = batadv_orig_router_get(next_gw->orig_node, |
| 270 | BATADV_IF_DEFAULT); | ||
| 241 | if (!router) { | 271 | if (!router) { |
| 242 | batadv_gw_deselect(bat_priv); | 272 | batadv_gw_reselect(bat_priv); |
| 273 | goto out; | ||
| 274 | } | ||
| 275 | |||
| 276 | router_ifinfo = batadv_neigh_ifinfo_get(router, | ||
| 277 | BATADV_IF_DEFAULT); | ||
| 278 | if (!router_ifinfo) { | ||
| 279 | batadv_gw_reselect(bat_priv); | ||
| 243 | goto out; | 280 | goto out; |
| 244 | } | 281 | } |
| 245 | } | 282 | } |
| @@ -256,7 +293,8 @@ void batadv_gw_election(struct batadv_priv *bat_priv) | |||
| 256 | next_gw->bandwidth_down / 10, | 293 | next_gw->bandwidth_down / 10, |
| 257 | next_gw->bandwidth_down % 10, | 294 | next_gw->bandwidth_down % 10, |
| 258 | next_gw->bandwidth_up / 10, | 295 | next_gw->bandwidth_up / 10, |
| 259 | next_gw->bandwidth_up % 10, router->bat_iv.tq_avg); | 296 | next_gw->bandwidth_up % 10, |
| 297 | router_ifinfo->bat_iv.tq_avg); | ||
| 260 | batadv_throw_uevent(bat_priv, BATADV_UEV_GW, BATADV_UEV_ADD, | 298 | batadv_throw_uevent(bat_priv, BATADV_UEV_GW, BATADV_UEV_ADD, |
| 261 | gw_addr); | 299 | gw_addr); |
| 262 | } else { | 300 | } else { |
| @@ -266,7 +304,8 @@ void batadv_gw_election(struct batadv_priv *bat_priv) | |||
| 266 | next_gw->bandwidth_down / 10, | 304 | next_gw->bandwidth_down / 10, |
| 267 | next_gw->bandwidth_down % 10, | 305 | next_gw->bandwidth_down % 10, |
| 268 | next_gw->bandwidth_up / 10, | 306 | next_gw->bandwidth_up / 10, |
| 269 | next_gw->bandwidth_up % 10, router->bat_iv.tq_avg); | 307 | next_gw->bandwidth_up % 10, |
| 308 | router_ifinfo->bat_iv.tq_avg); | ||
| 270 | batadv_throw_uevent(bat_priv, BATADV_UEV_GW, BATADV_UEV_CHANGE, | 309 | batadv_throw_uevent(bat_priv, BATADV_UEV_GW, BATADV_UEV_CHANGE, |
| 271 | gw_addr); | 310 | gw_addr); |
| 272 | } | 311 | } |
| @@ -280,33 +319,47 @@ out: | |||
| 280 | batadv_gw_node_free_ref(next_gw); | 319 | batadv_gw_node_free_ref(next_gw); |
| 281 | if (router) | 320 | if (router) |
| 282 | batadv_neigh_node_free_ref(router); | 321 | batadv_neigh_node_free_ref(router); |
| 322 | if (router_ifinfo) | ||
| 323 | batadv_neigh_ifinfo_free_ref(router_ifinfo); | ||
| 283 | } | 324 | } |
| 284 | 325 | ||
| 285 | void batadv_gw_check_election(struct batadv_priv *bat_priv, | 326 | void batadv_gw_check_election(struct batadv_priv *bat_priv, |
| 286 | struct batadv_orig_node *orig_node) | 327 | struct batadv_orig_node *orig_node) |
| 287 | { | 328 | { |
| 329 | struct batadv_neigh_ifinfo *router_orig_tq = NULL; | ||
| 330 | struct batadv_neigh_ifinfo *router_gw_tq = NULL; | ||
| 288 | struct batadv_orig_node *curr_gw_orig; | 331 | struct batadv_orig_node *curr_gw_orig; |
| 289 | struct batadv_neigh_node *router_gw = NULL, *router_orig = NULL; | 332 | struct batadv_neigh_node *router_gw = NULL, *router_orig = NULL; |
| 290 | uint8_t gw_tq_avg, orig_tq_avg; | 333 | uint8_t gw_tq_avg, orig_tq_avg; |
| 291 | 334 | ||
| 292 | curr_gw_orig = batadv_gw_get_selected_orig(bat_priv); | 335 | curr_gw_orig = batadv_gw_get_selected_orig(bat_priv); |
| 293 | if (!curr_gw_orig) | 336 | if (!curr_gw_orig) |
| 294 | goto deselect; | 337 | goto reselect; |
| 295 | 338 | ||
| 296 | router_gw = batadv_orig_node_get_router(curr_gw_orig); | 339 | router_gw = batadv_orig_router_get(curr_gw_orig, BATADV_IF_DEFAULT); |
| 297 | if (!router_gw) | 340 | if (!router_gw) |
| 298 | goto deselect; | 341 | goto reselect; |
| 342 | |||
| 343 | router_gw_tq = batadv_neigh_ifinfo_get(router_gw, | ||
| 344 | BATADV_IF_DEFAULT); | ||
| 345 | if (!router_gw_tq) | ||
| 346 | goto reselect; | ||
| 299 | 347 | ||
| 300 | /* this node already is the gateway */ | 348 | /* this node already is the gateway */ |
| 301 | if (curr_gw_orig == orig_node) | 349 | if (curr_gw_orig == orig_node) |
| 302 | goto out; | 350 | goto out; |
| 303 | 351 | ||
| 304 | router_orig = batadv_orig_node_get_router(orig_node); | 352 | router_orig = batadv_orig_router_get(orig_node, BATADV_IF_DEFAULT); |
| 305 | if (!router_orig) | 353 | if (!router_orig) |
| 306 | goto out; | 354 | goto out; |
| 307 | 355 | ||
| 308 | gw_tq_avg = router_gw->bat_iv.tq_avg; | 356 | router_orig_tq = batadv_neigh_ifinfo_get(router_orig, |
| 309 | orig_tq_avg = router_orig->bat_iv.tq_avg; | 357 | BATADV_IF_DEFAULT); |
| 358 | if (!router_orig_tq) | ||
| 359 | goto out; | ||
| 360 | |||
| 361 | gw_tq_avg = router_gw_tq->bat_iv.tq_avg; | ||
| 362 | orig_tq_avg = router_orig_tq->bat_iv.tq_avg; | ||
| 310 | 363 | ||
| 311 | /* the TQ value has to be better */ | 364 | /* the TQ value has to be better */ |
| 312 | if (orig_tq_avg < gw_tq_avg) | 365 | if (orig_tq_avg < gw_tq_avg) |
| @@ -323,8 +376,8 @@ void batadv_gw_check_election(struct batadv_priv *bat_priv, | |||
| 323 | "Restarting gateway selection: better gateway found (tq curr: %i, tq new: %i)\n", | 376 | "Restarting gateway selection: better gateway found (tq curr: %i, tq new: %i)\n", |
| 324 | gw_tq_avg, orig_tq_avg); | 377 | gw_tq_avg, orig_tq_avg); |
| 325 | 378 | ||
| 326 | deselect: | 379 | reselect: |
| 327 | batadv_gw_deselect(bat_priv); | 380 | batadv_gw_reselect(bat_priv); |
| 328 | out: | 381 | out: |
| 329 | if (curr_gw_orig) | 382 | if (curr_gw_orig) |
| 330 | batadv_orig_node_free_ref(curr_gw_orig); | 383 | batadv_orig_node_free_ref(curr_gw_orig); |
| @@ -332,6 +385,10 @@ out: | |||
| 332 | batadv_neigh_node_free_ref(router_gw); | 385 | batadv_neigh_node_free_ref(router_gw); |
| 333 | if (router_orig) | 386 | if (router_orig) |
| 334 | batadv_neigh_node_free_ref(router_orig); | 387 | batadv_neigh_node_free_ref(router_orig); |
| 388 | if (router_gw_tq) | ||
| 389 | batadv_neigh_ifinfo_free_ref(router_gw_tq); | ||
| 390 | if (router_orig_tq) | ||
| 391 | batadv_neigh_ifinfo_free_ref(router_orig_tq); | ||
| 335 | 392 | ||
| 336 | return; | 393 | return; |
| 337 | } | 394 | } |
| @@ -454,7 +511,7 @@ void batadv_gw_node_update(struct batadv_priv *bat_priv, | |||
| 454 | */ | 511 | */ |
| 455 | curr_gw = batadv_gw_get_selected_gw_node(bat_priv); | 512 | curr_gw = batadv_gw_get_selected_gw_node(bat_priv); |
| 456 | if (gw_node == curr_gw) | 513 | if (gw_node == curr_gw) |
| 457 | batadv_gw_deselect(bat_priv); | 514 | batadv_gw_reselect(bat_priv); |
| 458 | } | 515 | } |
| 459 | 516 | ||
| 460 | out: | 517 | out: |
| @@ -480,7 +537,7 @@ void batadv_gw_node_purge(struct batadv_priv *bat_priv) | |||
| 480 | struct batadv_gw_node *gw_node, *curr_gw; | 537 | struct batadv_gw_node *gw_node, *curr_gw; |
| 481 | struct hlist_node *node_tmp; | 538 | struct hlist_node *node_tmp; |
| 482 | unsigned long timeout = msecs_to_jiffies(2 * BATADV_PURGE_TIMEOUT); | 539 | unsigned long timeout = msecs_to_jiffies(2 * BATADV_PURGE_TIMEOUT); |
| 483 | int do_deselect = 0; | 540 | int do_reselect = 0; |
| 484 | 541 | ||
| 485 | curr_gw = batadv_gw_get_selected_gw_node(bat_priv); | 542 | curr_gw = batadv_gw_get_selected_gw_node(bat_priv); |
| 486 | 543 | ||
| @@ -494,7 +551,7 @@ void batadv_gw_node_purge(struct batadv_priv *bat_priv) | |||
| 494 | continue; | 551 | continue; |
| 495 | 552 | ||
| 496 | if (curr_gw == gw_node) | 553 | if (curr_gw == gw_node) |
| 497 | do_deselect = 1; | 554 | do_reselect = 1; |
| 498 | 555 | ||
| 499 | hlist_del_rcu(&gw_node->list); | 556 | hlist_del_rcu(&gw_node->list); |
| 500 | batadv_gw_node_free_ref(gw_node); | 557 | batadv_gw_node_free_ref(gw_node); |
| @@ -502,9 +559,9 @@ void batadv_gw_node_purge(struct batadv_priv *bat_priv) | |||
| 502 | 559 | ||
| 503 | spin_unlock_bh(&bat_priv->gw.list_lock); | 560 | spin_unlock_bh(&bat_priv->gw.list_lock); |
| 504 | 561 | ||
| 505 | /* gw_deselect() needs to acquire the gw_list_lock */ | 562 | /* gw_reselect() needs to acquire the gw_list_lock */ |
| 506 | if (do_deselect) | 563 | if (do_reselect) |
| 507 | batadv_gw_deselect(bat_priv); | 564 | batadv_gw_reselect(bat_priv); |
| 508 | 565 | ||
| 509 | if (curr_gw) | 566 | if (curr_gw) |
| 510 | batadv_gw_node_free_ref(curr_gw); | 567 | batadv_gw_node_free_ref(curr_gw); |
| @@ -517,28 +574,36 @@ static int batadv_write_buffer_text(struct batadv_priv *bat_priv, | |||
| 517 | { | 574 | { |
| 518 | struct batadv_gw_node *curr_gw; | 575 | struct batadv_gw_node *curr_gw; |
| 519 | struct batadv_neigh_node *router; | 576 | struct batadv_neigh_node *router; |
| 577 | struct batadv_neigh_ifinfo *router_ifinfo = NULL; | ||
| 520 | int ret = -1; | 578 | int ret = -1; |
| 521 | 579 | ||
| 522 | router = batadv_orig_node_get_router(gw_node->orig_node); | 580 | router = batadv_orig_router_get(gw_node->orig_node, BATADV_IF_DEFAULT); |
| 523 | if (!router) | 581 | if (!router) |
| 524 | goto out; | 582 | goto out; |
| 525 | 583 | ||
| 584 | router_ifinfo = batadv_neigh_ifinfo_get(router, BATADV_IF_DEFAULT); | ||
| 585 | if (!router_ifinfo) | ||
| 586 | goto out; | ||
| 587 | |||
| 526 | curr_gw = batadv_gw_get_selected_gw_node(bat_priv); | 588 | curr_gw = batadv_gw_get_selected_gw_node(bat_priv); |
| 527 | 589 | ||
| 528 | ret = seq_printf(seq, "%s %pM (%3i) %pM [%10s]: %u.%u/%u.%u MBit\n", | 590 | ret = seq_printf(seq, "%s %pM (%3i) %pM [%10s]: %u.%u/%u.%u MBit\n", |
| 529 | (curr_gw == gw_node ? "=>" : " "), | 591 | (curr_gw == gw_node ? "=>" : " "), |
| 530 | gw_node->orig_node->orig, | 592 | gw_node->orig_node->orig, |
| 531 | router->bat_iv.tq_avg, router->addr, | 593 | router_ifinfo->bat_iv.tq_avg, router->addr, |
| 532 | router->if_incoming->net_dev->name, | 594 | router->if_incoming->net_dev->name, |
| 533 | gw_node->bandwidth_down / 10, | 595 | gw_node->bandwidth_down / 10, |
| 534 | gw_node->bandwidth_down % 10, | 596 | gw_node->bandwidth_down % 10, |
| 535 | gw_node->bandwidth_up / 10, | 597 | gw_node->bandwidth_up / 10, |
| 536 | gw_node->bandwidth_up % 10); | 598 | gw_node->bandwidth_up % 10); |
| 537 | 599 | ||
| 538 | batadv_neigh_node_free_ref(router); | ||
| 539 | if (curr_gw) | 600 | if (curr_gw) |
| 540 | batadv_gw_node_free_ref(curr_gw); | 601 | batadv_gw_node_free_ref(curr_gw); |
| 541 | out: | 602 | out: |
| 603 | if (router_ifinfo) | ||
| 604 | batadv_neigh_ifinfo_free_ref(router_ifinfo); | ||
| 605 | if (router) | ||
| 606 | batadv_neigh_node_free_ref(router); | ||
| 542 | return ret; | 607 | return ret; |
| 543 | } | 608 | } |
| 544 | 609 | ||
| @@ -582,80 +647,39 @@ out: | |||
| 582 | return 0; | 647 | return 0; |
| 583 | } | 648 | } |
| 584 | 649 | ||
| 585 | /* this call might reallocate skb data */ | 650 | /** |
| 586 | static bool batadv_is_type_dhcprequest(struct sk_buff *skb, int header_len) | 651 | * batadv_gw_dhcp_recipient_get - check if a packet is a DHCP message |
| 587 | { | 652 | * @skb: the packet to check |
| 588 | int ret = false; | 653 | * @header_len: a pointer to the batman-adv header size |
| 589 | unsigned char *p; | 654 | * @chaddr: buffer where the client address will be stored. Valid |
| 590 | int pkt_len; | 655 | * only if the function returns BATADV_DHCP_TO_CLIENT |
| 591 | 656 | * | |
| 592 | if (skb_linearize(skb) < 0) | 657 | * Returns: |
| 593 | goto out; | 658 | * - BATADV_DHCP_NO if the packet is not a dhcp message or if there was an error |
| 594 | 659 | * while parsing it | |
| 595 | pkt_len = skb_headlen(skb); | 660 | * - BATADV_DHCP_TO_SERVER if this is a message going to the DHCP server |
| 596 | 661 | * - BATADV_DHCP_TO_CLIENT if this is a message going to a DHCP client | |
| 597 | if (pkt_len < header_len + BATADV_DHCP_OPTIONS_OFFSET + 1) | 662 | * |
| 598 | goto out; | 663 | * This function may re-allocate the data buffer of the skb passed as argument. |
| 599 | 664 | */ | |
| 600 | p = skb->data + header_len + BATADV_DHCP_OPTIONS_OFFSET; | 665 | enum batadv_dhcp_recipient |
| 601 | pkt_len -= header_len + BATADV_DHCP_OPTIONS_OFFSET + 1; | 666 | batadv_gw_dhcp_recipient_get(struct sk_buff *skb, unsigned int *header_len, |
| 602 | 667 | uint8_t *chaddr) | |
| 603 | /* Access the dhcp option lists. Each entry is made up by: | ||
| 604 | * - octet 1: option type | ||
| 605 | * - octet 2: option data len (only if type != 255 and 0) | ||
| 606 | * - octet 3: option data | ||
| 607 | */ | ||
| 608 | while (*p != 255 && !ret) { | ||
| 609 | /* p now points to the first octet: option type */ | ||
| 610 | if (*p == 53) { | ||
| 611 | /* type 53 is the message type option. | ||
| 612 | * Jump the len octet and go to the data octet | ||
| 613 | */ | ||
| 614 | if (pkt_len < 2) | ||
| 615 | goto out; | ||
| 616 | p += 2; | ||
| 617 | |||
| 618 | /* check if the message type is what we need */ | ||
| 619 | if (*p == BATADV_DHCP_REQUEST) | ||
| 620 | ret = true; | ||
| 621 | break; | ||
| 622 | } else if (*p == 0) { | ||
| 623 | /* option type 0 (padding), just go forward */ | ||
| 624 | if (pkt_len < 1) | ||
| 625 | goto out; | ||
| 626 | pkt_len--; | ||
| 627 | p++; | ||
| 628 | } else { | ||
| 629 | /* This is any other option. So we get the length... */ | ||
| 630 | if (pkt_len < 1) | ||
| 631 | goto out; | ||
| 632 | pkt_len--; | ||
| 633 | p++; | ||
| 634 | |||
| 635 | /* ...and then we jump over the data */ | ||
| 636 | if (pkt_len < 1 + (*p)) | ||
| 637 | goto out; | ||
| 638 | pkt_len -= 1 + (*p); | ||
| 639 | p += 1 + (*p); | ||
| 640 | } | ||
| 641 | } | ||
| 642 | out: | ||
| 643 | return ret; | ||
| 644 | } | ||
| 645 | |||
| 646 | /* this call might reallocate skb data */ | ||
| 647 | bool batadv_gw_is_dhcp_target(struct sk_buff *skb, unsigned int *header_len) | ||
| 648 | { | 668 | { |
| 669 | enum batadv_dhcp_recipient ret = BATADV_DHCP_NO; | ||
| 649 | struct ethhdr *ethhdr; | 670 | struct ethhdr *ethhdr; |
| 650 | struct iphdr *iphdr; | 671 | struct iphdr *iphdr; |
| 651 | struct ipv6hdr *ipv6hdr; | 672 | struct ipv6hdr *ipv6hdr; |
| 652 | struct udphdr *udphdr; | 673 | struct udphdr *udphdr; |
| 653 | struct vlan_ethhdr *vhdr; | 674 | struct vlan_ethhdr *vhdr; |
| 675 | int chaddr_offset; | ||
| 654 | __be16 proto; | 676 | __be16 proto; |
| 677 | uint8_t *p; | ||
| 655 | 678 | ||
| 656 | /* check for ethernet header */ | 679 | /* check for ethernet header */ |
| 657 | if (!pskb_may_pull(skb, *header_len + ETH_HLEN)) | 680 | if (!pskb_may_pull(skb, *header_len + ETH_HLEN)) |
| 658 | return false; | 681 | return BATADV_DHCP_NO; |
| 682 | |||
| 659 | ethhdr = (struct ethhdr *)skb->data; | 683 | ethhdr = (struct ethhdr *)skb->data; |
| 660 | proto = ethhdr->h_proto; | 684 | proto = ethhdr->h_proto; |
| 661 | *header_len += ETH_HLEN; | 685 | *header_len += ETH_HLEN; |
| @@ -663,7 +687,7 @@ bool batadv_gw_is_dhcp_target(struct sk_buff *skb, unsigned int *header_len) | |||
| 663 | /* check for initial vlan header */ | 687 | /* check for initial vlan header */ |
| 664 | if (proto == htons(ETH_P_8021Q)) { | 688 | if (proto == htons(ETH_P_8021Q)) { |
| 665 | if (!pskb_may_pull(skb, *header_len + VLAN_HLEN)) | 689 | if (!pskb_may_pull(skb, *header_len + VLAN_HLEN)) |
| 666 | return false; | 690 | return BATADV_DHCP_NO; |
| 667 | 691 | ||
| 668 | vhdr = (struct vlan_ethhdr *)skb->data; | 692 | vhdr = (struct vlan_ethhdr *)skb->data; |
| 669 | proto = vhdr->h_vlan_encapsulated_proto; | 693 | proto = vhdr->h_vlan_encapsulated_proto; |
| @@ -674,32 +698,34 @@ bool batadv_gw_is_dhcp_target(struct sk_buff *skb, unsigned int *header_len) | |||
| 674 | switch (proto) { | 698 | switch (proto) { |
| 675 | case htons(ETH_P_IP): | 699 | case htons(ETH_P_IP): |
| 676 | if (!pskb_may_pull(skb, *header_len + sizeof(*iphdr))) | 700 | if (!pskb_may_pull(skb, *header_len + sizeof(*iphdr))) |
| 677 | return false; | 701 | return BATADV_DHCP_NO; |
| 702 | |||
| 678 | iphdr = (struct iphdr *)(skb->data + *header_len); | 703 | iphdr = (struct iphdr *)(skb->data + *header_len); |
| 679 | *header_len += iphdr->ihl * 4; | 704 | *header_len += iphdr->ihl * 4; |
| 680 | 705 | ||
| 681 | /* check for udp header */ | 706 | /* check for udp header */ |
| 682 | if (iphdr->protocol != IPPROTO_UDP) | 707 | if (iphdr->protocol != IPPROTO_UDP) |
| 683 | return false; | 708 | return BATADV_DHCP_NO; |
| 684 | 709 | ||
| 685 | break; | 710 | break; |
| 686 | case htons(ETH_P_IPV6): | 711 | case htons(ETH_P_IPV6): |
| 687 | if (!pskb_may_pull(skb, *header_len + sizeof(*ipv6hdr))) | 712 | if (!pskb_may_pull(skb, *header_len + sizeof(*ipv6hdr))) |
| 688 | return false; | 713 | return BATADV_DHCP_NO; |
| 714 | |||
| 689 | ipv6hdr = (struct ipv6hdr *)(skb->data + *header_len); | 715 | ipv6hdr = (struct ipv6hdr *)(skb->data + *header_len); |
| 690 | *header_len += sizeof(*ipv6hdr); | 716 | *header_len += sizeof(*ipv6hdr); |
| 691 | 717 | ||
| 692 | /* check for udp header */ | 718 | /* check for udp header */ |
| 693 | if (ipv6hdr->nexthdr != IPPROTO_UDP) | 719 | if (ipv6hdr->nexthdr != IPPROTO_UDP) |
| 694 | return false; | 720 | return BATADV_DHCP_NO; |
| 695 | 721 | ||
| 696 | break; | 722 | break; |
| 697 | default: | 723 | default: |
| 698 | return false; | 724 | return BATADV_DHCP_NO; |
| 699 | } | 725 | } |
| 700 | 726 | ||
| 701 | if (!pskb_may_pull(skb, *header_len + sizeof(*udphdr))) | 727 | if (!pskb_may_pull(skb, *header_len + sizeof(*udphdr))) |
| 702 | return false; | 728 | return BATADV_DHCP_NO; |
| 703 | 729 | ||
| 704 | /* skb->data might have been reallocated by pskb_may_pull() */ | 730 | /* skb->data might have been reallocated by pskb_may_pull() */ |
| 705 | ethhdr = (struct ethhdr *)skb->data; | 731 | ethhdr = (struct ethhdr *)skb->data; |
| @@ -710,17 +736,40 @@ bool batadv_gw_is_dhcp_target(struct sk_buff *skb, unsigned int *header_len) | |||
| 710 | *header_len += sizeof(*udphdr); | 736 | *header_len += sizeof(*udphdr); |
| 711 | 737 | ||
| 712 | /* check for bootp port */ | 738 | /* check for bootp port */ |
| 713 | if ((proto == htons(ETH_P_IP)) && | 739 | switch (proto) { |
| 714 | (udphdr->dest != htons(67))) | 740 | case htons(ETH_P_IP): |
| 715 | return false; | 741 | if (udphdr->dest == htons(67)) |
| 742 | ret = BATADV_DHCP_TO_SERVER; | ||
| 743 | else if (udphdr->source == htons(67)) | ||
| 744 | ret = BATADV_DHCP_TO_CLIENT; | ||
| 745 | break; | ||
| 746 | case htons(ETH_P_IPV6): | ||
| 747 | if (udphdr->dest == htons(547)) | ||
| 748 | ret = BATADV_DHCP_TO_SERVER; | ||
| 749 | else if (udphdr->source == htons(547)) | ||
| 750 | ret = BATADV_DHCP_TO_CLIENT; | ||
| 751 | break; | ||
| 752 | } | ||
| 716 | 753 | ||
| 717 | if ((proto == htons(ETH_P_IPV6)) && | 754 | chaddr_offset = *header_len + BATADV_DHCP_CHADDR_OFFSET; |
| 718 | (udphdr->dest != htons(547))) | 755 | /* store the client address if the message is going to a client */ |
| 719 | return false; | 756 | if (ret == BATADV_DHCP_TO_CLIENT && |
| 757 | pskb_may_pull(skb, chaddr_offset + ETH_ALEN)) { | ||
| 758 | /* check if the DHCP packet carries an Ethernet DHCP */ | ||
| 759 | p = skb->data + *header_len + BATADV_DHCP_HTYPE_OFFSET; | ||
| 760 | if (*p != BATADV_DHCP_HTYPE_ETHERNET) | ||
| 761 | return BATADV_DHCP_NO; | ||
| 762 | |||
| 763 | /* check if the DHCP packet carries a valid Ethernet address */ | ||
| 764 | p = skb->data + *header_len + BATADV_DHCP_HLEN_OFFSET; | ||
| 765 | if (*p != ETH_ALEN) | ||
| 766 | return BATADV_DHCP_NO; | ||
| 767 | |||
| 768 | memcpy(chaddr, skb->data + chaddr_offset, ETH_ALEN); | ||
| 769 | } | ||
| 720 | 770 | ||
| 721 | return true; | 771 | return ret; |
| 722 | } | 772 | } |
| 723 | |||
| 724 | /** | 773 | /** |
| 725 | * batadv_gw_out_of_range - check if the dhcp request destination is the best gw | 774 | * batadv_gw_out_of_range - check if the dhcp request destination is the best gw |
| 726 | * @bat_priv: the bat priv with all the soft interface information | 775 | * @bat_priv: the bat priv with all the soft interface information |
| @@ -734,6 +783,7 @@ bool batadv_gw_is_dhcp_target(struct sk_buff *skb, unsigned int *header_len) | |||
| 734 | * false otherwise. | 783 | * false otherwise. |
| 735 | * | 784 | * |
| 736 | * This call might reallocate skb data. | 785 | * This call might reallocate skb data. |
| 786 | * Must be invoked only when the DHCP packet is going TO a DHCP SERVER. | ||
| 737 | */ | 787 | */ |
| 738 | bool batadv_gw_out_of_range(struct batadv_priv *bat_priv, | 788 | bool batadv_gw_out_of_range(struct batadv_priv *bat_priv, |
| 739 | struct sk_buff *skb) | 789 | struct sk_buff *skb) |
| @@ -741,19 +791,14 @@ bool batadv_gw_out_of_range(struct batadv_priv *bat_priv, | |||
| 741 | struct batadv_neigh_node *neigh_curr = NULL, *neigh_old = NULL; | 791 | struct batadv_neigh_node *neigh_curr = NULL, *neigh_old = NULL; |
| 742 | struct batadv_orig_node *orig_dst_node = NULL; | 792 | struct batadv_orig_node *orig_dst_node = NULL; |
| 743 | struct batadv_gw_node *gw_node = NULL, *curr_gw = NULL; | 793 | struct batadv_gw_node *gw_node = NULL, *curr_gw = NULL; |
| 744 | struct ethhdr *ethhdr; | 794 | struct batadv_neigh_ifinfo *curr_ifinfo, *old_ifinfo; |
| 745 | bool ret, out_of_range = false; | 795 | struct ethhdr *ethhdr = (struct ethhdr *)skb->data; |
| 746 | unsigned int header_len = 0; | 796 | bool out_of_range = false; |
| 747 | uint8_t curr_tq_avg; | 797 | uint8_t curr_tq_avg; |
| 748 | unsigned short vid; | 798 | unsigned short vid; |
| 749 | 799 | ||
| 750 | vid = batadv_get_vid(skb, 0); | 800 | vid = batadv_get_vid(skb, 0); |
| 751 | 801 | ||
| 752 | ret = batadv_gw_is_dhcp_target(skb, &header_len); | ||
| 753 | if (!ret) | ||
| 754 | goto out; | ||
| 755 | |||
| 756 | ethhdr = (struct ethhdr *)skb->data; | ||
| 757 | orig_dst_node = batadv_transtable_search(bat_priv, ethhdr->h_source, | 802 | orig_dst_node = batadv_transtable_search(bat_priv, ethhdr->h_source, |
| 758 | ethhdr->h_dest, vid); | 803 | ethhdr->h_dest, vid); |
| 759 | if (!orig_dst_node) | 804 | if (!orig_dst_node) |
| @@ -763,10 +808,6 @@ bool batadv_gw_out_of_range(struct batadv_priv *bat_priv, | |||
| 763 | if (!gw_node->bandwidth_down == 0) | 808 | if (!gw_node->bandwidth_down == 0) |
| 764 | goto out; | 809 | goto out; |
| 765 | 810 | ||
| 766 | ret = batadv_is_type_dhcprequest(skb, header_len); | ||
| 767 | if (!ret) | ||
| 768 | goto out; | ||
| 769 | |||
| 770 | switch (atomic_read(&bat_priv->gw_mode)) { | 811 | switch (atomic_read(&bat_priv->gw_mode)) { |
| 771 | case BATADV_GW_MODE_SERVER: | 812 | case BATADV_GW_MODE_SERVER: |
| 772 | /* If we are a GW then we are our best GW. We can artificially | 813 | /* If we are a GW then we are our best GW. We can artificially |
| @@ -792,7 +833,14 @@ bool batadv_gw_out_of_range(struct batadv_priv *bat_priv, | |||
| 792 | if (!neigh_curr) | 833 | if (!neigh_curr) |
| 793 | goto out; | 834 | goto out; |
| 794 | 835 | ||
| 795 | curr_tq_avg = neigh_curr->bat_iv.tq_avg; | 836 | curr_ifinfo = batadv_neigh_ifinfo_get(neigh_curr, |
| 837 | BATADV_IF_DEFAULT); | ||
| 838 | if (!curr_ifinfo) | ||
| 839 | goto out; | ||
| 840 | |||
| 841 | curr_tq_avg = curr_ifinfo->bat_iv.tq_avg; | ||
| 842 | batadv_neigh_ifinfo_free_ref(curr_ifinfo); | ||
| 843 | |||
| 796 | break; | 844 | break; |
| 797 | case BATADV_GW_MODE_OFF: | 845 | case BATADV_GW_MODE_OFF: |
| 798 | default: | 846 | default: |
| @@ -803,8 +851,13 @@ bool batadv_gw_out_of_range(struct batadv_priv *bat_priv, | |||
| 803 | if (!neigh_old) | 851 | if (!neigh_old) |
| 804 | goto out; | 852 | goto out; |
| 805 | 853 | ||
| 806 | if (curr_tq_avg - neigh_old->bat_iv.tq_avg > BATADV_GW_THRESHOLD) | 854 | old_ifinfo = batadv_neigh_ifinfo_get(neigh_old, BATADV_IF_DEFAULT); |
| 855 | if (!old_ifinfo) | ||
| 856 | goto out; | ||
| 857 | |||
| 858 | if ((curr_tq_avg - old_ifinfo->bat_iv.tq_avg) > BATADV_GW_THRESHOLD) | ||
| 807 | out_of_range = true; | 859 | out_of_range = true; |
| 860 | batadv_neigh_ifinfo_free_ref(old_ifinfo); | ||
| 808 | 861 | ||
| 809 | out: | 862 | out: |
| 810 | if (orig_dst_node) | 863 | if (orig_dst_node) |
diff --git a/net/batman-adv/gateway_client.h b/net/batman-adv/gateway_client.h index d95c2d23195e..7ee53bb7d50f 100644 --- a/net/batman-adv/gateway_client.h +++ b/net/batman-adv/gateway_client.h | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* Copyright (C) 2009-2013 B.A.T.M.A.N. contributors: | 1 | /* Copyright (C) 2009-2014 B.A.T.M.A.N. contributors: |
| 2 | * | 2 | * |
| 3 | * Marek Lindner | 3 | * Marek Lindner |
| 4 | * | 4 | * |
| @@ -12,16 +12,14 @@ | |||
| 12 | * General Public License for more details. | 12 | * General Public License for more details. |
| 13 | * | 13 | * |
| 14 | * You should have received a copy of the GNU General Public License | 14 | * You should have received a copy of the GNU General Public License |
| 15 | * along with this program; if not, write to the Free Software | 15 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 17 | * 02110-1301, USA | ||
| 18 | */ | 16 | */ |
| 19 | 17 | ||
| 20 | #ifndef _NET_BATMAN_ADV_GATEWAY_CLIENT_H_ | 18 | #ifndef _NET_BATMAN_ADV_GATEWAY_CLIENT_H_ |
| 21 | #define _NET_BATMAN_ADV_GATEWAY_CLIENT_H_ | 19 | #define _NET_BATMAN_ADV_GATEWAY_CLIENT_H_ |
| 22 | 20 | ||
| 23 | void batadv_gw_check_client_stop(struct batadv_priv *bat_priv); | 21 | void batadv_gw_check_client_stop(struct batadv_priv *bat_priv); |
| 24 | void batadv_gw_deselect(struct batadv_priv *bat_priv); | 22 | void batadv_gw_reselect(struct batadv_priv *bat_priv); |
| 25 | void batadv_gw_election(struct batadv_priv *bat_priv); | 23 | void batadv_gw_election(struct batadv_priv *bat_priv); |
| 26 | struct batadv_orig_node * | 24 | struct batadv_orig_node * |
| 27 | batadv_gw_get_selected_orig(struct batadv_priv *bat_priv); | 25 | batadv_gw_get_selected_orig(struct batadv_priv *bat_priv); |
| @@ -34,7 +32,9 @@ void batadv_gw_node_delete(struct batadv_priv *bat_priv, | |||
| 34 | struct batadv_orig_node *orig_node); | 32 | struct batadv_orig_node *orig_node); |
| 35 | void batadv_gw_node_purge(struct batadv_priv *bat_priv); | 33 | void batadv_gw_node_purge(struct batadv_priv *bat_priv); |
| 36 | int batadv_gw_client_seq_print_text(struct seq_file *seq, void *offset); | 34 | int batadv_gw_client_seq_print_text(struct seq_file *seq, void *offset); |
| 37 | bool batadv_gw_is_dhcp_target(struct sk_buff *skb, unsigned int *header_len); | ||
| 38 | bool batadv_gw_out_of_range(struct batadv_priv *bat_priv, struct sk_buff *skb); | 35 | bool batadv_gw_out_of_range(struct batadv_priv *bat_priv, struct sk_buff *skb); |
| 36 | enum batadv_dhcp_recipient | ||
| 37 | batadv_gw_dhcp_recipient_get(struct sk_buff *skb, unsigned int *header_len, | ||
| 38 | uint8_t *chaddr); | ||
| 39 | 39 | ||
| 40 | #endif /* _NET_BATMAN_ADV_GATEWAY_CLIENT_H_ */ | 40 | #endif /* _NET_BATMAN_ADV_GATEWAY_CLIENT_H_ */ |
diff --git a/net/batman-adv/gateway_common.c b/net/batman-adv/gateway_common.c index b211b0f9cb78..6f5e621f220a 100644 --- a/net/batman-adv/gateway_common.c +++ b/net/batman-adv/gateway_common.c | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* Copyright (C) 2009-2013 B.A.T.M.A.N. contributors: | 1 | /* Copyright (C) 2009-2014 B.A.T.M.A.N. contributors: |
| 2 | * | 2 | * |
| 3 | * Marek Lindner | 3 | * Marek Lindner |
| 4 | * | 4 | * |
| @@ -12,9 +12,7 @@ | |||
| 12 | * General Public License for more details. | 12 | * General Public License for more details. |
| 13 | * | 13 | * |
| 14 | * You should have received a copy of the GNU General Public License | 14 | * You should have received a copy of the GNU General Public License |
| 15 | * along with this program; if not, write to the Free Software | 15 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 17 | * 02110-1301, USA | ||
| 18 | */ | 16 | */ |
| 19 | 17 | ||
| 20 | #include "main.h" | 18 | #include "main.h" |
| @@ -164,7 +162,7 @@ ssize_t batadv_gw_bandwidth_set(struct net_device *net_dev, char *buff, | |||
| 164 | if ((down_curr == down_new) && (up_curr == up_new)) | 162 | if ((down_curr == down_new) && (up_curr == up_new)) |
| 165 | return count; | 163 | return count; |
| 166 | 164 | ||
| 167 | batadv_gw_deselect(bat_priv); | 165 | batadv_gw_reselect(bat_priv); |
| 168 | batadv_info(net_dev, | 166 | batadv_info(net_dev, |
| 169 | "Changing gateway bandwidth from: '%u.%u/%u.%u MBit' to: '%u.%u/%u.%u MBit'\n", | 167 | "Changing gateway bandwidth from: '%u.%u/%u.%u MBit' to: '%u.%u/%u.%u MBit'\n", |
| 170 | down_curr / 10, down_curr % 10, up_curr / 10, up_curr % 10, | 168 | down_curr / 10, down_curr % 10, up_curr / 10, up_curr % 10, |
diff --git a/net/batman-adv/gateway_common.h b/net/batman-adv/gateway_common.h index 56384a4cd18c..aa5116561947 100644 --- a/net/batman-adv/gateway_common.h +++ b/net/batman-adv/gateway_common.h | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* Copyright (C) 2009-2013 B.A.T.M.A.N. contributors: | 1 | /* Copyright (C) 2009-2014 B.A.T.M.A.N. contributors: |
| 2 | * | 2 | * |
| 3 | * Marek Lindner | 3 | * Marek Lindner |
| 4 | * | 4 | * |
| @@ -12,9 +12,7 @@ | |||
| 12 | * General Public License for more details. | 12 | * General Public License for more details. |
| 13 | * | 13 | * |
| 14 | * You should have received a copy of the GNU General Public License | 14 | * You should have received a copy of the GNU General Public License |
| 15 | * along with this program; if not, write to the Free Software | 15 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 17 | * 02110-1301, USA | ||
| 18 | */ | 16 | */ |
| 19 | 17 | ||
| 20 | #ifndef _NET_BATMAN_ADV_GATEWAY_COMMON_H_ | 18 | #ifndef _NET_BATMAN_ADV_GATEWAY_COMMON_H_ |
diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c index 57c2a19dcb5c..3d417d3641c6 100644 --- a/net/batman-adv/hard-interface.c +++ b/net/batman-adv/hard-interface.c | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors: | 1 | /* Copyright (C) 2007-2014 B.A.T.M.A.N. contributors: |
| 2 | * | 2 | * |
| 3 | * Marek Lindner, Simon Wunderlich | 3 | * Marek Lindner, Simon Wunderlich |
| 4 | * | 4 | * |
| @@ -12,9 +12,7 @@ | |||
| 12 | * General Public License for more details. | 12 | * General Public License for more details. |
| 13 | * | 13 | * |
| 14 | * You should have received a copy of the GNU General Public License | 14 | * You should have received a copy of the GNU General Public License |
| 15 | * along with this program; if not, write to the Free Software | 15 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 17 | * 02110-1301, USA | ||
| 18 | */ | 16 | */ |
| 19 | 17 | ||
| 20 | #include "main.h" | 18 | #include "main.h" |
| @@ -25,6 +23,7 @@ | |||
| 25 | #include "translation-table.h" | 23 | #include "translation-table.h" |
| 26 | #include "routing.h" | 24 | #include "routing.h" |
| 27 | #include "sysfs.h" | 25 | #include "sysfs.h" |
| 26 | #include "debugfs.h" | ||
| 28 | #include "originator.h" | 27 | #include "originator.h" |
| 29 | #include "hash.h" | 28 | #include "hash.h" |
| 30 | #include "bridge_loop_avoidance.h" | 29 | #include "bridge_loop_avoidance.h" |
| @@ -88,15 +87,13 @@ static bool batadv_is_on_batman_iface(const struct net_device *net_dev) | |||
| 88 | return false; | 87 | return false; |
| 89 | 88 | ||
| 90 | /* recurse over the parent device */ | 89 | /* recurse over the parent device */ |
| 91 | parent_dev = dev_get_by_index(&init_net, net_dev->iflink); | 90 | parent_dev = __dev_get_by_index(&init_net, net_dev->iflink); |
| 92 | /* if we got a NULL parent_dev there is something broken.. */ | 91 | /* if we got a NULL parent_dev there is something broken.. */ |
| 93 | if (WARN(!parent_dev, "Cannot find parent device")) | 92 | if (WARN(!parent_dev, "Cannot find parent device")) |
| 94 | return false; | 93 | return false; |
| 95 | 94 | ||
| 96 | ret = batadv_is_on_batman_iface(parent_dev); | 95 | ret = batadv_is_on_batman_iface(parent_dev); |
| 97 | 96 | ||
| 98 | if (parent_dev) | ||
| 99 | dev_put(parent_dev); | ||
| 100 | return ret; | 97 | return ret; |
| 101 | } | 98 | } |
| 102 | 99 | ||
| @@ -541,6 +538,7 @@ static void batadv_hardif_remove_interface_finish(struct work_struct *work) | |||
| 541 | hard_iface = container_of(work, struct batadv_hard_iface, | 538 | hard_iface = container_of(work, struct batadv_hard_iface, |
| 542 | cleanup_work); | 539 | cleanup_work); |
| 543 | 540 | ||
| 541 | batadv_debugfs_del_hardif(hard_iface); | ||
| 544 | batadv_sysfs_del_hardif(&hard_iface->hardif_obj); | 542 | batadv_sysfs_del_hardif(&hard_iface->hardif_obj); |
| 545 | batadv_hardif_free_ref(hard_iface); | 543 | batadv_hardif_free_ref(hard_iface); |
| 546 | } | 544 | } |
| @@ -571,6 +569,11 @@ batadv_hardif_add_interface(struct net_device *net_dev) | |||
| 571 | hard_iface->net_dev = net_dev; | 569 | hard_iface->net_dev = net_dev; |
| 572 | hard_iface->soft_iface = NULL; | 570 | hard_iface->soft_iface = NULL; |
| 573 | hard_iface->if_status = BATADV_IF_NOT_IN_USE; | 571 | hard_iface->if_status = BATADV_IF_NOT_IN_USE; |
| 572 | |||
| 573 | ret = batadv_debugfs_add_hardif(hard_iface); | ||
| 574 | if (ret) | ||
| 575 | goto free_sysfs; | ||
| 576 | |||
| 574 | INIT_LIST_HEAD(&hard_iface->list); | 577 | INIT_LIST_HEAD(&hard_iface->list); |
| 575 | INIT_WORK(&hard_iface->cleanup_work, | 578 | INIT_WORK(&hard_iface->cleanup_work, |
| 576 | batadv_hardif_remove_interface_finish); | 579 | batadv_hardif_remove_interface_finish); |
| @@ -587,6 +590,8 @@ batadv_hardif_add_interface(struct net_device *net_dev) | |||
| 587 | 590 | ||
| 588 | return hard_iface; | 591 | return hard_iface; |
| 589 | 592 | ||
| 593 | free_sysfs: | ||
| 594 | batadv_sysfs_del_hardif(&hard_iface->hardif_obj); | ||
| 590 | free_if: | 595 | free_if: |
| 591 | kfree(hard_iface); | 596 | kfree(hard_iface); |
| 592 | release_dev: | 597 | release_dev: |
diff --git a/net/batman-adv/hard-interface.h b/net/batman-adv/hard-interface.h index df4c8bd45c40..1918cd50b62e 100644 --- a/net/batman-adv/hard-interface.h +++ b/net/batman-adv/hard-interface.h | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors: | 1 | /* Copyright (C) 2007-2014 B.A.T.M.A.N. contributors: |
| 2 | * | 2 | * |
| 3 | * Marek Lindner, Simon Wunderlich | 3 | * Marek Lindner, Simon Wunderlich |
| 4 | * | 4 | * |
| @@ -12,9 +12,7 @@ | |||
| 12 | * General Public License for more details. | 12 | * General Public License for more details. |
| 13 | * | 13 | * |
| 14 | * You should have received a copy of the GNU General Public License | 14 | * You should have received a copy of the GNU General Public License |
| 15 | * along with this program; if not, write to the Free Software | 15 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 17 | * 02110-1301, USA | ||
| 18 | */ | 16 | */ |
| 19 | 17 | ||
| 20 | #ifndef _NET_BATMAN_ADV_HARD_INTERFACE_H_ | 18 | #ifndef _NET_BATMAN_ADV_HARD_INTERFACE_H_ |
| @@ -42,6 +40,7 @@ enum batadv_hard_if_cleanup { | |||
| 42 | extern struct notifier_block batadv_hard_if_notifier; | 40 | extern struct notifier_block batadv_hard_if_notifier; |
| 43 | 41 | ||
| 44 | bool batadv_is_wifi_netdev(struct net_device *net_device); | 42 | bool batadv_is_wifi_netdev(struct net_device *net_device); |
| 43 | bool batadv_is_wifi_iface(int ifindex); | ||
| 45 | struct batadv_hard_iface* | 44 | struct batadv_hard_iface* |
| 46 | batadv_hardif_get_by_netdev(const struct net_device *net_dev); | 45 | batadv_hardif_get_by_netdev(const struct net_device *net_dev); |
| 47 | int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface, | 46 | int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface, |
| @@ -53,6 +52,11 @@ int batadv_hardif_min_mtu(struct net_device *soft_iface); | |||
| 53 | void batadv_update_min_mtu(struct net_device *soft_iface); | 52 | void batadv_update_min_mtu(struct net_device *soft_iface); |
| 54 | void batadv_hardif_free_rcu(struct rcu_head *rcu); | 53 | void batadv_hardif_free_rcu(struct rcu_head *rcu); |
| 55 | 54 | ||
| 55 | /** | ||
| 56 | * batadv_hardif_free_ref - decrement the hard interface refcounter and | ||
| 57 | * possibly free it | ||
| 58 | * @hard_iface: the hard interface to free | ||
| 59 | */ | ||
| 56 | static inline void | 60 | static inline void |
| 57 | batadv_hardif_free_ref(struct batadv_hard_iface *hard_iface) | 61 | batadv_hardif_free_ref(struct batadv_hard_iface *hard_iface) |
| 58 | { | 62 | { |
| @@ -60,6 +64,18 @@ batadv_hardif_free_ref(struct batadv_hard_iface *hard_iface) | |||
| 60 | call_rcu(&hard_iface->rcu, batadv_hardif_free_rcu); | 64 | call_rcu(&hard_iface->rcu, batadv_hardif_free_rcu); |
| 61 | } | 65 | } |
| 62 | 66 | ||
| 67 | /** | ||
| 68 | * batadv_hardif_free_ref_now - decrement the hard interface refcounter and | ||
| 69 | * possibly free it (without rcu callback) | ||
| 70 | * @hard_iface: the hard interface to free | ||
| 71 | */ | ||
| 72 | static inline void | ||
| 73 | batadv_hardif_free_ref_now(struct batadv_hard_iface *hard_iface) | ||
| 74 | { | ||
| 75 | if (atomic_dec_and_test(&hard_iface->refcount)) | ||
| 76 | batadv_hardif_free_rcu(&hard_iface->rcu); | ||
| 77 | } | ||
| 78 | |||
| 63 | static inline struct batadv_hard_iface * | 79 | static inline struct batadv_hard_iface * |
| 64 | batadv_primary_if_get_selected(struct batadv_priv *bat_priv) | 80 | batadv_primary_if_get_selected(struct batadv_priv *bat_priv) |
| 65 | { | 81 | { |
diff --git a/net/batman-adv/hash.c b/net/batman-adv/hash.c index 7198dafd3bf3..63bdf7e94f1e 100644 --- a/net/batman-adv/hash.c +++ b/net/batman-adv/hash.c | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* Copyright (C) 2006-2013 B.A.T.M.A.N. contributors: | 1 | /* Copyright (C) 2006-2014 B.A.T.M.A.N. contributors: |
| 2 | * | 2 | * |
| 3 | * Simon Wunderlich, Marek Lindner | 3 | * Simon Wunderlich, Marek Lindner |
| 4 | * | 4 | * |
| @@ -12,9 +12,7 @@ | |||
| 12 | * General Public License for more details. | 12 | * General Public License for more details. |
| 13 | * | 13 | * |
| 14 | * You should have received a copy of the GNU General Public License | 14 | * You should have received a copy of the GNU General Public License |
| 15 | * along with this program; if not, write to the Free Software | 15 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 17 | * 02110-1301, USA | ||
| 18 | */ | 16 | */ |
| 19 | 17 | ||
| 20 | #include "main.h" | 18 | #include "main.h" |
diff --git a/net/batman-adv/hash.h b/net/batman-adv/hash.h index 1b4da72f2093..539fc1266793 100644 --- a/net/batman-adv/hash.h +++ b/net/batman-adv/hash.h | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* Copyright (C) 2006-2013 B.A.T.M.A.N. contributors: | 1 | /* Copyright (C) 2006-2014 B.A.T.M.A.N. contributors: |
| 2 | * | 2 | * |
| 3 | * Simon Wunderlich, Marek Lindner | 3 | * Simon Wunderlich, Marek Lindner |
| 4 | * | 4 | * |
| @@ -12,9 +12,7 @@ | |||
| 12 | * General Public License for more details. | 12 | * General Public License for more details. |
| 13 | * | 13 | * |
| 14 | * You should have received a copy of the GNU General Public License | 14 | * You should have received a copy of the GNU General Public License |
| 15 | * along with this program; if not, write to the Free Software | 15 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 17 | * 02110-1301, USA | ||
| 18 | */ | 16 | */ |
| 19 | 17 | ||
| 20 | #ifndef _NET_BATMAN_ADV_HASH_H_ | 18 | #ifndef _NET_BATMAN_ADV_HASH_H_ |
diff --git a/net/batman-adv/icmp_socket.c b/net/batman-adv/icmp_socket.c index 130cc3217e2b..abb9d6e0388b 100644 --- a/net/batman-adv/icmp_socket.c +++ b/net/batman-adv/icmp_socket.c | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors: | 1 | /* Copyright (C) 2007-2014 B.A.T.M.A.N. contributors: |
| 2 | * | 2 | * |
| 3 | * Marek Lindner | 3 | * Marek Lindner |
| 4 | * | 4 | * |
| @@ -12,9 +12,7 @@ | |||
| 12 | * General Public License for more details. | 12 | * General Public License for more details. |
| 13 | * | 13 | * |
| 14 | * You should have received a copy of the GNU General Public License | 14 | * You should have received a copy of the GNU General Public License |
| 15 | * along with this program; if not, write to the Free Software | 15 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 17 | * 02110-1301, USA | ||
| 18 | */ | 16 | */ |
| 19 | 17 | ||
| 20 | #include "main.h" | 18 | #include "main.h" |
| @@ -217,7 +215,8 @@ static ssize_t batadv_socket_write(struct file *file, const char __user *buff, | |||
| 217 | if (!orig_node) | 215 | if (!orig_node) |
| 218 | goto dst_unreach; | 216 | goto dst_unreach; |
| 219 | 217 | ||
| 220 | neigh_node = batadv_orig_node_get_router(orig_node); | 218 | neigh_node = batadv_orig_router_get(orig_node, |
| 219 | BATADV_IF_DEFAULT); | ||
| 221 | if (!neigh_node) | 220 | if (!neigh_node) |
| 222 | goto dst_unreach; | 221 | goto dst_unreach; |
| 223 | 222 | ||
diff --git a/net/batman-adv/icmp_socket.h b/net/batman-adv/icmp_socket.h index 6665080dff79..0c33950aa4aa 100644 --- a/net/batman-adv/icmp_socket.h +++ b/net/batman-adv/icmp_socket.h | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors: | 1 | /* Copyright (C) 2007-2014 B.A.T.M.A.N. contributors: |
| 2 | * | 2 | * |
| 3 | * Marek Lindner | 3 | * Marek Lindner |
| 4 | * | 4 | * |
| @@ -12,9 +12,7 @@ | |||
| 12 | * General Public License for more details. | 12 | * General Public License for more details. |
| 13 | * | 13 | * |
| 14 | * You should have received a copy of the GNU General Public License | 14 | * You should have received a copy of the GNU General Public License |
| 15 | * along with this program; if not, write to the Free Software | 15 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 17 | * 02110-1301, USA | ||
| 18 | */ | 16 | */ |
| 19 | 17 | ||
| 20 | #ifndef _NET_BATMAN_ADV_ICMP_SOCKET_H_ | 18 | #ifndef _NET_BATMAN_ADV_ICMP_SOCKET_H_ |
diff --git a/net/batman-adv/main.c b/net/batman-adv/main.c index faba0f61ad53..66ae135b9f27 100644 --- a/net/batman-adv/main.c +++ b/net/batman-adv/main.c | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors: | 1 | /* Copyright (C) 2007-2014 B.A.T.M.A.N. contributors: |
| 2 | * | 2 | * |
| 3 | * Marek Lindner, Simon Wunderlich | 3 | * Marek Lindner, Simon Wunderlich |
| 4 | * | 4 | * |
| @@ -12,9 +12,7 @@ | |||
| 12 | * General Public License for more details. | 12 | * General Public License for more details. |
| 13 | * | 13 | * |
| 14 | * You should have received a copy of the GNU General Public License | 14 | * You should have received a copy of the GNU General Public License |
| 15 | * along with this program; if not, write to the Free Software | 15 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 17 | * 02110-1301, USA | ||
| 18 | */ | 16 | */ |
| 19 | 17 | ||
| 20 | #include <linux/crc32c.h> | 18 | #include <linux/crc32c.h> |
| @@ -421,13 +419,23 @@ static void batadv_recv_handler_init(void) | |||
| 421 | for (i = BATADV_UNICAST_MIN; i <= BATADV_UNICAST_MAX; i++) | 419 | for (i = BATADV_UNICAST_MIN; i <= BATADV_UNICAST_MAX; i++) |
| 422 | batadv_rx_handler[i] = batadv_recv_unhandled_unicast_packet; | 420 | batadv_rx_handler[i] = batadv_recv_unhandled_unicast_packet; |
| 423 | 421 | ||
| 424 | /* compile time checks for struct member offsets */ | 422 | /* compile time checks for sizes */ |
| 425 | BUILD_BUG_ON(offsetof(struct batadv_unicast_4addr_packet, src) != 10); | 423 | BUILD_BUG_ON(sizeof(struct batadv_bla_claim_dst) != 6); |
| 426 | BUILD_BUG_ON(offsetof(struct batadv_unicast_packet, dest) != 4); | 424 | BUILD_BUG_ON(sizeof(struct batadv_ogm_packet) != 24); |
| 427 | BUILD_BUG_ON(offsetof(struct batadv_unicast_tvlv_packet, dst) != 4); | 425 | BUILD_BUG_ON(sizeof(struct batadv_icmp_header) != 20); |
| 428 | BUILD_BUG_ON(offsetof(struct batadv_frag_packet, dest) != 4); | 426 | BUILD_BUG_ON(sizeof(struct batadv_icmp_packet) != 20); |
| 429 | BUILD_BUG_ON(offsetof(struct batadv_icmp_packet, dst) != 4); | 427 | BUILD_BUG_ON(sizeof(struct batadv_icmp_packet_rr) != 116); |
| 430 | BUILD_BUG_ON(offsetof(struct batadv_icmp_packet_rr, dst) != 4); | 428 | BUILD_BUG_ON(sizeof(struct batadv_unicast_packet) != 10); |
| 429 | BUILD_BUG_ON(sizeof(struct batadv_unicast_4addr_packet) != 18); | ||
| 430 | BUILD_BUG_ON(sizeof(struct batadv_frag_packet) != 20); | ||
| 431 | BUILD_BUG_ON(sizeof(struct batadv_bcast_packet) != 14); | ||
| 432 | BUILD_BUG_ON(sizeof(struct batadv_coded_packet) != 46); | ||
| 433 | BUILD_BUG_ON(sizeof(struct batadv_unicast_tvlv_packet) != 20); | ||
| 434 | BUILD_BUG_ON(sizeof(struct batadv_tvlv_hdr) != 4); | ||
| 435 | BUILD_BUG_ON(sizeof(struct batadv_tvlv_gateway_data) != 8); | ||
| 436 | BUILD_BUG_ON(sizeof(struct batadv_tvlv_tt_vlan_data) != 8); | ||
| 437 | BUILD_BUG_ON(sizeof(struct batadv_tvlv_tt_change) != 12); | ||
| 438 | BUILD_BUG_ON(sizeof(struct batadv_tvlv_roam_adv) != 8); | ||
| 431 | 439 | ||
| 432 | /* broadcast packet */ | 440 | /* broadcast packet */ |
| 433 | batadv_rx_handler[BATADV_BCAST] = batadv_recv_bcast_packet; | 441 | batadv_rx_handler[BATADV_BCAST] = batadv_recv_bcast_packet; |
| @@ -1173,6 +1181,32 @@ unsigned short batadv_get_vid(struct sk_buff *skb, size_t header_len) | |||
| 1173 | return vid; | 1181 | return vid; |
| 1174 | } | 1182 | } |
| 1175 | 1183 | ||
| 1184 | /** | ||
| 1185 | * batadv_vlan_ap_isola_get - return the AP isolation status for the given vlan | ||
| 1186 | * @bat_priv: the bat priv with all the soft interface information | ||
| 1187 | * @vid: the VLAN identifier for which the AP isolation attributed as to be | ||
| 1188 | * looked up | ||
| 1189 | * | ||
| 1190 | * Returns true if AP isolation is on for the VLAN idenfied by vid, false | ||
| 1191 | * otherwise | ||
| 1192 | */ | ||
| 1193 | bool batadv_vlan_ap_isola_get(struct batadv_priv *bat_priv, unsigned short vid) | ||
| 1194 | { | ||
| 1195 | bool ap_isolation_enabled = false; | ||
| 1196 | struct batadv_softif_vlan *vlan; | ||
| 1197 | |||
| 1198 | /* if the AP isolation is requested on a VLAN, then check for its | ||
| 1199 | * setting in the proper VLAN private data structure | ||
| 1200 | */ | ||
| 1201 | vlan = batadv_softif_vlan_get(bat_priv, vid); | ||
| 1202 | if (vlan) { | ||
| 1203 | ap_isolation_enabled = atomic_read(&vlan->ap_isolation); | ||
| 1204 | batadv_softif_vlan_free_ref(vlan); | ||
| 1205 | } | ||
| 1206 | |||
| 1207 | return ap_isolation_enabled; | ||
| 1208 | } | ||
| 1209 | |||
| 1176 | static int batadv_param_set_ra(const char *val, const struct kernel_param *kp) | 1210 | static int batadv_param_set_ra(const char *val, const struct kernel_param *kp) |
| 1177 | { | 1211 | { |
| 1178 | struct batadv_algo_ops *bat_algo_ops; | 1212 | struct batadv_algo_ops *bat_algo_ops; |
diff --git a/net/batman-adv/main.h b/net/batman-adv/main.h index f94f287b8670..9374f1a51348 100644 --- a/net/batman-adv/main.h +++ b/net/batman-adv/main.h | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors: | 1 | /* Copyright (C) 2007-2014 B.A.T.M.A.N. contributors: |
| 2 | * | 2 | * |
| 3 | * Marek Lindner, Simon Wunderlich | 3 | * Marek Lindner, Simon Wunderlich |
| 4 | * | 4 | * |
| @@ -12,9 +12,7 @@ | |||
| 12 | * General Public License for more details. | 12 | * General Public License for more details. |
| 13 | * | 13 | * |
| 14 | * You should have received a copy of the GNU General Public License | 14 | * You should have received a copy of the GNU General Public License |
| 15 | * along with this program; if not, write to the Free Software | 15 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 17 | * 02110-1301, USA | ||
| 18 | */ | 16 | */ |
| 19 | 17 | ||
| 20 | #ifndef _NET_BATMAN_ADV_MAIN_H_ | 18 | #ifndef _NET_BATMAN_ADV_MAIN_H_ |
| @@ -26,7 +24,7 @@ | |||
| 26 | #define BATADV_DRIVER_DEVICE "batman-adv" | 24 | #define BATADV_DRIVER_DEVICE "batman-adv" |
| 27 | 25 | ||
| 28 | #ifndef BATADV_SOURCE_VERSION | 26 | #ifndef BATADV_SOURCE_VERSION |
| 29 | #define BATADV_SOURCE_VERSION "2013.5.0" | 27 | #define BATADV_SOURCE_VERSION "2014.1.0" |
| 30 | #endif | 28 | #endif |
| 31 | 29 | ||
| 32 | /* B.A.T.M.A.N. parameters */ | 30 | /* B.A.T.M.A.N. parameters */ |
| @@ -72,6 +70,14 @@ | |||
| 72 | 70 | ||
| 73 | #define BATADV_NULL_IFINDEX 0 /* dummy ifindex used to avoid iface checks */ | 71 | #define BATADV_NULL_IFINDEX 0 /* dummy ifindex used to avoid iface checks */ |
| 74 | 72 | ||
| 73 | #define BATADV_NO_MARK 0 | ||
| 74 | |||
| 75 | /* default interface for multi interface operation. The default interface is | ||
| 76 | * used for communication which originated locally (i.e. is not forwarded) | ||
| 77 | * or where special forwarding is not desired/necessary. | ||
| 78 | */ | ||
| 79 | #define BATADV_IF_DEFAULT ((struct batadv_hard_iface *)NULL) | ||
| 80 | |||
| 75 | #define BATADV_NUM_WORDS BITS_TO_LONGS(BATADV_TQ_LOCAL_WINDOW_SIZE) | 81 | #define BATADV_NUM_WORDS BITS_TO_LONGS(BATADV_TQ_LOCAL_WINDOW_SIZE) |
| 76 | 82 | ||
| 77 | #define BATADV_LOG_BUF_LEN 8192 /* has to be a power of 2 */ | 83 | #define BATADV_LOG_BUF_LEN 8192 /* has to be a power of 2 */ |
| @@ -266,7 +272,7 @@ static inline void batadv_dbg(int type __always_unused, | |||
| 266 | */ | 272 | */ |
| 267 | static inline int batadv_compare_eth(const void *data1, const void *data2) | 273 | static inline int batadv_compare_eth(const void *data1, const void *data2) |
| 268 | { | 274 | { |
| 269 | return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0); | 275 | return ether_addr_equal_unaligned(data1, data2); |
| 270 | } | 276 | } |
| 271 | 277 | ||
| 272 | /** | 278 | /** |
| @@ -369,5 +375,6 @@ void batadv_tvlv_unicast_send(struct batadv_priv *bat_priv, uint8_t *src, | |||
| 369 | uint8_t *dst, uint8_t type, uint8_t version, | 375 | uint8_t *dst, uint8_t type, uint8_t version, |
| 370 | void *tvlv_value, uint16_t tvlv_value_len); | 376 | void *tvlv_value, uint16_t tvlv_value_len); |
| 371 | unsigned short batadv_get_vid(struct sk_buff *skb, size_t header_len); | 377 | unsigned short batadv_get_vid(struct sk_buff *skb, size_t header_len); |
| 378 | bool batadv_vlan_ap_isola_get(struct batadv_priv *bat_priv, unsigned short vid); | ||
| 372 | 379 | ||
| 373 | #endif /* _NET_BATMAN_ADV_MAIN_H_ */ | 380 | #endif /* _NET_BATMAN_ADV_MAIN_H_ */ |
diff --git a/net/batman-adv/network-coding.c b/net/batman-adv/network-coding.c index 511d7e1eea38..f1b604d88dc3 100644 --- a/net/batman-adv/network-coding.c +++ b/net/batman-adv/network-coding.c | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* Copyright (C) 2012-2013 B.A.T.M.A.N. contributors: | 1 | /* Copyright (C) 2012-2014 B.A.T.M.A.N. contributors: |
| 2 | * | 2 | * |
| 3 | * Martin Hundebøll, Jeppe Ledet-Pedersen | 3 | * Martin Hundebøll, Jeppe Ledet-Pedersen |
| 4 | * | 4 | * |
| @@ -12,9 +12,7 @@ | |||
| 12 | * General Public License for more details. | 12 | * General Public License for more details. |
| 13 | * | 13 | * |
| 14 | * You should have received a copy of the GNU General Public License | 14 | * You should have received a copy of the GNU General Public License |
| 15 | * along with this program; if not, write to the Free Software | 15 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 17 | * 02110-1301, USA | ||
| 18 | */ | 16 | */ |
| 19 | 17 | ||
| 20 | #include <linux/debugfs.h> | 18 | #include <linux/debugfs.h> |
| @@ -720,9 +718,21 @@ static bool batadv_can_nc_with_orig(struct batadv_priv *bat_priv, | |||
| 720 | struct batadv_orig_node *orig_node, | 718 | struct batadv_orig_node *orig_node, |
| 721 | struct batadv_ogm_packet *ogm_packet) | 719 | struct batadv_ogm_packet *ogm_packet) |
| 722 | { | 720 | { |
| 723 | if (orig_node->last_real_seqno != ntohl(ogm_packet->seqno)) | 721 | struct batadv_orig_ifinfo *orig_ifinfo; |
| 722 | uint32_t last_real_seqno; | ||
| 723 | uint8_t last_ttl; | ||
| 724 | |||
| 725 | orig_ifinfo = batadv_orig_ifinfo_get(orig_node, BATADV_IF_DEFAULT); | ||
| 726 | if (!orig_ifinfo) | ||
| 724 | return false; | 727 | return false; |
| 725 | if (orig_node->last_ttl != ogm_packet->ttl + 1) | 728 | |
| 729 | last_ttl = orig_ifinfo->last_ttl; | ||
| 730 | last_real_seqno = orig_ifinfo->last_real_seqno; | ||
| 731 | batadv_orig_ifinfo_free_ref(orig_ifinfo); | ||
| 732 | |||
| 733 | if (last_real_seqno != ntohl(ogm_packet->seqno)) | ||
| 734 | return false; | ||
| 735 | if (last_ttl != ogm_packet->ttl + 1) | ||
| 726 | return false; | 736 | return false; |
| 727 | if (!batadv_compare_eth(ogm_packet->orig, ogm_packet->prev_sender)) | 737 | if (!batadv_compare_eth(ogm_packet->orig, ogm_packet->prev_sender)) |
| 728 | return false; | 738 | return false; |
| @@ -1010,6 +1020,8 @@ static bool batadv_nc_code_packets(struct batadv_priv *bat_priv, | |||
| 1010 | struct batadv_coded_packet *coded_packet; | 1020 | struct batadv_coded_packet *coded_packet; |
| 1011 | struct batadv_neigh_node *neigh_tmp, *router_neigh; | 1021 | struct batadv_neigh_node *neigh_tmp, *router_neigh; |
| 1012 | struct batadv_neigh_node *router_coding = NULL; | 1022 | struct batadv_neigh_node *router_coding = NULL; |
| 1023 | struct batadv_neigh_ifinfo *router_neigh_ifinfo = NULL; | ||
| 1024 | struct batadv_neigh_ifinfo *router_coding_ifinfo = NULL; | ||
| 1013 | uint8_t *first_source, *first_dest, *second_source, *second_dest; | 1025 | uint8_t *first_source, *first_dest, *second_source, *second_dest; |
| 1014 | __be32 packet_id1, packet_id2; | 1026 | __be32 packet_id1, packet_id2; |
| 1015 | size_t count; | 1027 | size_t count; |
| @@ -1019,19 +1031,34 @@ static bool batadv_nc_code_packets(struct batadv_priv *bat_priv, | |||
| 1019 | int coded_size = sizeof(*coded_packet); | 1031 | int coded_size = sizeof(*coded_packet); |
| 1020 | int header_add = coded_size - unicast_size; | 1032 | int header_add = coded_size - unicast_size; |
| 1021 | 1033 | ||
| 1022 | router_neigh = batadv_orig_node_get_router(neigh_node->orig_node); | 1034 | /* TODO: do we need to consider the outgoing interface for |
| 1035 | * coded packets? | ||
| 1036 | */ | ||
| 1037 | router_neigh = batadv_orig_router_get(neigh_node->orig_node, | ||
| 1038 | BATADV_IF_DEFAULT); | ||
| 1023 | if (!router_neigh) | 1039 | if (!router_neigh) |
| 1024 | goto out; | 1040 | goto out; |
| 1025 | 1041 | ||
| 1042 | router_neigh_ifinfo = batadv_neigh_ifinfo_get(router_neigh, | ||
| 1043 | BATADV_IF_DEFAULT); | ||
| 1044 | if (!router_neigh_ifinfo) | ||
| 1045 | goto out; | ||
| 1046 | |||
| 1026 | neigh_tmp = nc_packet->neigh_node; | 1047 | neigh_tmp = nc_packet->neigh_node; |
| 1027 | router_coding = batadv_orig_node_get_router(neigh_tmp->orig_node); | 1048 | router_coding = batadv_orig_router_get(neigh_tmp->orig_node, |
| 1049 | BATADV_IF_DEFAULT); | ||
| 1028 | if (!router_coding) | 1050 | if (!router_coding) |
| 1029 | goto out; | 1051 | goto out; |
| 1030 | 1052 | ||
| 1031 | tq_tmp = batadv_nc_random_weight_tq(router_neigh->bat_iv.tq_avg); | 1053 | router_coding_ifinfo = batadv_neigh_ifinfo_get(router_coding, |
| 1032 | tq_weighted_neigh = tq_tmp; | 1054 | BATADV_IF_DEFAULT); |
| 1033 | tq_tmp = batadv_nc_random_weight_tq(router_coding->bat_iv.tq_avg); | 1055 | if (!router_coding_ifinfo) |
| 1034 | tq_weighted_coding = tq_tmp; | 1056 | goto out; |
| 1057 | |||
| 1058 | tq_tmp = router_neigh_ifinfo->bat_iv.tq_avg; | ||
| 1059 | tq_weighted_neigh = batadv_nc_random_weight_tq(tq_tmp); | ||
| 1060 | tq_tmp = router_coding_ifinfo->bat_iv.tq_avg; | ||
| 1061 | tq_weighted_coding = batadv_nc_random_weight_tq(tq_tmp); | ||
| 1035 | 1062 | ||
| 1036 | /* Select one destination for the MAC-header dst-field based on | 1063 | /* Select one destination for the MAC-header dst-field based on |
| 1037 | * weighted TQ-values. | 1064 | * weighted TQ-values. |
| @@ -1155,6 +1182,10 @@ out: | |||
| 1155 | batadv_neigh_node_free_ref(router_neigh); | 1182 | batadv_neigh_node_free_ref(router_neigh); |
| 1156 | if (router_coding) | 1183 | if (router_coding) |
| 1157 | batadv_neigh_node_free_ref(router_coding); | 1184 | batadv_neigh_node_free_ref(router_coding); |
| 1185 | if (router_neigh_ifinfo) | ||
| 1186 | batadv_neigh_ifinfo_free_ref(router_neigh_ifinfo); | ||
| 1187 | if (router_coding_ifinfo) | ||
| 1188 | batadv_neigh_ifinfo_free_ref(router_coding_ifinfo); | ||
| 1158 | return res; | 1189 | return res; |
| 1159 | } | 1190 | } |
| 1160 | 1191 | ||
diff --git a/net/batman-adv/network-coding.h b/net/batman-adv/network-coding.h index d4fd315b5261..358c0d686ab0 100644 --- a/net/batman-adv/network-coding.h +++ b/net/batman-adv/network-coding.h | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* Copyright (C) 2012-2013 B.A.T.M.A.N. contributors: | 1 | /* Copyright (C) 2012-2014 B.A.T.M.A.N. contributors: |
| 2 | * | 2 | * |
| 3 | * Martin Hundebøll, Jeppe Ledet-Pedersen | 3 | * Martin Hundebøll, Jeppe Ledet-Pedersen |
| 4 | * | 4 | * |
| @@ -12,9 +12,7 @@ | |||
| 12 | * General Public License for more details. | 12 | * General Public License for more details. |
| 13 | * | 13 | * |
| 14 | * You should have received a copy of the GNU General Public License | 14 | * You should have received a copy of the GNU General Public License |
| 15 | * along with this program; if not, write to the Free Software | 15 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 17 | * 02110-1301, USA | ||
| 18 | */ | 16 | */ |
| 19 | 17 | ||
| 20 | #ifndef _NET_BATMAN_ADV_NETWORK_CODING_H_ | 18 | #ifndef _NET_BATMAN_ADV_NETWORK_CODING_H_ |
| @@ -64,7 +62,6 @@ static inline int batadv_nc_mesh_init(struct batadv_priv *bat_priv) | |||
| 64 | 62 | ||
| 65 | static inline void batadv_nc_mesh_free(struct batadv_priv *bat_priv) | 63 | static inline void batadv_nc_mesh_free(struct batadv_priv *bat_priv) |
| 66 | { | 64 | { |
| 67 | return; | ||
| 68 | } | 65 | } |
| 69 | 66 | ||
| 70 | static inline void | 67 | static inline void |
| @@ -74,7 +71,6 @@ batadv_nc_update_nc_node(struct batadv_priv *bat_priv, | |||
| 74 | struct batadv_ogm_packet *ogm_packet, | 71 | struct batadv_ogm_packet *ogm_packet, |
| 75 | int is_single_hop_neigh) | 72 | int is_single_hop_neigh) |
| 76 | { | 73 | { |
| 77 | return; | ||
| 78 | } | 74 | } |
| 79 | 75 | ||
| 80 | static inline void | 76 | static inline void |
| @@ -83,17 +79,14 @@ batadv_nc_purge_orig(struct batadv_priv *bat_priv, | |||
| 83 | bool (*to_purge)(struct batadv_priv *, | 79 | bool (*to_purge)(struct batadv_priv *, |
| 84 | struct batadv_nc_node *)) | 80 | struct batadv_nc_node *)) |
| 85 | { | 81 | { |
| 86 | return; | ||
| 87 | } | 82 | } |
| 88 | 83 | ||
| 89 | static inline void batadv_nc_init_bat_priv(struct batadv_priv *bat_priv) | 84 | static inline void batadv_nc_init_bat_priv(struct batadv_priv *bat_priv) |
| 90 | { | 85 | { |
| 91 | return; | ||
| 92 | } | 86 | } |
| 93 | 87 | ||
| 94 | static inline void batadv_nc_init_orig(struct batadv_orig_node *orig_node) | 88 | static inline void batadv_nc_init_orig(struct batadv_orig_node *orig_node) |
| 95 | { | 89 | { |
| 96 | return; | ||
| 97 | } | 90 | } |
| 98 | 91 | ||
| 99 | static inline bool batadv_nc_skb_forward(struct sk_buff *skb, | 92 | static inline bool batadv_nc_skb_forward(struct sk_buff *skb, |
| @@ -106,14 +99,12 @@ static inline void | |||
| 106 | batadv_nc_skb_store_for_decoding(struct batadv_priv *bat_priv, | 99 | batadv_nc_skb_store_for_decoding(struct batadv_priv *bat_priv, |
| 107 | struct sk_buff *skb) | 100 | struct sk_buff *skb) |
| 108 | { | 101 | { |
| 109 | return; | ||
| 110 | } | 102 | } |
| 111 | 103 | ||
| 112 | static inline void | 104 | static inline void |
| 113 | batadv_nc_skb_store_sniffed_unicast(struct batadv_priv *bat_priv, | 105 | batadv_nc_skb_store_sniffed_unicast(struct batadv_priv *bat_priv, |
| 114 | struct sk_buff *skb) | 106 | struct sk_buff *skb) |
| 115 | { | 107 | { |
| 116 | return; | ||
| 117 | } | 108 | } |
| 118 | 109 | ||
| 119 | static inline int batadv_nc_nodes_seq_print_text(struct seq_file *seq, | 110 | static inline int batadv_nc_nodes_seq_print_text(struct seq_file *seq, |
diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c index 8ab14340d10f..6df12a2e3605 100644 --- a/net/batman-adv/originator.c +++ b/net/batman-adv/originator.c | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* Copyright (C) 2009-2013 B.A.T.M.A.N. contributors: | 1 | /* Copyright (C) 2009-2014 B.A.T.M.A.N. contributors: |
| 2 | * | 2 | * |
| 3 | * Marek Lindner, Simon Wunderlich | 3 | * Marek Lindner, Simon Wunderlich |
| 4 | * | 4 | * |
| @@ -12,9 +12,7 @@ | |||
| 12 | * General Public License for more details. | 12 | * General Public License for more details. |
| 13 | * | 13 | * |
| 14 | * You should have received a copy of the GNU General Public License | 14 | * You should have received a copy of the GNU General Public License |
| 15 | * along with this program; if not, write to the Free Software | 15 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 17 | * 02110-1301, USA | ||
| 18 | */ | 16 | */ |
| 19 | 17 | ||
| 20 | #include "main.h" | 18 | #include "main.h" |
| @@ -41,7 +39,7 @@ int batadv_compare_orig(const struct hlist_node *node, const void *data2) | |||
| 41 | const void *data1 = container_of(node, struct batadv_orig_node, | 39 | const void *data1 = container_of(node, struct batadv_orig_node, |
| 42 | hash_entry); | 40 | hash_entry); |
| 43 | 41 | ||
| 44 | return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0); | 42 | return batadv_compare_eth(data1, data2); |
| 45 | } | 43 | } |
| 46 | 44 | ||
| 47 | /** | 45 | /** |
| @@ -150,20 +148,114 @@ err: | |||
| 150 | return -ENOMEM; | 148 | return -ENOMEM; |
| 151 | } | 149 | } |
| 152 | 150 | ||
| 151 | /** | ||
| 152 | * batadv_neigh_ifinfo_free_rcu - free the neigh_ifinfo object | ||
| 153 | * @rcu: rcu pointer of the neigh_ifinfo object | ||
| 154 | */ | ||
| 155 | static void batadv_neigh_ifinfo_free_rcu(struct rcu_head *rcu) | ||
| 156 | { | ||
| 157 | struct batadv_neigh_ifinfo *neigh_ifinfo; | ||
| 158 | |||
| 159 | neigh_ifinfo = container_of(rcu, struct batadv_neigh_ifinfo, rcu); | ||
| 160 | |||
| 161 | if (neigh_ifinfo->if_outgoing != BATADV_IF_DEFAULT) | ||
| 162 | batadv_hardif_free_ref_now(neigh_ifinfo->if_outgoing); | ||
| 163 | |||
| 164 | kfree(neigh_ifinfo); | ||
| 165 | } | ||
| 166 | |||
| 167 | /** | ||
| 168 | * batadv_neigh_ifinfo_free_now - decrement the refcounter and possibly free | ||
| 169 | * the neigh_ifinfo (without rcu callback) | ||
| 170 | * @neigh_ifinfo: the neigh_ifinfo object to release | ||
| 171 | */ | ||
| 172 | static void | ||
| 173 | batadv_neigh_ifinfo_free_ref_now(struct batadv_neigh_ifinfo *neigh_ifinfo) | ||
| 174 | { | ||
| 175 | if (atomic_dec_and_test(&neigh_ifinfo->refcount)) | ||
| 176 | batadv_neigh_ifinfo_free_rcu(&neigh_ifinfo->rcu); | ||
| 177 | } | ||
| 178 | |||
| 179 | /** | ||
| 180 | * batadv_neigh_ifinfo_free_ref - decrement the refcounter and possibly free | ||
| 181 | * the neigh_ifinfo | ||
| 182 | * @neigh_ifinfo: the neigh_ifinfo object to release | ||
| 183 | */ | ||
| 184 | void batadv_neigh_ifinfo_free_ref(struct batadv_neigh_ifinfo *neigh_ifinfo) | ||
| 185 | { | ||
| 186 | if (atomic_dec_and_test(&neigh_ifinfo->refcount)) | ||
| 187 | call_rcu(&neigh_ifinfo->rcu, batadv_neigh_ifinfo_free_rcu); | ||
| 188 | } | ||
| 189 | |||
| 190 | /** | ||
| 191 | * batadv_neigh_node_free_rcu - free the neigh_node | ||
| 192 | * @rcu: rcu pointer of the neigh_node | ||
| 193 | */ | ||
| 194 | static void batadv_neigh_node_free_rcu(struct rcu_head *rcu) | ||
| 195 | { | ||
| 196 | struct hlist_node *node_tmp; | ||
| 197 | struct batadv_neigh_node *neigh_node; | ||
| 198 | struct batadv_neigh_ifinfo *neigh_ifinfo; | ||
| 199 | |||
| 200 | neigh_node = container_of(rcu, struct batadv_neigh_node, rcu); | ||
| 201 | |||
| 202 | hlist_for_each_entry_safe(neigh_ifinfo, node_tmp, | ||
| 203 | &neigh_node->ifinfo_list, list) { | ||
| 204 | batadv_neigh_ifinfo_free_ref_now(neigh_ifinfo); | ||
| 205 | } | ||
| 206 | batadv_hardif_free_ref_now(neigh_node->if_incoming); | ||
| 207 | |||
| 208 | kfree(neigh_node); | ||
| 209 | } | ||
| 210 | |||
| 211 | /** | ||
| 212 | * batadv_neigh_node_free_ref_now - decrement the neighbors refcounter | ||
| 213 | * and possibly free it (without rcu callback) | ||
| 214 | * @neigh_node: neigh neighbor to free | ||
| 215 | */ | ||
| 216 | static void | ||
| 217 | batadv_neigh_node_free_ref_now(struct batadv_neigh_node *neigh_node) | ||
| 218 | { | ||
| 219 | if (atomic_dec_and_test(&neigh_node->refcount)) | ||
| 220 | batadv_neigh_node_free_rcu(&neigh_node->rcu); | ||
| 221 | } | ||
| 222 | |||
| 223 | /** | ||
| 224 | * batadv_neigh_node_free_ref - decrement the neighbors refcounter | ||
| 225 | * and possibly free it | ||
| 226 | * @neigh_node: neigh neighbor to free | ||
| 227 | */ | ||
| 153 | void batadv_neigh_node_free_ref(struct batadv_neigh_node *neigh_node) | 228 | void batadv_neigh_node_free_ref(struct batadv_neigh_node *neigh_node) |
| 154 | { | 229 | { |
| 155 | if (atomic_dec_and_test(&neigh_node->refcount)) | 230 | if (atomic_dec_and_test(&neigh_node->refcount)) |
| 156 | kfree_rcu(neigh_node, rcu); | 231 | call_rcu(&neigh_node->rcu, batadv_neigh_node_free_rcu); |
| 157 | } | 232 | } |
| 158 | 233 | ||
| 159 | /* increases the refcounter of a found router */ | 234 | /** |
| 235 | * batadv_orig_node_get_router - router to the originator depending on iface | ||
| 236 | * @orig_node: the orig node for the router | ||
| 237 | * @if_outgoing: the interface where the payload packet has been received or | ||
| 238 | * the OGM should be sent to | ||
| 239 | * | ||
| 240 | * Returns the neighbor which should be router for this orig_node/iface. | ||
| 241 | * | ||
| 242 | * The object is returned with refcounter increased by 1. | ||
| 243 | */ | ||
| 160 | struct batadv_neigh_node * | 244 | struct batadv_neigh_node * |
| 161 | batadv_orig_node_get_router(struct batadv_orig_node *orig_node) | 245 | batadv_orig_router_get(struct batadv_orig_node *orig_node, |
| 246 | const struct batadv_hard_iface *if_outgoing) | ||
| 162 | { | 247 | { |
| 163 | struct batadv_neigh_node *router; | 248 | struct batadv_orig_ifinfo *orig_ifinfo; |
| 249 | struct batadv_neigh_node *router = NULL; | ||
| 164 | 250 | ||
| 165 | rcu_read_lock(); | 251 | rcu_read_lock(); |
| 166 | router = rcu_dereference(orig_node->router); | 252 | hlist_for_each_entry_rcu(orig_ifinfo, &orig_node->ifinfo_list, list) { |
| 253 | if (orig_ifinfo->if_outgoing != if_outgoing) | ||
| 254 | continue; | ||
| 255 | |||
| 256 | router = rcu_dereference(orig_ifinfo->router); | ||
| 257 | break; | ||
| 258 | } | ||
| 167 | 259 | ||
| 168 | if (router && !atomic_inc_not_zero(&router->refcount)) | 260 | if (router && !atomic_inc_not_zero(&router->refcount)) |
| 169 | router = NULL; | 261 | router = NULL; |
| @@ -173,6 +265,164 @@ batadv_orig_node_get_router(struct batadv_orig_node *orig_node) | |||
| 173 | } | 265 | } |
| 174 | 266 | ||
| 175 | /** | 267 | /** |
| 268 | * batadv_orig_ifinfo_get - find the ifinfo from an orig_node | ||
| 269 | * @orig_node: the orig node to be queried | ||
| 270 | * @if_outgoing: the interface for which the ifinfo should be acquired | ||
| 271 | * | ||
| 272 | * Returns the requested orig_ifinfo or NULL if not found. | ||
| 273 | * | ||
| 274 | * The object is returned with refcounter increased by 1. | ||
| 275 | */ | ||
| 276 | struct batadv_orig_ifinfo * | ||
| 277 | batadv_orig_ifinfo_get(struct batadv_orig_node *orig_node, | ||
| 278 | struct batadv_hard_iface *if_outgoing) | ||
| 279 | { | ||
| 280 | struct batadv_orig_ifinfo *tmp, *orig_ifinfo = NULL; | ||
| 281 | |||
| 282 | rcu_read_lock(); | ||
| 283 | hlist_for_each_entry_rcu(tmp, &orig_node->ifinfo_list, | ||
| 284 | list) { | ||
| 285 | if (tmp->if_outgoing != if_outgoing) | ||
| 286 | continue; | ||
| 287 | |||
| 288 | if (!atomic_inc_not_zero(&tmp->refcount)) | ||
| 289 | continue; | ||
| 290 | |||
| 291 | orig_ifinfo = tmp; | ||
| 292 | break; | ||
| 293 | } | ||
| 294 | rcu_read_unlock(); | ||
| 295 | |||
| 296 | return orig_ifinfo; | ||
| 297 | } | ||
| 298 | |||
| 299 | /** | ||
| 300 | * batadv_orig_ifinfo_new - search and possibly create an orig_ifinfo object | ||
| 301 | * @orig_node: the orig node to be queried | ||
| 302 | * @if_outgoing: the interface for which the ifinfo should be acquired | ||
| 303 | * | ||
| 304 | * Returns NULL in case of failure or the orig_ifinfo object for the if_outgoing | ||
| 305 | * interface otherwise. The object is created and added to the list | ||
| 306 | * if it does not exist. | ||
| 307 | * | ||
| 308 | * The object is returned with refcounter increased by 1. | ||
| 309 | */ | ||
| 310 | struct batadv_orig_ifinfo * | ||
| 311 | batadv_orig_ifinfo_new(struct batadv_orig_node *orig_node, | ||
| 312 | struct batadv_hard_iface *if_outgoing) | ||
| 313 | { | ||
| 314 | struct batadv_orig_ifinfo *orig_ifinfo = NULL; | ||
| 315 | unsigned long reset_time; | ||
| 316 | |||
| 317 | spin_lock_bh(&orig_node->neigh_list_lock); | ||
| 318 | |||
| 319 | orig_ifinfo = batadv_orig_ifinfo_get(orig_node, if_outgoing); | ||
| 320 | if (orig_ifinfo) | ||
| 321 | goto out; | ||
| 322 | |||
| 323 | orig_ifinfo = kzalloc(sizeof(*orig_ifinfo), GFP_ATOMIC); | ||
| 324 | if (!orig_ifinfo) | ||
| 325 | goto out; | ||
| 326 | |||
| 327 | if (if_outgoing != BATADV_IF_DEFAULT && | ||
| 328 | !atomic_inc_not_zero(&if_outgoing->refcount)) { | ||
| 329 | kfree(orig_ifinfo); | ||
| 330 | orig_ifinfo = NULL; | ||
| 331 | goto out; | ||
| 332 | } | ||
| 333 | |||
| 334 | reset_time = jiffies - 1; | ||
| 335 | reset_time -= msecs_to_jiffies(BATADV_RESET_PROTECTION_MS); | ||
| 336 | orig_ifinfo->batman_seqno_reset = reset_time; | ||
| 337 | orig_ifinfo->if_outgoing = if_outgoing; | ||
| 338 | INIT_HLIST_NODE(&orig_ifinfo->list); | ||
| 339 | atomic_set(&orig_ifinfo->refcount, 2); | ||
| 340 | hlist_add_head_rcu(&orig_ifinfo->list, | ||
| 341 | &orig_node->ifinfo_list); | ||
| 342 | out: | ||
| 343 | spin_unlock_bh(&orig_node->neigh_list_lock); | ||
| 344 | return orig_ifinfo; | ||
| 345 | } | ||
| 346 | |||
| 347 | /** | ||
| 348 | * batadv_neigh_ifinfo_get - find the ifinfo from an neigh_node | ||
| 349 | * @neigh_node: the neigh node to be queried | ||
| 350 | * @if_outgoing: the interface for which the ifinfo should be acquired | ||
| 351 | * | ||
| 352 | * The object is returned with refcounter increased by 1. | ||
| 353 | * | ||
| 354 | * Returns the requested neigh_ifinfo or NULL if not found | ||
| 355 | */ | ||
| 356 | struct batadv_neigh_ifinfo * | ||
| 357 | batadv_neigh_ifinfo_get(struct batadv_neigh_node *neigh, | ||
| 358 | struct batadv_hard_iface *if_outgoing) | ||
| 359 | { | ||
| 360 | struct batadv_neigh_ifinfo *neigh_ifinfo = NULL, | ||
| 361 | *tmp_neigh_ifinfo; | ||
| 362 | |||
| 363 | rcu_read_lock(); | ||
| 364 | hlist_for_each_entry_rcu(tmp_neigh_ifinfo, &neigh->ifinfo_list, | ||
| 365 | list) { | ||
| 366 | if (tmp_neigh_ifinfo->if_outgoing != if_outgoing) | ||
| 367 | continue; | ||
| 368 | |||
| 369 | if (!atomic_inc_not_zero(&tmp_neigh_ifinfo->refcount)) | ||
| 370 | continue; | ||
| 371 | |||
| 372 | neigh_ifinfo = tmp_neigh_ifinfo; | ||
| 373 | break; | ||
| 374 | } | ||
| 375 | rcu_read_unlock(); | ||
| 376 | |||
| 377 | return neigh_ifinfo; | ||
| 378 | } | ||
| 379 | |||
| 380 | /** | ||
| 381 | * batadv_neigh_ifinfo_new - search and possibly create an neigh_ifinfo object | ||
| 382 | * @neigh_node: the neigh node to be queried | ||
| 383 | * @if_outgoing: the interface for which the ifinfo should be acquired | ||
| 384 | * | ||
| 385 | * Returns NULL in case of failure or the neigh_ifinfo object for the | ||
| 386 | * if_outgoing interface otherwise. The object is created and added to the list | ||
| 387 | * if it does not exist. | ||
| 388 | * | ||
| 389 | * The object is returned with refcounter increased by 1. | ||
| 390 | */ | ||
| 391 | struct batadv_neigh_ifinfo * | ||
| 392 | batadv_neigh_ifinfo_new(struct batadv_neigh_node *neigh, | ||
| 393 | struct batadv_hard_iface *if_outgoing) | ||
| 394 | { | ||
| 395 | struct batadv_neigh_ifinfo *neigh_ifinfo; | ||
| 396 | |||
| 397 | spin_lock_bh(&neigh->ifinfo_lock); | ||
| 398 | |||
| 399 | neigh_ifinfo = batadv_neigh_ifinfo_get(neigh, if_outgoing); | ||
| 400 | if (neigh_ifinfo) | ||
| 401 | goto out; | ||
| 402 | |||
| 403 | neigh_ifinfo = kzalloc(sizeof(*neigh_ifinfo), GFP_ATOMIC); | ||
| 404 | if (!neigh_ifinfo) | ||
| 405 | goto out; | ||
| 406 | |||
| 407 | if (if_outgoing && !atomic_inc_not_zero(&if_outgoing->refcount)) { | ||
| 408 | kfree(neigh_ifinfo); | ||
| 409 | neigh_ifinfo = NULL; | ||
| 410 | goto out; | ||
| 411 | } | ||
| 412 | |||
| 413 | INIT_HLIST_NODE(&neigh_ifinfo->list); | ||
| 414 | atomic_set(&neigh_ifinfo->refcount, 2); | ||
| 415 | neigh_ifinfo->if_outgoing = if_outgoing; | ||
| 416 | |||
| 417 | hlist_add_head_rcu(&neigh_ifinfo->list, &neigh->ifinfo_list); | ||
| 418 | |||
| 419 | out: | ||
| 420 | spin_unlock_bh(&neigh->ifinfo_lock); | ||
| 421 | |||
| 422 | return neigh_ifinfo; | ||
| 423 | } | ||
| 424 | |||
| 425 | /** | ||
| 176 | * batadv_neigh_node_new - create and init a new neigh_node object | 426 | * batadv_neigh_node_new - create and init a new neigh_node object |
| 177 | * @hard_iface: the interface where the neighbour is connected to | 427 | * @hard_iface: the interface where the neighbour is connected to |
| 178 | * @neigh_addr: the mac address of the neighbour interface | 428 | * @neigh_addr: the mac address of the neighbour interface |
| @@ -193,13 +443,13 @@ batadv_neigh_node_new(struct batadv_hard_iface *hard_iface, | |||
| 193 | goto out; | 443 | goto out; |
| 194 | 444 | ||
| 195 | INIT_HLIST_NODE(&neigh_node->list); | 445 | INIT_HLIST_NODE(&neigh_node->list); |
| 446 | INIT_HLIST_HEAD(&neigh_node->ifinfo_list); | ||
| 447 | spin_lock_init(&neigh_node->ifinfo_lock); | ||
| 196 | 448 | ||
| 197 | memcpy(neigh_node->addr, neigh_addr, ETH_ALEN); | 449 | memcpy(neigh_node->addr, neigh_addr, ETH_ALEN); |
| 198 | neigh_node->if_incoming = hard_iface; | 450 | neigh_node->if_incoming = hard_iface; |
| 199 | neigh_node->orig_node = orig_node; | 451 | neigh_node->orig_node = orig_node; |
| 200 | 452 | ||
| 201 | INIT_LIST_HEAD(&neigh_node->bonding_list); | ||
| 202 | |||
| 203 | /* extra reference for return */ | 453 | /* extra reference for return */ |
| 204 | atomic_set(&neigh_node->refcount, 2); | 454 | atomic_set(&neigh_node->refcount, 2); |
| 205 | 455 | ||
| @@ -207,30 +457,68 @@ out: | |||
| 207 | return neigh_node; | 457 | return neigh_node; |
| 208 | } | 458 | } |
| 209 | 459 | ||
| 460 | /** | ||
| 461 | * batadv_orig_ifinfo_free_rcu - free the orig_ifinfo object | ||
| 462 | * @rcu: rcu pointer of the orig_ifinfo object | ||
| 463 | */ | ||
| 464 | static void batadv_orig_ifinfo_free_rcu(struct rcu_head *rcu) | ||
| 465 | { | ||
| 466 | struct batadv_orig_ifinfo *orig_ifinfo; | ||
| 467 | |||
| 468 | orig_ifinfo = container_of(rcu, struct batadv_orig_ifinfo, rcu); | ||
| 469 | |||
| 470 | if (orig_ifinfo->if_outgoing != BATADV_IF_DEFAULT) | ||
| 471 | batadv_hardif_free_ref_now(orig_ifinfo->if_outgoing); | ||
| 472 | |||
| 473 | kfree(orig_ifinfo); | ||
| 474 | } | ||
| 475 | |||
| 476 | /** | ||
| 477 | * batadv_orig_ifinfo_free_ref - decrement the refcounter and possibly free | ||
| 478 | * the orig_ifinfo (without rcu callback) | ||
| 479 | * @orig_ifinfo: the orig_ifinfo object to release | ||
| 480 | */ | ||
| 481 | static void | ||
| 482 | batadv_orig_ifinfo_free_ref_now(struct batadv_orig_ifinfo *orig_ifinfo) | ||
| 483 | { | ||
| 484 | if (atomic_dec_and_test(&orig_ifinfo->refcount)) | ||
| 485 | batadv_orig_ifinfo_free_rcu(&orig_ifinfo->rcu); | ||
| 486 | } | ||
| 487 | |||
| 488 | /** | ||
| 489 | * batadv_orig_ifinfo_free_ref - decrement the refcounter and possibly free | ||
| 490 | * the orig_ifinfo | ||
| 491 | * @orig_ifinfo: the orig_ifinfo object to release | ||
| 492 | */ | ||
| 493 | void batadv_orig_ifinfo_free_ref(struct batadv_orig_ifinfo *orig_ifinfo) | ||
| 494 | { | ||
| 495 | if (atomic_dec_and_test(&orig_ifinfo->refcount)) | ||
| 496 | call_rcu(&orig_ifinfo->rcu, batadv_orig_ifinfo_free_rcu); | ||
| 497 | } | ||
| 498 | |||
| 210 | static void batadv_orig_node_free_rcu(struct rcu_head *rcu) | 499 | static void batadv_orig_node_free_rcu(struct rcu_head *rcu) |
| 211 | { | 500 | { |
| 212 | struct hlist_node *node_tmp; | 501 | struct hlist_node *node_tmp; |
| 213 | struct batadv_neigh_node *neigh_node, *tmp_neigh_node; | 502 | struct batadv_neigh_node *neigh_node; |
| 214 | struct batadv_orig_node *orig_node; | 503 | struct batadv_orig_node *orig_node; |
| 504 | struct batadv_orig_ifinfo *orig_ifinfo; | ||
| 215 | 505 | ||
| 216 | orig_node = container_of(rcu, struct batadv_orig_node, rcu); | 506 | orig_node = container_of(rcu, struct batadv_orig_node, rcu); |
| 217 | 507 | ||
| 218 | spin_lock_bh(&orig_node->neigh_list_lock); | 508 | spin_lock_bh(&orig_node->neigh_list_lock); |
| 219 | 509 | ||
| 220 | /* for all bonding members ... */ | ||
| 221 | list_for_each_entry_safe(neigh_node, tmp_neigh_node, | ||
| 222 | &orig_node->bond_list, bonding_list) { | ||
| 223 | list_del_rcu(&neigh_node->bonding_list); | ||
| 224 | batadv_neigh_node_free_ref(neigh_node); | ||
| 225 | } | ||
| 226 | |||
| 227 | /* for all neighbors towards this originator ... */ | 510 | /* for all neighbors towards this originator ... */ |
| 228 | hlist_for_each_entry_safe(neigh_node, node_tmp, | 511 | hlist_for_each_entry_safe(neigh_node, node_tmp, |
| 229 | &orig_node->neigh_list, list) { | 512 | &orig_node->neigh_list, list) { |
| 230 | hlist_del_rcu(&neigh_node->list); | 513 | hlist_del_rcu(&neigh_node->list); |
| 231 | batadv_neigh_node_free_ref(neigh_node); | 514 | batadv_neigh_node_free_ref_now(neigh_node); |
| 232 | } | 515 | } |
| 233 | 516 | ||
| 517 | hlist_for_each_entry_safe(orig_ifinfo, node_tmp, | ||
| 518 | &orig_node->ifinfo_list, list) { | ||
| 519 | hlist_del_rcu(&orig_ifinfo->list); | ||
| 520 | batadv_orig_ifinfo_free_ref_now(orig_ifinfo); | ||
| 521 | } | ||
| 234 | spin_unlock_bh(&orig_node->neigh_list_lock); | 522 | spin_unlock_bh(&orig_node->neigh_list_lock); |
| 235 | 523 | ||
| 236 | /* Free nc_nodes */ | 524 | /* Free nc_nodes */ |
| @@ -327,8 +615,8 @@ struct batadv_orig_node *batadv_orig_node_new(struct batadv_priv *bat_priv, | |||
| 327 | return NULL; | 615 | return NULL; |
| 328 | 616 | ||
| 329 | INIT_HLIST_HEAD(&orig_node->neigh_list); | 617 | INIT_HLIST_HEAD(&orig_node->neigh_list); |
| 330 | INIT_LIST_HEAD(&orig_node->bond_list); | ||
| 331 | INIT_LIST_HEAD(&orig_node->vlan_list); | 618 | INIT_LIST_HEAD(&orig_node->vlan_list); |
| 619 | INIT_HLIST_HEAD(&orig_node->ifinfo_list); | ||
| 332 | spin_lock_init(&orig_node->bcast_seqno_lock); | 620 | spin_lock_init(&orig_node->bcast_seqno_lock); |
| 333 | spin_lock_init(&orig_node->neigh_list_lock); | 621 | spin_lock_init(&orig_node->neigh_list_lock); |
| 334 | spin_lock_init(&orig_node->tt_buff_lock); | 622 | spin_lock_init(&orig_node->tt_buff_lock); |
| @@ -344,15 +632,11 @@ struct batadv_orig_node *batadv_orig_node_new(struct batadv_priv *bat_priv, | |||
| 344 | orig_node->bat_priv = bat_priv; | 632 | orig_node->bat_priv = bat_priv; |
| 345 | memcpy(orig_node->orig, addr, ETH_ALEN); | 633 | memcpy(orig_node->orig, addr, ETH_ALEN); |
| 346 | batadv_dat_init_orig_node_addr(orig_node); | 634 | batadv_dat_init_orig_node_addr(orig_node); |
| 347 | orig_node->router = NULL; | ||
| 348 | atomic_set(&orig_node->last_ttvn, 0); | 635 | atomic_set(&orig_node->last_ttvn, 0); |
| 349 | orig_node->tt_buff = NULL; | 636 | orig_node->tt_buff = NULL; |
| 350 | orig_node->tt_buff_len = 0; | 637 | orig_node->tt_buff_len = 0; |
| 351 | reset_time = jiffies - 1 - msecs_to_jiffies(BATADV_RESET_PROTECTION_MS); | 638 | reset_time = jiffies - 1 - msecs_to_jiffies(BATADV_RESET_PROTECTION_MS); |
| 352 | orig_node->bcast_seqno_reset = reset_time; | 639 | orig_node->bcast_seqno_reset = reset_time; |
| 353 | orig_node->batman_seqno_reset = reset_time; | ||
| 354 | |||
| 355 | atomic_set(&orig_node->bond_candidates, 0); | ||
| 356 | 640 | ||
| 357 | /* create a vlan object for the "untagged" LAN */ | 641 | /* create a vlan object for the "untagged" LAN */ |
| 358 | vlan = batadv_orig_node_vlan_new(orig_node, BATADV_NO_FLAGS); | 642 | vlan = batadv_orig_node_vlan_new(orig_node, BATADV_NO_FLAGS); |
| @@ -376,20 +660,76 @@ free_orig_node: | |||
| 376 | return NULL; | 660 | return NULL; |
| 377 | } | 661 | } |
| 378 | 662 | ||
| 663 | /** | ||
| 664 | * batadv_purge_orig_ifinfo - purge obsolete ifinfo entries from originator | ||
| 665 | * @bat_priv: the bat priv with all the soft interface information | ||
| 666 | * @orig_node: orig node which is to be checked | ||
| 667 | * | ||
| 668 | * Returns true if any ifinfo entry was purged, false otherwise. | ||
| 669 | */ | ||
| 670 | static bool | ||
| 671 | batadv_purge_orig_ifinfo(struct batadv_priv *bat_priv, | ||
| 672 | struct batadv_orig_node *orig_node) | ||
| 673 | { | ||
| 674 | struct batadv_orig_ifinfo *orig_ifinfo; | ||
| 675 | struct batadv_hard_iface *if_outgoing; | ||
| 676 | struct hlist_node *node_tmp; | ||
| 677 | bool ifinfo_purged = false; | ||
| 678 | |||
| 679 | spin_lock_bh(&orig_node->neigh_list_lock); | ||
| 680 | |||
| 681 | /* for all ifinfo objects for this originator */ | ||
| 682 | hlist_for_each_entry_safe(orig_ifinfo, node_tmp, | ||
| 683 | &orig_node->ifinfo_list, list) { | ||
| 684 | if_outgoing = orig_ifinfo->if_outgoing; | ||
| 685 | |||
| 686 | /* always keep the default interface */ | ||
| 687 | if (if_outgoing == BATADV_IF_DEFAULT) | ||
| 688 | continue; | ||
| 689 | |||
| 690 | /* don't purge if the interface is not (going) down */ | ||
| 691 | if ((if_outgoing->if_status != BATADV_IF_INACTIVE) && | ||
| 692 | (if_outgoing->if_status != BATADV_IF_NOT_IN_USE) && | ||
| 693 | (if_outgoing->if_status != BATADV_IF_TO_BE_REMOVED)) | ||
| 694 | continue; | ||
| 695 | |||
| 696 | batadv_dbg(BATADV_DBG_BATMAN, bat_priv, | ||
| 697 | "router/ifinfo purge: originator %pM, iface: %s\n", | ||
| 698 | orig_node->orig, if_outgoing->net_dev->name); | ||
| 699 | |||
| 700 | ifinfo_purged = true; | ||
| 701 | |||
| 702 | hlist_del_rcu(&orig_ifinfo->list); | ||
| 703 | batadv_orig_ifinfo_free_ref(orig_ifinfo); | ||
| 704 | if (orig_node->last_bonding_candidate == orig_ifinfo) { | ||
| 705 | orig_node->last_bonding_candidate = NULL; | ||
| 706 | batadv_orig_ifinfo_free_ref(orig_ifinfo); | ||
| 707 | } | ||
| 708 | } | ||
| 709 | |||
| 710 | spin_unlock_bh(&orig_node->neigh_list_lock); | ||
| 711 | |||
| 712 | return ifinfo_purged; | ||
| 713 | } | ||
| 714 | |||
| 715 | |||
| 716 | /** | ||
| 717 | * batadv_purge_orig_neighbors - purges neighbors from originator | ||
| 718 | * @bat_priv: the bat priv with all the soft interface information | ||
| 719 | * @orig_node: orig node which is to be checked | ||
| 720 | * | ||
| 721 | * Returns true if any neighbor was purged, false otherwise | ||
| 722 | */ | ||
| 379 | static bool | 723 | static bool |
| 380 | batadv_purge_orig_neighbors(struct batadv_priv *bat_priv, | 724 | batadv_purge_orig_neighbors(struct batadv_priv *bat_priv, |
| 381 | struct batadv_orig_node *orig_node, | 725 | struct batadv_orig_node *orig_node) |
| 382 | struct batadv_neigh_node **best_neigh) | ||
| 383 | { | 726 | { |
| 384 | struct batadv_algo_ops *bao = bat_priv->bat_algo_ops; | ||
| 385 | struct hlist_node *node_tmp; | 727 | struct hlist_node *node_tmp; |
| 386 | struct batadv_neigh_node *neigh_node; | 728 | struct batadv_neigh_node *neigh_node; |
| 387 | bool neigh_purged = false; | 729 | bool neigh_purged = false; |
| 388 | unsigned long last_seen; | 730 | unsigned long last_seen; |
| 389 | struct batadv_hard_iface *if_incoming; | 731 | struct batadv_hard_iface *if_incoming; |
| 390 | 732 | ||
| 391 | *best_neigh = NULL; | ||
| 392 | |||
| 393 | spin_lock_bh(&orig_node->neigh_list_lock); | 733 | spin_lock_bh(&orig_node->neigh_list_lock); |
| 394 | 734 | ||
| 395 | /* for all neighbors towards this originator ... */ | 735 | /* for all neighbors towards this originator ... */ |
| @@ -418,15 +758,7 @@ batadv_purge_orig_neighbors(struct batadv_priv *bat_priv, | |||
| 418 | neigh_purged = true; | 758 | neigh_purged = true; |
| 419 | 759 | ||
| 420 | hlist_del_rcu(&neigh_node->list); | 760 | hlist_del_rcu(&neigh_node->list); |
| 421 | batadv_bonding_candidate_del(orig_node, neigh_node); | ||
| 422 | batadv_neigh_node_free_ref(neigh_node); | 761 | batadv_neigh_node_free_ref(neigh_node); |
| 423 | } else { | ||
| 424 | /* store the best_neighbour if this is the first | ||
| 425 | * iteration or if a better neighbor has been found | ||
| 426 | */ | ||
| 427 | if (!*best_neigh || | ||
| 428 | bao->bat_neigh_cmp(neigh_node, *best_neigh) > 0) | ||
| 429 | *best_neigh = neigh_node; | ||
| 430 | } | 762 | } |
| 431 | } | 763 | } |
| 432 | 764 | ||
| @@ -434,10 +766,57 @@ batadv_purge_orig_neighbors(struct batadv_priv *bat_priv, | |||
| 434 | return neigh_purged; | 766 | return neigh_purged; |
| 435 | } | 767 | } |
| 436 | 768 | ||
| 769 | /** | ||
| 770 | * batadv_find_best_neighbor - finds the best neighbor after purging | ||
| 771 | * @bat_priv: the bat priv with all the soft interface information | ||
| 772 | * @orig_node: orig node which is to be checked | ||
| 773 | * @if_outgoing: the interface for which the metric should be compared | ||
| 774 | * | ||
| 775 | * Returns the current best neighbor, with refcount increased. | ||
| 776 | */ | ||
| 777 | static struct batadv_neigh_node * | ||
| 778 | batadv_find_best_neighbor(struct batadv_priv *bat_priv, | ||
| 779 | struct batadv_orig_node *orig_node, | ||
| 780 | struct batadv_hard_iface *if_outgoing) | ||
| 781 | { | ||
| 782 | struct batadv_neigh_node *best = NULL, *neigh; | ||
| 783 | struct batadv_algo_ops *bao = bat_priv->bat_algo_ops; | ||
| 784 | |||
| 785 | rcu_read_lock(); | ||
| 786 | hlist_for_each_entry_rcu(neigh, &orig_node->neigh_list, list) { | ||
| 787 | if (best && (bao->bat_neigh_cmp(neigh, if_outgoing, | ||
| 788 | best, if_outgoing) <= 0)) | ||
| 789 | continue; | ||
| 790 | |||
| 791 | if (!atomic_inc_not_zero(&neigh->refcount)) | ||
| 792 | continue; | ||
| 793 | |||
| 794 | if (best) | ||
| 795 | batadv_neigh_node_free_ref(best); | ||
| 796 | |||
| 797 | best = neigh; | ||
| 798 | } | ||
| 799 | rcu_read_unlock(); | ||
| 800 | |||
| 801 | return best; | ||
| 802 | } | ||
| 803 | |||
| 804 | /** | ||
| 805 | * batadv_purge_orig_node - purges obsolete information from an orig_node | ||
| 806 | * @bat_priv: the bat priv with all the soft interface information | ||
| 807 | * @orig_node: orig node which is to be checked | ||
| 808 | * | ||
| 809 | * This function checks if the orig_node or substructures of it have become | ||
| 810 | * obsolete, and purges this information if that's the case. | ||
| 811 | * | ||
| 812 | * Returns true if the orig_node is to be removed, false otherwise. | ||
| 813 | */ | ||
| 437 | static bool batadv_purge_orig_node(struct batadv_priv *bat_priv, | 814 | static bool batadv_purge_orig_node(struct batadv_priv *bat_priv, |
| 438 | struct batadv_orig_node *orig_node) | 815 | struct batadv_orig_node *orig_node) |
| 439 | { | 816 | { |
| 440 | struct batadv_neigh_node *best_neigh_node; | 817 | struct batadv_neigh_node *best_neigh_node; |
| 818 | struct batadv_hard_iface *hard_iface; | ||
| 819 | bool changed; | ||
| 441 | 820 | ||
| 442 | if (batadv_has_timed_out(orig_node->last_seen, | 821 | if (batadv_has_timed_out(orig_node->last_seen, |
| 443 | 2 * BATADV_PURGE_TIMEOUT)) { | 822 | 2 * BATADV_PURGE_TIMEOUT)) { |
| @@ -446,12 +825,39 @@ static bool batadv_purge_orig_node(struct batadv_priv *bat_priv, | |||
| 446 | orig_node->orig, | 825 | orig_node->orig, |
| 447 | jiffies_to_msecs(orig_node->last_seen)); | 826 | jiffies_to_msecs(orig_node->last_seen)); |
| 448 | return true; | 827 | return true; |
| 449 | } else { | ||
| 450 | if (batadv_purge_orig_neighbors(bat_priv, orig_node, | ||
| 451 | &best_neigh_node)) | ||
| 452 | batadv_update_route(bat_priv, orig_node, | ||
| 453 | best_neigh_node); | ||
| 454 | } | 828 | } |
| 829 | changed = batadv_purge_orig_ifinfo(bat_priv, orig_node); | ||
| 830 | changed = changed || batadv_purge_orig_neighbors(bat_priv, orig_node); | ||
| 831 | |||
| 832 | if (!changed) | ||
| 833 | return false; | ||
| 834 | |||
| 835 | /* first for NULL ... */ | ||
| 836 | best_neigh_node = batadv_find_best_neighbor(bat_priv, orig_node, | ||
| 837 | BATADV_IF_DEFAULT); | ||
| 838 | batadv_update_route(bat_priv, orig_node, BATADV_IF_DEFAULT, | ||
| 839 | best_neigh_node); | ||
| 840 | if (best_neigh_node) | ||
| 841 | batadv_neigh_node_free_ref(best_neigh_node); | ||
| 842 | |||
| 843 | /* ... then for all other interfaces. */ | ||
| 844 | rcu_read_lock(); | ||
| 845 | list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) { | ||
| 846 | if (hard_iface->if_status != BATADV_IF_ACTIVE) | ||
| 847 | continue; | ||
| 848 | |||
| 849 | if (hard_iface->soft_iface != bat_priv->soft_iface) | ||
| 850 | continue; | ||
| 851 | |||
| 852 | best_neigh_node = batadv_find_best_neighbor(bat_priv, | ||
| 853 | orig_node, | ||
| 854 | hard_iface); | ||
| 855 | batadv_update_route(bat_priv, orig_node, hard_iface, | ||
| 856 | best_neigh_node); | ||
| 857 | if (best_neigh_node) | ||
| 858 | batadv_neigh_node_free_ref(best_neigh_node); | ||
| 859 | } | ||
| 860 | rcu_read_unlock(); | ||
| 455 | 861 | ||
| 456 | return false; | 862 | return false; |
| 457 | } | 863 | } |
| @@ -534,8 +940,54 @@ int batadv_orig_seq_print_text(struct seq_file *seq, void *offset) | |||
| 534 | return 0; | 940 | return 0; |
| 535 | } | 941 | } |
| 536 | 942 | ||
| 537 | bat_priv->bat_algo_ops->bat_orig_print(bat_priv, seq); | 943 | bat_priv->bat_algo_ops->bat_orig_print(bat_priv, seq, |
| 944 | BATADV_IF_DEFAULT); | ||
| 945 | |||
| 946 | return 0; | ||
| 947 | } | ||
| 948 | |||
| 949 | /** | ||
| 950 | * batadv_orig_hardif_seq_print_text - writes originator infos for a specific | ||
| 951 | * outgoing interface | ||
| 952 | * @seq: debugfs table seq_file struct | ||
| 953 | * @offset: not used | ||
| 954 | * | ||
| 955 | * Returns 0 | ||
| 956 | */ | ||
| 957 | int batadv_orig_hardif_seq_print_text(struct seq_file *seq, void *offset) | ||
| 958 | { | ||
| 959 | struct net_device *net_dev = (struct net_device *)seq->private; | ||
| 960 | struct batadv_hard_iface *hard_iface; | ||
| 961 | struct batadv_priv *bat_priv; | ||
| 962 | |||
| 963 | hard_iface = batadv_hardif_get_by_netdev(net_dev); | ||
| 964 | |||
| 965 | if (!hard_iface || !hard_iface->soft_iface) { | ||
| 966 | seq_puts(seq, "Interface not known to B.A.T.M.A.N.\n"); | ||
| 967 | goto out; | ||
| 968 | } | ||
| 969 | |||
| 970 | bat_priv = netdev_priv(hard_iface->soft_iface); | ||
| 971 | if (!bat_priv->bat_algo_ops->bat_orig_print) { | ||
| 972 | seq_puts(seq, | ||
| 973 | "No printing function for this routing protocol\n"); | ||
| 974 | goto out; | ||
| 975 | } | ||
| 976 | |||
| 977 | if (hard_iface->if_status != BATADV_IF_ACTIVE) { | ||
| 978 | seq_puts(seq, "Interface not active\n"); | ||
| 979 | goto out; | ||
| 980 | } | ||
| 538 | 981 | ||
| 982 | seq_printf(seq, "[B.A.T.M.A.N. adv %s, IF/MAC: %s/%pM (%s %s)]\n", | ||
| 983 | BATADV_SOURCE_VERSION, hard_iface->net_dev->name, | ||
| 984 | hard_iface->net_dev->dev_addr, | ||
| 985 | hard_iface->soft_iface->name, bat_priv->bat_algo_ops->name); | ||
| 986 | |||
| 987 | bat_priv->bat_algo_ops->bat_orig_print(bat_priv, seq, hard_iface); | ||
| 988 | |||
| 989 | out: | ||
| 990 | batadv_hardif_free_ref(hard_iface); | ||
| 539 | return 0; | 991 | return 0; |
| 540 | } | 992 | } |
| 541 | 993 | ||
diff --git a/net/batman-adv/originator.h b/net/batman-adv/originator.h index 6f77d808a916..37be290f63f6 100644 --- a/net/batman-adv/originator.h +++ b/net/batman-adv/originator.h | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors: | 1 | /* Copyright (C) 2007-2014 B.A.T.M.A.N. contributors: |
| 2 | * | 2 | * |
| 3 | * Marek Lindner, Simon Wunderlich | 3 | * Marek Lindner, Simon Wunderlich |
| 4 | * | 4 | * |
| @@ -12,9 +12,7 @@ | |||
| 12 | * General Public License for more details. | 12 | * General Public License for more details. |
| 13 | * | 13 | * |
| 14 | * You should have received a copy of the GNU General Public License | 14 | * You should have received a copy of the GNU General Public License |
| 15 | * along with this program; if not, write to the Free Software | 15 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 17 | * 02110-1301, USA | ||
| 18 | */ | 16 | */ |
| 19 | 17 | ||
| 20 | #ifndef _NET_BATMAN_ADV_ORIGINATOR_H_ | 18 | #ifndef _NET_BATMAN_ADV_ORIGINATOR_H_ |
| @@ -36,8 +34,26 @@ batadv_neigh_node_new(struct batadv_hard_iface *hard_iface, | |||
| 36 | struct batadv_orig_node *orig_node); | 34 | struct batadv_orig_node *orig_node); |
| 37 | void batadv_neigh_node_free_ref(struct batadv_neigh_node *neigh_node); | 35 | void batadv_neigh_node_free_ref(struct batadv_neigh_node *neigh_node); |
| 38 | struct batadv_neigh_node * | 36 | struct batadv_neigh_node * |
| 39 | batadv_orig_node_get_router(struct batadv_orig_node *orig_node); | 37 | batadv_orig_router_get(struct batadv_orig_node *orig_node, |
| 38 | const struct batadv_hard_iface *if_outgoing); | ||
| 39 | struct batadv_neigh_ifinfo * | ||
| 40 | batadv_neigh_ifinfo_new(struct batadv_neigh_node *neigh, | ||
| 41 | struct batadv_hard_iface *if_outgoing); | ||
| 42 | struct batadv_neigh_ifinfo * | ||
| 43 | batadv_neigh_ifinfo_get(struct batadv_neigh_node *neigh, | ||
| 44 | struct batadv_hard_iface *if_outgoing); | ||
| 45 | void batadv_neigh_ifinfo_free_ref(struct batadv_neigh_ifinfo *neigh_ifinfo); | ||
| 46 | |||
| 47 | struct batadv_orig_ifinfo * | ||
| 48 | batadv_orig_ifinfo_get(struct batadv_orig_node *orig_node, | ||
| 49 | struct batadv_hard_iface *if_outgoing); | ||
| 50 | struct batadv_orig_ifinfo * | ||
| 51 | batadv_orig_ifinfo_new(struct batadv_orig_node *orig_node, | ||
| 52 | struct batadv_hard_iface *if_outgoing); | ||
| 53 | void batadv_orig_ifinfo_free_ref(struct batadv_orig_ifinfo *orig_ifinfo); | ||
| 54 | |||
| 40 | int batadv_orig_seq_print_text(struct seq_file *seq, void *offset); | 55 | int batadv_orig_seq_print_text(struct seq_file *seq, void *offset); |
| 56 | int batadv_orig_hardif_seq_print_text(struct seq_file *seq, void *offset); | ||
| 41 | int batadv_orig_hash_add_if(struct batadv_hard_iface *hard_iface, | 57 | int batadv_orig_hash_add_if(struct batadv_hard_iface *hard_iface, |
| 42 | int max_if_num); | 58 | int max_if_num); |
| 43 | int batadv_orig_hash_del_if(struct batadv_hard_iface *hard_iface, | 59 | int batadv_orig_hash_del_if(struct batadv_hard_iface *hard_iface, |
diff --git a/net/batman-adv/packet.h b/net/batman-adv/packet.h index 2dd8f2422550..0a381d1174c1 100644 --- a/net/batman-adv/packet.h +++ b/net/batman-adv/packet.h | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors: | 1 | /* Copyright (C) 2007-2014 B.A.T.M.A.N. contributors: |
| 2 | * | 2 | * |
| 3 | * Marek Lindner, Simon Wunderlich | 3 | * Marek Lindner, Simon Wunderlich |
| 4 | * | 4 | * |
| @@ -12,9 +12,7 @@ | |||
| 12 | * General Public License for more details. | 12 | * General Public License for more details. |
| 13 | * | 13 | * |
| 14 | * You should have received a copy of the GNU General Public License | 14 | * You should have received a copy of the GNU General Public License |
| 15 | * along with this program; if not, write to the Free Software | 15 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 17 | * 02110-1301, USA | ||
| 18 | */ | 16 | */ |
| 19 | 17 | ||
| 20 | #ifndef _NET_BATMAN_ADV_PACKET_H_ | 18 | #ifndef _NET_BATMAN_ADV_PACKET_H_ |
| @@ -117,6 +115,7 @@ enum batadv_tt_client_flags { | |||
| 117 | BATADV_TT_CLIENT_DEL = BIT(0), | 115 | BATADV_TT_CLIENT_DEL = BIT(0), |
| 118 | BATADV_TT_CLIENT_ROAM = BIT(1), | 116 | BATADV_TT_CLIENT_ROAM = BIT(1), |
| 119 | BATADV_TT_CLIENT_WIFI = BIT(4), | 117 | BATADV_TT_CLIENT_WIFI = BIT(4), |
| 118 | BATADV_TT_CLIENT_ISOLA = BIT(5), | ||
| 120 | BATADV_TT_CLIENT_NOPURGE = BIT(8), | 119 | BATADV_TT_CLIENT_NOPURGE = BIT(8), |
| 121 | BATADV_TT_CLIENT_NEW = BIT(9), | 120 | BATADV_TT_CLIENT_NEW = BIT(9), |
| 122 | BATADV_TT_CLIENT_PENDING = BIT(10), | 121 | BATADV_TT_CLIENT_PENDING = BIT(10), |
diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c index 46278bfb8fdb..1ed9f7c9ecea 100644 --- a/net/batman-adv/routing.c +++ b/net/batman-adv/routing.c | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors: | 1 | /* Copyright (C) 2007-2014 B.A.T.M.A.N. contributors: |
| 2 | * | 2 | * |
| 3 | * Marek Lindner, Simon Wunderlich | 3 | * Marek Lindner, Simon Wunderlich |
| 4 | * | 4 | * |
| @@ -12,9 +12,7 @@ | |||
| 12 | * General Public License for more details. | 12 | * General Public License for more details. |
| 13 | * | 13 | * |
| 14 | * You should have received a copy of the GNU General Public License | 14 | * You should have received a copy of the GNU General Public License |
| 15 | * along with this program; if not, write to the Free Software | 15 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 17 | * 02110-1301, USA | ||
| 18 | */ | 16 | */ |
| 19 | 17 | ||
| 20 | #include "main.h" | 18 | #include "main.h" |
| @@ -35,13 +33,32 @@ | |||
| 35 | static int batadv_route_unicast_packet(struct sk_buff *skb, | 33 | static int batadv_route_unicast_packet(struct sk_buff *skb, |
| 36 | struct batadv_hard_iface *recv_if); | 34 | struct batadv_hard_iface *recv_if); |
| 37 | 35 | ||
| 36 | /** | ||
| 37 | * _batadv_update_route - set the router for this originator | ||
| 38 | * @bat_priv: the bat priv with all the soft interface information | ||
| 39 | * @orig_node: orig node which is to be configured | ||
| 40 | * @recv_if: the receive interface for which this route is set | ||
| 41 | * @neigh_node: neighbor which should be the next router | ||
| 42 | * | ||
| 43 | * This function does not perform any error checks | ||
| 44 | */ | ||
| 38 | static void _batadv_update_route(struct batadv_priv *bat_priv, | 45 | static void _batadv_update_route(struct batadv_priv *bat_priv, |
| 39 | struct batadv_orig_node *orig_node, | 46 | struct batadv_orig_node *orig_node, |
| 47 | struct batadv_hard_iface *recv_if, | ||
| 40 | struct batadv_neigh_node *neigh_node) | 48 | struct batadv_neigh_node *neigh_node) |
| 41 | { | 49 | { |
| 50 | struct batadv_orig_ifinfo *orig_ifinfo; | ||
| 42 | struct batadv_neigh_node *curr_router; | 51 | struct batadv_neigh_node *curr_router; |
| 43 | 52 | ||
| 44 | curr_router = batadv_orig_node_get_router(orig_node); | 53 | orig_ifinfo = batadv_orig_ifinfo_get(orig_node, recv_if); |
| 54 | if (!orig_ifinfo) | ||
| 55 | return; | ||
| 56 | |||
| 57 | rcu_read_lock(); | ||
| 58 | curr_router = rcu_dereference(orig_ifinfo->router); | ||
| 59 | if (curr_router && !atomic_inc_not_zero(&curr_router->refcount)) | ||
| 60 | curr_router = NULL; | ||
| 61 | rcu_read_unlock(); | ||
| 45 | 62 | ||
| 46 | /* route deleted */ | 63 | /* route deleted */ |
| 47 | if ((curr_router) && (!neigh_node)) { | 64 | if ((curr_router) && (!neigh_node)) { |
| @@ -71,16 +88,25 @@ static void _batadv_update_route(struct batadv_priv *bat_priv, | |||
| 71 | neigh_node = NULL; | 88 | neigh_node = NULL; |
| 72 | 89 | ||
| 73 | spin_lock_bh(&orig_node->neigh_list_lock); | 90 | spin_lock_bh(&orig_node->neigh_list_lock); |
| 74 | rcu_assign_pointer(orig_node->router, neigh_node); | 91 | rcu_assign_pointer(orig_ifinfo->router, neigh_node); |
| 75 | spin_unlock_bh(&orig_node->neigh_list_lock); | 92 | spin_unlock_bh(&orig_node->neigh_list_lock); |
| 93 | batadv_orig_ifinfo_free_ref(orig_ifinfo); | ||
| 76 | 94 | ||
| 77 | /* decrease refcount of previous best neighbor */ | 95 | /* decrease refcount of previous best neighbor */ |
| 78 | if (curr_router) | 96 | if (curr_router) |
| 79 | batadv_neigh_node_free_ref(curr_router); | 97 | batadv_neigh_node_free_ref(curr_router); |
| 80 | } | 98 | } |
| 81 | 99 | ||
| 100 | /** | ||
| 101 | * batadv_update_route - set the router for this originator | ||
| 102 | * @bat_priv: the bat priv with all the soft interface information | ||
| 103 | * @orig_node: orig node which is to be configured | ||
| 104 | * @recv_if: the receive interface for which this route is set | ||
| 105 | * @neigh_node: neighbor which should be the next router | ||
| 106 | */ | ||
| 82 | void batadv_update_route(struct batadv_priv *bat_priv, | 107 | void batadv_update_route(struct batadv_priv *bat_priv, |
| 83 | struct batadv_orig_node *orig_node, | 108 | struct batadv_orig_node *orig_node, |
| 109 | struct batadv_hard_iface *recv_if, | ||
| 84 | struct batadv_neigh_node *neigh_node) | 110 | struct batadv_neigh_node *neigh_node) |
| 85 | { | 111 | { |
| 86 | struct batadv_neigh_node *router = NULL; | 112 | struct batadv_neigh_node *router = NULL; |
| @@ -88,125 +114,16 @@ void batadv_update_route(struct batadv_priv *bat_priv, | |||
| 88 | if (!orig_node) | 114 | if (!orig_node) |
| 89 | goto out; | 115 | goto out; |
| 90 | 116 | ||
| 91 | router = batadv_orig_node_get_router(orig_node); | 117 | router = batadv_orig_router_get(orig_node, recv_if); |
| 92 | 118 | ||
| 93 | if (router != neigh_node) | 119 | if (router != neigh_node) |
| 94 | _batadv_update_route(bat_priv, orig_node, neigh_node); | 120 | _batadv_update_route(bat_priv, orig_node, recv_if, neigh_node); |
| 95 | 121 | ||
| 96 | out: | 122 | out: |
| 97 | if (router) | 123 | if (router) |
| 98 | batadv_neigh_node_free_ref(router); | 124 | batadv_neigh_node_free_ref(router); |
| 99 | } | 125 | } |
| 100 | 126 | ||
| 101 | /* caller must hold the neigh_list_lock */ | ||
| 102 | void batadv_bonding_candidate_del(struct batadv_orig_node *orig_node, | ||
| 103 | struct batadv_neigh_node *neigh_node) | ||
| 104 | { | ||
| 105 | /* this neighbor is not part of our candidate list */ | ||
| 106 | if (list_empty(&neigh_node->bonding_list)) | ||
| 107 | goto out; | ||
| 108 | |||
| 109 | list_del_rcu(&neigh_node->bonding_list); | ||
| 110 | INIT_LIST_HEAD(&neigh_node->bonding_list); | ||
| 111 | batadv_neigh_node_free_ref(neigh_node); | ||
| 112 | atomic_dec(&orig_node->bond_candidates); | ||
| 113 | |||
| 114 | out: | ||
| 115 | return; | ||
| 116 | } | ||
| 117 | |||
| 118 | /** | ||
| 119 | * batadv_bonding_candidate_add - consider a new link for bonding mode towards | ||
| 120 | * the given originator | ||
| 121 | * @bat_priv: the bat priv with all the soft interface information | ||
| 122 | * @orig_node: the target node | ||
| 123 | * @neigh_node: the neighbor representing the new link to consider for bonding | ||
| 124 | * mode | ||
| 125 | */ | ||
| 126 | void batadv_bonding_candidate_add(struct batadv_priv *bat_priv, | ||
| 127 | struct batadv_orig_node *orig_node, | ||
| 128 | struct batadv_neigh_node *neigh_node) | ||
| 129 | { | ||
| 130 | struct batadv_algo_ops *bao = bat_priv->bat_algo_ops; | ||
| 131 | struct batadv_neigh_node *tmp_neigh_node, *router = NULL; | ||
| 132 | uint8_t interference_candidate = 0; | ||
| 133 | |||
| 134 | spin_lock_bh(&orig_node->neigh_list_lock); | ||
| 135 | |||
| 136 | /* only consider if it has the same primary address ... */ | ||
| 137 | if (!batadv_compare_eth(orig_node->orig, | ||
| 138 | neigh_node->orig_node->primary_addr)) | ||
| 139 | goto candidate_del; | ||
| 140 | |||
| 141 | router = batadv_orig_node_get_router(orig_node); | ||
| 142 | if (!router) | ||
| 143 | goto candidate_del; | ||
| 144 | |||
| 145 | |||
| 146 | /* ... and is good enough to be considered */ | ||
| 147 | if (bao->bat_neigh_is_equiv_or_better(neigh_node, router)) | ||
| 148 | goto candidate_del; | ||
| 149 | |||
| 150 | /* check if we have another candidate with the same mac address or | ||
| 151 | * interface. If we do, we won't select this candidate because of | ||
| 152 | * possible interference. | ||
| 153 | */ | ||
| 154 | hlist_for_each_entry_rcu(tmp_neigh_node, | ||
| 155 | &orig_node->neigh_list, list) { | ||
| 156 | if (tmp_neigh_node == neigh_node) | ||
| 157 | continue; | ||
| 158 | |||
| 159 | /* we only care if the other candidate is even | ||
| 160 | * considered as candidate. | ||
| 161 | */ | ||
| 162 | if (list_empty(&tmp_neigh_node->bonding_list)) | ||
| 163 | continue; | ||
| 164 | |||
| 165 | if ((neigh_node->if_incoming == tmp_neigh_node->if_incoming) || | ||
| 166 | (batadv_compare_eth(neigh_node->addr, | ||
| 167 | tmp_neigh_node->addr))) { | ||
| 168 | interference_candidate = 1; | ||
| 169 | break; | ||
| 170 | } | ||
| 171 | } | ||
| 172 | |||
| 173 | /* don't care further if it is an interference candidate */ | ||
| 174 | if (interference_candidate) | ||
| 175 | goto candidate_del; | ||
| 176 | |||
| 177 | /* this neighbor already is part of our candidate list */ | ||
| 178 | if (!list_empty(&neigh_node->bonding_list)) | ||
| 179 | goto out; | ||
| 180 | |||
| 181 | if (!atomic_inc_not_zero(&neigh_node->refcount)) | ||
| 182 | goto out; | ||
| 183 | |||
| 184 | list_add_rcu(&neigh_node->bonding_list, &orig_node->bond_list); | ||
| 185 | atomic_inc(&orig_node->bond_candidates); | ||
| 186 | goto out; | ||
| 187 | |||
| 188 | candidate_del: | ||
| 189 | batadv_bonding_candidate_del(orig_node, neigh_node); | ||
| 190 | |||
| 191 | out: | ||
| 192 | spin_unlock_bh(&orig_node->neigh_list_lock); | ||
| 193 | |||
| 194 | if (router) | ||
| 195 | batadv_neigh_node_free_ref(router); | ||
| 196 | } | ||
| 197 | |||
| 198 | /* copy primary address for bonding */ | ||
| 199 | void | ||
| 200 | batadv_bonding_save_primary(const struct batadv_orig_node *orig_node, | ||
| 201 | struct batadv_orig_node *orig_neigh_node, | ||
| 202 | const struct batadv_ogm_packet *batman_ogm_packet) | ||
| 203 | { | ||
| 204 | if (!(batman_ogm_packet->flags & BATADV_PRIMARIES_FIRST_HOP)) | ||
| 205 | return; | ||
| 206 | |||
| 207 | memcpy(orig_neigh_node->primary_addr, orig_node->orig, ETH_ALEN); | ||
| 208 | } | ||
| 209 | |||
| 210 | /* checks whether the host restarted and is in the protection time. | 127 | /* checks whether the host restarted and is in the protection time. |
| 211 | * returns: | 128 | * returns: |
| 212 | * 0 if the packet is to be accepted | 129 | * 0 if the packet is to be accepted |
| @@ -461,114 +378,6 @@ out: | |||
| 461 | return ret; | 378 | return ret; |
| 462 | } | 379 | } |
| 463 | 380 | ||
| 464 | /* In the bonding case, send the packets in a round | ||
| 465 | * robin fashion over the remaining interfaces. | ||
| 466 | * | ||
| 467 | * This method rotates the bonding list and increases the | ||
| 468 | * returned router's refcount. | ||
| 469 | */ | ||
| 470 | static struct batadv_neigh_node * | ||
| 471 | batadv_find_bond_router(struct batadv_orig_node *primary_orig, | ||
| 472 | const struct batadv_hard_iface *recv_if) | ||
| 473 | { | ||
| 474 | struct batadv_neigh_node *tmp_neigh_node; | ||
| 475 | struct batadv_neigh_node *router = NULL, *first_candidate = NULL; | ||
| 476 | |||
| 477 | rcu_read_lock(); | ||
| 478 | list_for_each_entry_rcu(tmp_neigh_node, &primary_orig->bond_list, | ||
| 479 | bonding_list) { | ||
| 480 | if (!first_candidate) | ||
| 481 | first_candidate = tmp_neigh_node; | ||
| 482 | |||
| 483 | /* recv_if == NULL on the first node. */ | ||
| 484 | if (tmp_neigh_node->if_incoming == recv_if) | ||
| 485 | continue; | ||
| 486 | |||
| 487 | if (!atomic_inc_not_zero(&tmp_neigh_node->refcount)) | ||
| 488 | continue; | ||
| 489 | |||
| 490 | router = tmp_neigh_node; | ||
| 491 | break; | ||
| 492 | } | ||
| 493 | |||
| 494 | /* use the first candidate if nothing was found. */ | ||
| 495 | if (!router && first_candidate && | ||
| 496 | atomic_inc_not_zero(&first_candidate->refcount)) | ||
| 497 | router = first_candidate; | ||
| 498 | |||
| 499 | if (!router) | ||
| 500 | goto out; | ||
| 501 | |||
| 502 | /* selected should point to the next element | ||
| 503 | * after the current router | ||
| 504 | */ | ||
| 505 | spin_lock_bh(&primary_orig->neigh_list_lock); | ||
| 506 | /* this is a list_move(), which unfortunately | ||
| 507 | * does not exist as rcu version | ||
| 508 | */ | ||
| 509 | list_del_rcu(&primary_orig->bond_list); | ||
| 510 | list_add_rcu(&primary_orig->bond_list, | ||
| 511 | &router->bonding_list); | ||
| 512 | spin_unlock_bh(&primary_orig->neigh_list_lock); | ||
| 513 | |||
| 514 | out: | ||
| 515 | rcu_read_unlock(); | ||
| 516 | return router; | ||
| 517 | } | ||
| 518 | |||
| 519 | /** | ||
| 520 | * batadv_find_ifalter_router - find the best of the remaining candidates which | ||
| 521 | * are not using this interface | ||
| 522 | * @bat_priv: the bat priv with all the soft interface information | ||
| 523 | * @primary_orig: the destination | ||
| 524 | * @recv_if: the interface that the router returned by this function has to not | ||
| 525 | * use | ||
| 526 | * | ||
| 527 | * Returns the best candidate towards primary_orig that is not using recv_if. | ||
| 528 | * Increases the returned neighbor's refcount | ||
| 529 | */ | ||
| 530 | static struct batadv_neigh_node * | ||
| 531 | batadv_find_ifalter_router(struct batadv_priv *bat_priv, | ||
| 532 | struct batadv_orig_node *primary_orig, | ||
| 533 | const struct batadv_hard_iface *recv_if) | ||
| 534 | { | ||
| 535 | struct batadv_neigh_node *router = NULL, *first_candidate = NULL; | ||
| 536 | struct batadv_algo_ops *bao = bat_priv->bat_algo_ops; | ||
| 537 | struct batadv_neigh_node *tmp_neigh_node; | ||
| 538 | |||
| 539 | rcu_read_lock(); | ||
| 540 | list_for_each_entry_rcu(tmp_neigh_node, &primary_orig->bond_list, | ||
| 541 | bonding_list) { | ||
| 542 | if (!first_candidate) | ||
| 543 | first_candidate = tmp_neigh_node; | ||
| 544 | |||
| 545 | /* recv_if == NULL on the first node. */ | ||
| 546 | if (tmp_neigh_node->if_incoming == recv_if) | ||
| 547 | continue; | ||
| 548 | |||
| 549 | if (router && bao->bat_neigh_cmp(tmp_neigh_node, router)) | ||
| 550 | continue; | ||
| 551 | |||
| 552 | if (!atomic_inc_not_zero(&tmp_neigh_node->refcount)) | ||
| 553 | continue; | ||
| 554 | |||
| 555 | /* decrement refcount of previously selected router */ | ||
| 556 | if (router) | ||
| 557 | batadv_neigh_node_free_ref(router); | ||
| 558 | |||
| 559 | /* we found a better router (or at least one valid router) */ | ||
| 560 | router = tmp_neigh_node; | ||
| 561 | } | ||
| 562 | |||
| 563 | /* use the first candidate if nothing was found. */ | ||
| 564 | if (!router && first_candidate && | ||
| 565 | atomic_inc_not_zero(&first_candidate->refcount)) | ||
| 566 | router = first_candidate; | ||
| 567 | |||
| 568 | rcu_read_unlock(); | ||
| 569 | return router; | ||
| 570 | } | ||
| 571 | |||
| 572 | /** | 381 | /** |
| 573 | * batadv_check_unicast_packet - Check for malformed unicast packets | 382 | * batadv_check_unicast_packet - Check for malformed unicast packets |
| 574 | * @bat_priv: the bat priv with all the soft interface information | 383 | * @bat_priv: the bat priv with all the soft interface information |
| @@ -606,95 +415,141 @@ static int batadv_check_unicast_packet(struct batadv_priv *bat_priv, | |||
| 606 | return 0; | 415 | return 0; |
| 607 | } | 416 | } |
| 608 | 417 | ||
| 609 | /* find a suitable router for this originator, and use | 418 | /** |
| 610 | * bonding if possible. increases the found neighbors | 419 | * batadv_find_router - find a suitable router for this originator |
| 611 | * refcount. | 420 | * @bat_priv: the bat priv with all the soft interface information |
| 421 | * @orig_node: the destination node | ||
| 422 | * @recv_if: pointer to interface this packet was received on | ||
| 423 | * | ||
| 424 | * Returns the router which should be used for this orig_node on | ||
| 425 | * this interface, or NULL if not available. | ||
| 612 | */ | 426 | */ |
| 613 | struct batadv_neigh_node * | 427 | struct batadv_neigh_node * |
| 614 | batadv_find_router(struct batadv_priv *bat_priv, | 428 | batadv_find_router(struct batadv_priv *bat_priv, |
| 615 | struct batadv_orig_node *orig_node, | 429 | struct batadv_orig_node *orig_node, |
| 616 | const struct batadv_hard_iface *recv_if) | 430 | struct batadv_hard_iface *recv_if) |
| 617 | { | 431 | { |
| 618 | struct batadv_orig_node *primary_orig_node; | 432 | struct batadv_algo_ops *bao = bat_priv->bat_algo_ops; |
| 619 | struct batadv_orig_node *router_orig; | 433 | struct batadv_neigh_node *first_candidate_router = NULL; |
| 620 | struct batadv_neigh_node *router; | 434 | struct batadv_neigh_node *next_candidate_router = NULL; |
| 621 | static uint8_t zero_mac[ETH_ALEN] = {0, 0, 0, 0, 0, 0}; | 435 | struct batadv_neigh_node *router, *cand_router = NULL; |
| 622 | int bonding_enabled; | 436 | struct batadv_neigh_node *last_cand_router = NULL; |
| 623 | uint8_t *primary_addr; | 437 | struct batadv_orig_ifinfo *cand, *first_candidate = NULL; |
| 438 | struct batadv_orig_ifinfo *next_candidate = NULL; | ||
| 439 | struct batadv_orig_ifinfo *last_candidate; | ||
| 440 | bool last_candidate_found = false; | ||
| 624 | 441 | ||
| 625 | if (!orig_node) | 442 | if (!orig_node) |
| 626 | return NULL; | 443 | return NULL; |
| 627 | 444 | ||
| 628 | router = batadv_orig_node_get_router(orig_node); | 445 | router = batadv_orig_router_get(orig_node, recv_if); |
| 629 | if (!router) | ||
| 630 | goto err; | ||
| 631 | 446 | ||
| 632 | /* without bonding, the first node should | 447 | /* only consider bonding for recv_if == BATADV_IF_DEFAULT (first hop) |
| 633 | * always choose the default router. | 448 | * and if activated. |
| 449 | */ | ||
| 450 | if (recv_if == BATADV_IF_DEFAULT || !atomic_read(&bat_priv->bonding) || | ||
| 451 | !router) | ||
| 452 | return router; | ||
| 453 | |||
| 454 | /* bonding: loop through the list of possible routers found | ||
| 455 | * for the various outgoing interfaces and find a candidate after | ||
| 456 | * the last chosen bonding candidate (next_candidate). If no such | ||
| 457 | * router is found, use the first candidate found (the previously | ||
| 458 | * chosen bonding candidate might have been the last one in the list). | ||
| 459 | * If this can't be found either, return the previously choosen | ||
| 460 | * router - obviously there are no other candidates. | ||
| 634 | */ | 461 | */ |
| 635 | bonding_enabled = atomic_read(&bat_priv->bonding); | ||
| 636 | |||
| 637 | rcu_read_lock(); | 462 | rcu_read_lock(); |
| 638 | /* select default router to output */ | 463 | last_candidate = orig_node->last_bonding_candidate; |
| 639 | router_orig = router->orig_node; | 464 | if (last_candidate) |
| 640 | if (!router_orig) | 465 | last_cand_router = rcu_dereference(last_candidate->router); |
| 641 | goto err_unlock; | ||
| 642 | 466 | ||
| 643 | if ((!recv_if) && (!bonding_enabled)) | 467 | hlist_for_each_entry_rcu(cand, &orig_node->ifinfo_list, list) { |
| 644 | goto return_router; | 468 | /* acquire some structures and references ... */ |
| 469 | if (!atomic_inc_not_zero(&cand->refcount)) | ||
| 470 | continue; | ||
| 645 | 471 | ||
| 646 | primary_addr = router_orig->primary_addr; | 472 | cand_router = rcu_dereference(cand->router); |
| 473 | if (!cand_router) | ||
| 474 | goto next; | ||
| 647 | 475 | ||
| 648 | /* if we have something in the primary_addr, we can search | 476 | if (!atomic_inc_not_zero(&cand_router->refcount)) { |
| 649 | * for a potential bonding candidate. | 477 | cand_router = NULL; |
| 650 | */ | 478 | goto next; |
| 651 | if (batadv_compare_eth(primary_addr, zero_mac)) | 479 | } |
| 652 | goto return_router; | ||
| 653 | 480 | ||
| 654 | /* find the orig_node which has the primary interface. might | 481 | /* alternative candidate should be good enough to be |
| 655 | * even be the same as our router_orig in many cases | 482 | * considered |
| 656 | */ | 483 | */ |
| 657 | if (batadv_compare_eth(primary_addr, router_orig->orig)) { | 484 | if (!bao->bat_neigh_is_equiv_or_better(cand_router, |
| 658 | primary_orig_node = router_orig; | 485 | cand->if_outgoing, |
| 659 | } else { | 486 | router, recv_if)) |
| 660 | primary_orig_node = batadv_orig_hash_find(bat_priv, | 487 | goto next; |
| 661 | primary_addr); | 488 | |
| 662 | if (!primary_orig_node) | 489 | /* don't use the same router twice */ |
| 663 | goto return_router; | 490 | if (last_cand_router == cand_router) |
| 491 | goto next; | ||
| 492 | |||
| 493 | /* mark the first possible candidate */ | ||
| 494 | if (!first_candidate) { | ||
| 495 | atomic_inc(&cand_router->refcount); | ||
| 496 | atomic_inc(&cand->refcount); | ||
| 497 | first_candidate = cand; | ||
| 498 | first_candidate_router = cand_router; | ||
| 499 | } | ||
| 500 | |||
| 501 | /* check if the loop has already passed the previously selected | ||
| 502 | * candidate ... this function should select the next candidate | ||
| 503 | * AFTER the previously used bonding candidate. | ||
| 504 | */ | ||
| 505 | if (!last_candidate || last_candidate_found) { | ||
| 506 | next_candidate = cand; | ||
| 507 | next_candidate_router = cand_router; | ||
| 508 | break; | ||
| 509 | } | ||
| 664 | 510 | ||
| 665 | batadv_orig_node_free_ref(primary_orig_node); | 511 | if (last_candidate == cand) |
| 512 | last_candidate_found = true; | ||
| 513 | next: | ||
| 514 | /* free references */ | ||
| 515 | if (cand_router) { | ||
| 516 | batadv_neigh_node_free_ref(cand_router); | ||
| 517 | cand_router = NULL; | ||
| 518 | } | ||
| 519 | batadv_orig_ifinfo_free_ref(cand); | ||
| 666 | } | 520 | } |
| 521 | rcu_read_unlock(); | ||
| 667 | 522 | ||
| 668 | /* with less than 2 candidates, we can't do any | 523 | /* last_bonding_candidate is reset below, remove the old reference. */ |
| 669 | * bonding and prefer the original router. | 524 | if (orig_node->last_bonding_candidate) |
| 670 | */ | 525 | batadv_orig_ifinfo_free_ref(orig_node->last_bonding_candidate); |
| 671 | if (atomic_read(&primary_orig_node->bond_candidates) < 2) | ||
| 672 | goto return_router; | ||
| 673 | 526 | ||
| 674 | /* all nodes between should choose a candidate which | 527 | /* After finding candidates, handle the three cases: |
| 675 | * is is not on the interface where the packet came | 528 | * 1) there is a next candidate, use that |
| 676 | * in. | 529 | * 2) there is no next candidate, use the first of the list |
| 530 | * 3) there is no candidate at all, return the default router | ||
| 677 | */ | 531 | */ |
| 678 | batadv_neigh_node_free_ref(router); | 532 | if (next_candidate) { |
| 533 | batadv_neigh_node_free_ref(router); | ||
| 679 | 534 | ||
| 680 | if (bonding_enabled) | 535 | /* remove references to first candidate, we don't need it. */ |
| 681 | router = batadv_find_bond_router(primary_orig_node, recv_if); | 536 | if (first_candidate) { |
| 682 | else | 537 | batadv_neigh_node_free_ref(first_candidate_router); |
| 683 | router = batadv_find_ifalter_router(bat_priv, primary_orig_node, | 538 | batadv_orig_ifinfo_free_ref(first_candidate); |
| 684 | recv_if); | 539 | } |
| 540 | router = next_candidate_router; | ||
| 541 | orig_node->last_bonding_candidate = next_candidate; | ||
| 542 | } else if (first_candidate) { | ||
| 543 | batadv_neigh_node_free_ref(router); | ||
| 685 | 544 | ||
| 686 | return_router: | 545 | /* refcounting has already been done in the loop above. */ |
| 687 | if (router && router->if_incoming->if_status != BATADV_IF_ACTIVE) | 546 | router = first_candidate_router; |
| 688 | goto err_unlock; | 547 | orig_node->last_bonding_candidate = first_candidate; |
| 548 | } else { | ||
| 549 | orig_node->last_bonding_candidate = NULL; | ||
| 550 | } | ||
| 689 | 551 | ||
| 690 | rcu_read_unlock(); | ||
| 691 | return router; | 552 | return router; |
| 692 | err_unlock: | ||
| 693 | rcu_read_unlock(); | ||
| 694 | err: | ||
| 695 | if (router) | ||
| 696 | batadv_neigh_node_free_ref(router); | ||
| 697 | return NULL; | ||
| 698 | } | 553 | } |
| 699 | 554 | ||
| 700 | static int batadv_route_unicast_packet(struct sk_buff *skb, | 555 | static int batadv_route_unicast_packet(struct sk_buff *skb, |
| @@ -1135,6 +990,7 @@ int batadv_recv_bcast_packet(struct sk_buff *skb, | |||
| 1135 | int hdr_size = sizeof(*bcast_packet); | 990 | int hdr_size = sizeof(*bcast_packet); |
| 1136 | int ret = NET_RX_DROP; | 991 | int ret = NET_RX_DROP; |
| 1137 | int32_t seq_diff; | 992 | int32_t seq_diff; |
| 993 | uint32_t seqno; | ||
| 1138 | 994 | ||
| 1139 | /* drop packet if it has not necessary minimum size */ | 995 | /* drop packet if it has not necessary minimum size */ |
| 1140 | if (unlikely(!pskb_may_pull(skb, hdr_size))) | 996 | if (unlikely(!pskb_may_pull(skb, hdr_size))) |
| @@ -1170,12 +1026,13 @@ int batadv_recv_bcast_packet(struct sk_buff *skb, | |||
| 1170 | 1026 | ||
| 1171 | spin_lock_bh(&orig_node->bcast_seqno_lock); | 1027 | spin_lock_bh(&orig_node->bcast_seqno_lock); |
| 1172 | 1028 | ||
| 1029 | seqno = ntohl(bcast_packet->seqno); | ||
| 1173 | /* check whether the packet is a duplicate */ | 1030 | /* check whether the packet is a duplicate */ |
| 1174 | if (batadv_test_bit(orig_node->bcast_bits, orig_node->last_bcast_seqno, | 1031 | if (batadv_test_bit(orig_node->bcast_bits, orig_node->last_bcast_seqno, |
| 1175 | ntohl(bcast_packet->seqno))) | 1032 | seqno)) |
| 1176 | goto spin_unlock; | 1033 | goto spin_unlock; |
| 1177 | 1034 | ||
| 1178 | seq_diff = ntohl(bcast_packet->seqno) - orig_node->last_bcast_seqno; | 1035 | seq_diff = seqno - orig_node->last_bcast_seqno; |
| 1179 | 1036 | ||
| 1180 | /* check whether the packet is old and the host just restarted. */ | 1037 | /* check whether the packet is old and the host just restarted. */ |
| 1181 | if (batadv_window_protected(bat_priv, seq_diff, | 1038 | if (batadv_window_protected(bat_priv, seq_diff, |
| @@ -1186,7 +1043,7 @@ int batadv_recv_bcast_packet(struct sk_buff *skb, | |||
| 1186 | * if required. | 1043 | * if required. |
| 1187 | */ | 1044 | */ |
| 1188 | if (batadv_bit_get_packet(bat_priv, orig_node->bcast_bits, seq_diff, 1)) | 1045 | if (batadv_bit_get_packet(bat_priv, orig_node->bcast_bits, seq_diff, 1)) |
| 1189 | orig_node->last_bcast_seqno = ntohl(bcast_packet->seqno); | 1046 | orig_node->last_bcast_seqno = seqno; |
| 1190 | 1047 | ||
| 1191 | spin_unlock_bh(&orig_node->bcast_seqno_lock); | 1048 | spin_unlock_bh(&orig_node->bcast_seqno_lock); |
| 1192 | 1049 | ||
diff --git a/net/batman-adv/routing.h b/net/batman-adv/routing.h index 19544ddb81b5..557d3d12a9ab 100644 --- a/net/batman-adv/routing.h +++ b/net/batman-adv/routing.h | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors: | 1 | /* Copyright (C) 2007-2014 B.A.T.M.A.N. contributors: |
| 2 | * | 2 | * |
| 3 | * Marek Lindner, Simon Wunderlich | 3 | * Marek Lindner, Simon Wunderlich |
| 4 | * | 4 | * |
| @@ -12,9 +12,7 @@ | |||
| 12 | * General Public License for more details. | 12 | * General Public License for more details. |
| 13 | * | 13 | * |
| 14 | * You should have received a copy of the GNU General Public License | 14 | * You should have received a copy of the GNU General Public License |
| 15 | * along with this program; if not, write to the Free Software | 15 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 17 | * 02110-1301, USA | ||
| 18 | */ | 16 | */ |
| 19 | 17 | ||
| 20 | #ifndef _NET_BATMAN_ADV_ROUTING_H_ | 18 | #ifndef _NET_BATMAN_ADV_ROUTING_H_ |
| @@ -25,6 +23,7 @@ bool batadv_check_management_packet(struct sk_buff *skb, | |||
| 25 | int header_len); | 23 | int header_len); |
| 26 | void batadv_update_route(struct batadv_priv *bat_priv, | 24 | void batadv_update_route(struct batadv_priv *bat_priv, |
| 27 | struct batadv_orig_node *orig_node, | 25 | struct batadv_orig_node *orig_node, |
| 26 | struct batadv_hard_iface *recv_if, | ||
| 28 | struct batadv_neigh_node *neigh_node); | 27 | struct batadv_neigh_node *neigh_node); |
| 29 | int batadv_recv_icmp_packet(struct sk_buff *skb, | 28 | int batadv_recv_icmp_packet(struct sk_buff *skb, |
| 30 | struct batadv_hard_iface *recv_if); | 29 | struct batadv_hard_iface *recv_if); |
| @@ -45,16 +44,7 @@ int batadv_recv_unhandled_unicast_packet(struct sk_buff *skb, | |||
| 45 | struct batadv_neigh_node * | 44 | struct batadv_neigh_node * |
| 46 | batadv_find_router(struct batadv_priv *bat_priv, | 45 | batadv_find_router(struct batadv_priv *bat_priv, |
| 47 | struct batadv_orig_node *orig_node, | 46 | struct batadv_orig_node *orig_node, |
| 48 | const struct batadv_hard_iface *recv_if); | 47 | struct batadv_hard_iface *recv_if); |
| 49 | void batadv_bonding_candidate_del(struct batadv_orig_node *orig_node, | ||
| 50 | struct batadv_neigh_node *neigh_node); | ||
| 51 | void batadv_bonding_candidate_add(struct batadv_priv *bat_priv, | ||
| 52 | struct batadv_orig_node *orig_node, | ||
| 53 | struct batadv_neigh_node *neigh_node); | ||
| 54 | void batadv_bonding_save_primary(const struct batadv_orig_node *orig_node, | ||
| 55 | struct batadv_orig_node *orig_neigh_node, | ||
| 56 | const struct batadv_ogm_packet | ||
| 57 | *batman_ogm_packet); | ||
| 58 | int batadv_window_protected(struct batadv_priv *bat_priv, int32_t seq_num_diff, | 48 | int batadv_window_protected(struct batadv_priv *bat_priv, int32_t seq_num_diff, |
| 59 | unsigned long *last_reset); | 49 | unsigned long *last_reset); |
| 60 | 50 | ||
diff --git a/net/batman-adv/send.c b/net/batman-adv/send.c index fba4dcfcfac2..579f5f00a385 100644 --- a/net/batman-adv/send.c +++ b/net/batman-adv/send.c | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors: | 1 | /* Copyright (C) 2007-2014 B.A.T.M.A.N. contributors: |
| 2 | * | 2 | * |
| 3 | * Marek Lindner, Simon Wunderlich | 3 | * Marek Lindner, Simon Wunderlich |
| 4 | * | 4 | * |
| @@ -12,9 +12,7 @@ | |||
| 12 | * General Public License for more details. | 12 | * General Public License for more details. |
| 13 | * | 13 | * |
| 14 | * You should have received a copy of the GNU General Public License | 14 | * You should have received a copy of the GNU General Public License |
| 15 | * along with this program; if not, write to the Free Software | 15 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 17 | * 02110-1301, USA | ||
| 18 | */ | 16 | */ |
| 19 | 17 | ||
| 20 | #include "main.h" | 18 | #include "main.h" |
| @@ -321,13 +319,23 @@ out: | |||
| 321 | */ | 319 | */ |
| 322 | int batadv_send_skb_via_tt_generic(struct batadv_priv *bat_priv, | 320 | int batadv_send_skb_via_tt_generic(struct batadv_priv *bat_priv, |
| 323 | struct sk_buff *skb, int packet_type, | 321 | struct sk_buff *skb, int packet_type, |
| 324 | int packet_subtype, unsigned short vid) | 322 | int packet_subtype, uint8_t *dst_hint, |
| 323 | unsigned short vid) | ||
| 325 | { | 324 | { |
| 326 | struct ethhdr *ethhdr = (struct ethhdr *)skb->data; | 325 | struct ethhdr *ethhdr = (struct ethhdr *)skb->data; |
| 327 | struct batadv_orig_node *orig_node; | 326 | struct batadv_orig_node *orig_node; |
| 327 | uint8_t *src, *dst; | ||
| 328 | |||
| 329 | src = ethhdr->h_source; | ||
| 330 | dst = ethhdr->h_dest; | ||
| 331 | |||
| 332 | /* if we got an hint! let's send the packet to this client (if any) */ | ||
| 333 | if (dst_hint) { | ||
| 334 | src = NULL; | ||
| 335 | dst = dst_hint; | ||
| 336 | } | ||
| 337 | orig_node = batadv_transtable_search(bat_priv, src, dst, vid); | ||
| 328 | 338 | ||
| 329 | orig_node = batadv_transtable_search(bat_priv, ethhdr->h_source, | ||
| 330 | ethhdr->h_dest, vid); | ||
| 331 | return batadv_send_skb_unicast(bat_priv, skb, packet_type, | 339 | return batadv_send_skb_unicast(bat_priv, skb, packet_type, |
| 332 | packet_subtype, orig_node, vid); | 340 | packet_subtype, orig_node, vid); |
| 333 | } | 341 | } |
| @@ -379,6 +387,8 @@ static void batadv_forw_packet_free(struct batadv_forw_packet *forw_packet) | |||
| 379 | kfree_skb(forw_packet->skb); | 387 | kfree_skb(forw_packet->skb); |
| 380 | if (forw_packet->if_incoming) | 388 | if (forw_packet->if_incoming) |
| 381 | batadv_hardif_free_ref(forw_packet->if_incoming); | 389 | batadv_hardif_free_ref(forw_packet->if_incoming); |
| 390 | if (forw_packet->if_outgoing) | ||
| 391 | batadv_hardif_free_ref(forw_packet->if_outgoing); | ||
| 382 | kfree(forw_packet); | 392 | kfree(forw_packet); |
| 383 | } | 393 | } |
| 384 | 394 | ||
| @@ -442,6 +452,7 @@ int batadv_add_bcast_packet_to_list(struct batadv_priv *bat_priv, | |||
| 442 | 452 | ||
| 443 | forw_packet->skb = newskb; | 453 | forw_packet->skb = newskb; |
| 444 | forw_packet->if_incoming = primary_if; | 454 | forw_packet->if_incoming = primary_if; |
| 455 | forw_packet->if_outgoing = NULL; | ||
| 445 | 456 | ||
| 446 | /* how often did we send the bcast packet ? */ | 457 | /* how often did we send the bcast packet ? */ |
| 447 | forw_packet->num_packets = 0; | 458 | forw_packet->num_packets = 0; |
| @@ -537,11 +548,16 @@ void batadv_send_outstanding_bat_ogm_packet(struct work_struct *work) | |||
| 537 | 548 | ||
| 538 | bat_priv->bat_algo_ops->bat_ogm_emit(forw_packet); | 549 | bat_priv->bat_algo_ops->bat_ogm_emit(forw_packet); |
| 539 | 550 | ||
| 540 | /* we have to have at least one packet in the queue | 551 | /* we have to have at least one packet in the queue to determine the |
| 541 | * to determine the queues wake up time unless we are | 552 | * queues wake up time unless we are shutting down. |
| 542 | * shutting down | 553 | * |
| 554 | * only re-schedule if this is the "original" copy, e.g. the OGM of the | ||
| 555 | * primary interface should only be rescheduled once per period, but | ||
| 556 | * this function will be called for the forw_packet instances of the | ||
| 557 | * other secondary interfaces as well. | ||
| 543 | */ | 558 | */ |
| 544 | if (forw_packet->own) | 559 | if (forw_packet->own && |
| 560 | forw_packet->if_incoming == forw_packet->if_outgoing) | ||
| 545 | batadv_schedule_bat_ogm(forw_packet->if_incoming); | 561 | batadv_schedule_bat_ogm(forw_packet->if_incoming); |
| 546 | 562 | ||
| 547 | out: | 563 | out: |
| @@ -602,7 +618,8 @@ batadv_purge_outstanding_packets(struct batadv_priv *bat_priv, | |||
| 602 | * we delete only packets belonging to the given interface | 618 | * we delete only packets belonging to the given interface |
| 603 | */ | 619 | */ |
| 604 | if ((hard_iface) && | 620 | if ((hard_iface) && |
| 605 | (forw_packet->if_incoming != hard_iface)) | 621 | (forw_packet->if_incoming != hard_iface) && |
| 622 | (forw_packet->if_outgoing != hard_iface)) | ||
| 606 | continue; | 623 | continue; |
| 607 | 624 | ||
| 608 | spin_unlock_bh(&bat_priv->forw_bat_list_lock); | 625 | spin_unlock_bh(&bat_priv->forw_bat_list_lock); |
diff --git a/net/batman-adv/send.h b/net/batman-adv/send.h index aa2e2537a739..aaddaa9661ce 100644 --- a/net/batman-adv/send.h +++ b/net/batman-adv/send.h | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors: | 1 | /* Copyright (C) 2007-2014 B.A.T.M.A.N. contributors: |
| 2 | * | 2 | * |
| 3 | * Marek Lindner, Simon Wunderlich | 3 | * Marek Lindner, Simon Wunderlich |
| 4 | * | 4 | * |
| @@ -12,9 +12,7 @@ | |||
| 12 | * General Public License for more details. | 12 | * General Public License for more details. |
| 13 | * | 13 | * |
| 14 | * You should have received a copy of the GNU General Public License | 14 | * You should have received a copy of the GNU General Public License |
| 15 | * along with this program; if not, write to the Free Software | 15 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 17 | * 02110-1301, USA | ||
| 18 | */ | 16 | */ |
| 19 | 17 | ||
| 20 | #ifndef _NET_BATMAN_ADV_SEND_H_ | 18 | #ifndef _NET_BATMAN_ADV_SEND_H_ |
| @@ -40,7 +38,8 @@ bool batadv_send_skb_prepare_unicast_4addr(struct batadv_priv *bat_priv, | |||
| 40 | int packet_subtype); | 38 | int packet_subtype); |
| 41 | int batadv_send_skb_via_tt_generic(struct batadv_priv *bat_priv, | 39 | int batadv_send_skb_via_tt_generic(struct batadv_priv *bat_priv, |
| 42 | struct sk_buff *skb, int packet_type, | 40 | struct sk_buff *skb, int packet_type, |
| 43 | int packet_subtype, unsigned short vid); | 41 | int packet_subtype, uint8_t *dst_hint, |
| 42 | unsigned short vid); | ||
| 44 | int batadv_send_skb_via_gw(struct batadv_priv *bat_priv, struct sk_buff *skb, | 43 | int batadv_send_skb_via_gw(struct batadv_priv *bat_priv, struct sk_buff *skb, |
| 45 | unsigned short vid); | 44 | unsigned short vid); |
| 46 | 45 | ||
| @@ -57,11 +56,11 @@ int batadv_send_skb_via_gw(struct batadv_priv *bat_priv, struct sk_buff *skb, | |||
| 57 | * Returns NET_XMIT_DROP in case of error or NET_XMIT_SUCCESS otherwise. | 56 | * Returns NET_XMIT_DROP in case of error or NET_XMIT_SUCCESS otherwise. |
| 58 | */ | 57 | */ |
| 59 | static inline int batadv_send_skb_via_tt(struct batadv_priv *bat_priv, | 58 | static inline int batadv_send_skb_via_tt(struct batadv_priv *bat_priv, |
| 60 | struct sk_buff *skb, | 59 | struct sk_buff *skb, uint8_t *dst_hint, |
| 61 | unsigned short vid) | 60 | unsigned short vid) |
| 62 | { | 61 | { |
| 63 | return batadv_send_skb_via_tt_generic(bat_priv, skb, BATADV_UNICAST, 0, | 62 | return batadv_send_skb_via_tt_generic(bat_priv, skb, BATADV_UNICAST, 0, |
| 64 | vid); | 63 | dst_hint, vid); |
| 65 | } | 64 | } |
| 66 | 65 | ||
| 67 | /** | 66 | /** |
| @@ -81,11 +80,12 @@ static inline int batadv_send_skb_via_tt(struct batadv_priv *bat_priv, | |||
| 81 | static inline int batadv_send_skb_via_tt_4addr(struct batadv_priv *bat_priv, | 80 | static inline int batadv_send_skb_via_tt_4addr(struct batadv_priv *bat_priv, |
| 82 | struct sk_buff *skb, | 81 | struct sk_buff *skb, |
| 83 | int packet_subtype, | 82 | int packet_subtype, |
| 83 | uint8_t *dst_hint, | ||
| 84 | unsigned short vid) | 84 | unsigned short vid) |
| 85 | { | 85 | { |
| 86 | return batadv_send_skb_via_tt_generic(bat_priv, skb, | 86 | return batadv_send_skb_via_tt_generic(bat_priv, skb, |
| 87 | BATADV_UNICAST_4ADDR, | 87 | BATADV_UNICAST_4ADDR, |
| 88 | packet_subtype, vid); | 88 | packet_subtype, dst_hint, vid); |
| 89 | } | 89 | } |
| 90 | 90 | ||
| 91 | #endif /* _NET_BATMAN_ADV_SEND_H_ */ | 91 | #endif /* _NET_BATMAN_ADV_SEND_H_ */ |
diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c index a8f99d1486c0..f82c267e1886 100644 --- a/net/batman-adv/soft-interface.c +++ b/net/batman-adv/soft-interface.c | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors: | 1 | /* Copyright (C) 2007-2014 B.A.T.M.A.N. contributors: |
| 2 | * | 2 | * |
| 3 | * Marek Lindner, Simon Wunderlich | 3 | * Marek Lindner, Simon Wunderlich |
| 4 | * | 4 | * |
| @@ -12,9 +12,7 @@ | |||
| 12 | * General Public License for more details. | 12 | * General Public License for more details. |
| 13 | * | 13 | * |
| 14 | * You should have received a copy of the GNU General Public License | 14 | * You should have received a copy of the GNU General Public License |
| 15 | * along with this program; if not, write to the Free Software | 15 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 17 | * 02110-1301, USA | ||
| 18 | */ | 16 | */ |
| 19 | 17 | ||
| 20 | #include "main.h" | 18 | #include "main.h" |
| @@ -121,7 +119,7 @@ static int batadv_interface_set_mac_addr(struct net_device *dev, void *p) | |||
| 121 | batadv_tt_local_remove(bat_priv, old_addr, BATADV_NO_FLAGS, | 119 | batadv_tt_local_remove(bat_priv, old_addr, BATADV_NO_FLAGS, |
| 122 | "mac address changed", false); | 120 | "mac address changed", false); |
| 123 | batadv_tt_local_add(dev, addr->sa_data, BATADV_NO_FLAGS, | 121 | batadv_tt_local_add(dev, addr->sa_data, BATADV_NO_FLAGS, |
| 124 | BATADV_NULL_IFINDEX); | 122 | BATADV_NULL_IFINDEX, BATADV_NO_MARK); |
| 125 | } | 123 | } |
| 126 | 124 | ||
| 127 | return 0; | 125 | return 0; |
| @@ -162,6 +160,8 @@ static int batadv_interface_tx(struct sk_buff *skb, | |||
| 162 | 0x00, 0x00}; | 160 | 0x00, 0x00}; |
| 163 | static const uint8_t ectp_addr[ETH_ALEN] = {0xCF, 0x00, 0x00, 0x00, | 161 | static const uint8_t ectp_addr[ETH_ALEN] = {0xCF, 0x00, 0x00, 0x00, |
| 164 | 0x00, 0x00}; | 162 | 0x00, 0x00}; |
| 163 | enum batadv_dhcp_recipient dhcp_rcp = BATADV_DHCP_NO; | ||
| 164 | uint8_t *dst_hint = NULL, chaddr[ETH_ALEN]; | ||
| 165 | struct vlan_ethhdr *vhdr; | 165 | struct vlan_ethhdr *vhdr; |
| 166 | unsigned int header_len = 0; | 166 | unsigned int header_len = 0; |
| 167 | int data_len = skb->len, ret; | 167 | int data_len = skb->len, ret; |
| @@ -169,6 +169,7 @@ static int batadv_interface_tx(struct sk_buff *skb, | |||
| 169 | bool do_bcast = false, client_added; | 169 | bool do_bcast = false, client_added; |
| 170 | unsigned short vid; | 170 | unsigned short vid; |
| 171 | uint32_t seqno; | 171 | uint32_t seqno; |
| 172 | int gw_mode; | ||
| 172 | 173 | ||
| 173 | if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE) | 174 | if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE) |
| 174 | goto dropped; | 175 | goto dropped; |
| @@ -198,7 +199,8 @@ static int batadv_interface_tx(struct sk_buff *skb, | |||
| 198 | /* Register the client MAC in the transtable */ | 199 | /* Register the client MAC in the transtable */ |
| 199 | if (!is_multicast_ether_addr(ethhdr->h_source)) { | 200 | if (!is_multicast_ether_addr(ethhdr->h_source)) { |
| 200 | client_added = batadv_tt_local_add(soft_iface, ethhdr->h_source, | 201 | client_added = batadv_tt_local_add(soft_iface, ethhdr->h_source, |
| 201 | vid, skb->skb_iif); | 202 | vid, skb->skb_iif, |
| 203 | skb->mark); | ||
| 202 | if (!client_added) | 204 | if (!client_added) |
| 203 | goto dropped; | 205 | goto dropped; |
| 204 | } | 206 | } |
| @@ -215,36 +217,39 @@ static int batadv_interface_tx(struct sk_buff *skb, | |||
| 215 | if (batadv_compare_eth(ethhdr->h_dest, ectp_addr)) | 217 | if (batadv_compare_eth(ethhdr->h_dest, ectp_addr)) |
| 216 | goto dropped; | 218 | goto dropped; |
| 217 | 219 | ||
| 220 | gw_mode = atomic_read(&bat_priv->gw_mode); | ||
| 218 | if (is_multicast_ether_addr(ethhdr->h_dest)) { | 221 | if (is_multicast_ether_addr(ethhdr->h_dest)) { |
| 219 | do_bcast = true; | 222 | /* if gw mode is off, broadcast every packet */ |
| 220 | 223 | if (gw_mode == BATADV_GW_MODE_OFF) { | |
| 221 | switch (atomic_read(&bat_priv->gw_mode)) { | 224 | do_bcast = true; |
| 222 | case BATADV_GW_MODE_SERVER: | 225 | goto send; |
| 223 | /* gateway servers should not send dhcp | ||
| 224 | * requests into the mesh | ||
| 225 | */ | ||
| 226 | ret = batadv_gw_is_dhcp_target(skb, &header_len); | ||
| 227 | if (ret) | ||
| 228 | goto dropped; | ||
| 229 | break; | ||
| 230 | case BATADV_GW_MODE_CLIENT: | ||
| 231 | /* gateway clients should send dhcp requests | ||
| 232 | * via unicast to their gateway | ||
| 233 | */ | ||
| 234 | ret = batadv_gw_is_dhcp_target(skb, &header_len); | ||
| 235 | if (ret) | ||
| 236 | do_bcast = false; | ||
| 237 | break; | ||
| 238 | case BATADV_GW_MODE_OFF: | ||
| 239 | default: | ||
| 240 | break; | ||
| 241 | } | 226 | } |
| 242 | 227 | ||
| 243 | /* reminder: ethhdr might have become unusable from here on | 228 | dhcp_rcp = batadv_gw_dhcp_recipient_get(skb, &header_len, |
| 244 | * (batadv_gw_is_dhcp_target() might have reallocated skb data) | 229 | chaddr); |
| 230 | /* skb->data may have been modified by | ||
| 231 | * batadv_gw_dhcp_recipient_get() | ||
| 245 | */ | 232 | */ |
| 233 | ethhdr = (struct ethhdr *)skb->data; | ||
| 234 | /* if gw_mode is on, broadcast any non-DHCP message. | ||
| 235 | * All the DHCP packets are going to be sent as unicast | ||
| 236 | */ | ||
| 237 | if (dhcp_rcp == BATADV_DHCP_NO) { | ||
| 238 | do_bcast = true; | ||
| 239 | goto send; | ||
| 240 | } | ||
| 241 | |||
| 242 | if (dhcp_rcp == BATADV_DHCP_TO_CLIENT) | ||
| 243 | dst_hint = chaddr; | ||
| 244 | else if ((gw_mode == BATADV_GW_MODE_SERVER) && | ||
| 245 | (dhcp_rcp == BATADV_DHCP_TO_SERVER)) | ||
| 246 | /* gateways should not forward any DHCP message if | ||
| 247 | * directed to a DHCP server | ||
| 248 | */ | ||
| 249 | goto dropped; | ||
| 246 | } | 250 | } |
| 247 | 251 | ||
| 252 | send: | ||
| 248 | batadv_skb_set_priority(skb, 0); | 253 | batadv_skb_set_priority(skb, 0); |
| 249 | 254 | ||
| 250 | /* ethernet packet should be broadcasted */ | 255 | /* ethernet packet should be broadcasted */ |
| @@ -290,22 +295,22 @@ static int batadv_interface_tx(struct sk_buff *skb, | |||
| 290 | 295 | ||
| 291 | /* unicast packet */ | 296 | /* unicast packet */ |
| 292 | } else { | 297 | } else { |
| 293 | if (atomic_read(&bat_priv->gw_mode) != BATADV_GW_MODE_OFF) { | 298 | /* DHCP packets going to a server will use the GW feature */ |
| 299 | if (dhcp_rcp == BATADV_DHCP_TO_SERVER) { | ||
| 294 | ret = batadv_gw_out_of_range(bat_priv, skb); | 300 | ret = batadv_gw_out_of_range(bat_priv, skb); |
| 295 | if (ret) | 301 | if (ret) |
| 296 | goto dropped; | 302 | goto dropped; |
| 297 | } | ||
| 298 | |||
| 299 | if (batadv_dat_snoop_outgoing_arp_request(bat_priv, skb)) | ||
| 300 | goto dropped; | ||
| 301 | |||
| 302 | batadv_dat_snoop_outgoing_arp_reply(bat_priv, skb); | ||
| 303 | |||
| 304 | if (is_multicast_ether_addr(ethhdr->h_dest)) | ||
| 305 | ret = batadv_send_skb_via_gw(bat_priv, skb, vid); | 303 | ret = batadv_send_skb_via_gw(bat_priv, skb, vid); |
| 306 | else | 304 | } else { |
| 307 | ret = batadv_send_skb_via_tt(bat_priv, skb, vid); | 305 | if (batadv_dat_snoop_outgoing_arp_request(bat_priv, |
| 306 | skb)) | ||
| 307 | goto dropped; | ||
| 308 | 308 | ||
| 309 | batadv_dat_snoop_outgoing_arp_reply(bat_priv, skb); | ||
| 310 | |||
| 311 | ret = batadv_send_skb_via_tt(bat_priv, skb, dst_hint, | ||
| 312 | vid); | ||
| 313 | } | ||
| 309 | if (ret == NET_XMIT_DROP) | 314 | if (ret == NET_XMIT_DROP) |
| 310 | goto dropped_freed; | 315 | goto dropped_freed; |
| 311 | } | 316 | } |
| @@ -394,9 +399,23 @@ void batadv_interface_rx(struct net_device *soft_iface, | |||
| 394 | batadv_tt_add_temporary_global_entry(bat_priv, orig_node, | 399 | batadv_tt_add_temporary_global_entry(bat_priv, orig_node, |
| 395 | ethhdr->h_source, vid); | 400 | ethhdr->h_source, vid); |
| 396 | 401 | ||
| 397 | if (batadv_is_ap_isolated(bat_priv, ethhdr->h_source, ethhdr->h_dest, | 402 | if (is_multicast_ether_addr(ethhdr->h_dest)) { |
| 398 | vid)) | 403 | /* set the mark on broadcast packets if AP isolation is ON and |
| 404 | * the packet is coming from an "isolated" client | ||
| 405 | */ | ||
| 406 | if (batadv_vlan_ap_isola_get(bat_priv, vid) && | ||
| 407 | batadv_tt_global_is_isolated(bat_priv, ethhdr->h_source, | ||
| 408 | vid)) { | ||
| 409 | /* save bits in skb->mark not covered by the mask and | ||
| 410 | * apply the mark on the rest | ||
| 411 | */ | ||
| 412 | skb->mark &= ~bat_priv->isolation_mark_mask; | ||
| 413 | skb->mark |= bat_priv->isolation_mark; | ||
| 414 | } | ||
| 415 | } else if (batadv_is_ap_isolated(bat_priv, ethhdr->h_source, | ||
| 416 | ethhdr->h_dest, vid)) { | ||
| 399 | goto dropped; | 417 | goto dropped; |
| 418 | } | ||
| 400 | 419 | ||
| 401 | netif_rx(skb); | 420 | netif_rx(skb); |
| 402 | goto out; | 421 | goto out; |
| @@ -485,7 +504,7 @@ int batadv_softif_create_vlan(struct batadv_priv *bat_priv, unsigned short vid) | |||
| 485 | */ | 504 | */ |
| 486 | batadv_tt_local_add(bat_priv->soft_iface, | 505 | batadv_tt_local_add(bat_priv->soft_iface, |
| 487 | bat_priv->soft_iface->dev_addr, vid, | 506 | bat_priv->soft_iface->dev_addr, vid, |
| 488 | BATADV_NULL_IFINDEX); | 507 | BATADV_NULL_IFINDEX, BATADV_NO_MARK); |
| 489 | 508 | ||
| 490 | spin_lock_bh(&bat_priv->softif_vlan_list_lock); | 509 | spin_lock_bh(&bat_priv->softif_vlan_list_lock); |
| 491 | hlist_add_head_rcu(&vlan->list, &bat_priv->softif_vlan_list); | 510 | hlist_add_head_rcu(&vlan->list, &bat_priv->softif_vlan_list); |
| @@ -678,7 +697,7 @@ static int batadv_softif_init_late(struct net_device *dev) | |||
| 678 | atomic_set(&bat_priv->gw.bandwidth_down, 100); | 697 | atomic_set(&bat_priv->gw.bandwidth_down, 100); |
| 679 | atomic_set(&bat_priv->gw.bandwidth_up, 20); | 698 | atomic_set(&bat_priv->gw.bandwidth_up, 20); |
| 680 | atomic_set(&bat_priv->orig_interval, 1000); | 699 | atomic_set(&bat_priv->orig_interval, 1000); |
| 681 | atomic_set(&bat_priv->hop_penalty, 30); | 700 | atomic_set(&bat_priv->hop_penalty, 15); |
| 682 | #ifdef CONFIG_BATMAN_ADV_DEBUG | 701 | #ifdef CONFIG_BATMAN_ADV_DEBUG |
| 683 | atomic_set(&bat_priv->log_level, 0); | 702 | atomic_set(&bat_priv->log_level, 0); |
| 684 | #endif | 703 | #endif |
| @@ -697,6 +716,8 @@ static int batadv_softif_init_late(struct net_device *dev) | |||
| 697 | #endif | 716 | #endif |
| 698 | bat_priv->tt.last_changeset = NULL; | 717 | bat_priv->tt.last_changeset = NULL; |
| 699 | bat_priv->tt.last_changeset_len = 0; | 718 | bat_priv->tt.last_changeset_len = 0; |
| 719 | bat_priv->isolation_mark = 0; | ||
| 720 | bat_priv->isolation_mark_mask = 0; | ||
| 700 | 721 | ||
| 701 | /* randomize initial seqno to avoid collision */ | 722 | /* randomize initial seqno to avoid collision */ |
| 702 | get_random_bytes(&random_seqno, sizeof(random_seqno)); | 723 | get_random_bytes(&random_seqno, sizeof(random_seqno)); |
diff --git a/net/batman-adv/soft-interface.h b/net/batman-adv/soft-interface.h index 06fc91ff5a02..dbab22fd89a5 100644 --- a/net/batman-adv/soft-interface.h +++ b/net/batman-adv/soft-interface.h | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors: | 1 | /* Copyright (C) 2007-2014 B.A.T.M.A.N. contributors: |
| 2 | * | 2 | * |
| 3 | * Marek Lindner | 3 | * Marek Lindner |
| 4 | * | 4 | * |
| @@ -12,9 +12,7 @@ | |||
| 12 | * General Public License for more details. | 12 | * General Public License for more details. |
| 13 | * | 13 | * |
| 14 | * You should have received a copy of the GNU General Public License | 14 | * You should have received a copy of the GNU General Public License |
| 15 | * along with this program; if not, write to the Free Software | 15 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 17 | * 02110-1301, USA | ||
| 18 | */ | 16 | */ |
| 19 | 17 | ||
| 20 | #ifndef _NET_BATMAN_ADV_SOFT_INTERFACE_H_ | 18 | #ifndef _NET_BATMAN_ADV_SOFT_INTERFACE_H_ |
diff --git a/net/batman-adv/sysfs.c b/net/batman-adv/sysfs.c index 6335433310af..e456bf6bb284 100644 --- a/net/batman-adv/sysfs.c +++ b/net/batman-adv/sysfs.c | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* Copyright (C) 2010-2013 B.A.T.M.A.N. contributors: | 1 | /* Copyright (C) 2010-2014 B.A.T.M.A.N. contributors: |
| 2 | * | 2 | * |
| 3 | * Marek Lindner | 3 | * Marek Lindner |
| 4 | * | 4 | * |
| @@ -12,9 +12,7 @@ | |||
| 12 | * General Public License for more details. | 12 | * General Public License for more details. |
| 13 | * | 13 | * |
| 14 | * You should have received a copy of the GNU General Public License | 14 | * You should have received a copy of the GNU General Public License |
| 15 | * along with this program; if not, write to the Free Software | 15 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 17 | * 02110-1301, USA | ||
| 18 | */ | 16 | */ |
| 19 | 17 | ||
| 20 | #include "main.h" | 18 | #include "main.h" |
| @@ -329,10 +327,10 @@ static ssize_t batadv_show_bat_algo(struct kobject *kobj, | |||
| 329 | return sprintf(buff, "%s\n", bat_priv->bat_algo_ops->name); | 327 | return sprintf(buff, "%s\n", bat_priv->bat_algo_ops->name); |
| 330 | } | 328 | } |
| 331 | 329 | ||
| 332 | static void batadv_post_gw_deselect(struct net_device *net_dev) | 330 | static void batadv_post_gw_reselect(struct net_device *net_dev) |
| 333 | { | 331 | { |
| 334 | struct batadv_priv *bat_priv = netdev_priv(net_dev); | 332 | struct batadv_priv *bat_priv = netdev_priv(net_dev); |
| 335 | batadv_gw_deselect(bat_priv); | 333 | batadv_gw_reselect(bat_priv); |
| 336 | } | 334 | } |
| 337 | 335 | ||
| 338 | static ssize_t batadv_show_gw_mode(struct kobject *kobj, struct attribute *attr, | 336 | static ssize_t batadv_show_gw_mode(struct kobject *kobj, struct attribute *attr, |
| @@ -408,7 +406,16 @@ static ssize_t batadv_store_gw_mode(struct kobject *kobj, | |||
| 408 | batadv_info(net_dev, "Changing gw mode from: %s to: %s\n", | 406 | batadv_info(net_dev, "Changing gw mode from: %s to: %s\n", |
| 409 | curr_gw_mode_str, buff); | 407 | curr_gw_mode_str, buff); |
| 410 | 408 | ||
| 411 | batadv_gw_deselect(bat_priv); | 409 | /* Invoking batadv_gw_reselect() is not enough to really de-select the |
| 410 | * current GW. It will only instruct the gateway client code to perform | ||
| 411 | * a re-election the next time that this is needed. | ||
| 412 | * | ||
| 413 | * When gw client mode is being switched off the current GW must be | ||
| 414 | * de-selected explicitly otherwise no GW_ADD uevent is thrown on | ||
| 415 | * client mode re-activation. This is operation is performed in | ||
| 416 | * batadv_gw_check_client_stop(). | ||
| 417 | */ | ||
| 418 | batadv_gw_reselect(bat_priv); | ||
| 412 | /* always call batadv_gw_check_client_stop() before changing the gateway | 419 | /* always call batadv_gw_check_client_stop() before changing the gateway |
| 413 | * state | 420 | * state |
| 414 | */ | 421 | */ |
| @@ -443,6 +450,74 @@ static ssize_t batadv_store_gw_bwidth(struct kobject *kobj, | |||
| 443 | return batadv_gw_bandwidth_set(net_dev, buff, count); | 450 | return batadv_gw_bandwidth_set(net_dev, buff, count); |
| 444 | } | 451 | } |
| 445 | 452 | ||
| 453 | /** | ||
| 454 | * batadv_show_isolation_mark - print the current isolation mark/mask | ||
| 455 | * @kobj: kobject representing the private mesh sysfs directory | ||
| 456 | * @attr: the batman-adv attribute the user is interacting with | ||
| 457 | * @buff: the buffer that will contain the data to send back to the user | ||
| 458 | * | ||
| 459 | * Returns the number of bytes written into 'buff' on success or a negative | ||
| 460 | * error code in case of failure | ||
| 461 | */ | ||
| 462 | static ssize_t batadv_show_isolation_mark(struct kobject *kobj, | ||
| 463 | struct attribute *attr, char *buff) | ||
| 464 | { | ||
| 465 | struct batadv_priv *bat_priv = batadv_kobj_to_batpriv(kobj); | ||
| 466 | |||
| 467 | return sprintf(buff, "%#.8x/%#.8x\n", bat_priv->isolation_mark, | ||
| 468 | bat_priv->isolation_mark_mask); | ||
| 469 | } | ||
| 470 | |||
| 471 | /** | ||
| 472 | * batadv_store_isolation_mark - parse and store the isolation mark/mask entered | ||
| 473 | * by the user | ||
| 474 | * @kobj: kobject representing the private mesh sysfs directory | ||
| 475 | * @attr: the batman-adv attribute the user is interacting with | ||
| 476 | * @buff: the buffer containing the user data | ||
| 477 | * @count: number of bytes in the buffer | ||
| 478 | * | ||
| 479 | * Returns 'count' on success or a negative error code in case of failure | ||
| 480 | */ | ||
| 481 | static ssize_t batadv_store_isolation_mark(struct kobject *kobj, | ||
| 482 | struct attribute *attr, char *buff, | ||
| 483 | size_t count) | ||
| 484 | { | ||
| 485 | struct net_device *net_dev = batadv_kobj_to_netdev(kobj); | ||
| 486 | struct batadv_priv *bat_priv = netdev_priv(net_dev); | ||
| 487 | uint32_t mark, mask; | ||
| 488 | char *mask_ptr; | ||
| 489 | |||
| 490 | /* parse the mask if it has been specified, otherwise assume the mask is | ||
| 491 | * the biggest possible | ||
| 492 | */ | ||
| 493 | mask = 0xFFFFFFFF; | ||
| 494 | mask_ptr = strchr(buff, '/'); | ||
| 495 | if (mask_ptr) { | ||
| 496 | *mask_ptr = '\0'; | ||
| 497 | mask_ptr++; | ||
| 498 | |||
| 499 | /* the mask must be entered in hex base as it is going to be a | ||
| 500 | * bitmask and not a prefix length | ||
| 501 | */ | ||
| 502 | if (kstrtou32(mask_ptr, 16, &mask) < 0) | ||
| 503 | return -EINVAL; | ||
| 504 | } | ||
| 505 | |||
| 506 | /* the mark can be entered in any base */ | ||
| 507 | if (kstrtou32(buff, 0, &mark) < 0) | ||
| 508 | return -EINVAL; | ||
| 509 | |||
| 510 | bat_priv->isolation_mark_mask = mask; | ||
| 511 | /* erase bits not covered by the mask */ | ||
| 512 | bat_priv->isolation_mark = mark & bat_priv->isolation_mark_mask; | ||
| 513 | |||
| 514 | batadv_info(net_dev, | ||
| 515 | "New skb mark for extended isolation: %#.8x/%#.8x\n", | ||
| 516 | bat_priv->isolation_mark, bat_priv->isolation_mark_mask); | ||
| 517 | |||
| 518 | return count; | ||
| 519 | } | ||
| 520 | |||
| 446 | BATADV_ATTR_SIF_BOOL(aggregated_ogms, S_IRUGO | S_IWUSR, NULL); | 521 | BATADV_ATTR_SIF_BOOL(aggregated_ogms, S_IRUGO | S_IWUSR, NULL); |
| 447 | BATADV_ATTR_SIF_BOOL(bonding, S_IRUGO | S_IWUSR, NULL); | 522 | BATADV_ATTR_SIF_BOOL(bonding, S_IRUGO | S_IWUSR, NULL); |
| 448 | #ifdef CONFIG_BATMAN_ADV_BLA | 523 | #ifdef CONFIG_BATMAN_ADV_BLA |
| @@ -461,7 +536,7 @@ BATADV_ATTR_SIF_UINT(orig_interval, S_IRUGO | S_IWUSR, 2 * BATADV_JITTER, | |||
| 461 | BATADV_ATTR_SIF_UINT(hop_penalty, S_IRUGO | S_IWUSR, 0, BATADV_TQ_MAX_VALUE, | 536 | BATADV_ATTR_SIF_UINT(hop_penalty, S_IRUGO | S_IWUSR, 0, BATADV_TQ_MAX_VALUE, |
| 462 | NULL); | 537 | NULL); |
| 463 | BATADV_ATTR_SIF_UINT(gw_sel_class, S_IRUGO | S_IWUSR, 1, BATADV_TQ_MAX_VALUE, | 538 | BATADV_ATTR_SIF_UINT(gw_sel_class, S_IRUGO | S_IWUSR, 1, BATADV_TQ_MAX_VALUE, |
| 464 | batadv_post_gw_deselect); | 539 | batadv_post_gw_reselect); |
| 465 | static BATADV_ATTR(gw_bandwidth, S_IRUGO | S_IWUSR, batadv_show_gw_bwidth, | 540 | static BATADV_ATTR(gw_bandwidth, S_IRUGO | S_IWUSR, batadv_show_gw_bwidth, |
| 466 | batadv_store_gw_bwidth); | 541 | batadv_store_gw_bwidth); |
| 467 | #ifdef CONFIG_BATMAN_ADV_DEBUG | 542 | #ifdef CONFIG_BATMAN_ADV_DEBUG |
| @@ -471,6 +546,8 @@ BATADV_ATTR_SIF_UINT(log_level, S_IRUGO | S_IWUSR, 0, BATADV_DBG_ALL, NULL); | |||
| 471 | BATADV_ATTR_SIF_BOOL(network_coding, S_IRUGO | S_IWUSR, | 546 | BATADV_ATTR_SIF_BOOL(network_coding, S_IRUGO | S_IWUSR, |
| 472 | batadv_nc_status_update); | 547 | batadv_nc_status_update); |
| 473 | #endif | 548 | #endif |
| 549 | static BATADV_ATTR(isolation_mark, S_IRUGO | S_IWUSR, | ||
| 550 | batadv_show_isolation_mark, batadv_store_isolation_mark); | ||
| 474 | 551 | ||
| 475 | static struct batadv_attribute *batadv_mesh_attrs[] = { | 552 | static struct batadv_attribute *batadv_mesh_attrs[] = { |
| 476 | &batadv_attr_aggregated_ogms, | 553 | &batadv_attr_aggregated_ogms, |
| @@ -494,6 +571,7 @@ static struct batadv_attribute *batadv_mesh_attrs[] = { | |||
| 494 | #ifdef CONFIG_BATMAN_ADV_NC | 571 | #ifdef CONFIG_BATMAN_ADV_NC |
| 495 | &batadv_attr_network_coding, | 572 | &batadv_attr_network_coding, |
| 496 | #endif | 573 | #endif |
| 574 | &batadv_attr_isolation_mark, | ||
| 497 | NULL, | 575 | NULL, |
| 498 | }; | 576 | }; |
| 499 | 577 | ||
diff --git a/net/batman-adv/sysfs.h b/net/batman-adv/sysfs.h index c7d725de50ad..b715b60db7cd 100644 --- a/net/batman-adv/sysfs.h +++ b/net/batman-adv/sysfs.h | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* Copyright (C) 2010-2013 B.A.T.M.A.N. contributors: | 1 | /* Copyright (C) 2010-2014 B.A.T.M.A.N. contributors: |
| 2 | * | 2 | * |
| 3 | * Marek Lindner | 3 | * Marek Lindner |
| 4 | * | 4 | * |
| @@ -12,9 +12,7 @@ | |||
| 12 | * General Public License for more details. | 12 | * General Public License for more details. |
| 13 | * | 13 | * |
| 14 | * You should have received a copy of the GNU General Public License | 14 | * You should have received a copy of the GNU General Public License |
| 15 | * along with this program; if not, write to the Free Software | 15 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 17 | * 02110-1301, USA | ||
| 18 | */ | 16 | */ |
| 19 | 17 | ||
| 20 | #ifndef _NET_BATMAN_ADV_SYSFS_H_ | 18 | #ifndef _NET_BATMAN_ADV_SYSFS_H_ |
diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c index ff625fedbc5e..b6071f675a3e 100644 --- a/net/batman-adv/translation-table.c +++ b/net/batman-adv/translation-table.c | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors: | 1 | /* Copyright (C) 2007-2014 B.A.T.M.A.N. contributors: |
| 2 | * | 2 | * |
| 3 | * Marek Lindner, Simon Wunderlich, Antonio Quartulli | 3 | * Marek Lindner, Simon Wunderlich, Antonio Quartulli |
| 4 | * | 4 | * |
| @@ -12,9 +12,7 @@ | |||
| 12 | * General Public License for more details. | 12 | * General Public License for more details. |
| 13 | * | 13 | * |
| 14 | * You should have received a copy of the GNU General Public License | 14 | * You should have received a copy of the GNU General Public License |
| 15 | * along with this program; if not, write to the Free Software | 15 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 17 | * 02110-1301, USA | ||
| 18 | */ | 16 | */ |
| 19 | 17 | ||
| 20 | #include "main.h" | 18 | #include "main.h" |
| @@ -51,7 +49,7 @@ static int batadv_compare_tt(const struct hlist_node *node, const void *data2) | |||
| 51 | const void *data1 = container_of(node, struct batadv_tt_common_entry, | 49 | const void *data1 = container_of(node, struct batadv_tt_common_entry, |
| 52 | hash_entry); | 50 | hash_entry); |
| 53 | 51 | ||
| 54 | return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0); | 52 | return batadv_compare_eth(data1, data2); |
| 55 | } | 53 | } |
| 56 | 54 | ||
| 57 | /** | 55 | /** |
| @@ -476,11 +474,13 @@ static void batadv_tt_global_free(struct batadv_priv *bat_priv, | |||
| 476 | * @vid: VLAN identifier | 474 | * @vid: VLAN identifier |
| 477 | * @ifindex: index of the interface where the client is connected to (useful to | 475 | * @ifindex: index of the interface where the client is connected to (useful to |
| 478 | * identify wireless clients) | 476 | * identify wireless clients) |
| 477 | * @mark: the value contained in the skb->mark field of the received packet (if | ||
| 478 | * any) | ||
| 479 | * | 479 | * |
| 480 | * Returns true if the client was successfully added, false otherwise. | 480 | * Returns true if the client was successfully added, false otherwise. |
| 481 | */ | 481 | */ |
| 482 | bool batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr, | 482 | bool batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr, |
| 483 | unsigned short vid, int ifindex) | 483 | unsigned short vid, int ifindex, uint32_t mark) |
| 484 | { | 484 | { |
| 485 | struct batadv_priv *bat_priv = netdev_priv(soft_iface); | 485 | struct batadv_priv *bat_priv = netdev_priv(soft_iface); |
| 486 | struct batadv_tt_local_entry *tt_local; | 486 | struct batadv_tt_local_entry *tt_local; |
| @@ -491,6 +491,7 @@ bool batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr, | |||
| 491 | int hash_added, table_size, packet_size_max; | 491 | int hash_added, table_size, packet_size_max; |
| 492 | bool ret = false, roamed_back = false; | 492 | bool ret = false, roamed_back = false; |
| 493 | uint8_t remote_flags; | 493 | uint8_t remote_flags; |
| 494 | uint32_t match_mark; | ||
| 494 | 495 | ||
| 495 | if (ifindex != BATADV_NULL_IFINDEX) | 496 | if (ifindex != BATADV_NULL_IFINDEX) |
| 496 | in_dev = dev_get_by_index(&init_net, ifindex); | 497 | in_dev = dev_get_by_index(&init_net, ifindex); |
| @@ -615,6 +616,17 @@ check_roaming: | |||
| 615 | else | 616 | else |
| 616 | tt_local->common.flags &= ~BATADV_TT_CLIENT_WIFI; | 617 | tt_local->common.flags &= ~BATADV_TT_CLIENT_WIFI; |
| 617 | 618 | ||
| 619 | /* check the mark in the skb: if it's equal to the configured | ||
| 620 | * isolation_mark, it means the packet is coming from an isolated | ||
| 621 | * non-mesh client | ||
| 622 | */ | ||
| 623 | match_mark = (mark & bat_priv->isolation_mark_mask); | ||
| 624 | if (bat_priv->isolation_mark_mask && | ||
| 625 | match_mark == bat_priv->isolation_mark) | ||
| 626 | tt_local->common.flags |= BATADV_TT_CLIENT_ISOLA; | ||
| 627 | else | ||
| 628 | tt_local->common.flags &= ~BATADV_TT_CLIENT_ISOLA; | ||
| 629 | |||
| 618 | /* if any "dynamic" flag has been modified, resend an ADD event for this | 630 | /* if any "dynamic" flag has been modified, resend an ADD event for this |
| 619 | * entry so that all the nodes can get the new flags | 631 | * entry so that all the nodes can get the new flags |
| 620 | */ | 632 | */ |
| @@ -875,7 +887,7 @@ int batadv_tt_local_seq_print_text(struct seq_file *seq, void *offset) | |||
| 875 | seq_printf(seq, | 887 | seq_printf(seq, |
| 876 | "Locally retrieved addresses (from %s) announced via TT (TTVN: %u):\n", | 888 | "Locally retrieved addresses (from %s) announced via TT (TTVN: %u):\n", |
| 877 | net_dev->name, (uint8_t)atomic_read(&bat_priv->tt.vn)); | 889 | net_dev->name, (uint8_t)atomic_read(&bat_priv->tt.vn)); |
| 878 | seq_printf(seq, " %-13s %s %-7s %-9s (%-10s)\n", "Client", "VID", | 890 | seq_printf(seq, " %-13s %s %-8s %-9s (%-10s)\n", "Client", "VID", |
| 879 | "Flags", "Last seen", "CRC"); | 891 | "Flags", "Last seen", "CRC"); |
| 880 | 892 | ||
| 881 | for (i = 0; i < hash->size; i++) { | 893 | for (i = 0; i < hash->size; i++) { |
| @@ -903,7 +915,7 @@ int batadv_tt_local_seq_print_text(struct seq_file *seq, void *offset) | |||
| 903 | } | 915 | } |
| 904 | 916 | ||
| 905 | seq_printf(seq, | 917 | seq_printf(seq, |
| 906 | " * %pM %4i [%c%c%c%c%c] %3u.%03u (%#.8x)\n", | 918 | " * %pM %4i [%c%c%c%c%c%c] %3u.%03u (%#.8x)\n", |
| 907 | tt_common_entry->addr, | 919 | tt_common_entry->addr, |
| 908 | BATADV_PRINT_VID(tt_common_entry->vid), | 920 | BATADV_PRINT_VID(tt_common_entry->vid), |
| 909 | (tt_common_entry->flags & | 921 | (tt_common_entry->flags & |
| @@ -915,6 +927,8 @@ int batadv_tt_local_seq_print_text(struct seq_file *seq, void *offset) | |||
| 915 | BATADV_TT_CLIENT_PENDING ? 'X' : '.'), | 927 | BATADV_TT_CLIENT_PENDING ? 'X' : '.'), |
| 916 | (tt_common_entry->flags & | 928 | (tt_common_entry->flags & |
| 917 | BATADV_TT_CLIENT_WIFI ? 'W' : '.'), | 929 | BATADV_TT_CLIENT_WIFI ? 'W' : '.'), |
| 930 | (tt_common_entry->flags & | ||
| 931 | BATADV_TT_CLIENT_ISOLA ? 'I' : '.'), | ||
| 918 | no_purge ? 0 : last_seen_secs, | 932 | no_purge ? 0 : last_seen_secs, |
| 919 | no_purge ? 0 : last_seen_msecs, | 933 | no_purge ? 0 : last_seen_msecs, |
| 920 | vlan->tt.crc); | 934 | vlan->tt.crc); |
| @@ -1368,7 +1382,8 @@ out: | |||
| 1368 | return ret; | 1382 | return ret; |
| 1369 | } | 1383 | } |
| 1370 | 1384 | ||
| 1371 | /* batadv_transtable_best_orig - Get best originator list entry from tt entry | 1385 | /** |
| 1386 | * batadv_transtable_best_orig - Get best originator list entry from tt entry | ||
| 1372 | * @bat_priv: the bat priv with all the soft interface information | 1387 | * @bat_priv: the bat priv with all the soft interface information |
| 1373 | * @tt_global_entry: global translation table entry to be analyzed | 1388 | * @tt_global_entry: global translation table entry to be analyzed |
| 1374 | * | 1389 | * |
| @@ -1386,12 +1401,14 @@ batadv_transtable_best_orig(struct batadv_priv *bat_priv, | |||
| 1386 | 1401 | ||
| 1387 | head = &tt_global_entry->orig_list; | 1402 | head = &tt_global_entry->orig_list; |
| 1388 | hlist_for_each_entry_rcu(orig_entry, head, list) { | 1403 | hlist_for_each_entry_rcu(orig_entry, head, list) { |
| 1389 | router = batadv_orig_node_get_router(orig_entry->orig_node); | 1404 | router = batadv_orig_router_get(orig_entry->orig_node, |
| 1405 | BATADV_IF_DEFAULT); | ||
| 1390 | if (!router) | 1406 | if (!router) |
| 1391 | continue; | 1407 | continue; |
| 1392 | 1408 | ||
| 1393 | if (best_router && | 1409 | if (best_router && |
| 1394 | bao->bat_neigh_cmp(router, best_router) <= 0) { | 1410 | bao->bat_neigh_cmp(router, BATADV_IF_DEFAULT, |
| 1411 | best_router, BATADV_IF_DEFAULT) <= 0) { | ||
| 1395 | batadv_neigh_node_free_ref(router); | 1412 | batadv_neigh_node_free_ref(router); |
| 1396 | continue; | 1413 | continue; |
| 1397 | } | 1414 | } |
| @@ -1410,8 +1427,9 @@ batadv_transtable_best_orig(struct batadv_priv *bat_priv, | |||
| 1410 | return best_entry; | 1427 | return best_entry; |
| 1411 | } | 1428 | } |
| 1412 | 1429 | ||
| 1413 | /* batadv_tt_global_print_entry - print all orig nodes who announce the address | 1430 | /** |
| 1414 | * for this global entry | 1431 | * batadv_tt_global_print_entry - print all orig nodes who announce the address |
| 1432 | * for this global entry | ||
| 1415 | * @bat_priv: the bat priv with all the soft interface information | 1433 | * @bat_priv: the bat priv with all the soft interface information |
| 1416 | * @tt_global_entry: global translation table entry to be printed | 1434 | * @tt_global_entry: global translation table entry to be printed |
| 1417 | * @seq: debugfs table seq_file struct | 1435 | * @seq: debugfs table seq_file struct |
| @@ -1447,13 +1465,14 @@ batadv_tt_global_print_entry(struct batadv_priv *bat_priv, | |||
| 1447 | 1465 | ||
| 1448 | last_ttvn = atomic_read(&best_entry->orig_node->last_ttvn); | 1466 | last_ttvn = atomic_read(&best_entry->orig_node->last_ttvn); |
| 1449 | seq_printf(seq, | 1467 | seq_printf(seq, |
| 1450 | " %c %pM %4i (%3u) via %pM (%3u) (%#.8x) [%c%c%c]\n", | 1468 | " %c %pM %4i (%3u) via %pM (%3u) (%#.8x) [%c%c%c%c]\n", |
| 1451 | '*', tt_global_entry->common.addr, | 1469 | '*', tt_global_entry->common.addr, |
| 1452 | BATADV_PRINT_VID(tt_global_entry->common.vid), | 1470 | BATADV_PRINT_VID(tt_global_entry->common.vid), |
| 1453 | best_entry->ttvn, best_entry->orig_node->orig, | 1471 | best_entry->ttvn, best_entry->orig_node->orig, |
| 1454 | last_ttvn, vlan->tt.crc, | 1472 | last_ttvn, vlan->tt.crc, |
| 1455 | (flags & BATADV_TT_CLIENT_ROAM ? 'R' : '.'), | 1473 | (flags & BATADV_TT_CLIENT_ROAM ? 'R' : '.'), |
| 1456 | (flags & BATADV_TT_CLIENT_WIFI ? 'W' : '.'), | 1474 | (flags & BATADV_TT_CLIENT_WIFI ? 'W' : '.'), |
| 1475 | (flags & BATADV_TT_CLIENT_ISOLA ? 'I' : '.'), | ||
| 1457 | (flags & BATADV_TT_CLIENT_TEMP ? 'T' : '.')); | 1476 | (flags & BATADV_TT_CLIENT_TEMP ? 'T' : '.')); |
| 1458 | 1477 | ||
| 1459 | batadv_orig_node_vlan_free_ref(vlan); | 1478 | batadv_orig_node_vlan_free_ref(vlan); |
| @@ -1478,13 +1497,14 @@ print_list: | |||
| 1478 | 1497 | ||
| 1479 | last_ttvn = atomic_read(&orig_entry->orig_node->last_ttvn); | 1498 | last_ttvn = atomic_read(&orig_entry->orig_node->last_ttvn); |
| 1480 | seq_printf(seq, | 1499 | seq_printf(seq, |
| 1481 | " %c %pM %4d (%3u) via %pM (%3u) (%#.8x) [%c%c%c]\n", | 1500 | " %c %pM %4d (%3u) via %pM (%3u) (%#.8x) [%c%c%c%c]\n", |
| 1482 | '+', tt_global_entry->common.addr, | 1501 | '+', tt_global_entry->common.addr, |
| 1483 | BATADV_PRINT_VID(tt_global_entry->common.vid), | 1502 | BATADV_PRINT_VID(tt_global_entry->common.vid), |
| 1484 | orig_entry->ttvn, orig_entry->orig_node->orig, | 1503 | orig_entry->ttvn, orig_entry->orig_node->orig, |
| 1485 | last_ttvn, vlan->tt.crc, | 1504 | last_ttvn, vlan->tt.crc, |
| 1486 | (flags & BATADV_TT_CLIENT_ROAM ? 'R' : '.'), | 1505 | (flags & BATADV_TT_CLIENT_ROAM ? 'R' : '.'), |
| 1487 | (flags & BATADV_TT_CLIENT_WIFI ? 'W' : '.'), | 1506 | (flags & BATADV_TT_CLIENT_WIFI ? 'W' : '.'), |
| 1507 | (flags & BATADV_TT_CLIENT_ISOLA ? 'I' : '.'), | ||
| 1488 | (flags & BATADV_TT_CLIENT_TEMP ? 'T' : '.')); | 1508 | (flags & BATADV_TT_CLIENT_TEMP ? 'T' : '.')); |
| 1489 | 1509 | ||
| 1490 | batadv_orig_node_vlan_free_ref(vlan); | 1510 | batadv_orig_node_vlan_free_ref(vlan); |
| @@ -1853,6 +1873,11 @@ _batadv_is_ap_isolated(struct batadv_tt_local_entry *tt_local_entry, | |||
| 1853 | tt_global_entry->common.flags & BATADV_TT_CLIENT_WIFI) | 1873 | tt_global_entry->common.flags & BATADV_TT_CLIENT_WIFI) |
| 1854 | ret = true; | 1874 | ret = true; |
| 1855 | 1875 | ||
| 1876 | /* check if the two clients are marked as isolated */ | ||
| 1877 | if (tt_local_entry->common.flags & BATADV_TT_CLIENT_ISOLA && | ||
| 1878 | tt_global_entry->common.flags & BATADV_TT_CLIENT_ISOLA) | ||
| 1879 | ret = true; | ||
| 1880 | |||
| 1856 | return ret; | 1881 | return ret; |
| 1857 | } | 1882 | } |
| 1858 | 1883 | ||
| @@ -1879,19 +1904,8 @@ struct batadv_orig_node *batadv_transtable_search(struct batadv_priv *bat_priv, | |||
| 1879 | struct batadv_tt_global_entry *tt_global_entry = NULL; | 1904 | struct batadv_tt_global_entry *tt_global_entry = NULL; |
| 1880 | struct batadv_orig_node *orig_node = NULL; | 1905 | struct batadv_orig_node *orig_node = NULL; |
| 1881 | struct batadv_tt_orig_list_entry *best_entry; | 1906 | struct batadv_tt_orig_list_entry *best_entry; |
| 1882 | bool ap_isolation_enabled = false; | ||
| 1883 | struct batadv_softif_vlan *vlan; | ||
| 1884 | 1907 | ||
| 1885 | /* if the AP isolation is requested on a VLAN, then check for its | 1908 | if (src && batadv_vlan_ap_isola_get(bat_priv, vid)) { |
| 1886 | * setting in the proper VLAN private data structure | ||
| 1887 | */ | ||
| 1888 | vlan = batadv_softif_vlan_get(bat_priv, vid); | ||
| 1889 | if (vlan) { | ||
| 1890 | ap_isolation_enabled = atomic_read(&vlan->ap_isolation); | ||
| 1891 | batadv_softif_vlan_free_ref(vlan); | ||
| 1892 | } | ||
| 1893 | |||
| 1894 | if (src && ap_isolation_enabled) { | ||
| 1895 | tt_local_entry = batadv_tt_local_hash_find(bat_priv, src, vid); | 1909 | tt_local_entry = batadv_tt_local_hash_find(bat_priv, src, vid); |
| 1896 | if (!tt_local_entry || | 1910 | if (!tt_local_entry || |
| 1897 | (tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING)) | 1911 | (tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING)) |
| @@ -3567,3 +3581,29 @@ int batadv_tt_init(struct batadv_priv *bat_priv) | |||
| 3567 | 3581 | ||
| 3568 | return 1; | 3582 | return 1; |
| 3569 | } | 3583 | } |
| 3584 | |||
| 3585 | /** | ||
| 3586 | * batadv_tt_global_is_isolated - check if a client is marked as isolated | ||
| 3587 | * @bat_priv: the bat priv with all the soft interface information | ||
| 3588 | * @addr: the mac address of the client | ||
| 3589 | * @vid: the identifier of the VLAN where this client is connected | ||
| 3590 | * | ||
| 3591 | * Returns true if the client is marked with the TT_CLIENT_ISOLA flag, false | ||
| 3592 | * otherwise | ||
| 3593 | */ | ||
| 3594 | bool batadv_tt_global_is_isolated(struct batadv_priv *bat_priv, | ||
| 3595 | const uint8_t *addr, unsigned short vid) | ||
| 3596 | { | ||
| 3597 | struct batadv_tt_global_entry *tt; | ||
| 3598 | bool ret; | ||
| 3599 | |||
| 3600 | tt = batadv_tt_global_hash_find(bat_priv, addr, vid); | ||
| 3601 | if (!tt) | ||
| 3602 | return false; | ||
| 3603 | |||
| 3604 | ret = tt->common.flags & BATADV_TT_CLIENT_ISOLA; | ||
| 3605 | |||
| 3606 | batadv_tt_global_entry_free_ref(tt); | ||
| 3607 | |||
| 3608 | return ret; | ||
| 3609 | } | ||
diff --git a/net/batman-adv/translation-table.h b/net/batman-adv/translation-table.h index 026b1ffa6746..20a1d7861ded 100644 --- a/net/batman-adv/translation-table.h +++ b/net/batman-adv/translation-table.h | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors: | 1 | /* Copyright (C) 2007-2014 B.A.T.M.A.N. contributors: |
| 2 | * | 2 | * |
| 3 | * Marek Lindner, Simon Wunderlich, Antonio Quartulli | 3 | * Marek Lindner, Simon Wunderlich, Antonio Quartulli |
| 4 | * | 4 | * |
| @@ -12,9 +12,7 @@ | |||
| 12 | * General Public License for more details. | 12 | * General Public License for more details. |
| 13 | * | 13 | * |
| 14 | * You should have received a copy of the GNU General Public License | 14 | * You should have received a copy of the GNU General Public License |
| 15 | * along with this program; if not, write to the Free Software | 15 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 17 | * 02110-1301, USA | ||
| 18 | */ | 16 | */ |
| 19 | 17 | ||
| 20 | #ifndef _NET_BATMAN_ADV_TRANSLATION_TABLE_H_ | 18 | #ifndef _NET_BATMAN_ADV_TRANSLATION_TABLE_H_ |
| @@ -22,7 +20,7 @@ | |||
| 22 | 20 | ||
| 23 | int batadv_tt_init(struct batadv_priv *bat_priv); | 21 | int batadv_tt_init(struct batadv_priv *bat_priv); |
| 24 | bool batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr, | 22 | bool batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr, |
| 25 | unsigned short vid, int ifindex); | 23 | unsigned short vid, int ifindex, uint32_t mark); |
| 26 | uint16_t batadv_tt_local_remove(struct batadv_priv *bat_priv, | 24 | uint16_t batadv_tt_local_remove(struct batadv_priv *bat_priv, |
| 27 | const uint8_t *addr, unsigned short vid, | 25 | const uint8_t *addr, unsigned short vid, |
| 28 | const char *message, bool roaming); | 26 | const char *message, bool roaming); |
| @@ -50,5 +48,7 @@ bool batadv_tt_add_temporary_global_entry(struct batadv_priv *bat_priv, | |||
| 50 | struct batadv_orig_node *orig_node, | 48 | struct batadv_orig_node *orig_node, |
| 51 | const unsigned char *addr, | 49 | const unsigned char *addr, |
| 52 | unsigned short vid); | 50 | unsigned short vid); |
| 51 | bool batadv_tt_global_is_isolated(struct batadv_priv *bat_priv, | ||
| 52 | const uint8_t *addr, unsigned short vid); | ||
| 53 | 53 | ||
| 54 | #endif /* _NET_BATMAN_ADV_TRANSLATION_TABLE_H_ */ | 54 | #endif /* _NET_BATMAN_ADV_TRANSLATION_TABLE_H_ */ |
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index 91dd369b0ff2..78370ab31f9c 100644 --- a/net/batman-adv/types.h +++ b/net/batman-adv/types.h | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors: | 1 | /* Copyright (C) 2007-2014 B.A.T.M.A.N. contributors: |
| 2 | * | 2 | * |
| 3 | * Marek Lindner, Simon Wunderlich | 3 | * Marek Lindner, Simon Wunderlich |
| 4 | * | 4 | * |
| @@ -12,9 +12,7 @@ | |||
| 12 | * General Public License for more details. | 12 | * General Public License for more details. |
| 13 | * | 13 | * |
| 14 | * You should have received a copy of the GNU General Public License | 14 | * You should have received a copy of the GNU General Public License |
| 15 | * along with this program; if not, write to the Free Software | 15 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 17 | * 02110-1301, USA | ||
| 18 | */ | 16 | */ |
| 19 | 17 | ||
| 20 | #ifndef _NET_BATMAN_ADV_TYPES_H_ | 18 | #ifndef _NET_BATMAN_ADV_TYPES_H_ |
| @@ -36,6 +34,18 @@ | |||
| 36 | #endif /* CONFIG_BATMAN_ADV_DAT */ | 34 | #endif /* CONFIG_BATMAN_ADV_DAT */ |
| 37 | 35 | ||
| 38 | /** | 36 | /** |
| 37 | * enum batadv_dhcp_recipient - dhcp destination | ||
| 38 | * @BATADV_DHCP_NO: packet is not a dhcp message | ||
| 39 | * @BATADV_DHCP_TO_SERVER: dhcp message is directed to a server | ||
| 40 | * @BATADV_DHCP_TO_CLIENT: dhcp message is directed to a client | ||
| 41 | */ | ||
| 42 | enum batadv_dhcp_recipient { | ||
| 43 | BATADV_DHCP_NO = 0, | ||
| 44 | BATADV_DHCP_TO_SERVER, | ||
| 45 | BATADV_DHCP_TO_CLIENT, | ||
| 46 | }; | ||
| 47 | |||
| 48 | /** | ||
| 39 | * BATADV_TT_REMOTE_MASK - bitmask selecting the flags that are sent over the | 49 | * BATADV_TT_REMOTE_MASK - bitmask selecting the flags that are sent over the |
| 40 | * wire only | 50 | * wire only |
| 41 | */ | 51 | */ |
| @@ -74,6 +84,7 @@ struct batadv_hard_iface_bat_iv { | |||
| 74 | * @rcu: struct used for freeing in an RCU-safe manner | 84 | * @rcu: struct used for freeing in an RCU-safe manner |
| 75 | * @bat_iv: BATMAN IV specific per hard interface data | 85 | * @bat_iv: BATMAN IV specific per hard interface data |
| 76 | * @cleanup_work: work queue callback item for hard interface deinit | 86 | * @cleanup_work: work queue callback item for hard interface deinit |
| 87 | * @debug_dir: dentry for nc subdir in batman-adv directory in debugfs | ||
| 77 | */ | 88 | */ |
| 78 | struct batadv_hard_iface { | 89 | struct batadv_hard_iface { |
| 79 | struct list_head list; | 90 | struct list_head list; |
| @@ -88,6 +99,29 @@ struct batadv_hard_iface { | |||
| 88 | struct rcu_head rcu; | 99 | struct rcu_head rcu; |
| 89 | struct batadv_hard_iface_bat_iv bat_iv; | 100 | struct batadv_hard_iface_bat_iv bat_iv; |
| 90 | struct work_struct cleanup_work; | 101 | struct work_struct cleanup_work; |
| 102 | struct dentry *debug_dir; | ||
| 103 | }; | ||
| 104 | |||
| 105 | /** | ||
| 106 | * struct batadv_orig_ifinfo - originator info per outgoing interface | ||
| 107 | * @list: list node for orig_node::ifinfo_list | ||
| 108 | * @if_outgoing: pointer to outgoing hard interface | ||
| 109 | * @router: router that should be used to reach this originator | ||
| 110 | * @last_real_seqno: last and best known sequence number | ||
| 111 | * @last_ttl: ttl of last received packet | ||
| 112 | * @batman_seqno_reset: time when the batman seqno window was reset | ||
| 113 | * @refcount: number of contexts the object is used | ||
| 114 | * @rcu: struct used for freeing in an RCU-safe manner | ||
| 115 | */ | ||
| 116 | struct batadv_orig_ifinfo { | ||
| 117 | struct hlist_node list; | ||
| 118 | struct batadv_hard_iface *if_outgoing; | ||
| 119 | struct batadv_neigh_node __rcu *router; /* rcu protected pointer */ | ||
| 120 | uint32_t last_real_seqno; | ||
| 121 | uint8_t last_ttl; | ||
| 122 | unsigned long batman_seqno_reset; | ||
| 123 | atomic_t refcount; | ||
| 124 | struct rcu_head rcu; | ||
| 91 | }; | 125 | }; |
| 92 | 126 | ||
| 93 | /** | 127 | /** |
| @@ -165,11 +199,11 @@ struct batadv_orig_bat_iv { | |||
| 165 | * struct batadv_orig_node - structure for orig_list maintaining nodes of mesh | 199 | * struct batadv_orig_node - structure for orig_list maintaining nodes of mesh |
| 166 | * @orig: originator ethernet address | 200 | * @orig: originator ethernet address |
| 167 | * @primary_addr: hosts primary interface address | 201 | * @primary_addr: hosts primary interface address |
| 168 | * @router: router that should be used to reach this originator | 202 | * @ifinfo_list: list for routers per outgoing interface |
| 203 | * @last_bonding_candidate: pointer to last ifinfo of last used router | ||
| 169 | * @batadv_dat_addr_t: address of the orig node in the distributed hash | 204 | * @batadv_dat_addr_t: address of the orig node in the distributed hash |
| 170 | * @last_seen: time when last packet from this node was received | 205 | * @last_seen: time when last packet from this node was received |
| 171 | * @bcast_seqno_reset: time when the broadcast seqno window was reset | 206 | * @bcast_seqno_reset: time when the broadcast seqno window was reset |
| 172 | * @batman_seqno_reset: time when the batman seqno window was reset | ||
| 173 | * @capabilities: announced capabilities of this originator | 207 | * @capabilities: announced capabilities of this originator |
| 174 | * @last_ttvn: last seen translation table version number | 208 | * @last_ttvn: last seen translation table version number |
| 175 | * @tt_buff: last tt changeset this node received from the orig node | 209 | * @tt_buff: last tt changeset this node received from the orig node |
| @@ -182,19 +216,15 @@ struct batadv_orig_bat_iv { | |||
| 182 | * made up by two operations (data structure update and metdata -CRC/TTVN- | 216 | * made up by two operations (data structure update and metdata -CRC/TTVN- |
| 183 | * recalculation) and they have to be executed atomically in order to avoid | 217 | * recalculation) and they have to be executed atomically in order to avoid |
| 184 | * another thread to read the table/metadata between those. | 218 | * another thread to read the table/metadata between those. |
| 185 | * @last_real_seqno: last and best known sequence number | ||
| 186 | * @last_ttl: ttl of last received packet | ||
| 187 | * @bcast_bits: bitfield containing the info which payload broadcast originated | 219 | * @bcast_bits: bitfield containing the info which payload broadcast originated |
| 188 | * from this orig node this host already has seen (relative to | 220 | * from this orig node this host already has seen (relative to |
| 189 | * last_bcast_seqno) | 221 | * last_bcast_seqno) |
| 190 | * @last_bcast_seqno: last broadcast sequence number received by this host | 222 | * @last_bcast_seqno: last broadcast sequence number received by this host |
| 191 | * @neigh_list: list of potential next hop neighbor towards this orig node | 223 | * @neigh_list: list of potential next hop neighbor towards this orig node |
| 192 | * @neigh_list_lock: lock protecting neigh_list, router and bonding_list | 224 | * @neigh_list_lock: lock protecting neigh_list and router |
| 193 | * @hash_entry: hlist node for batadv_priv::orig_hash | 225 | * @hash_entry: hlist node for batadv_priv::orig_hash |
| 194 | * @bat_priv: pointer to soft_iface this orig node belongs to | 226 | * @bat_priv: pointer to soft_iface this orig node belongs to |
| 195 | * @bcast_seqno_lock: lock protecting bcast_bits & last_bcast_seqno | 227 | * @bcast_seqno_lock: lock protecting bcast_bits & last_bcast_seqno |
| 196 | * @bond_candidates: how many candidates are available | ||
| 197 | * @bond_list: list of bonding candidates | ||
| 198 | * @refcount: number of contexts the object is used | 228 | * @refcount: number of contexts the object is used |
| 199 | * @rcu: struct used for freeing in an RCU-safe manner | 229 | * @rcu: struct used for freeing in an RCU-safe manner |
| 200 | * @in_coding_list: list of nodes this orig can hear | 230 | * @in_coding_list: list of nodes this orig can hear |
| @@ -210,13 +240,13 @@ struct batadv_orig_bat_iv { | |||
| 210 | struct batadv_orig_node { | 240 | struct batadv_orig_node { |
| 211 | uint8_t orig[ETH_ALEN]; | 241 | uint8_t orig[ETH_ALEN]; |
| 212 | uint8_t primary_addr[ETH_ALEN]; | 242 | uint8_t primary_addr[ETH_ALEN]; |
| 213 | struct batadv_neigh_node __rcu *router; /* rcu protected pointer */ | 243 | struct hlist_head ifinfo_list; |
| 244 | struct batadv_orig_ifinfo *last_bonding_candidate; | ||
| 214 | #ifdef CONFIG_BATMAN_ADV_DAT | 245 | #ifdef CONFIG_BATMAN_ADV_DAT |
| 215 | batadv_dat_addr_t dat_addr; | 246 | batadv_dat_addr_t dat_addr; |
| 216 | #endif | 247 | #endif |
| 217 | unsigned long last_seen; | 248 | unsigned long last_seen; |
| 218 | unsigned long bcast_seqno_reset; | 249 | unsigned long bcast_seqno_reset; |
| 219 | unsigned long batman_seqno_reset; | ||
| 220 | uint8_t capabilities; | 250 | uint8_t capabilities; |
| 221 | atomic_t last_ttvn; | 251 | atomic_t last_ttvn; |
| 222 | unsigned char *tt_buff; | 252 | unsigned char *tt_buff; |
| @@ -225,19 +255,15 @@ struct batadv_orig_node { | |||
| 225 | bool tt_initialised; | 255 | bool tt_initialised; |
| 226 | /* prevents from changing the table while reading it */ | 256 | /* prevents from changing the table while reading it */ |
| 227 | spinlock_t tt_lock; | 257 | spinlock_t tt_lock; |
| 228 | uint32_t last_real_seqno; | ||
| 229 | uint8_t last_ttl; | ||
| 230 | DECLARE_BITMAP(bcast_bits, BATADV_TQ_LOCAL_WINDOW_SIZE); | 258 | DECLARE_BITMAP(bcast_bits, BATADV_TQ_LOCAL_WINDOW_SIZE); |
| 231 | uint32_t last_bcast_seqno; | 259 | uint32_t last_bcast_seqno; |
| 232 | struct hlist_head neigh_list; | 260 | struct hlist_head neigh_list; |
| 233 | /* neigh_list_lock protects: neigh_list, router & bonding_list */ | 261 | /* neigh_list_lock protects: neigh_list and router */ |
| 234 | spinlock_t neigh_list_lock; | 262 | spinlock_t neigh_list_lock; |
| 235 | struct hlist_node hash_entry; | 263 | struct hlist_node hash_entry; |
| 236 | struct batadv_priv *bat_priv; | 264 | struct batadv_priv *bat_priv; |
| 237 | /* bcast_seqno_lock protects: bcast_bits & last_bcast_seqno */ | 265 | /* bcast_seqno_lock protects: bcast_bits & last_bcast_seqno */ |
| 238 | spinlock_t bcast_seqno_lock; | 266 | spinlock_t bcast_seqno_lock; |
| 239 | atomic_t bond_candidates; | ||
| 240 | struct list_head bond_list; | ||
| 241 | atomic_t refcount; | 267 | atomic_t refcount; |
| 242 | struct rcu_head rcu; | 268 | struct rcu_head rcu; |
| 243 | #ifdef CONFIG_BATMAN_ADV_NC | 269 | #ifdef CONFIG_BATMAN_ADV_NC |
| @@ -283,49 +309,64 @@ struct batadv_gw_node { | |||
| 283 | }; | 309 | }; |
| 284 | 310 | ||
| 285 | /** | 311 | /** |
| 286 | * struct batadv_neigh_bat_iv - B.A.T.M.A.N. IV specific structure for single | 312 | * struct batadv_neigh_node - structure for single hops neighbors |
| 287 | * hop neighbors | 313 | * @list: list node for batadv_orig_node::neigh_list |
| 314 | * @orig_node: pointer to corresponding orig_node | ||
| 315 | * @addr: the MAC address of the neighboring interface | ||
| 316 | * @ifinfo_list: list for routing metrics per outgoing interface | ||
| 317 | * @ifinfo_lock: lock protecting private ifinfo members and list | ||
| 318 | * @if_incoming: pointer to incoming hard interface | ||
| 319 | * @last_seen: when last packet via this neighbor was received | ||
| 320 | * @last_ttl: last received ttl from this neigh node | ||
| 321 | * @rcu: struct used for freeing in an RCU-safe manner | ||
| 322 | * @bat_iv: B.A.T.M.A.N. IV private structure | ||
| 323 | */ | ||
| 324 | struct batadv_neigh_node { | ||
| 325 | struct hlist_node list; | ||
| 326 | struct batadv_orig_node *orig_node; | ||
| 327 | uint8_t addr[ETH_ALEN]; | ||
| 328 | struct hlist_head ifinfo_list; | ||
| 329 | spinlock_t ifinfo_lock; /* protects ifinfo_list and its members */ | ||
| 330 | struct batadv_hard_iface *if_incoming; | ||
| 331 | unsigned long last_seen; | ||
| 332 | atomic_t refcount; | ||
| 333 | struct rcu_head rcu; | ||
| 334 | }; | ||
| 335 | |||
| 336 | /** | ||
| 337 | * struct batadv_neigh_node_bat_iv - neighbor information per outgoing | ||
| 338 | * interface for BATMAN IV | ||
| 288 | * @tq_recv: ring buffer of received TQ values from this neigh node | 339 | * @tq_recv: ring buffer of received TQ values from this neigh node |
| 289 | * @tq_index: ring buffer index | 340 | * @tq_index: ring buffer index |
| 290 | * @tq_avg: averaged tq of all tq values in the ring buffer (tq_recv) | 341 | * @tq_avg: averaged tq of all tq values in the ring buffer (tq_recv) |
| 291 | * @real_bits: bitfield containing the number of OGMs received from this neigh | 342 | * @real_bits: bitfield containing the number of OGMs received from this neigh |
| 292 | * node (relative to orig_node->last_real_seqno) | 343 | * node (relative to orig_node->last_real_seqno) |
| 293 | * @real_packet_count: counted result of real_bits | 344 | * @real_packet_count: counted result of real_bits |
| 294 | * @lq_update_lock: lock protecting tq_recv & tq_index | ||
| 295 | */ | 345 | */ |
| 296 | struct batadv_neigh_bat_iv { | 346 | struct batadv_neigh_ifinfo_bat_iv { |
| 297 | uint8_t tq_recv[BATADV_TQ_GLOBAL_WINDOW_SIZE]; | 347 | uint8_t tq_recv[BATADV_TQ_GLOBAL_WINDOW_SIZE]; |
| 298 | uint8_t tq_index; | 348 | uint8_t tq_index; |
| 299 | uint8_t tq_avg; | 349 | uint8_t tq_avg; |
| 300 | DECLARE_BITMAP(real_bits, BATADV_TQ_LOCAL_WINDOW_SIZE); | 350 | DECLARE_BITMAP(real_bits, BATADV_TQ_LOCAL_WINDOW_SIZE); |
| 301 | uint8_t real_packet_count; | 351 | uint8_t real_packet_count; |
| 302 | spinlock_t lq_update_lock; /* protects tq_recv & tq_index */ | ||
| 303 | }; | 352 | }; |
| 304 | 353 | ||
| 305 | /** | 354 | /** |
| 306 | * struct batadv_neigh_node - structure for single hops neighbors | 355 | * struct batadv_neigh_ifinfo - neighbor information per outgoing interface |
| 307 | * @list: list node for batadv_orig_node::neigh_list | 356 | * @list: list node for batadv_neigh_node::ifinfo_list |
| 308 | * @orig_node: pointer to corresponding orig_node | 357 | * @if_outgoing: pointer to outgoing hard interface |
| 309 | * @addr: the MAC address of the neighboring interface | 358 | * @bat_iv: B.A.T.M.A.N. IV private structure |
| 310 | * @if_incoming: pointer to incoming hard interface | ||
| 311 | * @last_seen: when last packet via this neighbor was received | ||
| 312 | * @last_ttl: last received ttl from this neigh node | 359 | * @last_ttl: last received ttl from this neigh node |
| 313 | * @bonding_list: list node for batadv_orig_node::bond_list | ||
| 314 | * @refcount: number of contexts the object is used | 360 | * @refcount: number of contexts the object is used |
| 315 | * @rcu: struct used for freeing in an RCU-safe manner | 361 | * @rcu: struct used for freeing in a RCU-safe manner |
| 316 | * @bat_iv: B.A.T.M.A.N. IV private structure | ||
| 317 | */ | 362 | */ |
| 318 | struct batadv_neigh_node { | 363 | struct batadv_neigh_ifinfo { |
| 319 | struct hlist_node list; | 364 | struct hlist_node list; |
| 320 | struct batadv_orig_node *orig_node; | 365 | struct batadv_hard_iface *if_outgoing; |
| 321 | uint8_t addr[ETH_ALEN]; | 366 | struct batadv_neigh_ifinfo_bat_iv bat_iv; |
| 322 | struct batadv_hard_iface *if_incoming; | ||
| 323 | unsigned long last_seen; | ||
| 324 | uint8_t last_ttl; | 367 | uint8_t last_ttl; |
| 325 | struct list_head bonding_list; | ||
| 326 | atomic_t refcount; | 368 | atomic_t refcount; |
| 327 | struct rcu_head rcu; | 369 | struct rcu_head rcu; |
| 328 | struct batadv_neigh_bat_iv bat_iv; | ||
| 329 | }; | 370 | }; |
| 330 | 371 | ||
| 331 | /** | 372 | /** |
| @@ -687,6 +728,8 @@ struct batadv_priv { | |||
| 687 | #ifdef CONFIG_BATMAN_ADV_DEBUG | 728 | #ifdef CONFIG_BATMAN_ADV_DEBUG |
| 688 | atomic_t log_level; | 729 | atomic_t log_level; |
| 689 | #endif | 730 | #endif |
| 731 | uint32_t isolation_mark; | ||
| 732 | uint32_t isolation_mark_mask; | ||
| 690 | atomic_t bcast_seqno; | 733 | atomic_t bcast_seqno; |
| 691 | atomic_t bcast_queue_left; | 734 | atomic_t bcast_queue_left; |
| 692 | atomic_t batman_queue_left; | 735 | atomic_t batman_queue_left; |
| @@ -981,8 +1024,10 @@ struct batadv_skb_cb { | |||
| 981 | * @direct_link_flags: direct link flags for aggregated OGM packets | 1024 | * @direct_link_flags: direct link flags for aggregated OGM packets |
| 982 | * @num_packets: counter for bcast packet retransmission | 1025 | * @num_packets: counter for bcast packet retransmission |
| 983 | * @delayed_work: work queue callback item for packet sending | 1026 | * @delayed_work: work queue callback item for packet sending |
| 984 | * @if_incoming: pointer incoming hard-iface or primary iface if locally | 1027 | * @if_incoming: pointer to incoming hard-iface or primary iface if |
| 985 | * generated packet | 1028 | * locally generated packet |
| 1029 | * @if_outgoing: packet where the packet should be sent to, or NULL if | ||
| 1030 | * unspecified | ||
| 986 | */ | 1031 | */ |
| 987 | struct batadv_forw_packet { | 1032 | struct batadv_forw_packet { |
| 988 | struct hlist_node list; | 1033 | struct hlist_node list; |
| @@ -994,6 +1039,7 @@ struct batadv_forw_packet { | |||
| 994 | uint8_t num_packets; | 1039 | uint8_t num_packets; |
| 995 | struct delayed_work delayed_work; | 1040 | struct delayed_work delayed_work; |
| 996 | struct batadv_hard_iface *if_incoming; | 1041 | struct batadv_hard_iface *if_incoming; |
| 1042 | struct batadv_hard_iface *if_outgoing; | ||
| 997 | }; | 1043 | }; |
| 998 | 1044 | ||
| 999 | /** | 1045 | /** |
| @@ -1007,9 +1053,11 @@ struct batadv_forw_packet { | |||
| 1007 | * @bat_primary_iface_set: called when primary interface is selected / changed | 1053 | * @bat_primary_iface_set: called when primary interface is selected / changed |
| 1008 | * @bat_ogm_schedule: prepare a new outgoing OGM for the send queue | 1054 | * @bat_ogm_schedule: prepare a new outgoing OGM for the send queue |
| 1009 | * @bat_ogm_emit: send scheduled OGM | 1055 | * @bat_ogm_emit: send scheduled OGM |
| 1010 | * @bat_neigh_cmp: compare the metrics of two neighbors | 1056 | * @bat_neigh_cmp: compare the metrics of two neighbors for their respective |
| 1011 | * @bat_neigh_is_equiv_or_better: check if neigh1 is equally good or | 1057 | * outgoing interfaces |
| 1012 | * better than neigh2 from the metric prospective | 1058 | * @bat_neigh_is_equiv_or_better: check if neigh1 is equally good or better |
| 1059 | * than neigh2 for their respective outgoing interface from the metric | ||
| 1060 | * prospective | ||
| 1013 | * @bat_orig_print: print the originator table (optional) | 1061 | * @bat_orig_print: print the originator table (optional) |
| 1014 | * @bat_orig_free: free the resources allocated by the routing algorithm for an | 1062 | * @bat_orig_free: free the resources allocated by the routing algorithm for an |
| 1015 | * orig_node object | 1063 | * orig_node object |
| @@ -1028,11 +1076,17 @@ struct batadv_algo_ops { | |||
| 1028 | void (*bat_ogm_schedule)(struct batadv_hard_iface *hard_iface); | 1076 | void (*bat_ogm_schedule)(struct batadv_hard_iface *hard_iface); |
| 1029 | void (*bat_ogm_emit)(struct batadv_forw_packet *forw_packet); | 1077 | void (*bat_ogm_emit)(struct batadv_forw_packet *forw_packet); |
| 1030 | int (*bat_neigh_cmp)(struct batadv_neigh_node *neigh1, | 1078 | int (*bat_neigh_cmp)(struct batadv_neigh_node *neigh1, |
| 1031 | struct batadv_neigh_node *neigh2); | 1079 | struct batadv_hard_iface *if_outgoing1, |
| 1032 | bool (*bat_neigh_is_equiv_or_better)(struct batadv_neigh_node *neigh1, | 1080 | struct batadv_neigh_node *neigh2, |
| 1033 | struct batadv_neigh_node *neigh2); | 1081 | struct batadv_hard_iface *if_outgoing2); |
| 1082 | bool (*bat_neigh_is_equiv_or_better) | ||
| 1083 | (struct batadv_neigh_node *neigh1, | ||
| 1084 | struct batadv_hard_iface *if_outgoing1, | ||
| 1085 | struct batadv_neigh_node *neigh2, | ||
| 1086 | struct batadv_hard_iface *if_outgoing2); | ||
| 1034 | /* orig_node handling API */ | 1087 | /* orig_node handling API */ |
| 1035 | void (*bat_orig_print)(struct batadv_priv *priv, struct seq_file *seq); | 1088 | void (*bat_orig_print)(struct batadv_priv *priv, struct seq_file *seq, |
| 1089 | struct batadv_hard_iface *hard_iface); | ||
| 1036 | void (*bat_orig_free)(struct batadv_orig_node *orig_node); | 1090 | void (*bat_orig_free)(struct batadv_orig_node *orig_node); |
| 1037 | int (*bat_orig_add_if)(struct batadv_orig_node *orig_node, | 1091 | int (*bat_orig_add_if)(struct batadv_orig_node *orig_node, |
| 1038 | int max_if_num); | 1092 | int max_if_num); |
diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c new file mode 100644 index 000000000000..adb3ea04adaa --- /dev/null +++ b/net/bluetooth/6lowpan.c | |||
| @@ -0,0 +1,860 @@ | |||
| 1 | /* | ||
| 2 | Copyright (c) 2013 Intel Corp. | ||
| 3 | |||
| 4 | This program is free software; you can redistribute it and/or modify | ||
| 5 | it under the terms of the GNU General Public License version 2 and | ||
| 6 | only version 2 as published by the Free Software Foundation. | ||
| 7 | |||
| 8 | This program is distributed in the hope that it will be useful, | ||
| 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | GNU General Public License for more details. | ||
| 12 | */ | ||
| 13 | |||
| 14 | #include <linux/if_arp.h> | ||
| 15 | #include <linux/netdevice.h> | ||
| 16 | #include <linux/etherdevice.h> | ||
| 17 | |||
| 18 | #include <net/ipv6.h> | ||
| 19 | #include <net/ip6_route.h> | ||
| 20 | #include <net/addrconf.h> | ||
| 21 | |||
| 22 | #include <net/af_ieee802154.h> /* to get the address type */ | ||
| 23 | |||
| 24 | #include <net/bluetooth/bluetooth.h> | ||
| 25 | #include <net/bluetooth/hci_core.h> | ||
| 26 | #include <net/bluetooth/l2cap.h> | ||
| 27 | |||
| 28 | #include "6lowpan.h" | ||
| 29 | |||
| 30 | #include "../ieee802154/6lowpan.h" /* for the compression support */ | ||
| 31 | |||
| 32 | #define IFACE_NAME_TEMPLATE "bt%d" | ||
| 33 | #define EUI64_ADDR_LEN 8 | ||
| 34 | |||
| 35 | struct skb_cb { | ||
| 36 | struct in6_addr addr; | ||
| 37 | struct l2cap_conn *conn; | ||
| 38 | }; | ||
| 39 | #define lowpan_cb(skb) ((struct skb_cb *)((skb)->cb)) | ||
| 40 | |||
| 41 | /* The devices list contains those devices that we are acting | ||
| 42 | * as a proxy. The BT 6LoWPAN device is a virtual device that | ||
| 43 | * connects to the Bluetooth LE device. The real connection to | ||
| 44 | * BT device is done via l2cap layer. There exists one | ||
| 45 | * virtual device / one BT 6LoWPAN network (=hciX device). | ||
| 46 | * The list contains struct lowpan_dev elements. | ||
| 47 | */ | ||
| 48 | static LIST_HEAD(bt_6lowpan_devices); | ||
| 49 | static DEFINE_RWLOCK(devices_lock); | ||
| 50 | |||
| 51 | struct lowpan_peer { | ||
| 52 | struct list_head list; | ||
| 53 | struct l2cap_conn *conn; | ||
| 54 | |||
| 55 | /* peer addresses in various formats */ | ||
| 56 | unsigned char eui64_addr[EUI64_ADDR_LEN]; | ||
| 57 | struct in6_addr peer_addr; | ||
| 58 | }; | ||
| 59 | |||
| 60 | struct lowpan_dev { | ||
| 61 | struct list_head list; | ||
| 62 | |||
| 63 | struct hci_dev *hdev; | ||
| 64 | struct net_device *netdev; | ||
| 65 | struct list_head peers; | ||
| 66 | atomic_t peer_count; /* number of items in peers list */ | ||
| 67 | |||
| 68 | struct work_struct delete_netdev; | ||
| 69 | struct delayed_work notify_peers; | ||
| 70 | }; | ||
| 71 | |||
| 72 | static inline struct lowpan_dev *lowpan_dev(const struct net_device *netdev) | ||
| 73 | { | ||
| 74 | return netdev_priv(netdev); | ||
| 75 | } | ||
| 76 | |||
| 77 | static inline void peer_add(struct lowpan_dev *dev, struct lowpan_peer *peer) | ||
| 78 | { | ||
| 79 | list_add(&peer->list, &dev->peers); | ||
| 80 | atomic_inc(&dev->peer_count); | ||
| 81 | } | ||
| 82 | |||
| 83 | static inline bool peer_del(struct lowpan_dev *dev, struct lowpan_peer *peer) | ||
| 84 | { | ||
| 85 | list_del(&peer->list); | ||
| 86 | |||
| 87 | if (atomic_dec_and_test(&dev->peer_count)) { | ||
| 88 | BT_DBG("last peer"); | ||
| 89 | return true; | ||
| 90 | } | ||
| 91 | |||
| 92 | return false; | ||
| 93 | } | ||
| 94 | |||
| 95 | static inline struct lowpan_peer *peer_lookup_ba(struct lowpan_dev *dev, | ||
| 96 | bdaddr_t *ba, __u8 type) | ||
| 97 | { | ||
| 98 | struct lowpan_peer *peer, *tmp; | ||
| 99 | |||
| 100 | BT_DBG("peers %d addr %pMR type %d", atomic_read(&dev->peer_count), | ||
| 101 | ba, type); | ||
| 102 | |||
| 103 | list_for_each_entry_safe(peer, tmp, &dev->peers, list) { | ||
| 104 | BT_DBG("addr %pMR type %d", | ||
| 105 | &peer->conn->hcon->dst, peer->conn->hcon->dst_type); | ||
| 106 | |||
| 107 | if (bacmp(&peer->conn->hcon->dst, ba)) | ||
| 108 | continue; | ||
| 109 | |||
| 110 | if (type == peer->conn->hcon->dst_type) | ||
| 111 | return peer; | ||
| 112 | } | ||
| 113 | |||
| 114 | return NULL; | ||
| 115 | } | ||
| 116 | |||
| 117 | static inline struct lowpan_peer *peer_lookup_conn(struct lowpan_dev *dev, | ||
| 118 | struct l2cap_conn *conn) | ||
| 119 | { | ||
| 120 | struct lowpan_peer *peer, *tmp; | ||
| 121 | |||
| 122 | list_for_each_entry_safe(peer, tmp, &dev->peers, list) { | ||
| 123 | if (peer->conn == conn) | ||
| 124 | return peer; | ||
| 125 | } | ||
| 126 | |||
| 127 | return NULL; | ||
| 128 | } | ||
| 129 | |||
| 130 | static struct lowpan_peer *lookup_peer(struct l2cap_conn *conn) | ||
| 131 | { | ||
| 132 | struct lowpan_dev *entry, *tmp; | ||
| 133 | struct lowpan_peer *peer = NULL; | ||
| 134 | unsigned long flags; | ||
| 135 | |||
| 136 | read_lock_irqsave(&devices_lock, flags); | ||
| 137 | |||
| 138 | list_for_each_entry_safe(entry, tmp, &bt_6lowpan_devices, list) { | ||
| 139 | peer = peer_lookup_conn(entry, conn); | ||
| 140 | if (peer) | ||
| 141 | break; | ||
| 142 | } | ||
| 143 | |||
| 144 | read_unlock_irqrestore(&devices_lock, flags); | ||
| 145 | |||
| 146 | return peer; | ||
| 147 | } | ||
| 148 | |||
| 149 | static struct lowpan_dev *lookup_dev(struct l2cap_conn *conn) | ||
| 150 | { | ||
| 151 | struct lowpan_dev *entry, *tmp; | ||
| 152 | struct lowpan_dev *dev = NULL; | ||
| 153 | unsigned long flags; | ||
| 154 | |||
| 155 | read_lock_irqsave(&devices_lock, flags); | ||
| 156 | |||
| 157 | list_for_each_entry_safe(entry, tmp, &bt_6lowpan_devices, list) { | ||
| 158 | if (conn->hcon->hdev == entry->hdev) { | ||
| 159 | dev = entry; | ||
| 160 | break; | ||
| 161 | } | ||
| 162 | } | ||
| 163 | |||
| 164 | read_unlock_irqrestore(&devices_lock, flags); | ||
| 165 | |||
| 166 | return dev; | ||
| 167 | } | ||
| 168 | |||
| 169 | static int give_skb_to_upper(struct sk_buff *skb, struct net_device *dev) | ||
| 170 | { | ||
| 171 | struct sk_buff *skb_cp; | ||
| 172 | int ret; | ||
| 173 | |||
| 174 | skb_cp = skb_copy(skb, GFP_ATOMIC); | ||
| 175 | if (!skb_cp) | ||
| 176 | return -ENOMEM; | ||
| 177 | |||
| 178 | ret = netif_rx(skb_cp); | ||
| 179 | |||
| 180 | BT_DBG("receive skb %d", ret); | ||
| 181 | if (ret < 0) | ||
| 182 | return NET_RX_DROP; | ||
| 183 | |||
| 184 | return ret; | ||
| 185 | } | ||
| 186 | |||
| 187 | static int process_data(struct sk_buff *skb, struct net_device *netdev, | ||
| 188 | struct l2cap_conn *conn) | ||
| 189 | { | ||
| 190 | const u8 *saddr, *daddr; | ||
| 191 | u8 iphc0, iphc1; | ||
| 192 | struct lowpan_dev *dev; | ||
| 193 | struct lowpan_peer *peer; | ||
| 194 | unsigned long flags; | ||
| 195 | |||
| 196 | dev = lowpan_dev(netdev); | ||
| 197 | |||
| 198 | read_lock_irqsave(&devices_lock, flags); | ||
| 199 | peer = peer_lookup_conn(dev, conn); | ||
| 200 | read_unlock_irqrestore(&devices_lock, flags); | ||
| 201 | if (!peer) | ||
| 202 | goto drop; | ||
| 203 | |||
| 204 | saddr = peer->eui64_addr; | ||
| 205 | daddr = dev->netdev->dev_addr; | ||
| 206 | |||
| 207 | /* at least two bytes will be used for the encoding */ | ||
| 208 | if (skb->len < 2) | ||
| 209 | goto drop; | ||
| 210 | |||
| 211 | if (lowpan_fetch_skb_u8(skb, &iphc0)) | ||
| 212 | goto drop; | ||
| 213 | |||
| 214 | if (lowpan_fetch_skb_u8(skb, &iphc1)) | ||
| 215 | goto drop; | ||
| 216 | |||
| 217 | return lowpan_process_data(skb, netdev, | ||
| 218 | saddr, IEEE802154_ADDR_LONG, EUI64_ADDR_LEN, | ||
| 219 | daddr, IEEE802154_ADDR_LONG, EUI64_ADDR_LEN, | ||
| 220 | iphc0, iphc1, give_skb_to_upper); | ||
| 221 | |||
| 222 | drop: | ||
| 223 | kfree_skb(skb); | ||
| 224 | return -EINVAL; | ||
| 225 | } | ||
| 226 | |||
| 227 | static int recv_pkt(struct sk_buff *skb, struct net_device *dev, | ||
| 228 | struct l2cap_conn *conn) | ||
| 229 | { | ||
| 230 | struct sk_buff *local_skb; | ||
| 231 | int ret; | ||
| 232 | |||
| 233 | if (!netif_running(dev)) | ||
| 234 | goto drop; | ||
| 235 | |||
| 236 | if (dev->type != ARPHRD_6LOWPAN) | ||
| 237 | goto drop; | ||
| 238 | |||
| 239 | /* check that it's our buffer */ | ||
| 240 | if (skb->data[0] == LOWPAN_DISPATCH_IPV6) { | ||
| 241 | /* Copy the packet so that the IPv6 header is | ||
| 242 | * properly aligned. | ||
| 243 | */ | ||
| 244 | local_skb = skb_copy_expand(skb, NET_SKB_PAD - 1, | ||
| 245 | skb_tailroom(skb), GFP_ATOMIC); | ||
| 246 | if (!local_skb) | ||
| 247 | goto drop; | ||
| 248 | |||
| 249 | local_skb->protocol = htons(ETH_P_IPV6); | ||
| 250 | local_skb->pkt_type = PACKET_HOST; | ||
| 251 | |||
| 252 | skb_reset_network_header(local_skb); | ||
| 253 | skb_set_transport_header(local_skb, sizeof(struct ipv6hdr)); | ||
| 254 | |||
| 255 | if (give_skb_to_upper(local_skb, dev) != NET_RX_SUCCESS) { | ||
| 256 | kfree_skb(local_skb); | ||
| 257 | goto drop; | ||
| 258 | } | ||
| 259 | |||
| 260 | dev->stats.rx_bytes += skb->len; | ||
| 261 | dev->stats.rx_packets++; | ||
| 262 | |||
| 263 | kfree_skb(local_skb); | ||
| 264 | kfree_skb(skb); | ||
| 265 | } else { | ||
| 266 | switch (skb->data[0] & 0xe0) { | ||
| 267 | case LOWPAN_DISPATCH_IPHC: /* ipv6 datagram */ | ||
| 268 | local_skb = skb_clone(skb, GFP_ATOMIC); | ||
| 269 | if (!local_skb) | ||
| 270 | goto drop; | ||
| 271 | |||
| 272 | ret = process_data(local_skb, dev, conn); | ||
| 273 | if (ret != NET_RX_SUCCESS) | ||
| 274 | goto drop; | ||
| 275 | |||
| 276 | dev->stats.rx_bytes += skb->len; | ||
| 277 | dev->stats.rx_packets++; | ||
| 278 | |||
| 279 | kfree_skb(skb); | ||
| 280 | break; | ||
| 281 | default: | ||
| 282 | break; | ||
| 283 | } | ||
| 284 | } | ||
| 285 | |||
| 286 | return NET_RX_SUCCESS; | ||
| 287 | |||
| 288 | drop: | ||
| 289 | kfree_skb(skb); | ||
| 290 | return NET_RX_DROP; | ||
| 291 | } | ||
| 292 | |||
| 293 | /* Packet from BT LE device */ | ||
| 294 | int bt_6lowpan_recv(struct l2cap_conn *conn, struct sk_buff *skb) | ||
| 295 | { | ||
| 296 | struct lowpan_dev *dev; | ||
| 297 | struct lowpan_peer *peer; | ||
| 298 | int err; | ||
| 299 | |||
| 300 | peer = lookup_peer(conn); | ||
| 301 | if (!peer) | ||
| 302 | return -ENOENT; | ||
| 303 | |||
| 304 | dev = lookup_dev(conn); | ||
| 305 | if (!dev || !dev->netdev) | ||
| 306 | return -ENOENT; | ||
| 307 | |||
| 308 | err = recv_pkt(skb, dev->netdev, conn); | ||
| 309 | BT_DBG("recv pkt %d", err); | ||
| 310 | |||
| 311 | return err; | ||
| 312 | } | ||
| 313 | |||
| 314 | static inline int skbuff_copy(void *msg, int len, int count, int mtu, | ||
| 315 | struct sk_buff *skb, struct net_device *dev) | ||
| 316 | { | ||
| 317 | struct sk_buff **frag; | ||
| 318 | int sent = 0; | ||
| 319 | |||
| 320 | memcpy(skb_put(skb, count), msg, count); | ||
| 321 | |||
| 322 | sent += count; | ||
| 323 | msg += count; | ||
| 324 | len -= count; | ||
| 325 | |||
| 326 | dev->stats.tx_bytes += count; | ||
| 327 | dev->stats.tx_packets++; | ||
| 328 | |||
| 329 | raw_dump_table(__func__, "Sending", skb->data, skb->len); | ||
| 330 | |||
| 331 | /* Continuation fragments (no L2CAP header) */ | ||
| 332 | frag = &skb_shinfo(skb)->frag_list; | ||
| 333 | while (len > 0) { | ||
| 334 | struct sk_buff *tmp; | ||
| 335 | |||
| 336 | count = min_t(unsigned int, mtu, len); | ||
| 337 | |||
| 338 | tmp = bt_skb_alloc(count, GFP_ATOMIC); | ||
| 339 | if (!tmp) | ||
| 340 | return -ENOMEM; | ||
| 341 | |||
| 342 | *frag = tmp; | ||
| 343 | |||
| 344 | memcpy(skb_put(*frag, count), msg, count); | ||
| 345 | |||
| 346 | raw_dump_table(__func__, "Sending fragment", | ||
| 347 | (*frag)->data, count); | ||
| 348 | |||
| 349 | (*frag)->priority = skb->priority; | ||
| 350 | |||
| 351 | sent += count; | ||
| 352 | msg += count; | ||
| 353 | len -= count; | ||
| 354 | |||
| 355 | skb->len += (*frag)->len; | ||
| 356 | skb->data_len += (*frag)->len; | ||
| 357 | |||
| 358 | frag = &(*frag)->next; | ||
| 359 | |||
| 360 | dev->stats.tx_bytes += count; | ||
| 361 | dev->stats.tx_packets++; | ||
| 362 | } | ||
| 363 | |||
| 364 | return sent; | ||
| 365 | } | ||
| 366 | |||
| 367 | static struct sk_buff *create_pdu(struct l2cap_conn *conn, void *msg, | ||
| 368 | size_t len, u32 priority, | ||
| 369 | struct net_device *dev) | ||
| 370 | { | ||
| 371 | struct sk_buff *skb; | ||
| 372 | int err, count; | ||
| 373 | struct l2cap_hdr *lh; | ||
| 374 | |||
| 375 | /* FIXME: This mtu check should be not needed and atm is only used for | ||
| 376 | * testing purposes | ||
| 377 | */ | ||
| 378 | if (conn->mtu > (L2CAP_LE_MIN_MTU + L2CAP_HDR_SIZE)) | ||
| 379 | conn->mtu = L2CAP_LE_MIN_MTU + L2CAP_HDR_SIZE; | ||
| 380 | |||
| 381 | count = min_t(unsigned int, (conn->mtu - L2CAP_HDR_SIZE), len); | ||
| 382 | |||
| 383 | BT_DBG("conn %p len %zu mtu %d count %d", conn, len, conn->mtu, count); | ||
| 384 | |||
| 385 | skb = bt_skb_alloc(count + L2CAP_HDR_SIZE, GFP_ATOMIC); | ||
| 386 | if (!skb) | ||
| 387 | return ERR_PTR(-ENOMEM); | ||
| 388 | |||
| 389 | skb->priority = priority; | ||
| 390 | |||
| 391 | lh = (struct l2cap_hdr *)skb_put(skb, L2CAP_HDR_SIZE); | ||
| 392 | lh->cid = cpu_to_le16(L2CAP_FC_6LOWPAN); | ||
| 393 | lh->len = cpu_to_le16(len); | ||
| 394 | |||
| 395 | err = skbuff_copy(msg, len, count, conn->mtu, skb, dev); | ||
| 396 | if (unlikely(err < 0)) { | ||
| 397 | kfree_skb(skb); | ||
| 398 | BT_DBG("skbuff copy %d failed", err); | ||
| 399 | return ERR_PTR(err); | ||
| 400 | } | ||
| 401 | |||
| 402 | return skb; | ||
| 403 | } | ||
| 404 | |||
| 405 | static int conn_send(struct l2cap_conn *conn, | ||
| 406 | void *msg, size_t len, u32 priority, | ||
| 407 | struct net_device *dev) | ||
| 408 | { | ||
| 409 | struct sk_buff *skb; | ||
| 410 | |||
| 411 | skb = create_pdu(conn, msg, len, priority, dev); | ||
| 412 | if (IS_ERR(skb)) | ||
| 413 | return -EINVAL; | ||
| 414 | |||
| 415 | BT_DBG("conn %p skb %p len %d priority %u", conn, skb, skb->len, | ||
| 416 | skb->priority); | ||
| 417 | |||
| 418 | hci_send_acl(conn->hchan, skb, ACL_START); | ||
| 419 | |||
| 420 | return 0; | ||
| 421 | } | ||
| 422 | |||
| 423 | static void get_dest_bdaddr(struct in6_addr *ip6_daddr, | ||
| 424 | bdaddr_t *addr, u8 *addr_type) | ||
| 425 | { | ||
| 426 | u8 *eui64; | ||
| 427 | |||
| 428 | eui64 = ip6_daddr->s6_addr + 8; | ||
| 429 | |||
| 430 | addr->b[0] = eui64[7]; | ||
| 431 | addr->b[1] = eui64[6]; | ||
| 432 | addr->b[2] = eui64[5]; | ||
| 433 | addr->b[3] = eui64[2]; | ||
| 434 | addr->b[4] = eui64[1]; | ||
| 435 | addr->b[5] = eui64[0]; | ||
| 436 | |||
| 437 | addr->b[5] ^= 2; | ||
| 438 | |||
| 439 | /* Set universal/local bit to 0 */ | ||
| 440 | if (addr->b[5] & 1) { | ||
| 441 | addr->b[5] &= ~1; | ||
| 442 | *addr_type = ADDR_LE_DEV_PUBLIC; | ||
| 443 | } else { | ||
| 444 | *addr_type = ADDR_LE_DEV_RANDOM; | ||
| 445 | } | ||
| 446 | } | ||
| 447 | |||
| 448 | static int header_create(struct sk_buff *skb, struct net_device *netdev, | ||
| 449 | unsigned short type, const void *_daddr, | ||
| 450 | const void *_saddr, unsigned int len) | ||
| 451 | { | ||
| 452 | struct ipv6hdr *hdr; | ||
| 453 | struct lowpan_dev *dev; | ||
| 454 | struct lowpan_peer *peer; | ||
| 455 | bdaddr_t addr, *any = BDADDR_ANY; | ||
| 456 | u8 *saddr, *daddr = any->b; | ||
| 457 | u8 addr_type; | ||
| 458 | |||
| 459 | if (type != ETH_P_IPV6) | ||
| 460 | return -EINVAL; | ||
| 461 | |||
| 462 | hdr = ipv6_hdr(skb); | ||
| 463 | |||
| 464 | dev = lowpan_dev(netdev); | ||
| 465 | |||
| 466 | if (ipv6_addr_is_multicast(&hdr->daddr)) { | ||
| 467 | memcpy(&lowpan_cb(skb)->addr, &hdr->daddr, | ||
| 468 | sizeof(struct in6_addr)); | ||
| 469 | lowpan_cb(skb)->conn = NULL; | ||
| 470 | } else { | ||
| 471 | unsigned long flags; | ||
| 472 | |||
| 473 | /* Get destination BT device from skb. | ||
| 474 | * If there is no such peer then discard the packet. | ||
| 475 | */ | ||
| 476 | get_dest_bdaddr(&hdr->daddr, &addr, &addr_type); | ||
| 477 | |||
| 478 | BT_DBG("dest addr %pMR type %d", &addr, addr_type); | ||
| 479 | |||
| 480 | read_lock_irqsave(&devices_lock, flags); | ||
| 481 | peer = peer_lookup_ba(dev, &addr, addr_type); | ||
| 482 | read_unlock_irqrestore(&devices_lock, flags); | ||
| 483 | |||
| 484 | if (!peer) { | ||
| 485 | BT_DBG("no such peer %pMR found", &addr); | ||
| 486 | return -ENOENT; | ||
| 487 | } | ||
| 488 | |||
| 489 | daddr = peer->eui64_addr; | ||
| 490 | |||
| 491 | memcpy(&lowpan_cb(skb)->addr, &hdr->daddr, | ||
| 492 | sizeof(struct in6_addr)); | ||
| 493 | lowpan_cb(skb)->conn = peer->conn; | ||
| 494 | } | ||
| 495 | |||
| 496 | saddr = dev->netdev->dev_addr; | ||
| 497 | |||
| 498 | return lowpan_header_compress(skb, netdev, type, daddr, saddr, len); | ||
| 499 | } | ||
| 500 | |||
| 501 | /* Packet to BT LE device */ | ||
| 502 | static int send_pkt(struct l2cap_conn *conn, const void *saddr, | ||
| 503 | const void *daddr, struct sk_buff *skb, | ||
| 504 | struct net_device *netdev) | ||
| 505 | { | ||
| 506 | raw_dump_table(__func__, "raw skb data dump before fragmentation", | ||
| 507 | skb->data, skb->len); | ||
| 508 | |||
| 509 | return conn_send(conn, skb->data, skb->len, 0, netdev); | ||
| 510 | } | ||
| 511 | |||
| 512 | static void send_mcast_pkt(struct sk_buff *skb, struct net_device *netdev) | ||
| 513 | { | ||
| 514 | struct sk_buff *local_skb; | ||
| 515 | struct lowpan_dev *entry, *tmp; | ||
| 516 | unsigned long flags; | ||
| 517 | |||
| 518 | read_lock_irqsave(&devices_lock, flags); | ||
| 519 | |||
| 520 | list_for_each_entry_safe(entry, tmp, &bt_6lowpan_devices, list) { | ||
| 521 | struct lowpan_peer *pentry, *ptmp; | ||
| 522 | struct lowpan_dev *dev; | ||
| 523 | |||
| 524 | if (entry->netdev != netdev) | ||
| 525 | continue; | ||
| 526 | |||
| 527 | dev = lowpan_dev(entry->netdev); | ||
| 528 | |||
| 529 | list_for_each_entry_safe(pentry, ptmp, &dev->peers, list) { | ||
| 530 | local_skb = skb_clone(skb, GFP_ATOMIC); | ||
| 531 | |||
| 532 | send_pkt(pentry->conn, netdev->dev_addr, | ||
| 533 | pentry->eui64_addr, local_skb, netdev); | ||
| 534 | |||
| 535 | kfree_skb(local_skb); | ||
| 536 | } | ||
| 537 | } | ||
| 538 | |||
| 539 | read_unlock_irqrestore(&devices_lock, flags); | ||
| 540 | } | ||
| 541 | |||
| 542 | static netdev_tx_t bt_xmit(struct sk_buff *skb, struct net_device *netdev) | ||
| 543 | { | ||
| 544 | int err = 0; | ||
| 545 | unsigned char *eui64_addr; | ||
| 546 | struct lowpan_dev *dev; | ||
| 547 | struct lowpan_peer *peer; | ||
| 548 | bdaddr_t addr; | ||
| 549 | u8 addr_type; | ||
| 550 | |||
| 551 | if (ipv6_addr_is_multicast(&lowpan_cb(skb)->addr)) { | ||
| 552 | /* We need to send the packet to every device | ||
| 553 | * behind this interface. | ||
| 554 | */ | ||
| 555 | send_mcast_pkt(skb, netdev); | ||
| 556 | } else { | ||
| 557 | unsigned long flags; | ||
| 558 | |||
| 559 | get_dest_bdaddr(&lowpan_cb(skb)->addr, &addr, &addr_type); | ||
| 560 | eui64_addr = lowpan_cb(skb)->addr.s6_addr + 8; | ||
| 561 | dev = lowpan_dev(netdev); | ||
| 562 | |||
| 563 | read_lock_irqsave(&devices_lock, flags); | ||
| 564 | peer = peer_lookup_ba(dev, &addr, addr_type); | ||
| 565 | read_unlock_irqrestore(&devices_lock, flags); | ||
| 566 | |||
| 567 | BT_DBG("xmit from %s to %pMR (%pI6c) peer %p", netdev->name, | ||
| 568 | &addr, &lowpan_cb(skb)->addr, peer); | ||
| 569 | |||
| 570 | if (peer && peer->conn) | ||
| 571 | err = send_pkt(peer->conn, netdev->dev_addr, | ||
| 572 | eui64_addr, skb, netdev); | ||
| 573 | } | ||
| 574 | dev_kfree_skb(skb); | ||
| 575 | |||
| 576 | if (err) | ||
| 577 | BT_DBG("ERROR: xmit failed (%d)", err); | ||
| 578 | |||
| 579 | return (err < 0) ? NET_XMIT_DROP : err; | ||
| 580 | } | ||
| 581 | |||
| 582 | static const struct net_device_ops netdev_ops = { | ||
| 583 | .ndo_start_xmit = bt_xmit, | ||
| 584 | }; | ||
| 585 | |||
| 586 | static struct header_ops header_ops = { | ||
| 587 | .create = header_create, | ||
| 588 | }; | ||
| 589 | |||
| 590 | static void netdev_setup(struct net_device *dev) | ||
| 591 | { | ||
| 592 | dev->addr_len = EUI64_ADDR_LEN; | ||
| 593 | dev->type = ARPHRD_6LOWPAN; | ||
| 594 | |||
| 595 | dev->hard_header_len = 0; | ||
| 596 | dev->needed_tailroom = 0; | ||
| 597 | dev->mtu = IPV6_MIN_MTU; | ||
| 598 | dev->tx_queue_len = 0; | ||
| 599 | dev->flags = IFF_RUNNING | IFF_POINTOPOINT; | ||
| 600 | dev->watchdog_timeo = 0; | ||
| 601 | |||
| 602 | dev->netdev_ops = &netdev_ops; | ||
| 603 | dev->header_ops = &header_ops; | ||
| 604 | dev->destructor = free_netdev; | ||
| 605 | } | ||
| 606 | |||
| 607 | static struct device_type bt_type = { | ||
| 608 | .name = "bluetooth", | ||
| 609 | }; | ||
| 610 | |||
| 611 | static void set_addr(u8 *eui, u8 *addr, u8 addr_type) | ||
| 612 | { | ||
| 613 | /* addr is the BT address in little-endian format */ | ||
| 614 | eui[0] = addr[5]; | ||
| 615 | eui[1] = addr[4]; | ||
| 616 | eui[2] = addr[3]; | ||
| 617 | eui[3] = 0xFF; | ||
| 618 | eui[4] = 0xFE; | ||
| 619 | eui[5] = addr[2]; | ||
| 620 | eui[6] = addr[1]; | ||
| 621 | eui[7] = addr[0]; | ||
| 622 | |||
| 623 | eui[0] ^= 2; | ||
| 624 | |||
| 625 | /* Universal/local bit set, RFC 4291 */ | ||
| 626 | if (addr_type == ADDR_LE_DEV_PUBLIC) | ||
| 627 | eui[0] |= 1; | ||
| 628 | else | ||
| 629 | eui[0] &= ~1; | ||
| 630 | } | ||
| 631 | |||
| 632 | static void set_dev_addr(struct net_device *netdev, bdaddr_t *addr, | ||
| 633 | u8 addr_type) | ||
| 634 | { | ||
| 635 | netdev->addr_assign_type = NET_ADDR_PERM; | ||
| 636 | set_addr(netdev->dev_addr, addr->b, addr_type); | ||
| 637 | netdev->dev_addr[0] ^= 2; | ||
| 638 | } | ||
| 639 | |||
| 640 | static void ifup(struct net_device *netdev) | ||
| 641 | { | ||
| 642 | int err; | ||
| 643 | |||
| 644 | rtnl_lock(); | ||
| 645 | err = dev_open(netdev); | ||
| 646 | if (err < 0) | ||
| 647 | BT_INFO("iface %s cannot be opened (%d)", netdev->name, err); | ||
| 648 | rtnl_unlock(); | ||
| 649 | } | ||
| 650 | |||
| 651 | static void do_notify_peers(struct work_struct *work) | ||
| 652 | { | ||
| 653 | struct lowpan_dev *dev = container_of(work, struct lowpan_dev, | ||
| 654 | notify_peers.work); | ||
| 655 | |||
| 656 | netdev_notify_peers(dev->netdev); /* send neighbour adv at startup */ | ||
| 657 | } | ||
| 658 | |||
| 659 | static bool is_bt_6lowpan(struct hci_conn *hcon) | ||
| 660 | { | ||
| 661 | if (hcon->type != LE_LINK) | ||
| 662 | return false; | ||
| 663 | |||
| 664 | return test_bit(HCI_CONN_6LOWPAN, &hcon->flags); | ||
| 665 | } | ||
| 666 | |||
| 667 | static int add_peer_conn(struct l2cap_conn *conn, struct lowpan_dev *dev) | ||
| 668 | { | ||
| 669 | struct lowpan_peer *peer; | ||
| 670 | unsigned long flags; | ||
| 671 | |||
| 672 | peer = kzalloc(sizeof(*peer), GFP_ATOMIC); | ||
| 673 | if (!peer) | ||
| 674 | return -ENOMEM; | ||
| 675 | |||
| 676 | peer->conn = conn; | ||
| 677 | memset(&peer->peer_addr, 0, sizeof(struct in6_addr)); | ||
| 678 | |||
| 679 | /* RFC 2464 ch. 5 */ | ||
| 680 | peer->peer_addr.s6_addr[0] = 0xFE; | ||
| 681 | peer->peer_addr.s6_addr[1] = 0x80; | ||
| 682 | set_addr((u8 *)&peer->peer_addr.s6_addr + 8, conn->hcon->dst.b, | ||
| 683 | conn->hcon->dst_type); | ||
| 684 | |||
| 685 | memcpy(&peer->eui64_addr, (u8 *)&peer->peer_addr.s6_addr + 8, | ||
| 686 | EUI64_ADDR_LEN); | ||
| 687 | peer->eui64_addr[0] ^= 2; /* second bit-flip (Universe/Local) | ||
| 688 | * is done according RFC2464 | ||
| 689 | */ | ||
| 690 | |||
| 691 | raw_dump_inline(__func__, "peer IPv6 address", | ||
| 692 | (unsigned char *)&peer->peer_addr, 16); | ||
| 693 | raw_dump_inline(__func__, "peer EUI64 address", peer->eui64_addr, 8); | ||
| 694 | |||
| 695 | write_lock_irqsave(&devices_lock, flags); | ||
| 696 | INIT_LIST_HEAD(&peer->list); | ||
| 697 | peer_add(dev, peer); | ||
| 698 | write_unlock_irqrestore(&devices_lock, flags); | ||
| 699 | |||
| 700 | /* Notifying peers about us needs to be done without locks held */ | ||
| 701 | INIT_DELAYED_WORK(&dev->notify_peers, do_notify_peers); | ||
| 702 | schedule_delayed_work(&dev->notify_peers, msecs_to_jiffies(100)); | ||
| 703 | |||
| 704 | return 0; | ||
| 705 | } | ||
| 706 | |||
| 707 | /* This gets called when BT LE 6LoWPAN device is connected. We then | ||
| 708 | * create network device that acts as a proxy between BT LE device | ||
| 709 | * and kernel network stack. | ||
| 710 | */ | ||
| 711 | int bt_6lowpan_add_conn(struct l2cap_conn *conn) | ||
| 712 | { | ||
| 713 | struct lowpan_peer *peer = NULL; | ||
| 714 | struct lowpan_dev *dev; | ||
| 715 | struct net_device *netdev; | ||
| 716 | int err = 0; | ||
| 717 | unsigned long flags; | ||
| 718 | |||
| 719 | if (!is_bt_6lowpan(conn->hcon)) | ||
| 720 | return 0; | ||
| 721 | |||
| 722 | peer = lookup_peer(conn); | ||
| 723 | if (peer) | ||
| 724 | return -EEXIST; | ||
| 725 | |||
| 726 | dev = lookup_dev(conn); | ||
| 727 | if (dev) | ||
| 728 | return add_peer_conn(conn, dev); | ||
| 729 | |||
| 730 | netdev = alloc_netdev(sizeof(*dev), IFACE_NAME_TEMPLATE, netdev_setup); | ||
| 731 | if (!netdev) | ||
| 732 | return -ENOMEM; | ||
| 733 | |||
| 734 | set_dev_addr(netdev, &conn->hcon->src, conn->hcon->src_type); | ||
| 735 | |||
| 736 | netdev->netdev_ops = &netdev_ops; | ||
| 737 | SET_NETDEV_DEV(netdev, &conn->hcon->dev); | ||
| 738 | SET_NETDEV_DEVTYPE(netdev, &bt_type); | ||
| 739 | |||
| 740 | err = register_netdev(netdev); | ||
| 741 | if (err < 0) { | ||
| 742 | BT_INFO("register_netdev failed %d", err); | ||
| 743 | free_netdev(netdev); | ||
| 744 | goto out; | ||
| 745 | } | ||
| 746 | |||
| 747 | BT_DBG("ifindex %d peer bdaddr %pMR my addr %pMR", | ||
| 748 | netdev->ifindex, &conn->hcon->dst, &conn->hcon->src); | ||
| 749 | set_bit(__LINK_STATE_PRESENT, &netdev->state); | ||
| 750 | |||
| 751 | dev = netdev_priv(netdev); | ||
| 752 | dev->netdev = netdev; | ||
| 753 | dev->hdev = conn->hcon->hdev; | ||
| 754 | INIT_LIST_HEAD(&dev->peers); | ||
| 755 | |||
| 756 | write_lock_irqsave(&devices_lock, flags); | ||
| 757 | INIT_LIST_HEAD(&dev->list); | ||
| 758 | list_add(&dev->list, &bt_6lowpan_devices); | ||
| 759 | write_unlock_irqrestore(&devices_lock, flags); | ||
| 760 | |||
| 761 | ifup(netdev); | ||
| 762 | |||
| 763 | return add_peer_conn(conn, dev); | ||
| 764 | |||
| 765 | out: | ||
| 766 | return err; | ||
| 767 | } | ||
| 768 | |||
| 769 | static void delete_netdev(struct work_struct *work) | ||
| 770 | { | ||
| 771 | struct lowpan_dev *entry = container_of(work, struct lowpan_dev, | ||
| 772 | delete_netdev); | ||
| 773 | |||
| 774 | unregister_netdev(entry->netdev); | ||
| 775 | |||
| 776 | /* The entry pointer is deleted in device_event() */ | ||
| 777 | } | ||
| 778 | |||
| 779 | int bt_6lowpan_del_conn(struct l2cap_conn *conn) | ||
| 780 | { | ||
| 781 | struct lowpan_dev *entry, *tmp; | ||
| 782 | struct lowpan_dev *dev = NULL; | ||
| 783 | struct lowpan_peer *peer; | ||
| 784 | int err = -ENOENT; | ||
| 785 | unsigned long flags; | ||
| 786 | bool last = false; | ||
| 787 | |||
| 788 | if (!conn || !is_bt_6lowpan(conn->hcon)) | ||
| 789 | return 0; | ||
| 790 | |||
| 791 | write_lock_irqsave(&devices_lock, flags); | ||
| 792 | |||
| 793 | list_for_each_entry_safe(entry, tmp, &bt_6lowpan_devices, list) { | ||
| 794 | dev = lowpan_dev(entry->netdev); | ||
| 795 | peer = peer_lookup_conn(dev, conn); | ||
| 796 | if (peer) { | ||
| 797 | last = peer_del(dev, peer); | ||
| 798 | err = 0; | ||
| 799 | break; | ||
| 800 | } | ||
| 801 | } | ||
| 802 | |||
| 803 | if (!err && last && dev && !atomic_read(&dev->peer_count)) { | ||
| 804 | write_unlock_irqrestore(&devices_lock, flags); | ||
| 805 | |||
| 806 | cancel_delayed_work_sync(&dev->notify_peers); | ||
| 807 | |||
| 808 | /* bt_6lowpan_del_conn() is called with hci dev lock held which | ||
| 809 | * means that we must delete the netdevice in worker thread. | ||
| 810 | */ | ||
| 811 | INIT_WORK(&entry->delete_netdev, delete_netdev); | ||
| 812 | schedule_work(&entry->delete_netdev); | ||
| 813 | } else { | ||
| 814 | write_unlock_irqrestore(&devices_lock, flags); | ||
| 815 | } | ||
| 816 | |||
| 817 | return err; | ||
| 818 | } | ||
| 819 | |||
| 820 | static int device_event(struct notifier_block *unused, | ||
| 821 | unsigned long event, void *ptr) | ||
| 822 | { | ||
| 823 | struct net_device *netdev = netdev_notifier_info_to_dev(ptr); | ||
| 824 | struct lowpan_dev *entry, *tmp; | ||
| 825 | unsigned long flags; | ||
| 826 | |||
| 827 | if (netdev->type != ARPHRD_6LOWPAN) | ||
| 828 | return NOTIFY_DONE; | ||
| 829 | |||
| 830 | switch (event) { | ||
| 831 | case NETDEV_UNREGISTER: | ||
| 832 | write_lock_irqsave(&devices_lock, flags); | ||
| 833 | list_for_each_entry_safe(entry, tmp, &bt_6lowpan_devices, | ||
| 834 | list) { | ||
| 835 | if (entry->netdev == netdev) { | ||
| 836 | list_del(&entry->list); | ||
| 837 | kfree(entry); | ||
| 838 | break; | ||
| 839 | } | ||
| 840 | } | ||
| 841 | write_unlock_irqrestore(&devices_lock, flags); | ||
| 842 | break; | ||
| 843 | } | ||
| 844 | |||
| 845 | return NOTIFY_DONE; | ||
| 846 | } | ||
| 847 | |||
| 848 | static struct notifier_block bt_6lowpan_dev_notifier = { | ||
| 849 | .notifier_call = device_event, | ||
| 850 | }; | ||
| 851 | |||
| 852 | int bt_6lowpan_init(void) | ||
| 853 | { | ||
| 854 | return register_netdevice_notifier(&bt_6lowpan_dev_notifier); | ||
| 855 | } | ||
| 856 | |||
| 857 | void bt_6lowpan_cleanup(void) | ||
| 858 | { | ||
| 859 | unregister_netdevice_notifier(&bt_6lowpan_dev_notifier); | ||
| 860 | } | ||
diff --git a/net/bluetooth/6lowpan.h b/net/bluetooth/6lowpan.h new file mode 100644 index 000000000000..680eac808d74 --- /dev/null +++ b/net/bluetooth/6lowpan.h | |||
| @@ -0,0 +1,26 @@ | |||
| 1 | /* | ||
| 2 | Copyright (c) 2013 Intel Corp. | ||
| 3 | |||
| 4 | This program is free software; you can redistribute it and/or modify | ||
| 5 | it under the terms of the GNU General Public License version 2 and | ||
| 6 | only version 2 as published by the Free Software Foundation. | ||
| 7 | |||
| 8 | This program is distributed in the hope that it will be useful, | ||
| 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | GNU General Public License for more details. | ||
| 12 | */ | ||
| 13 | |||
| 14 | #ifndef __6LOWPAN_H | ||
| 15 | #define __6LOWPAN_H | ||
| 16 | |||
| 17 | #include <linux/skbuff.h> | ||
| 18 | #include <net/bluetooth/l2cap.h> | ||
| 19 | |||
| 20 | int bt_6lowpan_recv(struct l2cap_conn *conn, struct sk_buff *skb); | ||
| 21 | int bt_6lowpan_add_conn(struct l2cap_conn *conn); | ||
| 22 | int bt_6lowpan_del_conn(struct l2cap_conn *conn); | ||
| 23 | int bt_6lowpan_init(void); | ||
| 24 | void bt_6lowpan_cleanup(void); | ||
| 25 | |||
| 26 | #endif /* __6LOWPAN_H */ | ||
diff --git a/net/bluetooth/Kconfig b/net/bluetooth/Kconfig index d3f3f7b1d32c..985b56070d26 100644 --- a/net/bluetooth/Kconfig +++ b/net/bluetooth/Kconfig | |||
| @@ -12,6 +12,7 @@ menuconfig BT | |||
| 12 | select CRYPTO_AES | 12 | select CRYPTO_AES |
| 13 | select CRYPTO_ECB | 13 | select CRYPTO_ECB |
| 14 | select CRYPTO_SHA256 | 14 | select CRYPTO_SHA256 |
| 15 | select 6LOWPAN_IPHC | ||
| 15 | help | 16 | help |
| 16 | Bluetooth is low-cost, low-power, short-range wireless technology. | 17 | Bluetooth is low-cost, low-power, short-range wireless technology. |
| 17 | It was designed as a replacement for cables and other short-range | 18 | It was designed as a replacement for cables and other short-range |
diff --git a/net/bluetooth/Makefile b/net/bluetooth/Makefile index 6a791e73e39d..80cb215826e8 100644 --- a/net/bluetooth/Makefile +++ b/net/bluetooth/Makefile | |||
| @@ -10,6 +10,6 @@ obj-$(CONFIG_BT_HIDP) += hidp/ | |||
| 10 | 10 | ||
| 11 | bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o \ | 11 | bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o \ |
| 12 | hci_sock.o hci_sysfs.o l2cap_core.o l2cap_sock.o smp.o sco.o lib.o \ | 12 | hci_sock.o hci_sysfs.o l2cap_core.o l2cap_sock.o smp.o sco.o lib.o \ |
| 13 | a2mp.o amp.o | 13 | a2mp.o amp.o 6lowpan.o |
| 14 | 14 | ||
| 15 | subdir-ccflags-y += -D__CHECK_ENDIAN__ | 15 | subdir-ccflags-y += -D__CHECK_ENDIAN__ |
diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c index 56ca494621c6..0c5866bb49b6 100644 --- a/net/bluetooth/af_bluetooth.c +++ b/net/bluetooth/af_bluetooth.c | |||
| @@ -31,7 +31,7 @@ | |||
| 31 | #include <net/bluetooth/bluetooth.h> | 31 | #include <net/bluetooth/bluetooth.h> |
| 32 | #include <linux/proc_fs.h> | 32 | #include <linux/proc_fs.h> |
| 33 | 33 | ||
| 34 | #define VERSION "2.17" | 34 | #define VERSION "2.18" |
| 35 | 35 | ||
| 36 | /* Bluetooth sockets */ | 36 | /* Bluetooth sockets */ |
| 37 | #define BT_MAX_PROTO 8 | 37 | #define BT_MAX_PROTO 8 |
diff --git a/net/bluetooth/bnep/bnep.h b/net/bluetooth/bnep/bnep.h index e7ee5314f39a..5a5b16f365e9 100644 --- a/net/bluetooth/bnep/bnep.h +++ b/net/bluetooth/bnep/bnep.h | |||
| @@ -12,8 +12,7 @@ | |||
| 12 | GNU General Public License for more details. | 12 | GNU General Public License for more details. |
| 13 | 13 | ||
| 14 | You should have received a copy of the GNU General Public License | 14 | You should have received a copy of the GNU General Public License |
| 15 | along with this program; if not, write to the Free Software | 15 | along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 16 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 17 | */ | 16 | */ |
| 18 | 17 | ||
| 19 | #ifndef _BNEP_H | 18 | #ifndef _BNEP_H |
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 6ccc4eb9e55e..5e8663c194c1 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c | |||
| @@ -636,6 +636,49 @@ static int conn_max_interval_get(void *data, u64 *val) | |||
| 636 | DEFINE_SIMPLE_ATTRIBUTE(conn_max_interval_fops, conn_max_interval_get, | 636 | DEFINE_SIMPLE_ATTRIBUTE(conn_max_interval_fops, conn_max_interval_get, |
| 637 | conn_max_interval_set, "%llu\n"); | 637 | conn_max_interval_set, "%llu\n"); |
| 638 | 638 | ||
| 639 | static ssize_t lowpan_read(struct file *file, char __user *user_buf, | ||
| 640 | size_t count, loff_t *ppos) | ||
| 641 | { | ||
| 642 | struct hci_dev *hdev = file->private_data; | ||
| 643 | char buf[3]; | ||
| 644 | |||
| 645 | buf[0] = test_bit(HCI_6LOWPAN_ENABLED, &hdev->dev_flags) ? 'Y' : 'N'; | ||
| 646 | buf[1] = '\n'; | ||
| 647 | buf[2] = '\0'; | ||
| 648 | return simple_read_from_buffer(user_buf, count, ppos, buf, 2); | ||
| 649 | } | ||
| 650 | |||
| 651 | static ssize_t lowpan_write(struct file *fp, const char __user *user_buffer, | ||
| 652 | size_t count, loff_t *position) | ||
| 653 | { | ||
| 654 | struct hci_dev *hdev = fp->private_data; | ||
| 655 | bool enable; | ||
| 656 | char buf[32]; | ||
| 657 | size_t buf_size = min(count, (sizeof(buf)-1)); | ||
| 658 | |||
| 659 | if (copy_from_user(buf, user_buffer, buf_size)) | ||
| 660 | return -EFAULT; | ||
| 661 | |||
| 662 | buf[buf_size] = '\0'; | ||
| 663 | |||
| 664 | if (strtobool(buf, &enable) < 0) | ||
| 665 | return -EINVAL; | ||
| 666 | |||
| 667 | if (enable == test_bit(HCI_6LOWPAN_ENABLED, &hdev->dev_flags)) | ||
| 668 | return -EALREADY; | ||
| 669 | |||
| 670 | change_bit(HCI_6LOWPAN_ENABLED, &hdev->dev_flags); | ||
| 671 | |||
| 672 | return count; | ||
| 673 | } | ||
| 674 | |||
| 675 | static const struct file_operations lowpan_debugfs_fops = { | ||
| 676 | .open = simple_open, | ||
| 677 | .read = lowpan_read, | ||
| 678 | .write = lowpan_write, | ||
| 679 | .llseek = default_llseek, | ||
| 680 | }; | ||
| 681 | |||
| 639 | /* ---- HCI requests ---- */ | 682 | /* ---- HCI requests ---- */ |
| 640 | 683 | ||
| 641 | static void hci_req_sync_complete(struct hci_dev *hdev, u8 result) | 684 | static void hci_req_sync_complete(struct hci_dev *hdev, u8 result) |
| @@ -1228,7 +1271,7 @@ static void hci_set_event_mask_page_2(struct hci_request *req) | |||
| 1228 | /* If Connectionless Slave Broadcast master role is supported | 1271 | /* If Connectionless Slave Broadcast master role is supported |
| 1229 | * enable all necessary events for it. | 1272 | * enable all necessary events for it. |
| 1230 | */ | 1273 | */ |
| 1231 | if (hdev->features[2][0] & 0x01) { | 1274 | if (lmp_csb_master_capable(hdev)) { |
| 1232 | events[1] |= 0x40; /* Triggered Clock Capture */ | 1275 | events[1] |= 0x40; /* Triggered Clock Capture */ |
| 1233 | events[1] |= 0x80; /* Synchronization Train Complete */ | 1276 | events[1] |= 0x80; /* Synchronization Train Complete */ |
| 1234 | events[2] |= 0x10; /* Slave Page Response Timeout */ | 1277 | events[2] |= 0x10; /* Slave Page Response Timeout */ |
| @@ -1238,7 +1281,7 @@ static void hci_set_event_mask_page_2(struct hci_request *req) | |||
| 1238 | /* If Connectionless Slave Broadcast slave role is supported | 1281 | /* If Connectionless Slave Broadcast slave role is supported |
| 1239 | * enable all necessary events for it. | 1282 | * enable all necessary events for it. |
| 1240 | */ | 1283 | */ |
| 1241 | if (hdev->features[2][0] & 0x02) { | 1284 | if (lmp_csb_slave_capable(hdev)) { |
| 1242 | events[2] |= 0x01; /* Synchronization Train Received */ | 1285 | events[2] |= 0x01; /* Synchronization Train Received */ |
| 1243 | events[2] |= 0x02; /* CSB Receive */ | 1286 | events[2] |= 0x02; /* CSB Receive */ |
| 1244 | events[2] |= 0x04; /* CSB Timeout */ | 1287 | events[2] |= 0x04; /* CSB Timeout */ |
| @@ -1261,8 +1304,13 @@ static void hci_init3_req(struct hci_request *req, unsigned long opt) | |||
| 1261 | * as supported send it. If not supported assume that the controller | 1304 | * as supported send it. If not supported assume that the controller |
| 1262 | * does not have actual support for stored link keys which makes this | 1305 | * does not have actual support for stored link keys which makes this |
| 1263 | * command redundant anyway. | 1306 | * command redundant anyway. |
| 1307 | * | ||
| 1308 | * Some controllers indicate that they support handling deleting | ||
| 1309 | * stored link keys, but they don't. The quirk lets a driver | ||
| 1310 | * just disable this command. | ||
| 1264 | */ | 1311 | */ |
| 1265 | if (hdev->commands[6] & 0x80) { | 1312 | if (hdev->commands[6] & 0x80 && |
| 1313 | !test_bit(HCI_QUIRK_BROKEN_STORED_LINK_KEY, &hdev->quirks)) { | ||
| 1266 | struct hci_cp_delete_stored_link_key cp; | 1314 | struct hci_cp_delete_stored_link_key cp; |
| 1267 | 1315 | ||
| 1268 | bacpy(&cp.bdaddr, BDADDR_ANY); | 1316 | bacpy(&cp.bdaddr, BDADDR_ANY); |
| @@ -1275,15 +1323,17 @@ static void hci_init3_req(struct hci_request *req, unsigned long opt) | |||
| 1275 | hci_setup_link_policy(req); | 1323 | hci_setup_link_policy(req); |
| 1276 | 1324 | ||
| 1277 | if (lmp_le_capable(hdev)) { | 1325 | if (lmp_le_capable(hdev)) { |
| 1278 | /* If the controller has a public BD_ADDR, then by | 1326 | if (test_bit(HCI_SETUP, &hdev->dev_flags)) { |
| 1279 | * default use that one. If this is a LE only | 1327 | /* If the controller has a public BD_ADDR, then |
| 1280 | * controller without one, default to the random | 1328 | * by default use that one. If this is a LE only |
| 1281 | * address. | 1329 | * controller without a public address, default |
| 1282 | */ | 1330 | * to the random address. |
| 1283 | if (bacmp(&hdev->bdaddr, BDADDR_ANY)) | 1331 | */ |
| 1284 | hdev->own_addr_type = ADDR_LE_DEV_PUBLIC; | 1332 | if (bacmp(&hdev->bdaddr, BDADDR_ANY)) |
| 1285 | else | 1333 | hdev->own_addr_type = ADDR_LE_DEV_PUBLIC; |
| 1286 | hdev->own_addr_type = ADDR_LE_DEV_RANDOM; | 1334 | else |
| 1335 | hdev->own_addr_type = ADDR_LE_DEV_RANDOM; | ||
| 1336 | } | ||
| 1287 | 1337 | ||
| 1288 | hci_set_le_support(req); | 1338 | hci_set_le_support(req); |
| 1289 | } | 1339 | } |
| @@ -1307,7 +1357,7 @@ static void hci_init4_req(struct hci_request *req, unsigned long opt) | |||
| 1307 | hci_set_event_mask_page_2(req); | 1357 | hci_set_event_mask_page_2(req); |
| 1308 | 1358 | ||
| 1309 | /* Check for Synchronization Train support */ | 1359 | /* Check for Synchronization Train support */ |
| 1310 | if (hdev->features[2][0] & 0x04) | 1360 | if (lmp_sync_train_capable(hdev)) |
| 1311 | hci_req_add(req, HCI_OP_READ_SYNC_TRAIN_PARAMS, 0, NULL); | 1361 | hci_req_add(req, HCI_OP_READ_SYNC_TRAIN_PARAMS, 0, NULL); |
| 1312 | } | 1362 | } |
| 1313 | 1363 | ||
| @@ -1404,6 +1454,8 @@ static int __hci_init(struct hci_dev *hdev) | |||
| 1404 | hdev, &conn_min_interval_fops); | 1454 | hdev, &conn_min_interval_fops); |
| 1405 | debugfs_create_file("conn_max_interval", 0644, hdev->debugfs, | 1455 | debugfs_create_file("conn_max_interval", 0644, hdev->debugfs, |
| 1406 | hdev, &conn_max_interval_fops); | 1456 | hdev, &conn_max_interval_fops); |
| 1457 | debugfs_create_file("6lowpan", 0644, hdev->debugfs, hdev, | ||
| 1458 | &lowpan_debugfs_fops); | ||
| 1407 | } | 1459 | } |
| 1408 | 1460 | ||
| 1409 | return 0; | 1461 | return 0; |
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 5935f748c0f9..5f812455a450 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c | |||
| @@ -486,7 +486,10 @@ static void hci_cc_read_local_commands(struct hci_dev *hdev, | |||
| 486 | 486 | ||
| 487 | BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); | 487 | BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); |
| 488 | 488 | ||
| 489 | if (!rp->status) | 489 | if (rp->status) |
| 490 | return; | ||
| 491 | |||
| 492 | if (test_bit(HCI_SETUP, &hdev->dev_flags)) | ||
| 490 | memcpy(hdev->commands, rp->commands, sizeof(hdev->commands)); | 493 | memcpy(hdev->commands, rp->commands, sizeof(hdev->commands)); |
| 491 | } | 494 | } |
| 492 | 495 | ||
| @@ -538,12 +541,6 @@ static void hci_cc_read_local_features(struct hci_dev *hdev, | |||
| 538 | 541 | ||
| 539 | if (hdev->features[0][5] & LMP_EDR_3S_ESCO) | 542 | if (hdev->features[0][5] & LMP_EDR_3S_ESCO) |
| 540 | hdev->esco_type |= (ESCO_2EV5 | ESCO_3EV5); | 543 | hdev->esco_type |= (ESCO_2EV5 | ESCO_3EV5); |
| 541 | |||
| 542 | BT_DBG("%s features 0x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x", hdev->name, | ||
| 543 | hdev->features[0][0], hdev->features[0][1], | ||
| 544 | hdev->features[0][2], hdev->features[0][3], | ||
| 545 | hdev->features[0][4], hdev->features[0][5], | ||
| 546 | hdev->features[0][6], hdev->features[0][7]); | ||
| 547 | } | 544 | } |
| 548 | 545 | ||
| 549 | static void hci_cc_read_local_ext_features(struct hci_dev *hdev, | 546 | static void hci_cc_read_local_ext_features(struct hci_dev *hdev, |
| @@ -1782,7 +1779,9 @@ static u8 hci_to_mgmt_reason(u8 err) | |||
| 1782 | static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) | 1779 | static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) |
| 1783 | { | 1780 | { |
| 1784 | struct hci_ev_disconn_complete *ev = (void *) skb->data; | 1781 | struct hci_ev_disconn_complete *ev = (void *) skb->data; |
| 1782 | u8 reason = hci_to_mgmt_reason(ev->reason); | ||
| 1785 | struct hci_conn *conn; | 1783 | struct hci_conn *conn; |
| 1784 | u8 type; | ||
| 1786 | 1785 | ||
| 1787 | BT_DBG("%s status 0x%2.2x", hdev->name, ev->status); | 1786 | BT_DBG("%s status 0x%2.2x", hdev->name, ev->status); |
| 1788 | 1787 | ||
| @@ -1792,43 +1791,38 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) | |||
| 1792 | if (!conn) | 1791 | if (!conn) |
| 1793 | goto unlock; | 1792 | goto unlock; |
| 1794 | 1793 | ||
| 1795 | if (ev->status == 0) | 1794 | if (ev->status) { |
| 1796 | conn->state = BT_CLOSED; | 1795 | mgmt_disconnect_failed(hdev, &conn->dst, conn->type, |
| 1796 | conn->dst_type, ev->status); | ||
| 1797 | goto unlock; | ||
| 1798 | } | ||
| 1797 | 1799 | ||
| 1798 | if (test_and_clear_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags) && | 1800 | conn->state = BT_CLOSED; |
| 1799 | (conn->type == ACL_LINK || conn->type == LE_LINK)) { | ||
| 1800 | if (ev->status) { | ||
| 1801 | mgmt_disconnect_failed(hdev, &conn->dst, conn->type, | ||
| 1802 | conn->dst_type, ev->status); | ||
| 1803 | } else { | ||
| 1804 | u8 reason = hci_to_mgmt_reason(ev->reason); | ||
| 1805 | 1801 | ||
| 1806 | mgmt_device_disconnected(hdev, &conn->dst, conn->type, | 1802 | if (test_and_clear_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) |
| 1807 | conn->dst_type, reason); | 1803 | mgmt_device_disconnected(hdev, &conn->dst, conn->type, |
| 1808 | } | 1804 | conn->dst_type, reason); |
| 1809 | } | ||
| 1810 | 1805 | ||
| 1811 | if (ev->status == 0) { | 1806 | if (conn->type == ACL_LINK && conn->flush_key) |
| 1812 | u8 type = conn->type; | 1807 | hci_remove_link_key(hdev, &conn->dst); |
| 1813 | 1808 | ||
| 1814 | if (type == ACL_LINK && conn->flush_key) | 1809 | type = conn->type; |
| 1815 | hci_remove_link_key(hdev, &conn->dst); | ||
| 1816 | hci_proto_disconn_cfm(conn, ev->reason); | ||
| 1817 | hci_conn_del(conn); | ||
| 1818 | 1810 | ||
| 1819 | /* Re-enable advertising if necessary, since it might | 1811 | hci_proto_disconn_cfm(conn, ev->reason); |
| 1820 | * have been disabled by the connection. From the | 1812 | hci_conn_del(conn); |
| 1821 | * HCI_LE_Set_Advertise_Enable command description in | 1813 | |
| 1822 | * the core specification (v4.0): | 1814 | /* Re-enable advertising if necessary, since it might |
| 1823 | * "The Controller shall continue advertising until the Host | 1815 | * have been disabled by the connection. From the |
| 1824 | * issues an LE_Set_Advertise_Enable command with | 1816 | * HCI_LE_Set_Advertise_Enable command description in |
| 1825 | * Advertising_Enable set to 0x00 (Advertising is disabled) | 1817 | * the core specification (v4.0): |
| 1826 | * or until a connection is created or until the Advertising | 1818 | * "The Controller shall continue advertising until the Host |
| 1827 | * is timed out due to Directed Advertising." | 1819 | * issues an LE_Set_Advertise_Enable command with |
| 1828 | */ | 1820 | * Advertising_Enable set to 0x00 (Advertising is disabled) |
| 1829 | if (type == LE_LINK) | 1821 | * or until a connection is created or until the Advertising |
| 1830 | mgmt_reenable_advertising(hdev); | 1822 | * is timed out due to Directed Advertising." |
| 1831 | } | 1823 | */ |
| 1824 | if (type == LE_LINK) | ||
| 1825 | mgmt_reenable_advertising(hdev); | ||
| 1832 | 1826 | ||
| 1833 | unlock: | 1827 | unlock: |
| 1834 | hci_dev_unlock(hdev); | 1828 | hci_dev_unlock(hdev); |
| @@ -3539,6 +3533,9 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) | |||
| 3539 | conn->handle = __le16_to_cpu(ev->handle); | 3533 | conn->handle = __le16_to_cpu(ev->handle); |
| 3540 | conn->state = BT_CONNECTED; | 3534 | conn->state = BT_CONNECTED; |
| 3541 | 3535 | ||
| 3536 | if (test_bit(HCI_6LOWPAN_ENABLED, &hdev->dev_flags)) | ||
| 3537 | set_bit(HCI_CONN_6LOWPAN, &conn->flags); | ||
| 3538 | |||
| 3542 | hci_conn_add_sysfs(conn); | 3539 | hci_conn_add_sysfs(conn); |
| 3543 | 3540 | ||
| 3544 | hci_proto_connect_cfm(conn, ev->status); | 3541 | hci_proto_connect_cfm(conn, ev->status); |
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 4af3821df880..b0ad2c752d73 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c | |||
| @@ -40,6 +40,7 @@ | |||
| 40 | #include "smp.h" | 40 | #include "smp.h" |
| 41 | #include "a2mp.h" | 41 | #include "a2mp.h" |
| 42 | #include "amp.h" | 42 | #include "amp.h" |
| 43 | #include "6lowpan.h" | ||
| 43 | 44 | ||
| 44 | bool disable_ertm; | 45 | bool disable_ertm; |
| 45 | 46 | ||
| @@ -49,6 +50,9 @@ static u8 l2cap_fixed_chan[8] = { L2CAP_FC_L2CAP | L2CAP_FC_CONNLESS, }; | |||
| 49 | static LIST_HEAD(chan_list); | 50 | static LIST_HEAD(chan_list); |
| 50 | static DEFINE_RWLOCK(chan_list_lock); | 51 | static DEFINE_RWLOCK(chan_list_lock); |
| 51 | 52 | ||
| 53 | static u16 le_max_credits = L2CAP_LE_MAX_CREDITS; | ||
| 54 | static u16 le_default_mps = L2CAP_LE_DEFAULT_MPS; | ||
| 55 | |||
| 52 | static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn, | 56 | static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn, |
| 53 | u8 code, u8 ident, u16 dlen, void *data); | 57 | u8 code, u8 ident, u16 dlen, void *data); |
| 54 | static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, | 58 | static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, |
| @@ -213,9 +217,14 @@ int l2cap_add_scid(struct l2cap_chan *chan, __u16 scid) | |||
| 213 | 217 | ||
| 214 | static u16 l2cap_alloc_cid(struct l2cap_conn *conn) | 218 | static u16 l2cap_alloc_cid(struct l2cap_conn *conn) |
| 215 | { | 219 | { |
| 216 | u16 cid = L2CAP_CID_DYN_START; | 220 | u16 cid, dyn_end; |
| 221 | |||
| 222 | if (conn->hcon->type == LE_LINK) | ||
| 223 | dyn_end = L2CAP_CID_LE_DYN_END; | ||
| 224 | else | ||
| 225 | dyn_end = L2CAP_CID_DYN_END; | ||
| 217 | 226 | ||
| 218 | for (; cid < L2CAP_CID_DYN_END; cid++) { | 227 | for (cid = L2CAP_CID_DYN_START; cid < dyn_end; cid++) { |
| 219 | if (!__l2cap_get_chan_by_scid(conn, cid)) | 228 | if (!__l2cap_get_chan_by_scid(conn, cid)) |
| 220 | return cid; | 229 | return cid; |
| 221 | } | 230 | } |
| @@ -490,6 +499,18 @@ void l2cap_chan_set_defaults(struct l2cap_chan *chan) | |||
| 490 | set_bit(FLAG_FORCE_ACTIVE, &chan->flags); | 499 | set_bit(FLAG_FORCE_ACTIVE, &chan->flags); |
| 491 | } | 500 | } |
| 492 | 501 | ||
| 502 | static void l2cap_le_flowctl_init(struct l2cap_chan *chan) | ||
| 503 | { | ||
| 504 | chan->sdu = NULL; | ||
| 505 | chan->sdu_last_frag = NULL; | ||
| 506 | chan->sdu_len = 0; | ||
| 507 | chan->tx_credits = 0; | ||
| 508 | chan->rx_credits = le_max_credits; | ||
| 509 | chan->mps = min_t(u16, chan->imtu, L2CAP_LE_DEFAULT_MPS); | ||
| 510 | |||
| 511 | skb_queue_head_init(&chan->tx_q); | ||
| 512 | } | ||
| 513 | |||
| 493 | void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) | 514 | void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) |
| 494 | { | 515 | { |
| 495 | BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn, | 516 | BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn, |
| @@ -502,12 +523,12 @@ void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) | |||
| 502 | switch (chan->chan_type) { | 523 | switch (chan->chan_type) { |
| 503 | case L2CAP_CHAN_CONN_ORIENTED: | 524 | case L2CAP_CHAN_CONN_ORIENTED: |
| 504 | if (conn->hcon->type == LE_LINK) { | 525 | if (conn->hcon->type == LE_LINK) { |
| 505 | /* LE connection */ | 526 | if (chan->dcid == L2CAP_CID_ATT) { |
| 506 | chan->omtu = L2CAP_DEFAULT_MTU; | 527 | chan->omtu = L2CAP_DEFAULT_MTU; |
| 507 | if (chan->dcid == L2CAP_CID_ATT) | ||
| 508 | chan->scid = L2CAP_CID_ATT; | 528 | chan->scid = L2CAP_CID_ATT; |
| 509 | else | 529 | } else { |
| 510 | chan->scid = l2cap_alloc_cid(conn); | 530 | chan->scid = l2cap_alloc_cid(conn); |
| 531 | } | ||
| 511 | } else { | 532 | } else { |
| 512 | /* Alloc CID for connection-oriented socket */ | 533 | /* Alloc CID for connection-oriented socket */ |
| 513 | chan->scid = l2cap_alloc_cid(conn); | 534 | chan->scid = l2cap_alloc_cid(conn); |
| @@ -597,6 +618,10 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err) | |||
| 597 | case L2CAP_MODE_BASIC: | 618 | case L2CAP_MODE_BASIC: |
| 598 | break; | 619 | break; |
| 599 | 620 | ||
| 621 | case L2CAP_MODE_LE_FLOWCTL: | ||
| 622 | skb_queue_purge(&chan->tx_q); | ||
| 623 | break; | ||
| 624 | |||
| 600 | case L2CAP_MODE_ERTM: | 625 | case L2CAP_MODE_ERTM: |
| 601 | __clear_retrans_timer(chan); | 626 | __clear_retrans_timer(chan); |
| 602 | __clear_monitor_timer(chan); | 627 | __clear_monitor_timer(chan); |
| @@ -617,6 +642,50 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err) | |||
| 617 | return; | 642 | return; |
| 618 | } | 643 | } |
| 619 | 644 | ||
| 645 | static void l2cap_chan_le_connect_reject(struct l2cap_chan *chan) | ||
| 646 | { | ||
| 647 | struct l2cap_conn *conn = chan->conn; | ||
| 648 | struct l2cap_le_conn_rsp rsp; | ||
| 649 | u16 result; | ||
| 650 | |||
| 651 | if (test_bit(FLAG_DEFER_SETUP, &chan->flags)) | ||
| 652 | result = L2CAP_CR_AUTHORIZATION; | ||
| 653 | else | ||
| 654 | result = L2CAP_CR_BAD_PSM; | ||
| 655 | |||
| 656 | l2cap_state_change(chan, BT_DISCONN); | ||
| 657 | |||
| 658 | rsp.dcid = cpu_to_le16(chan->scid); | ||
| 659 | rsp.mtu = cpu_to_le16(chan->imtu); | ||
| 660 | rsp.mps = cpu_to_le16(chan->mps); | ||
| 661 | rsp.credits = cpu_to_le16(chan->rx_credits); | ||
| 662 | rsp.result = cpu_to_le16(result); | ||
| 663 | |||
| 664 | l2cap_send_cmd(conn, chan->ident, L2CAP_LE_CONN_RSP, sizeof(rsp), | ||
| 665 | &rsp); | ||
| 666 | } | ||
| 667 | |||
| 668 | static void l2cap_chan_connect_reject(struct l2cap_chan *chan) | ||
| 669 | { | ||
| 670 | struct l2cap_conn *conn = chan->conn; | ||
| 671 | struct l2cap_conn_rsp rsp; | ||
| 672 | u16 result; | ||
| 673 | |||
| 674 | if (test_bit(FLAG_DEFER_SETUP, &chan->flags)) | ||
| 675 | result = L2CAP_CR_SEC_BLOCK; | ||
| 676 | else | ||
| 677 | result = L2CAP_CR_BAD_PSM; | ||
| 678 | |||
| 679 | l2cap_state_change(chan, BT_DISCONN); | ||
| 680 | |||
| 681 | rsp.scid = cpu_to_le16(chan->dcid); | ||
| 682 | rsp.dcid = cpu_to_le16(chan->scid); | ||
| 683 | rsp.result = cpu_to_le16(result); | ||
| 684 | rsp.status = __constant_cpu_to_le16(L2CAP_CS_NO_INFO); | ||
| 685 | |||
| 686 | l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP, sizeof(rsp), &rsp); | ||
| 687 | } | ||
| 688 | |||
| 620 | void l2cap_chan_close(struct l2cap_chan *chan, int reason) | 689 | void l2cap_chan_close(struct l2cap_chan *chan, int reason) |
| 621 | { | 690 | { |
| 622 | struct l2cap_conn *conn = chan->conn; | 691 | struct l2cap_conn *conn = chan->conn; |
| @@ -630,8 +699,10 @@ void l2cap_chan_close(struct l2cap_chan *chan, int reason) | |||
| 630 | 699 | ||
| 631 | case BT_CONNECTED: | 700 | case BT_CONNECTED: |
| 632 | case BT_CONFIG: | 701 | case BT_CONFIG: |
| 633 | if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED && | 702 | /* ATT uses L2CAP_CHAN_CONN_ORIENTED so we must also |
| 634 | conn->hcon->type == ACL_LINK) { | 703 | * check for chan->psm. |
| 704 | */ | ||
| 705 | if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED && chan->psm) { | ||
| 635 | __set_chan_timer(chan, chan->ops->get_sndtimeo(chan)); | 706 | __set_chan_timer(chan, chan->ops->get_sndtimeo(chan)); |
| 636 | l2cap_send_disconn_req(chan, reason); | 707 | l2cap_send_disconn_req(chan, reason); |
| 637 | } else | 708 | } else |
| @@ -639,24 +710,11 @@ void l2cap_chan_close(struct l2cap_chan *chan, int reason) | |||
| 639 | break; | 710 | break; |
| 640 | 711 | ||
| 641 | case BT_CONNECT2: | 712 | case BT_CONNECT2: |
| 642 | if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED && | 713 | if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED) { |
| 643 | conn->hcon->type == ACL_LINK) { | 714 | if (conn->hcon->type == ACL_LINK) |
| 644 | struct l2cap_conn_rsp rsp; | 715 | l2cap_chan_connect_reject(chan); |
| 645 | __u16 result; | 716 | else if (conn->hcon->type == LE_LINK) |
| 646 | 717 | l2cap_chan_le_connect_reject(chan); | |
| 647 | if (test_bit(FLAG_DEFER_SETUP, &chan->flags)) | ||
| 648 | result = L2CAP_CR_SEC_BLOCK; | ||
| 649 | else | ||
| 650 | result = L2CAP_CR_BAD_PSM; | ||
| 651 | |||
| 652 | l2cap_state_change(chan, BT_DISCONN); | ||
| 653 | |||
| 654 | rsp.scid = cpu_to_le16(chan->dcid); | ||
| 655 | rsp.dcid = cpu_to_le16(chan->scid); | ||
| 656 | rsp.result = cpu_to_le16(result); | ||
| 657 | rsp.status = __constant_cpu_to_le16(L2CAP_CS_NO_INFO); | ||
| 658 | l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP, | ||
| 659 | sizeof(rsp), &rsp); | ||
| 660 | } | 718 | } |
| 661 | 719 | ||
| 662 | l2cap_chan_del(chan, reason); | 720 | l2cap_chan_del(chan, reason); |
| @@ -726,6 +784,9 @@ int l2cap_chan_check_security(struct l2cap_chan *chan) | |||
| 726 | struct l2cap_conn *conn = chan->conn; | 784 | struct l2cap_conn *conn = chan->conn; |
| 727 | __u8 auth_type; | 785 | __u8 auth_type; |
| 728 | 786 | ||
| 787 | if (conn->hcon->type == LE_LINK) | ||
| 788 | return smp_conn_security(conn->hcon, chan->sec_level); | ||
| 789 | |||
| 729 | auth_type = l2cap_get_auth_type(chan); | 790 | auth_type = l2cap_get_auth_type(chan); |
| 730 | 791 | ||
| 731 | return hci_conn_security(conn->hcon, chan->sec_level, auth_type); | 792 | return hci_conn_security(conn->hcon, chan->sec_level, auth_type); |
| @@ -1152,16 +1213,57 @@ static void l2cap_chan_ready(struct l2cap_chan *chan) | |||
| 1152 | chan->conf_state = 0; | 1213 | chan->conf_state = 0; |
| 1153 | __clear_chan_timer(chan); | 1214 | __clear_chan_timer(chan); |
| 1154 | 1215 | ||
| 1216 | if (chan->mode == L2CAP_MODE_LE_FLOWCTL && !chan->tx_credits) | ||
| 1217 | chan->ops->suspend(chan); | ||
| 1218 | |||
| 1155 | chan->state = BT_CONNECTED; | 1219 | chan->state = BT_CONNECTED; |
| 1156 | 1220 | ||
| 1157 | chan->ops->ready(chan); | 1221 | chan->ops->ready(chan); |
| 1158 | } | 1222 | } |
| 1159 | 1223 | ||
| 1224 | static void l2cap_le_connect(struct l2cap_chan *chan) | ||
| 1225 | { | ||
| 1226 | struct l2cap_conn *conn = chan->conn; | ||
| 1227 | struct l2cap_le_conn_req req; | ||
| 1228 | |||
| 1229 | if (test_and_set_bit(FLAG_LE_CONN_REQ_SENT, &chan->flags)) | ||
| 1230 | return; | ||
| 1231 | |||
| 1232 | req.psm = chan->psm; | ||
| 1233 | req.scid = cpu_to_le16(chan->scid); | ||
| 1234 | req.mtu = cpu_to_le16(chan->imtu); | ||
| 1235 | req.mps = cpu_to_le16(chan->mps); | ||
| 1236 | req.credits = cpu_to_le16(chan->rx_credits); | ||
| 1237 | |||
| 1238 | chan->ident = l2cap_get_ident(conn); | ||
| 1239 | |||
| 1240 | l2cap_send_cmd(conn, chan->ident, L2CAP_LE_CONN_REQ, | ||
| 1241 | sizeof(req), &req); | ||
| 1242 | } | ||
| 1243 | |||
| 1244 | static void l2cap_le_start(struct l2cap_chan *chan) | ||
| 1245 | { | ||
| 1246 | struct l2cap_conn *conn = chan->conn; | ||
| 1247 | |||
| 1248 | if (!smp_conn_security(conn->hcon, chan->sec_level)) | ||
| 1249 | return; | ||
| 1250 | |||
| 1251 | if (!chan->psm) { | ||
| 1252 | l2cap_chan_ready(chan); | ||
| 1253 | return; | ||
| 1254 | } | ||
| 1255 | |||
| 1256 | if (chan->state == BT_CONNECT) | ||
| 1257 | l2cap_le_connect(chan); | ||
| 1258 | } | ||
| 1259 | |||
| 1160 | static void l2cap_start_connection(struct l2cap_chan *chan) | 1260 | static void l2cap_start_connection(struct l2cap_chan *chan) |
| 1161 | { | 1261 | { |
| 1162 | if (__amp_capable(chan)) { | 1262 | if (__amp_capable(chan)) { |
| 1163 | BT_DBG("chan %p AMP capable: discover AMPs", chan); | 1263 | BT_DBG("chan %p AMP capable: discover AMPs", chan); |
| 1164 | a2mp_discover_amp(chan); | 1264 | a2mp_discover_amp(chan); |
| 1265 | } else if (chan->conn->hcon->type == LE_LINK) { | ||
| 1266 | l2cap_le_start(chan); | ||
| 1165 | } else { | 1267 | } else { |
| 1166 | l2cap_send_conn_req(chan); | 1268 | l2cap_send_conn_req(chan); |
| 1167 | } | 1269 | } |
| @@ -1172,7 +1274,7 @@ static void l2cap_do_start(struct l2cap_chan *chan) | |||
| 1172 | struct l2cap_conn *conn = chan->conn; | 1274 | struct l2cap_conn *conn = chan->conn; |
| 1173 | 1275 | ||
| 1174 | if (conn->hcon->type == LE_LINK) { | 1276 | if (conn->hcon->type == LE_LINK) { |
| 1175 | l2cap_chan_ready(chan); | 1277 | l2cap_le_start(chan); |
| 1176 | return; | 1278 | return; |
| 1177 | } | 1279 | } |
| 1178 | 1280 | ||
| @@ -1367,6 +1469,8 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn) | |||
| 1367 | 1469 | ||
| 1368 | BT_DBG(""); | 1470 | BT_DBG(""); |
| 1369 | 1471 | ||
| 1472 | bt_6lowpan_add_conn(conn); | ||
| 1473 | |||
| 1370 | /* Check if we have socket listening on cid */ | 1474 | /* Check if we have socket listening on cid */ |
| 1371 | pchan = l2cap_global_chan_by_scid(BT_LISTEN, L2CAP_CID_ATT, | 1475 | pchan = l2cap_global_chan_by_scid(BT_LISTEN, L2CAP_CID_ATT, |
| 1372 | &hcon->src, &hcon->dst); | 1476 | &hcon->src, &hcon->dst); |
| @@ -1430,9 +1534,7 @@ static void l2cap_conn_ready(struct l2cap_conn *conn) | |||
| 1430 | } | 1534 | } |
| 1431 | 1535 | ||
| 1432 | if (hcon->type == LE_LINK) { | 1536 | if (hcon->type == LE_LINK) { |
| 1433 | if (smp_conn_security(hcon, chan->sec_level)) | 1537 | l2cap_le_start(chan); |
| 1434 | l2cap_chan_ready(chan); | ||
| 1435 | |||
| 1436 | } else if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) { | 1538 | } else if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) { |
| 1437 | l2cap_chan_ready(chan); | 1539 | l2cap_chan_ready(chan); |
| 1438 | 1540 | ||
| @@ -1703,7 +1805,8 @@ EXPORT_SYMBOL(l2cap_conn_put); | |||
| 1703 | */ | 1805 | */ |
| 1704 | static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, | 1806 | static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, |
| 1705 | bdaddr_t *src, | 1807 | bdaddr_t *src, |
| 1706 | bdaddr_t *dst) | 1808 | bdaddr_t *dst, |
| 1809 | u8 link_type) | ||
| 1707 | { | 1810 | { |
| 1708 | struct l2cap_chan *c, *c1 = NULL; | 1811 | struct l2cap_chan *c, *c1 = NULL; |
| 1709 | 1812 | ||
| @@ -1713,6 +1816,12 @@ static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, | |||
| 1713 | if (state && c->state != state) | 1816 | if (state && c->state != state) |
| 1714 | continue; | 1817 | continue; |
| 1715 | 1818 | ||
| 1819 | if (link_type == ACL_LINK && c->src_type != BDADDR_BREDR) | ||
| 1820 | continue; | ||
| 1821 | |||
| 1822 | if (link_type == LE_LINK && c->src_type == BDADDR_BREDR) | ||
| 1823 | continue; | ||
| 1824 | |||
| 1716 | if (c->psm == psm) { | 1825 | if (c->psm == psm) { |
| 1717 | int src_match, dst_match; | 1826 | int src_match, dst_match; |
| 1718 | int src_any, dst_any; | 1827 | int src_any, dst_any; |
| @@ -1739,6 +1848,18 @@ static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, | |||
| 1739 | return c1; | 1848 | return c1; |
| 1740 | } | 1849 | } |
| 1741 | 1850 | ||
| 1851 | static bool is_valid_psm(u16 psm, u8 dst_type) | ||
| 1852 | { | ||
| 1853 | if (!psm) | ||
| 1854 | return false; | ||
| 1855 | |||
| 1856 | if (bdaddr_type_is_le(dst_type)) | ||
| 1857 | return (psm <= 0x00ff); | ||
| 1858 | |||
| 1859 | /* PSM must be odd and lsb of upper byte must be 0 */ | ||
| 1860 | return ((psm & 0x0101) == 0x0001); | ||
| 1861 | } | ||
| 1862 | |||
| 1742 | int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, | 1863 | int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, |
| 1743 | bdaddr_t *dst, u8 dst_type) | 1864 | bdaddr_t *dst, u8 dst_type) |
| 1744 | { | 1865 | { |
| @@ -1759,8 +1880,7 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, | |||
| 1759 | 1880 | ||
| 1760 | l2cap_chan_lock(chan); | 1881 | l2cap_chan_lock(chan); |
| 1761 | 1882 | ||
| 1762 | /* PSM must be odd and lsb of upper byte must be 0 */ | 1883 | if (!is_valid_psm(__le16_to_cpu(psm), dst_type) && !cid && |
| 1763 | if ((__le16_to_cpu(psm) & 0x0101) != 0x0001 && !cid && | ||
| 1764 | chan->chan_type != L2CAP_CHAN_RAW) { | 1884 | chan->chan_type != L2CAP_CHAN_RAW) { |
| 1765 | err = -EINVAL; | 1885 | err = -EINVAL; |
| 1766 | goto done; | 1886 | goto done; |
| @@ -1774,6 +1894,9 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, | |||
| 1774 | switch (chan->mode) { | 1894 | switch (chan->mode) { |
| 1775 | case L2CAP_MODE_BASIC: | 1895 | case L2CAP_MODE_BASIC: |
| 1776 | break; | 1896 | break; |
| 1897 | case L2CAP_MODE_LE_FLOWCTL: | ||
| 1898 | l2cap_le_flowctl_init(chan); | ||
| 1899 | break; | ||
| 1777 | case L2CAP_MODE_ERTM: | 1900 | case L2CAP_MODE_ERTM: |
| 1778 | case L2CAP_MODE_STREAMING: | 1901 | case L2CAP_MODE_STREAMING: |
| 1779 | if (!disable_ertm) | 1902 | if (!disable_ertm) |
| @@ -2432,6 +2555,89 @@ static int l2cap_segment_sdu(struct l2cap_chan *chan, | |||
| 2432 | return 0; | 2555 | return 0; |
| 2433 | } | 2556 | } |
| 2434 | 2557 | ||
| 2558 | static struct sk_buff *l2cap_create_le_flowctl_pdu(struct l2cap_chan *chan, | ||
| 2559 | struct msghdr *msg, | ||
| 2560 | size_t len, u16 sdulen) | ||
| 2561 | { | ||
| 2562 | struct l2cap_conn *conn = chan->conn; | ||
| 2563 | struct sk_buff *skb; | ||
| 2564 | int err, count, hlen; | ||
| 2565 | struct l2cap_hdr *lh; | ||
| 2566 | |||
| 2567 | BT_DBG("chan %p len %zu", chan, len); | ||
| 2568 | |||
| 2569 | if (!conn) | ||
| 2570 | return ERR_PTR(-ENOTCONN); | ||
| 2571 | |||
| 2572 | hlen = L2CAP_HDR_SIZE; | ||
| 2573 | |||
| 2574 | if (sdulen) | ||
| 2575 | hlen += L2CAP_SDULEN_SIZE; | ||
| 2576 | |||
| 2577 | count = min_t(unsigned int, (conn->mtu - hlen), len); | ||
| 2578 | |||
| 2579 | skb = chan->ops->alloc_skb(chan, count + hlen, | ||
| 2580 | msg->msg_flags & MSG_DONTWAIT); | ||
| 2581 | if (IS_ERR(skb)) | ||
| 2582 | return skb; | ||
| 2583 | |||
| 2584 | /* Create L2CAP header */ | ||
| 2585 | lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE); | ||
| 2586 | lh->cid = cpu_to_le16(chan->dcid); | ||
| 2587 | lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE)); | ||
| 2588 | |||
| 2589 | if (sdulen) | ||
| 2590 | put_unaligned_le16(sdulen, skb_put(skb, L2CAP_SDULEN_SIZE)); | ||
| 2591 | |||
| 2592 | err = l2cap_skbuff_fromiovec(chan, msg, len, count, skb); | ||
| 2593 | if (unlikely(err < 0)) { | ||
| 2594 | kfree_skb(skb); | ||
| 2595 | return ERR_PTR(err); | ||
| 2596 | } | ||
| 2597 | |||
| 2598 | return skb; | ||
| 2599 | } | ||
| 2600 | |||
| 2601 | static int l2cap_segment_le_sdu(struct l2cap_chan *chan, | ||
| 2602 | struct sk_buff_head *seg_queue, | ||
| 2603 | struct msghdr *msg, size_t len) | ||
| 2604 | { | ||
| 2605 | struct sk_buff *skb; | ||
| 2606 | size_t pdu_len; | ||
| 2607 | u16 sdu_len; | ||
| 2608 | |||
| 2609 | BT_DBG("chan %p, msg %p, len %zu", chan, msg, len); | ||
| 2610 | |||
| 2611 | pdu_len = chan->conn->mtu - L2CAP_HDR_SIZE; | ||
| 2612 | |||
| 2613 | pdu_len = min_t(size_t, pdu_len, chan->remote_mps); | ||
| 2614 | |||
| 2615 | sdu_len = len; | ||
| 2616 | pdu_len -= L2CAP_SDULEN_SIZE; | ||
| 2617 | |||
| 2618 | while (len > 0) { | ||
| 2619 | if (len <= pdu_len) | ||
| 2620 | pdu_len = len; | ||
| 2621 | |||
| 2622 | skb = l2cap_create_le_flowctl_pdu(chan, msg, pdu_len, sdu_len); | ||
| 2623 | if (IS_ERR(skb)) { | ||
| 2624 | __skb_queue_purge(seg_queue); | ||
| 2625 | return PTR_ERR(skb); | ||
| 2626 | } | ||
| 2627 | |||
| 2628 | __skb_queue_tail(seg_queue, skb); | ||
| 2629 | |||
| 2630 | len -= pdu_len; | ||
| 2631 | |||
| 2632 | if (sdu_len) { | ||
| 2633 | sdu_len = 0; | ||
| 2634 | pdu_len += L2CAP_SDULEN_SIZE; | ||
| 2635 | } | ||
| 2636 | } | ||
| 2637 | |||
| 2638 | return 0; | ||
| 2639 | } | ||
| 2640 | |||
| 2435 | int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len, | 2641 | int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len, |
| 2436 | u32 priority) | 2642 | u32 priority) |
| 2437 | { | 2643 | { |
| @@ -2453,6 +2659,40 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len, | |||
| 2453 | } | 2659 | } |
| 2454 | 2660 | ||
| 2455 | switch (chan->mode) { | 2661 | switch (chan->mode) { |
| 2662 | case L2CAP_MODE_LE_FLOWCTL: | ||
| 2663 | /* Check outgoing MTU */ | ||
| 2664 | if (len > chan->omtu) | ||
| 2665 | return -EMSGSIZE; | ||
| 2666 | |||
| 2667 | if (!chan->tx_credits) | ||
| 2668 | return -EAGAIN; | ||
| 2669 | |||
| 2670 | __skb_queue_head_init(&seg_queue); | ||
| 2671 | |||
| 2672 | err = l2cap_segment_le_sdu(chan, &seg_queue, msg, len); | ||
| 2673 | |||
| 2674 | if (chan->state != BT_CONNECTED) { | ||
| 2675 | __skb_queue_purge(&seg_queue); | ||
| 2676 | err = -ENOTCONN; | ||
| 2677 | } | ||
| 2678 | |||
| 2679 | if (err) | ||
| 2680 | return err; | ||
| 2681 | |||
| 2682 | skb_queue_splice_tail_init(&seg_queue, &chan->tx_q); | ||
| 2683 | |||
| 2684 | while (chan->tx_credits && !skb_queue_empty(&chan->tx_q)) { | ||
| 2685 | l2cap_do_send(chan, skb_dequeue(&chan->tx_q)); | ||
| 2686 | chan->tx_credits--; | ||
| 2687 | } | ||
| 2688 | |||
| 2689 | if (!chan->tx_credits) | ||
| 2690 | chan->ops->suspend(chan); | ||
| 2691 | |||
| 2692 | err = len; | ||
| 2693 | |||
| 2694 | break; | ||
| 2695 | |||
| 2456 | case L2CAP_MODE_BASIC: | 2696 | case L2CAP_MODE_BASIC: |
| 2457 | /* Check outgoing MTU */ | 2697 | /* Check outgoing MTU */ |
| 2458 | if (len > chan->omtu) | 2698 | if (len > chan->omtu) |
| @@ -3592,6 +3832,23 @@ static int l2cap_build_conf_rsp(struct l2cap_chan *chan, void *data, | |||
| 3592 | return ptr - data; | 3832 | return ptr - data; |
| 3593 | } | 3833 | } |
| 3594 | 3834 | ||
| 3835 | void __l2cap_le_connect_rsp_defer(struct l2cap_chan *chan) | ||
| 3836 | { | ||
| 3837 | struct l2cap_le_conn_rsp rsp; | ||
| 3838 | struct l2cap_conn *conn = chan->conn; | ||
| 3839 | |||
| 3840 | BT_DBG("chan %p", chan); | ||
| 3841 | |||
| 3842 | rsp.dcid = cpu_to_le16(chan->scid); | ||
| 3843 | rsp.mtu = cpu_to_le16(chan->imtu); | ||
| 3844 | rsp.mps = cpu_to_le16(chan->mps); | ||
| 3845 | rsp.credits = cpu_to_le16(chan->rx_credits); | ||
| 3846 | rsp.result = __constant_cpu_to_le16(L2CAP_CR_SUCCESS); | ||
| 3847 | |||
| 3848 | l2cap_send_cmd(conn, chan->ident, L2CAP_LE_CONN_RSP, sizeof(rsp), | ||
| 3849 | &rsp); | ||
| 3850 | } | ||
| 3851 | |||
| 3595 | void __l2cap_connect_rsp_defer(struct l2cap_chan *chan) | 3852 | void __l2cap_connect_rsp_defer(struct l2cap_chan *chan) |
| 3596 | { | 3853 | { |
| 3597 | struct l2cap_conn_rsp rsp; | 3854 | struct l2cap_conn_rsp rsp; |
| @@ -3713,7 +3970,7 @@ static struct l2cap_chan *l2cap_connect(struct l2cap_conn *conn, | |||
| 3713 | 3970 | ||
| 3714 | /* Check if we have socket listening on psm */ | 3971 | /* Check if we have socket listening on psm */ |
| 3715 | pchan = l2cap_global_chan_by_psm(BT_LISTEN, psm, &conn->hcon->src, | 3972 | pchan = l2cap_global_chan_by_psm(BT_LISTEN, psm, &conn->hcon->src, |
| 3716 | &conn->hcon->dst); | 3973 | &conn->hcon->dst, ACL_LINK); |
| 3717 | if (!pchan) { | 3974 | if (!pchan) { |
| 3718 | result = L2CAP_CR_BAD_PSM; | 3975 | result = L2CAP_CR_BAD_PSM; |
| 3719 | goto sendresp; | 3976 | goto sendresp; |
| @@ -5155,18 +5412,17 @@ static inline int l2cap_check_conn_param(u16 min, u16 max, u16 latency, | |||
| 5155 | 5412 | ||
| 5156 | static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn, | 5413 | static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn, |
| 5157 | struct l2cap_cmd_hdr *cmd, | 5414 | struct l2cap_cmd_hdr *cmd, |
| 5158 | u8 *data) | 5415 | u16 cmd_len, u8 *data) |
| 5159 | { | 5416 | { |
| 5160 | struct hci_conn *hcon = conn->hcon; | 5417 | struct hci_conn *hcon = conn->hcon; |
| 5161 | struct l2cap_conn_param_update_req *req; | 5418 | struct l2cap_conn_param_update_req *req; |
| 5162 | struct l2cap_conn_param_update_rsp rsp; | 5419 | struct l2cap_conn_param_update_rsp rsp; |
| 5163 | u16 min, max, latency, to_multiplier, cmd_len; | 5420 | u16 min, max, latency, to_multiplier; |
| 5164 | int err; | 5421 | int err; |
| 5165 | 5422 | ||
| 5166 | if (!(hcon->link_mode & HCI_LM_MASTER)) | 5423 | if (!(hcon->link_mode & HCI_LM_MASTER)) |
| 5167 | return -EINVAL; | 5424 | return -EINVAL; |
| 5168 | 5425 | ||
| 5169 | cmd_len = __le16_to_cpu(cmd->len); | ||
| 5170 | if (cmd_len != sizeof(struct l2cap_conn_param_update_req)) | 5426 | if (cmd_len != sizeof(struct l2cap_conn_param_update_req)) |
| 5171 | return -EPROTO; | 5427 | return -EPROTO; |
| 5172 | 5428 | ||
| @@ -5196,6 +5452,65 @@ static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn, | |||
| 5196 | return 0; | 5452 | return 0; |
| 5197 | } | 5453 | } |
| 5198 | 5454 | ||
| 5455 | static int l2cap_le_connect_rsp(struct l2cap_conn *conn, | ||
| 5456 | struct l2cap_cmd_hdr *cmd, u16 cmd_len, | ||
| 5457 | u8 *data) | ||
| 5458 | { | ||
| 5459 | struct l2cap_le_conn_rsp *rsp = (struct l2cap_le_conn_rsp *) data; | ||
| 5460 | u16 dcid, mtu, mps, credits, result; | ||
| 5461 | struct l2cap_chan *chan; | ||
| 5462 | int err; | ||
| 5463 | |||
| 5464 | if (cmd_len < sizeof(*rsp)) | ||
| 5465 | return -EPROTO; | ||
| 5466 | |||
| 5467 | dcid = __le16_to_cpu(rsp->dcid); | ||
| 5468 | mtu = __le16_to_cpu(rsp->mtu); | ||
| 5469 | mps = __le16_to_cpu(rsp->mps); | ||
| 5470 | credits = __le16_to_cpu(rsp->credits); | ||
| 5471 | result = __le16_to_cpu(rsp->result); | ||
| 5472 | |||
| 5473 | if (result == L2CAP_CR_SUCCESS && (mtu < 23 || mps < 23)) | ||
| 5474 | return -EPROTO; | ||
| 5475 | |||
| 5476 | BT_DBG("dcid 0x%4.4x mtu %u mps %u credits %u result 0x%2.2x", | ||
| 5477 | dcid, mtu, mps, credits, result); | ||
| 5478 | |||
| 5479 | mutex_lock(&conn->chan_lock); | ||
| 5480 | |||
| 5481 | chan = __l2cap_get_chan_by_ident(conn, cmd->ident); | ||
| 5482 | if (!chan) { | ||
| 5483 | err = -EBADSLT; | ||
| 5484 | goto unlock; | ||
| 5485 | } | ||
| 5486 | |||
| 5487 | err = 0; | ||
| 5488 | |||
| 5489 | l2cap_chan_lock(chan); | ||
| 5490 | |||
| 5491 | switch (result) { | ||
| 5492 | case L2CAP_CR_SUCCESS: | ||
| 5493 | chan->ident = 0; | ||
| 5494 | chan->dcid = dcid; | ||
| 5495 | chan->omtu = mtu; | ||
| 5496 | chan->remote_mps = mps; | ||
| 5497 | chan->tx_credits = credits; | ||
| 5498 | l2cap_chan_ready(chan); | ||
| 5499 | break; | ||
| 5500 | |||
| 5501 | default: | ||
| 5502 | l2cap_chan_del(chan, ECONNREFUSED); | ||
| 5503 | break; | ||
| 5504 | } | ||
| 5505 | |||
| 5506 | l2cap_chan_unlock(chan); | ||
| 5507 | |||
| 5508 | unlock: | ||
| 5509 | mutex_unlock(&conn->chan_lock); | ||
| 5510 | |||
| 5511 | return err; | ||
| 5512 | } | ||
| 5513 | |||
| 5199 | static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn, | 5514 | static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn, |
| 5200 | struct l2cap_cmd_hdr *cmd, u16 cmd_len, | 5515 | struct l2cap_cmd_hdr *cmd, u16 cmd_len, |
| 5201 | u8 *data) | 5516 | u8 *data) |
| @@ -5276,23 +5591,235 @@ static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn, | |||
| 5276 | return err; | 5591 | return err; |
| 5277 | } | 5592 | } |
| 5278 | 5593 | ||
| 5594 | static int l2cap_le_connect_req(struct l2cap_conn *conn, | ||
| 5595 | struct l2cap_cmd_hdr *cmd, u16 cmd_len, | ||
| 5596 | u8 *data) | ||
| 5597 | { | ||
| 5598 | struct l2cap_le_conn_req *req = (struct l2cap_le_conn_req *) data; | ||
| 5599 | struct l2cap_le_conn_rsp rsp; | ||
| 5600 | struct l2cap_chan *chan, *pchan; | ||
| 5601 | u16 dcid, scid, credits, mtu, mps; | ||
| 5602 | __le16 psm; | ||
| 5603 | u8 result; | ||
| 5604 | |||
| 5605 | if (cmd_len != sizeof(*req)) | ||
| 5606 | return -EPROTO; | ||
| 5607 | |||
| 5608 | scid = __le16_to_cpu(req->scid); | ||
| 5609 | mtu = __le16_to_cpu(req->mtu); | ||
| 5610 | mps = __le16_to_cpu(req->mps); | ||
| 5611 | psm = req->psm; | ||
| 5612 | dcid = 0; | ||
| 5613 | credits = 0; | ||
| 5614 | |||
| 5615 | if (mtu < 23 || mps < 23) | ||
| 5616 | return -EPROTO; | ||
| 5617 | |||
| 5618 | BT_DBG("psm 0x%2.2x scid 0x%4.4x mtu %u mps %u", __le16_to_cpu(psm), | ||
| 5619 | scid, mtu, mps); | ||
| 5620 | |||
| 5621 | /* Check if we have socket listening on psm */ | ||
| 5622 | pchan = l2cap_global_chan_by_psm(BT_LISTEN, psm, &conn->hcon->src, | ||
| 5623 | &conn->hcon->dst, LE_LINK); | ||
| 5624 | if (!pchan) { | ||
| 5625 | result = L2CAP_CR_BAD_PSM; | ||
| 5626 | chan = NULL; | ||
| 5627 | goto response; | ||
| 5628 | } | ||
| 5629 | |||
| 5630 | mutex_lock(&conn->chan_lock); | ||
| 5631 | l2cap_chan_lock(pchan); | ||
| 5632 | |||
| 5633 | if (!smp_sufficient_security(conn->hcon, pchan->sec_level)) { | ||
| 5634 | result = L2CAP_CR_AUTHENTICATION; | ||
| 5635 | chan = NULL; | ||
| 5636 | goto response_unlock; | ||
| 5637 | } | ||
| 5638 | |||
| 5639 | /* Check if we already have channel with that dcid */ | ||
| 5640 | if (__l2cap_get_chan_by_dcid(conn, scid)) { | ||
| 5641 | result = L2CAP_CR_NO_MEM; | ||
| 5642 | chan = NULL; | ||
| 5643 | goto response_unlock; | ||
| 5644 | } | ||
| 5645 | |||
| 5646 | chan = pchan->ops->new_connection(pchan); | ||
| 5647 | if (!chan) { | ||
| 5648 | result = L2CAP_CR_NO_MEM; | ||
| 5649 | goto response_unlock; | ||
| 5650 | } | ||
| 5651 | |||
| 5652 | l2cap_le_flowctl_init(chan); | ||
| 5653 | |||
| 5654 | bacpy(&chan->src, &conn->hcon->src); | ||
| 5655 | bacpy(&chan->dst, &conn->hcon->dst); | ||
| 5656 | chan->src_type = bdaddr_type(conn->hcon, conn->hcon->src_type); | ||
| 5657 | chan->dst_type = bdaddr_type(conn->hcon, conn->hcon->dst_type); | ||
| 5658 | chan->psm = psm; | ||
| 5659 | chan->dcid = scid; | ||
| 5660 | chan->omtu = mtu; | ||
| 5661 | chan->remote_mps = mps; | ||
| 5662 | chan->tx_credits = __le16_to_cpu(req->credits); | ||
| 5663 | |||
| 5664 | __l2cap_chan_add(conn, chan); | ||
| 5665 | dcid = chan->scid; | ||
| 5666 | credits = chan->rx_credits; | ||
| 5667 | |||
| 5668 | __set_chan_timer(chan, chan->ops->get_sndtimeo(chan)); | ||
| 5669 | |||
| 5670 | chan->ident = cmd->ident; | ||
| 5671 | |||
| 5672 | if (test_bit(FLAG_DEFER_SETUP, &chan->flags)) { | ||
| 5673 | l2cap_state_change(chan, BT_CONNECT2); | ||
| 5674 | result = L2CAP_CR_PEND; | ||
| 5675 | chan->ops->defer(chan); | ||
| 5676 | } else { | ||
| 5677 | l2cap_chan_ready(chan); | ||
| 5678 | result = L2CAP_CR_SUCCESS; | ||
| 5679 | } | ||
| 5680 | |||
| 5681 | response_unlock: | ||
| 5682 | l2cap_chan_unlock(pchan); | ||
| 5683 | mutex_unlock(&conn->chan_lock); | ||
| 5684 | |||
| 5685 | if (result == L2CAP_CR_PEND) | ||
| 5686 | return 0; | ||
| 5687 | |||
| 5688 | response: | ||
| 5689 | if (chan) { | ||
| 5690 | rsp.mtu = cpu_to_le16(chan->imtu); | ||
| 5691 | rsp.mps = cpu_to_le16(chan->mps); | ||
| 5692 | } else { | ||
| 5693 | rsp.mtu = 0; | ||
| 5694 | rsp.mps = 0; | ||
| 5695 | } | ||
| 5696 | |||
| 5697 | rsp.dcid = cpu_to_le16(dcid); | ||
| 5698 | rsp.credits = cpu_to_le16(credits); | ||
| 5699 | rsp.result = cpu_to_le16(result); | ||
| 5700 | |||
| 5701 | l2cap_send_cmd(conn, cmd->ident, L2CAP_LE_CONN_RSP, sizeof(rsp), &rsp); | ||
| 5702 | |||
| 5703 | return 0; | ||
| 5704 | } | ||
| 5705 | |||
| 5706 | static inline int l2cap_le_credits(struct l2cap_conn *conn, | ||
| 5707 | struct l2cap_cmd_hdr *cmd, u16 cmd_len, | ||
| 5708 | u8 *data) | ||
| 5709 | { | ||
| 5710 | struct l2cap_le_credits *pkt; | ||
| 5711 | struct l2cap_chan *chan; | ||
| 5712 | u16 cid, credits; | ||
| 5713 | |||
| 5714 | if (cmd_len != sizeof(*pkt)) | ||
| 5715 | return -EPROTO; | ||
| 5716 | |||
| 5717 | pkt = (struct l2cap_le_credits *) data; | ||
| 5718 | cid = __le16_to_cpu(pkt->cid); | ||
| 5719 | credits = __le16_to_cpu(pkt->credits); | ||
| 5720 | |||
| 5721 | BT_DBG("cid 0x%4.4x credits 0x%4.4x", cid, credits); | ||
| 5722 | |||
| 5723 | chan = l2cap_get_chan_by_dcid(conn, cid); | ||
| 5724 | if (!chan) | ||
| 5725 | return -EBADSLT; | ||
| 5726 | |||
| 5727 | chan->tx_credits += credits; | ||
| 5728 | |||
| 5729 | while (chan->tx_credits && !skb_queue_empty(&chan->tx_q)) { | ||
| 5730 | l2cap_do_send(chan, skb_dequeue(&chan->tx_q)); | ||
| 5731 | chan->tx_credits--; | ||
| 5732 | } | ||
| 5733 | |||
| 5734 | if (chan->tx_credits) | ||
| 5735 | chan->ops->resume(chan); | ||
| 5736 | |||
| 5737 | l2cap_chan_unlock(chan); | ||
| 5738 | |||
| 5739 | return 0; | ||
| 5740 | } | ||
| 5741 | |||
| 5742 | static inline int l2cap_le_command_rej(struct l2cap_conn *conn, | ||
| 5743 | struct l2cap_cmd_hdr *cmd, u16 cmd_len, | ||
| 5744 | u8 *data) | ||
| 5745 | { | ||
| 5746 | struct l2cap_cmd_rej_unk *rej = (struct l2cap_cmd_rej_unk *) data; | ||
| 5747 | struct l2cap_chan *chan; | ||
| 5748 | |||
| 5749 | if (cmd_len < sizeof(*rej)) | ||
| 5750 | return -EPROTO; | ||
| 5751 | |||
| 5752 | mutex_lock(&conn->chan_lock); | ||
| 5753 | |||
| 5754 | chan = __l2cap_get_chan_by_ident(conn, cmd->ident); | ||
| 5755 | if (!chan) | ||
| 5756 | goto done; | ||
| 5757 | |||
| 5758 | l2cap_chan_lock(chan); | ||
| 5759 | l2cap_chan_del(chan, ECONNREFUSED); | ||
| 5760 | l2cap_chan_unlock(chan); | ||
| 5761 | |||
| 5762 | done: | ||
| 5763 | mutex_unlock(&conn->chan_lock); | ||
| 5764 | return 0; | ||
| 5765 | } | ||
| 5766 | |||
| 5279 | static inline int l2cap_le_sig_cmd(struct l2cap_conn *conn, | 5767 | static inline int l2cap_le_sig_cmd(struct l2cap_conn *conn, |
| 5280 | struct l2cap_cmd_hdr *cmd, u8 *data) | 5768 | struct l2cap_cmd_hdr *cmd, u16 cmd_len, |
| 5769 | u8 *data) | ||
| 5281 | { | 5770 | { |
| 5771 | int err = 0; | ||
| 5772 | |||
| 5773 | if (!enable_lecoc) { | ||
| 5774 | switch (cmd->code) { | ||
| 5775 | case L2CAP_LE_CONN_REQ: | ||
| 5776 | case L2CAP_LE_CONN_RSP: | ||
| 5777 | case L2CAP_LE_CREDITS: | ||
| 5778 | case L2CAP_DISCONN_REQ: | ||
| 5779 | case L2CAP_DISCONN_RSP: | ||
| 5780 | return -EINVAL; | ||
| 5781 | } | ||
| 5782 | } | ||
| 5783 | |||
| 5282 | switch (cmd->code) { | 5784 | switch (cmd->code) { |
| 5283 | case L2CAP_COMMAND_REJ: | 5785 | case L2CAP_COMMAND_REJ: |
| 5284 | return 0; | 5786 | l2cap_le_command_rej(conn, cmd, cmd_len, data); |
| 5787 | break; | ||
| 5285 | 5788 | ||
| 5286 | case L2CAP_CONN_PARAM_UPDATE_REQ: | 5789 | case L2CAP_CONN_PARAM_UPDATE_REQ: |
| 5287 | return l2cap_conn_param_update_req(conn, cmd, data); | 5790 | err = l2cap_conn_param_update_req(conn, cmd, cmd_len, data); |
| 5791 | break; | ||
| 5288 | 5792 | ||
| 5289 | case L2CAP_CONN_PARAM_UPDATE_RSP: | 5793 | case L2CAP_CONN_PARAM_UPDATE_RSP: |
| 5290 | return 0; | 5794 | break; |
| 5795 | |||
| 5796 | case L2CAP_LE_CONN_RSP: | ||
| 5797 | l2cap_le_connect_rsp(conn, cmd, cmd_len, data); | ||
| 5798 | break; | ||
| 5799 | |||
| 5800 | case L2CAP_LE_CONN_REQ: | ||
| 5801 | err = l2cap_le_connect_req(conn, cmd, cmd_len, data); | ||
| 5802 | break; | ||
| 5803 | |||
| 5804 | case L2CAP_LE_CREDITS: | ||
| 5805 | err = l2cap_le_credits(conn, cmd, cmd_len, data); | ||
| 5806 | break; | ||
| 5807 | |||
| 5808 | case L2CAP_DISCONN_REQ: | ||
| 5809 | err = l2cap_disconnect_req(conn, cmd, cmd_len, data); | ||
| 5810 | break; | ||
| 5811 | |||
| 5812 | case L2CAP_DISCONN_RSP: | ||
| 5813 | l2cap_disconnect_rsp(conn, cmd, cmd_len, data); | ||
| 5814 | break; | ||
| 5291 | 5815 | ||
| 5292 | default: | 5816 | default: |
| 5293 | BT_ERR("Unknown LE signaling command 0x%2.2x", cmd->code); | 5817 | BT_ERR("Unknown LE signaling command 0x%2.2x", cmd->code); |
| 5294 | return -EINVAL; | 5818 | err = -EINVAL; |
| 5819 | break; | ||
| 5295 | } | 5820 | } |
| 5821 | |||
| 5822 | return err; | ||
| 5296 | } | 5823 | } |
| 5297 | 5824 | ||
| 5298 | static inline void l2cap_le_sig_channel(struct l2cap_conn *conn, | 5825 | static inline void l2cap_le_sig_channel(struct l2cap_conn *conn, |
| @@ -5321,7 +5848,7 @@ static inline void l2cap_le_sig_channel(struct l2cap_conn *conn, | |||
| 5321 | goto drop; | 5848 | goto drop; |
| 5322 | } | 5849 | } |
| 5323 | 5850 | ||
| 5324 | err = l2cap_le_sig_cmd(conn, cmd, skb->data); | 5851 | err = l2cap_le_sig_cmd(conn, cmd, len, skb->data); |
| 5325 | if (err) { | 5852 | if (err) { |
| 5326 | struct l2cap_cmd_rej_unk rej; | 5853 | struct l2cap_cmd_rej_unk rej; |
| 5327 | 5854 | ||
| @@ -6312,6 +6839,121 @@ drop: | |||
| 6312 | return 0; | 6839 | return 0; |
| 6313 | } | 6840 | } |
| 6314 | 6841 | ||
| 6842 | static void l2cap_chan_le_send_credits(struct l2cap_chan *chan) | ||
| 6843 | { | ||
| 6844 | struct l2cap_conn *conn = chan->conn; | ||
| 6845 | struct l2cap_le_credits pkt; | ||
| 6846 | u16 return_credits; | ||
| 6847 | |||
| 6848 | /* We return more credits to the sender only after the amount of | ||
| 6849 | * credits falls below half of the initial amount. | ||
| 6850 | */ | ||
| 6851 | if (chan->rx_credits >= (le_max_credits + 1) / 2) | ||
| 6852 | return; | ||
| 6853 | |||
| 6854 | return_credits = le_max_credits - chan->rx_credits; | ||
| 6855 | |||
| 6856 | BT_DBG("chan %p returning %u credits to sender", chan, return_credits); | ||
| 6857 | |||
| 6858 | chan->rx_credits += return_credits; | ||
| 6859 | |||
| 6860 | pkt.cid = cpu_to_le16(chan->scid); | ||
| 6861 | pkt.credits = cpu_to_le16(return_credits); | ||
| 6862 | |||
| 6863 | chan->ident = l2cap_get_ident(conn); | ||
| 6864 | |||
| 6865 | l2cap_send_cmd(conn, chan->ident, L2CAP_LE_CREDITS, sizeof(pkt), &pkt); | ||
| 6866 | } | ||
| 6867 | |||
| 6868 | static int l2cap_le_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb) | ||
| 6869 | { | ||
| 6870 | int err; | ||
| 6871 | |||
| 6872 | if (!chan->rx_credits) { | ||
| 6873 | BT_ERR("No credits to receive LE L2CAP data"); | ||
| 6874 | return -ENOBUFS; | ||
| 6875 | } | ||
| 6876 | |||
| 6877 | if (chan->imtu < skb->len) { | ||
| 6878 | BT_ERR("Too big LE L2CAP PDU"); | ||
| 6879 | return -ENOBUFS; | ||
| 6880 | } | ||
| 6881 | |||
| 6882 | chan->rx_credits--; | ||
| 6883 | BT_DBG("rx_credits %u -> %u", chan->rx_credits + 1, chan->rx_credits); | ||
| 6884 | |||
| 6885 | l2cap_chan_le_send_credits(chan); | ||
| 6886 | |||
| 6887 | err = 0; | ||
| 6888 | |||
| 6889 | if (!chan->sdu) { | ||
| 6890 | u16 sdu_len; | ||
| 6891 | |||
| 6892 | sdu_len = get_unaligned_le16(skb->data); | ||
| 6893 | skb_pull(skb, L2CAP_SDULEN_SIZE); | ||
| 6894 | |||
| 6895 | BT_DBG("Start of new SDU. sdu_len %u skb->len %u imtu %u", | ||
| 6896 | sdu_len, skb->len, chan->imtu); | ||
| 6897 | |||
| 6898 | if (sdu_len > chan->imtu) { | ||
| 6899 | BT_ERR("Too big LE L2CAP SDU length received"); | ||
| 6900 | err = -EMSGSIZE; | ||
| 6901 | goto failed; | ||
| 6902 | } | ||
| 6903 | |||
| 6904 | if (skb->len > sdu_len) { | ||
| 6905 | BT_ERR("Too much LE L2CAP data received"); | ||
| 6906 | err = -EINVAL; | ||
| 6907 | goto failed; | ||
| 6908 | } | ||
| 6909 | |||
| 6910 | if (skb->len == sdu_len) | ||
| 6911 | return chan->ops->recv(chan, skb); | ||
| 6912 | |||
| 6913 | chan->sdu = skb; | ||
| 6914 | chan->sdu_len = sdu_len; | ||
| 6915 | chan->sdu_last_frag = skb; | ||
| 6916 | |||
| 6917 | return 0; | ||
| 6918 | } | ||
| 6919 | |||
| 6920 | BT_DBG("SDU fragment. chan->sdu->len %u skb->len %u chan->sdu_len %u", | ||
| 6921 | chan->sdu->len, skb->len, chan->sdu_len); | ||
| 6922 | |||
| 6923 | if (chan->sdu->len + skb->len > chan->sdu_len) { | ||
| 6924 | BT_ERR("Too much LE L2CAP data received"); | ||
| 6925 | err = -EINVAL; | ||
| 6926 | goto failed; | ||
| 6927 | } | ||
| 6928 | |||
| 6929 | append_skb_frag(chan->sdu, skb, &chan->sdu_last_frag); | ||
| 6930 | skb = NULL; | ||
| 6931 | |||
| 6932 | if (chan->sdu->len == chan->sdu_len) { | ||
| 6933 | err = chan->ops->recv(chan, chan->sdu); | ||
| 6934 | if (!err) { | ||
| 6935 | chan->sdu = NULL; | ||
| 6936 | chan->sdu_last_frag = NULL; | ||
| 6937 | chan->sdu_len = 0; | ||
| 6938 | } | ||
| 6939 | } | ||
| 6940 | |||
| 6941 | failed: | ||
| 6942 | if (err) { | ||
| 6943 | kfree_skb(skb); | ||
| 6944 | kfree_skb(chan->sdu); | ||
| 6945 | chan->sdu = NULL; | ||
| 6946 | chan->sdu_last_frag = NULL; | ||
| 6947 | chan->sdu_len = 0; | ||
| 6948 | } | ||
| 6949 | |||
| 6950 | /* We can't return an error here since we took care of the skb | ||
| 6951 | * freeing internally. An error return would cause the caller to | ||
| 6952 | * do a double-free of the skb. | ||
| 6953 | */ | ||
| 6954 | return 0; | ||
| 6955 | } | ||
| 6956 | |||
| 6315 | static void l2cap_data_channel(struct l2cap_conn *conn, u16 cid, | 6957 | static void l2cap_data_channel(struct l2cap_conn *conn, u16 cid, |
| 6316 | struct sk_buff *skb) | 6958 | struct sk_buff *skb) |
| 6317 | { | 6959 | { |
| @@ -6341,6 +6983,12 @@ static void l2cap_data_channel(struct l2cap_conn *conn, u16 cid, | |||
| 6341 | goto drop; | 6983 | goto drop; |
| 6342 | 6984 | ||
| 6343 | switch (chan->mode) { | 6985 | switch (chan->mode) { |
| 6986 | case L2CAP_MODE_LE_FLOWCTL: | ||
| 6987 | if (l2cap_le_data_rcv(chan, skb) < 0) | ||
| 6988 | goto drop; | ||
| 6989 | |||
| 6990 | goto done; | ||
| 6991 | |||
| 6344 | case L2CAP_MODE_BASIC: | 6992 | case L2CAP_MODE_BASIC: |
| 6345 | /* If socket recv buffers overflows we drop data here | 6993 | /* If socket recv buffers overflows we drop data here |
| 6346 | * which is *bad* because L2CAP has to be reliable. | 6994 | * which is *bad* because L2CAP has to be reliable. |
| @@ -6380,7 +7028,8 @@ static void l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, | |||
| 6380 | if (hcon->type != ACL_LINK) | 7028 | if (hcon->type != ACL_LINK) |
| 6381 | goto drop; | 7029 | goto drop; |
| 6382 | 7030 | ||
| 6383 | chan = l2cap_global_chan_by_psm(0, psm, &hcon->src, &hcon->dst); | 7031 | chan = l2cap_global_chan_by_psm(0, psm, &hcon->src, &hcon->dst, |
| 7032 | ACL_LINK); | ||
| 6384 | if (!chan) | 7033 | if (!chan) |
| 6385 | goto drop; | 7034 | goto drop; |
| 6386 | 7035 | ||
| @@ -6473,6 +7122,10 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb) | |||
| 6473 | l2cap_conn_del(conn->hcon, EACCES); | 7122 | l2cap_conn_del(conn->hcon, EACCES); |
| 6474 | break; | 7123 | break; |
| 6475 | 7124 | ||
| 7125 | case L2CAP_FC_6LOWPAN: | ||
| 7126 | bt_6lowpan_recv(conn, skb); | ||
| 7127 | break; | ||
| 7128 | |||
| 6476 | default: | 7129 | default: |
| 6477 | l2cap_data_channel(conn, cid, skb); | 7130 | l2cap_data_channel(conn, cid, skb); |
| 6478 | break; | 7131 | break; |
| @@ -6540,6 +7193,8 @@ void l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason) | |||
| 6540 | { | 7193 | { |
| 6541 | BT_DBG("hcon %p reason %d", hcon, reason); | 7194 | BT_DBG("hcon %p reason %d", hcon, reason); |
| 6542 | 7195 | ||
| 7196 | bt_6lowpan_del_conn(hcon->l2cap_data); | ||
| 7197 | |||
| 6543 | l2cap_conn_del(hcon, bt_to_errno(reason)); | 7198 | l2cap_conn_del(hcon, bt_to_errno(reason)); |
| 6544 | } | 7199 | } |
| 6545 | 7200 | ||
| @@ -6612,11 +7267,10 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) | |||
| 6612 | } | 7267 | } |
| 6613 | 7268 | ||
| 6614 | if (chan->state == BT_CONNECT) { | 7269 | if (chan->state == BT_CONNECT) { |
| 6615 | if (!status) { | 7270 | if (!status) |
| 6616 | l2cap_start_connection(chan); | 7271 | l2cap_start_connection(chan); |
| 6617 | } else { | 7272 | else |
| 6618 | __set_chan_timer(chan, L2CAP_DISC_TIMEOUT); | 7273 | __set_chan_timer(chan, L2CAP_DISC_TIMEOUT); |
| 6619 | } | ||
| 6620 | } else if (chan->state == BT_CONNECT2) { | 7274 | } else if (chan->state == BT_CONNECT2) { |
| 6621 | struct l2cap_conn_rsp rsp; | 7275 | struct l2cap_conn_rsp rsp; |
| 6622 | __u16 res, stat; | 7276 | __u16 res, stat; |
| @@ -6817,11 +7471,19 @@ int __init l2cap_init(void) | |||
| 6817 | l2cap_debugfs = debugfs_create_file("l2cap", 0444, bt_debugfs, | 7471 | l2cap_debugfs = debugfs_create_file("l2cap", 0444, bt_debugfs, |
| 6818 | NULL, &l2cap_debugfs_fops); | 7472 | NULL, &l2cap_debugfs_fops); |
| 6819 | 7473 | ||
| 7474 | debugfs_create_u16("l2cap_le_max_credits", 0466, bt_debugfs, | ||
| 7475 | &le_max_credits); | ||
| 7476 | debugfs_create_u16("l2cap_le_default_mps", 0466, bt_debugfs, | ||
| 7477 | &le_default_mps); | ||
| 7478 | |||
| 7479 | bt_6lowpan_init(); | ||
| 7480 | |||
| 6820 | return 0; | 7481 | return 0; |
| 6821 | } | 7482 | } |
| 6822 | 7483 | ||
| 6823 | void l2cap_exit(void) | 7484 | void l2cap_exit(void) |
| 6824 | { | 7485 | { |
| 7486 | bt_6lowpan_cleanup(); | ||
| 6825 | debugfs_remove(l2cap_debugfs); | 7487 | debugfs_remove(l2cap_debugfs); |
| 6826 | l2cap_cleanup_sockets(); | 7488 | l2cap_cleanup_sockets(); |
| 6827 | } | 7489 | } |
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 7cc24d263caa..d58f76bcebd1 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c | |||
| @@ -27,6 +27,7 @@ | |||
| 27 | 27 | ||
| 28 | /* Bluetooth L2CAP sockets. */ | 28 | /* Bluetooth L2CAP sockets. */ |
| 29 | 29 | ||
| 30 | #include <linux/module.h> | ||
| 30 | #include <linux/export.h> | 31 | #include <linux/export.h> |
| 31 | 32 | ||
| 32 | #include <net/bluetooth/bluetooth.h> | 33 | #include <net/bluetooth/bluetooth.h> |
| @@ -35,6 +36,8 @@ | |||
| 35 | 36 | ||
| 36 | #include "smp.h" | 37 | #include "smp.h" |
| 37 | 38 | ||
| 39 | bool enable_lecoc; | ||
| 40 | |||
| 38 | static struct bt_sock_list l2cap_sk_list = { | 41 | static struct bt_sock_list l2cap_sk_list = { |
| 39 | .lock = __RW_LOCK_UNLOCKED(l2cap_sk_list.lock) | 42 | .lock = __RW_LOCK_UNLOCKED(l2cap_sk_list.lock) |
| 40 | }; | 43 | }; |
| @@ -50,6 +53,32 @@ bool l2cap_is_socket(struct socket *sock) | |||
| 50 | } | 53 | } |
| 51 | EXPORT_SYMBOL(l2cap_is_socket); | 54 | EXPORT_SYMBOL(l2cap_is_socket); |
| 52 | 55 | ||
| 56 | static int l2cap_validate_bredr_psm(u16 psm) | ||
| 57 | { | ||
| 58 | /* PSM must be odd and lsb of upper byte must be 0 */ | ||
| 59 | if ((psm & 0x0101) != 0x0001) | ||
| 60 | return -EINVAL; | ||
| 61 | |||
| 62 | /* Restrict usage of well-known PSMs */ | ||
| 63 | if (psm < 0x1001 && !capable(CAP_NET_BIND_SERVICE)) | ||
| 64 | return -EACCES; | ||
| 65 | |||
| 66 | return 0; | ||
| 67 | } | ||
| 68 | |||
| 69 | static int l2cap_validate_le_psm(u16 psm) | ||
| 70 | { | ||
| 71 | /* Valid LE_PSM ranges are defined only until 0x00ff */ | ||
| 72 | if (psm > 0x00ff) | ||
| 73 | return -EINVAL; | ||
| 74 | |||
| 75 | /* Restrict fixed, SIG assigned PSM values to CAP_NET_BIND_SERVICE */ | ||
| 76 | if (psm <= 0x007f && !capable(CAP_NET_BIND_SERVICE)) | ||
| 77 | return -EACCES; | ||
| 78 | |||
| 79 | return 0; | ||
| 80 | } | ||
| 81 | |||
| 53 | static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) | 82 | static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) |
| 54 | { | 83 | { |
| 55 | struct sock *sk = sock->sk; | 84 | struct sock *sk = sock->sk; |
| @@ -73,11 +102,11 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) | |||
| 73 | return -EINVAL; | 102 | return -EINVAL; |
| 74 | 103 | ||
| 75 | if (bdaddr_type_is_le(la.l2_bdaddr_type)) { | 104 | if (bdaddr_type_is_le(la.l2_bdaddr_type)) { |
| 76 | /* Connection oriented channels are not supported on LE */ | 105 | if (!enable_lecoc && la.l2_psm) |
| 77 | if (la.l2_psm) | ||
| 78 | return -EINVAL; | 106 | return -EINVAL; |
| 79 | /* We only allow ATT user space socket */ | 107 | /* We only allow ATT user space socket */ |
| 80 | if (la.l2_cid != __constant_cpu_to_le16(L2CAP_CID_ATT)) | 108 | if (la.l2_cid && |
| 109 | la.l2_cid != __constant_cpu_to_le16(L2CAP_CID_ATT)) | ||
| 81 | return -EINVAL; | 110 | return -EINVAL; |
| 82 | } | 111 | } |
| 83 | 112 | ||
| @@ -91,17 +120,13 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) | |||
| 91 | if (la.l2_psm) { | 120 | if (la.l2_psm) { |
| 92 | __u16 psm = __le16_to_cpu(la.l2_psm); | 121 | __u16 psm = __le16_to_cpu(la.l2_psm); |
| 93 | 122 | ||
| 94 | /* PSM must be odd and lsb of upper byte must be 0 */ | 123 | if (la.l2_bdaddr_type == BDADDR_BREDR) |
| 95 | if ((psm & 0x0101) != 0x0001) { | 124 | err = l2cap_validate_bredr_psm(psm); |
| 96 | err = -EINVAL; | 125 | else |
| 97 | goto done; | 126 | err = l2cap_validate_le_psm(psm); |
| 98 | } | ||
| 99 | 127 | ||
| 100 | /* Restrict usage of well-known PSMs */ | 128 | if (err) |
| 101 | if (psm < 0x1001 && !capable(CAP_NET_BIND_SERVICE)) { | ||
| 102 | err = -EACCES; | ||
| 103 | goto done; | 129 | goto done; |
| 104 | } | ||
| 105 | } | 130 | } |
| 106 | 131 | ||
| 107 | if (la.l2_cid) | 132 | if (la.l2_cid) |
| @@ -122,11 +147,17 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) | |||
| 122 | __le16_to_cpu(la.l2_psm) == L2CAP_PSM_RFCOMM) | 147 | __le16_to_cpu(la.l2_psm) == L2CAP_PSM_RFCOMM) |
| 123 | chan->sec_level = BT_SECURITY_SDP; | 148 | chan->sec_level = BT_SECURITY_SDP; |
| 124 | break; | 149 | break; |
| 150 | case L2CAP_CHAN_RAW: | ||
| 151 | chan->sec_level = BT_SECURITY_SDP; | ||
| 152 | break; | ||
| 125 | } | 153 | } |
| 126 | 154 | ||
| 127 | bacpy(&chan->src, &la.l2_bdaddr); | 155 | bacpy(&chan->src, &la.l2_bdaddr); |
| 128 | chan->src_type = la.l2_bdaddr_type; | 156 | chan->src_type = la.l2_bdaddr_type; |
| 129 | 157 | ||
| 158 | if (chan->psm && bdaddr_type_is_le(chan->src_type)) | ||
| 159 | chan->mode = L2CAP_MODE_LE_FLOWCTL; | ||
| 160 | |||
| 130 | chan->state = BT_BOUND; | 161 | chan->state = BT_BOUND; |
| 131 | sk->sk_state = BT_BOUND; | 162 | sk->sk_state = BT_BOUND; |
| 132 | 163 | ||
| @@ -189,14 +220,17 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, | |||
| 189 | return -EINVAL; | 220 | return -EINVAL; |
| 190 | 221 | ||
| 191 | if (bdaddr_type_is_le(la.l2_bdaddr_type)) { | 222 | if (bdaddr_type_is_le(la.l2_bdaddr_type)) { |
| 192 | /* Connection oriented channels are not supported on LE */ | 223 | if (!enable_lecoc && la.l2_psm) |
| 193 | if (la.l2_psm) | ||
| 194 | return -EINVAL; | 224 | return -EINVAL; |
| 195 | /* We only allow ATT user space socket */ | 225 | /* We only allow ATT user space socket */ |
| 196 | if (la.l2_cid != __constant_cpu_to_le16(L2CAP_CID_ATT)) | 226 | if (la.l2_cid && |
| 227 | la.l2_cid != __constant_cpu_to_le16(L2CAP_CID_ATT)) | ||
| 197 | return -EINVAL; | 228 | return -EINVAL; |
| 198 | } | 229 | } |
| 199 | 230 | ||
| 231 | if (chan->psm && bdaddr_type_is_le(chan->src_type)) | ||
| 232 | chan->mode = L2CAP_MODE_LE_FLOWCTL; | ||
| 233 | |||
| 200 | err = l2cap_chan_connect(chan, la.l2_psm, __le16_to_cpu(la.l2_cid), | 234 | err = l2cap_chan_connect(chan, la.l2_psm, __le16_to_cpu(la.l2_cid), |
| 201 | &la.l2_bdaddr, la.l2_bdaddr_type); | 235 | &la.l2_bdaddr, la.l2_bdaddr_type); |
| 202 | if (err) | 236 | if (err) |
| @@ -234,6 +268,7 @@ static int l2cap_sock_listen(struct socket *sock, int backlog) | |||
| 234 | 268 | ||
| 235 | switch (chan->mode) { | 269 | switch (chan->mode) { |
| 236 | case L2CAP_MODE_BASIC: | 270 | case L2CAP_MODE_BASIC: |
| 271 | case L2CAP_MODE_LE_FLOWCTL: | ||
| 237 | break; | 272 | break; |
| 238 | case L2CAP_MODE_ERTM: | 273 | case L2CAP_MODE_ERTM: |
| 239 | case L2CAP_MODE_STREAMING: | 274 | case L2CAP_MODE_STREAMING: |
| @@ -360,6 +395,16 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, | |||
| 360 | 395 | ||
| 361 | switch (optname) { | 396 | switch (optname) { |
| 362 | case L2CAP_OPTIONS: | 397 | case L2CAP_OPTIONS: |
| 398 | /* LE sockets should use BT_SNDMTU/BT_RCVMTU, but since | ||
| 399 | * legacy ATT code depends on getsockopt for | ||
| 400 | * L2CAP_OPTIONS we need to let this pass. | ||
| 401 | */ | ||
| 402 | if (bdaddr_type_is_le(chan->src_type) && | ||
| 403 | chan->scid != L2CAP_CID_ATT) { | ||
| 404 | err = -EINVAL; | ||
| 405 | break; | ||
| 406 | } | ||
| 407 | |||
| 363 | memset(&opts, 0, sizeof(opts)); | 408 | memset(&opts, 0, sizeof(opts)); |
| 364 | opts.imtu = chan->imtu; | 409 | opts.imtu = chan->imtu; |
| 365 | opts.omtu = chan->omtu; | 410 | opts.omtu = chan->omtu; |
| @@ -514,6 +559,41 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, | |||
| 514 | err = -EFAULT; | 559 | err = -EFAULT; |
| 515 | break; | 560 | break; |
| 516 | 561 | ||
| 562 | case BT_SNDMTU: | ||
| 563 | if (!enable_lecoc) { | ||
| 564 | err = -EPROTONOSUPPORT; | ||
| 565 | break; | ||
| 566 | } | ||
| 567 | |||
| 568 | if (!bdaddr_type_is_le(chan->src_type)) { | ||
| 569 | err = -EINVAL; | ||
| 570 | break; | ||
| 571 | } | ||
| 572 | |||
| 573 | if (sk->sk_state != BT_CONNECTED) { | ||
| 574 | err = -ENOTCONN; | ||
| 575 | break; | ||
| 576 | } | ||
| 577 | |||
| 578 | if (put_user(chan->omtu, (u16 __user *) optval)) | ||
| 579 | err = -EFAULT; | ||
| 580 | break; | ||
| 581 | |||
| 582 | case BT_RCVMTU: | ||
| 583 | if (!enable_lecoc) { | ||
| 584 | err = -EPROTONOSUPPORT; | ||
| 585 | break; | ||
| 586 | } | ||
| 587 | |||
| 588 | if (!bdaddr_type_is_le(chan->src_type)) { | ||
| 589 | err = -EINVAL; | ||
| 590 | break; | ||
| 591 | } | ||
| 592 | |||
| 593 | if (put_user(chan->imtu, (u16 __user *) optval)) | ||
| 594 | err = -EFAULT; | ||
| 595 | break; | ||
| 596 | |||
| 517 | default: | 597 | default: |
| 518 | err = -ENOPROTOOPT; | 598 | err = -ENOPROTOOPT; |
| 519 | break; | 599 | break; |
| @@ -554,6 +634,11 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, | |||
| 554 | 634 | ||
| 555 | switch (optname) { | 635 | switch (optname) { |
| 556 | case L2CAP_OPTIONS: | 636 | case L2CAP_OPTIONS: |
| 637 | if (bdaddr_type_is_le(chan->src_type)) { | ||
| 638 | err = -EINVAL; | ||
| 639 | break; | ||
| 640 | } | ||
| 641 | |||
| 557 | if (sk->sk_state == BT_CONNECTED) { | 642 | if (sk->sk_state == BT_CONNECTED) { |
| 558 | err = -EINVAL; | 643 | err = -EINVAL; |
| 559 | break; | 644 | break; |
| @@ -585,6 +670,8 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, | |||
| 585 | 670 | ||
| 586 | chan->mode = opts.mode; | 671 | chan->mode = opts.mode; |
| 587 | switch (chan->mode) { | 672 | switch (chan->mode) { |
| 673 | case L2CAP_MODE_LE_FLOWCTL: | ||
| 674 | break; | ||
| 588 | case L2CAP_MODE_BASIC: | 675 | case L2CAP_MODE_BASIC: |
| 589 | clear_bit(CONF_STATE2_DEVICE, &chan->conf_state); | 676 | clear_bit(CONF_STATE2_DEVICE, &chan->conf_state); |
| 590 | break; | 677 | break; |
| @@ -807,6 +894,47 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, | |||
| 807 | 894 | ||
| 808 | break; | 895 | break; |
| 809 | 896 | ||
| 897 | case BT_SNDMTU: | ||
| 898 | if (!enable_lecoc) { | ||
| 899 | err = -EPROTONOSUPPORT; | ||
| 900 | break; | ||
| 901 | } | ||
| 902 | |||
| 903 | if (!bdaddr_type_is_le(chan->src_type)) { | ||
| 904 | err = -EINVAL; | ||
| 905 | break; | ||
| 906 | } | ||
| 907 | |||
| 908 | /* Setting is not supported as it's the remote side that | ||
| 909 | * decides this. | ||
| 910 | */ | ||
| 911 | err = -EPERM; | ||
| 912 | break; | ||
| 913 | |||
| 914 | case BT_RCVMTU: | ||
| 915 | if (!enable_lecoc) { | ||
| 916 | err = -EPROTONOSUPPORT; | ||
| 917 | break; | ||
| 918 | } | ||
| 919 | |||
| 920 | if (!bdaddr_type_is_le(chan->src_type)) { | ||
| 921 | err = -EINVAL; | ||
| 922 | break; | ||
| 923 | } | ||
| 924 | |||
| 925 | if (sk->sk_state == BT_CONNECTED) { | ||
| 926 | err = -EISCONN; | ||
| 927 | break; | ||
| 928 | } | ||
| 929 | |||
| 930 | if (get_user(opt, (u32 __user *) optval)) { | ||
| 931 | err = -EFAULT; | ||
| 932 | break; | ||
| 933 | } | ||
| 934 | |||
| 935 | chan->imtu = opt; | ||
| 936 | break; | ||
| 937 | |||
| 810 | default: | 938 | default: |
| 811 | err = -ENOPROTOOPT; | 939 | err = -ENOPROTOOPT; |
| 812 | break; | 940 | break; |
| @@ -859,10 +987,16 @@ static int l2cap_sock_recvmsg(struct kiocb *iocb, struct socket *sock, | |||
| 859 | 987 | ||
| 860 | if (sk->sk_state == BT_CONNECT2 && test_bit(BT_SK_DEFER_SETUP, | 988 | if (sk->sk_state == BT_CONNECT2 && test_bit(BT_SK_DEFER_SETUP, |
| 861 | &bt_sk(sk)->flags)) { | 989 | &bt_sk(sk)->flags)) { |
| 862 | sk->sk_state = BT_CONFIG; | 990 | if (bdaddr_type_is_le(pi->chan->src_type)) { |
| 863 | pi->chan->state = BT_CONFIG; | 991 | sk->sk_state = BT_CONNECTED; |
| 992 | pi->chan->state = BT_CONNECTED; | ||
| 993 | __l2cap_le_connect_rsp_defer(pi->chan); | ||
| 994 | } else { | ||
| 995 | sk->sk_state = BT_CONFIG; | ||
| 996 | pi->chan->state = BT_CONFIG; | ||
| 997 | __l2cap_connect_rsp_defer(pi->chan); | ||
| 998 | } | ||
| 864 | 999 | ||
| 865 | __l2cap_connect_rsp_defer(pi->chan); | ||
| 866 | err = 0; | 1000 | err = 0; |
| 867 | goto done; | 1001 | goto done; |
| 868 | } | 1002 | } |
| @@ -1236,6 +1370,14 @@ static long l2cap_sock_get_sndtimeo_cb(struct l2cap_chan *chan) | |||
| 1236 | return sk->sk_sndtimeo; | 1370 | return sk->sk_sndtimeo; |
| 1237 | } | 1371 | } |
| 1238 | 1372 | ||
| 1373 | static void l2cap_sock_suspend_cb(struct l2cap_chan *chan) | ||
| 1374 | { | ||
| 1375 | struct sock *sk = chan->data; | ||
| 1376 | |||
| 1377 | set_bit(BT_SK_SUSPEND, &bt_sk(sk)->flags); | ||
| 1378 | sk->sk_state_change(sk); | ||
| 1379 | } | ||
| 1380 | |||
| 1239 | static struct l2cap_ops l2cap_chan_ops = { | 1381 | static struct l2cap_ops l2cap_chan_ops = { |
| 1240 | .name = "L2CAP Socket Interface", | 1382 | .name = "L2CAP Socket Interface", |
| 1241 | .new_connection = l2cap_sock_new_connection_cb, | 1383 | .new_connection = l2cap_sock_new_connection_cb, |
| @@ -1246,6 +1388,7 @@ static struct l2cap_ops l2cap_chan_ops = { | |||
| 1246 | .ready = l2cap_sock_ready_cb, | 1388 | .ready = l2cap_sock_ready_cb, |
| 1247 | .defer = l2cap_sock_defer_cb, | 1389 | .defer = l2cap_sock_defer_cb, |
| 1248 | .resume = l2cap_sock_resume_cb, | 1390 | .resume = l2cap_sock_resume_cb, |
| 1391 | .suspend = l2cap_sock_suspend_cb, | ||
| 1249 | .set_shutdown = l2cap_sock_set_shutdown_cb, | 1392 | .set_shutdown = l2cap_sock_set_shutdown_cb, |
| 1250 | .get_sndtimeo = l2cap_sock_get_sndtimeo_cb, | 1393 | .get_sndtimeo = l2cap_sock_get_sndtimeo_cb, |
| 1251 | .alloc_skb = l2cap_sock_alloc_skb_cb, | 1394 | .alloc_skb = l2cap_sock_alloc_skb_cb, |
| @@ -1270,7 +1413,7 @@ static void l2cap_sock_destruct(struct sock *sk) | |||
| 1270 | static void l2cap_skb_msg_name(struct sk_buff *skb, void *msg_name, | 1413 | static void l2cap_skb_msg_name(struct sk_buff *skb, void *msg_name, |
| 1271 | int *msg_namelen) | 1414 | int *msg_namelen) |
| 1272 | { | 1415 | { |
| 1273 | struct sockaddr_l2 *la = (struct sockaddr_l2 *) msg_name; | 1416 | DECLARE_SOCKADDR(struct sockaddr_l2 *, la, msg_name); |
| 1274 | 1417 | ||
| 1275 | memset(la, 0, sizeof(struct sockaddr_l2)); | 1418 | memset(la, 0, sizeof(struct sockaddr_l2)); |
| 1276 | la->l2_family = AF_BLUETOOTH; | 1419 | la->l2_family = AF_BLUETOOTH; |
| @@ -1303,6 +1446,8 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent) | |||
| 1303 | chan->tx_win_max = pchan->tx_win_max; | 1446 | chan->tx_win_max = pchan->tx_win_max; |
| 1304 | chan->sec_level = pchan->sec_level; | 1447 | chan->sec_level = pchan->sec_level; |
| 1305 | chan->flags = pchan->flags; | 1448 | chan->flags = pchan->flags; |
| 1449 | chan->tx_credits = pchan->tx_credits; | ||
| 1450 | chan->rx_credits = pchan->rx_credits; | ||
| 1306 | 1451 | ||
| 1307 | security_sk_clone(parent, sk); | 1452 | security_sk_clone(parent, sk); |
| 1308 | } else { | 1453 | } else { |
| @@ -1469,3 +1614,6 @@ void l2cap_cleanup_sockets(void) | |||
| 1469 | bt_sock_unregister(BTPROTO_L2CAP); | 1614 | bt_sock_unregister(BTPROTO_L2CAP); |
| 1470 | proto_unregister(&l2cap_proto); | 1615 | proto_unregister(&l2cap_proto); |
| 1471 | } | 1616 | } |
| 1617 | |||
| 1618 | module_param(enable_lecoc, bool, 0644); | ||
| 1619 | MODULE_PARM_DESC(enable_lecoc, "Enable support for LE CoC"); | ||
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 074d83690a41..a03ca3ca91bf 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c | |||
| @@ -1264,7 +1264,7 @@ static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data, | |||
| 1264 | 1264 | ||
| 1265 | if (cp->val == 0x02) { | 1265 | if (cp->val == 0x02) { |
| 1266 | /* Limited discoverable mode */ | 1266 | /* Limited discoverable mode */ |
| 1267 | hci_cp.num_iac = 2; | 1267 | hci_cp.num_iac = min_t(u8, hdev->num_iac, 2); |
| 1268 | hci_cp.iac_lap[0] = 0x00; /* LIAC */ | 1268 | hci_cp.iac_lap[0] = 0x00; /* LIAC */ |
| 1269 | hci_cp.iac_lap[1] = 0x8b; | 1269 | hci_cp.iac_lap[1] = 0x8b; |
| 1270 | hci_cp.iac_lap[2] = 0x9e; | 1270 | hci_cp.iac_lap[2] = 0x9e; |
| @@ -4595,6 +4595,9 @@ void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, | |||
| 4595 | struct mgmt_ev_device_disconnected ev; | 4595 | struct mgmt_ev_device_disconnected ev; |
| 4596 | struct sock *sk = NULL; | 4596 | struct sock *sk = NULL; |
| 4597 | 4597 | ||
| 4598 | if (link_type != ACL_LINK && link_type != LE_LINK) | ||
| 4599 | return; | ||
| 4600 | |||
| 4598 | mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk); | 4601 | mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk); |
| 4599 | 4602 | ||
| 4600 | bacpy(&ev.addr.bdaddr, bdaddr); | 4603 | bacpy(&ev.addr.bdaddr, bdaddr); |
| @@ -4613,6 +4616,8 @@ void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, | |||
| 4613 | void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, | 4616 | void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, |
| 4614 | u8 link_type, u8 addr_type, u8 status) | 4617 | u8 link_type, u8 addr_type, u8 status) |
| 4615 | { | 4618 | { |
| 4619 | u8 bdaddr_type = link_to_bdaddr(link_type, addr_type); | ||
| 4620 | struct mgmt_cp_disconnect *cp; | ||
| 4616 | struct mgmt_rp_disconnect rp; | 4621 | struct mgmt_rp_disconnect rp; |
| 4617 | struct pending_cmd *cmd; | 4622 | struct pending_cmd *cmd; |
| 4618 | 4623 | ||
| @@ -4623,8 +4628,16 @@ void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, | |||
| 4623 | if (!cmd) | 4628 | if (!cmd) |
| 4624 | return; | 4629 | return; |
| 4625 | 4630 | ||
| 4631 | cp = cmd->param; | ||
| 4632 | |||
| 4633 | if (bacmp(bdaddr, &cp->addr.bdaddr)) | ||
| 4634 | return; | ||
| 4635 | |||
| 4636 | if (cp->addr.type != bdaddr_type) | ||
| 4637 | return; | ||
| 4638 | |||
| 4626 | bacpy(&rp.addr.bdaddr, bdaddr); | 4639 | bacpy(&rp.addr.bdaddr, bdaddr); |
| 4627 | rp.addr.type = link_to_bdaddr(link_type, addr_type); | 4640 | rp.addr.type = bdaddr_type; |
| 4628 | 4641 | ||
| 4629 | cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, | 4642 | cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, |
| 4630 | mgmt_status(status), &rp, sizeof(rp)); | 4643 | mgmt_status(status), &rp, sizeof(rp)); |
diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index 84fcf9fff3ea..f9c0980abeea 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c | |||
| @@ -58,6 +58,7 @@ struct rfcomm_dev { | |||
| 58 | uint modem_status; | 58 | uint modem_status; |
| 59 | 59 | ||
| 60 | struct rfcomm_dlc *dlc; | 60 | struct rfcomm_dlc *dlc; |
| 61 | wait_queue_head_t conn_wait; | ||
| 61 | 62 | ||
| 62 | struct device *tty_dev; | 63 | struct device *tty_dev; |
| 63 | 64 | ||
| @@ -103,20 +104,60 @@ static void rfcomm_dev_destruct(struct tty_port *port) | |||
| 103 | module_put(THIS_MODULE); | 104 | module_put(THIS_MODULE); |
| 104 | } | 105 | } |
| 105 | 106 | ||
| 106 | /* device-specific initialization: open the dlc */ | 107 | static struct device *rfcomm_get_device(struct rfcomm_dev *dev) |
| 107 | static int rfcomm_dev_activate(struct tty_port *port, struct tty_struct *tty) | ||
| 108 | { | 108 | { |
| 109 | struct rfcomm_dev *dev = container_of(port, struct rfcomm_dev, port); | 109 | struct hci_dev *hdev; |
| 110 | struct hci_conn *conn; | ||
| 110 | 111 | ||
| 111 | return rfcomm_dlc_open(dev->dlc, &dev->src, &dev->dst, dev->channel); | 112 | hdev = hci_get_route(&dev->dst, &dev->src); |
| 113 | if (!hdev) | ||
| 114 | return NULL; | ||
| 115 | |||
| 116 | conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &dev->dst); | ||
| 117 | |||
| 118 | hci_dev_put(hdev); | ||
| 119 | |||
| 120 | return conn ? &conn->dev : NULL; | ||
| 112 | } | 121 | } |
| 113 | 122 | ||
| 114 | /* we block the open until the dlc->state becomes BT_CONNECTED */ | 123 | /* device-specific initialization: open the dlc */ |
| 115 | static int rfcomm_dev_carrier_raised(struct tty_port *port) | 124 | static int rfcomm_dev_activate(struct tty_port *port, struct tty_struct *tty) |
| 116 | { | 125 | { |
| 117 | struct rfcomm_dev *dev = container_of(port, struct rfcomm_dev, port); | 126 | struct rfcomm_dev *dev = container_of(port, struct rfcomm_dev, port); |
| 127 | DEFINE_WAIT(wait); | ||
| 128 | int err; | ||
| 129 | |||
| 130 | err = rfcomm_dlc_open(dev->dlc, &dev->src, &dev->dst, dev->channel); | ||
| 131 | if (err) | ||
| 132 | return err; | ||
| 133 | |||
| 134 | while (1) { | ||
| 135 | prepare_to_wait(&dev->conn_wait, &wait, TASK_INTERRUPTIBLE); | ||
| 136 | |||
| 137 | if (dev->dlc->state == BT_CLOSED) { | ||
| 138 | err = -dev->err; | ||
| 139 | break; | ||
| 140 | } | ||
| 141 | |||
| 142 | if (dev->dlc->state == BT_CONNECTED) | ||
| 143 | break; | ||
| 144 | |||
| 145 | if (signal_pending(current)) { | ||
| 146 | err = -ERESTARTSYS; | ||
| 147 | break; | ||
| 148 | } | ||
| 149 | |||
| 150 | tty_unlock(tty); | ||
| 151 | schedule(); | ||
| 152 | tty_lock(tty); | ||
| 153 | } | ||
| 154 | finish_wait(&dev->conn_wait, &wait); | ||
| 155 | |||
| 156 | if (!err) | ||
| 157 | device_move(dev->tty_dev, rfcomm_get_device(dev), | ||
| 158 | DPM_ORDER_DEV_AFTER_PARENT); | ||
| 118 | 159 | ||
| 119 | return (dev->dlc->state == BT_CONNECTED); | 160 | return err; |
| 120 | } | 161 | } |
| 121 | 162 | ||
| 122 | /* device-specific cleanup: close the dlc */ | 163 | /* device-specific cleanup: close the dlc */ |
| @@ -135,7 +176,6 @@ static const struct tty_port_operations rfcomm_port_ops = { | |||
| 135 | .destruct = rfcomm_dev_destruct, | 176 | .destruct = rfcomm_dev_destruct, |
| 136 | .activate = rfcomm_dev_activate, | 177 | .activate = rfcomm_dev_activate, |
| 137 | .shutdown = rfcomm_dev_shutdown, | 178 | .shutdown = rfcomm_dev_shutdown, |
| 138 | .carrier_raised = rfcomm_dev_carrier_raised, | ||
| 139 | }; | 179 | }; |
| 140 | 180 | ||
| 141 | static struct rfcomm_dev *__rfcomm_dev_get(int id) | 181 | static struct rfcomm_dev *__rfcomm_dev_get(int id) |
| @@ -169,22 +209,6 @@ static struct rfcomm_dev *rfcomm_dev_get(int id) | |||
| 169 | return dev; | 209 | return dev; |
| 170 | } | 210 | } |
| 171 | 211 | ||
| 172 | static struct device *rfcomm_get_device(struct rfcomm_dev *dev) | ||
| 173 | { | ||
| 174 | struct hci_dev *hdev; | ||
| 175 | struct hci_conn *conn; | ||
| 176 | |||
| 177 | hdev = hci_get_route(&dev->dst, &dev->src); | ||
| 178 | if (!hdev) | ||
| 179 | return NULL; | ||
| 180 | |||
| 181 | conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &dev->dst); | ||
| 182 | |||
| 183 | hci_dev_put(hdev); | ||
| 184 | |||
| 185 | return conn ? &conn->dev : NULL; | ||
| 186 | } | ||
| 187 | |||
| 188 | static ssize_t show_address(struct device *tty_dev, struct device_attribute *attr, char *buf) | 212 | static ssize_t show_address(struct device *tty_dev, struct device_attribute *attr, char *buf) |
| 189 | { | 213 | { |
| 190 | struct rfcomm_dev *dev = dev_get_drvdata(tty_dev); | 214 | struct rfcomm_dev *dev = dev_get_drvdata(tty_dev); |
| @@ -258,6 +282,7 @@ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc) | |||
| 258 | 282 | ||
| 259 | tty_port_init(&dev->port); | 283 | tty_port_init(&dev->port); |
| 260 | dev->port.ops = &rfcomm_port_ops; | 284 | dev->port.ops = &rfcomm_port_ops; |
| 285 | init_waitqueue_head(&dev->conn_wait); | ||
| 261 | 286 | ||
| 262 | skb_queue_head_init(&dev->pending); | 287 | skb_queue_head_init(&dev->pending); |
| 263 | 288 | ||
| @@ -437,7 +462,8 @@ static int rfcomm_release_dev(void __user *arg) | |||
| 437 | tty_kref_put(tty); | 462 | tty_kref_put(tty); |
| 438 | } | 463 | } |
| 439 | 464 | ||
| 440 | if (!test_and_set_bit(RFCOMM_TTY_RELEASED, &dev->flags)) | 465 | if (!test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags) && |
| 466 | !test_and_set_bit(RFCOMM_TTY_RELEASED, &dev->flags)) | ||
| 441 | tty_port_put(&dev->port); | 467 | tty_port_put(&dev->port); |
| 442 | 468 | ||
| 443 | tty_port_put(&dev->port); | 469 | tty_port_put(&dev->port); |
| @@ -575,12 +601,9 @@ static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err) | |||
| 575 | BT_DBG("dlc %p dev %p err %d", dlc, dev, err); | 601 | BT_DBG("dlc %p dev %p err %d", dlc, dev, err); |
| 576 | 602 | ||
| 577 | dev->err = err; | 603 | dev->err = err; |
| 578 | if (dlc->state == BT_CONNECTED) { | 604 | wake_up_interruptible(&dev->conn_wait); |
| 579 | device_move(dev->tty_dev, rfcomm_get_device(dev), | ||
| 580 | DPM_ORDER_DEV_AFTER_PARENT); | ||
| 581 | 605 | ||
| 582 | wake_up_interruptible(&dev->port.open_wait); | 606 | if (dlc->state == BT_CLOSED) |
| 583 | } else if (dlc->state == BT_CLOSED) | ||
| 584 | tty_port_tty_hangup(&dev->port, false); | 607 | tty_port_tty_hangup(&dev->port, false); |
| 585 | } | 608 | } |
| 586 | 609 | ||
| @@ -670,10 +693,20 @@ static int rfcomm_tty_install(struct tty_driver *driver, struct tty_struct *tty) | |||
| 670 | 693 | ||
| 671 | /* install the tty_port */ | 694 | /* install the tty_port */ |
| 672 | err = tty_port_install(&dev->port, driver, tty); | 695 | err = tty_port_install(&dev->port, driver, tty); |
| 673 | if (err) | 696 | if (err) { |
| 674 | rfcomm_tty_cleanup(tty); | 697 | rfcomm_tty_cleanup(tty); |
| 698 | return err; | ||
| 699 | } | ||
| 675 | 700 | ||
| 676 | return err; | 701 | /* take over the tty_port reference if the port was created with the |
| 702 | * flag RFCOMM_RELEASE_ONHUP. This will force the release of the port | ||
| 703 | * when the last process closes the tty. The behaviour is expected by | ||
| 704 | * userspace. | ||
| 705 | */ | ||
| 706 | if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags)) | ||
| 707 | tty_port_put(&dev->port); | ||
| 708 | |||
| 709 | return 0; | ||
| 677 | } | 710 | } |
| 678 | 711 | ||
| 679 | static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp) | 712 | static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp) |
| @@ -1010,10 +1043,6 @@ static void rfcomm_tty_hangup(struct tty_struct *tty) | |||
| 1010 | BT_DBG("tty %p dev %p", tty, dev); | 1043 | BT_DBG("tty %p dev %p", tty, dev); |
| 1011 | 1044 | ||
| 1012 | tty_port_hangup(&dev->port); | 1045 | tty_port_hangup(&dev->port); |
| 1013 | |||
| 1014 | if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags) && | ||
| 1015 | !test_and_set_bit(RFCOMM_TTY_RELEASED, &dev->flags)) | ||
| 1016 | tty_port_put(&dev->port); | ||
| 1017 | } | 1046 | } |
| 1018 | 1047 | ||
| 1019 | static int rfcomm_tty_tiocmget(struct tty_struct *tty) | 1048 | static int rfcomm_tty_tiocmget(struct tty_struct *tty) |
| @@ -1096,7 +1125,7 @@ int __init rfcomm_init_ttys(void) | |||
| 1096 | rfcomm_tty_driver->subtype = SERIAL_TYPE_NORMAL; | 1125 | rfcomm_tty_driver->subtype = SERIAL_TYPE_NORMAL; |
| 1097 | rfcomm_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; | 1126 | rfcomm_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; |
| 1098 | rfcomm_tty_driver->init_termios = tty_std_termios; | 1127 | rfcomm_tty_driver->init_termios = tty_std_termios; |
| 1099 | rfcomm_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL; | 1128 | rfcomm_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; |
| 1100 | rfcomm_tty_driver->init_termios.c_lflag &= ~ICANON; | 1129 | rfcomm_tty_driver->init_termios.c_lflag &= ~ICANON; |
| 1101 | tty_set_operations(rfcomm_tty_driver, &rfcomm_ops); | 1130 | tty_set_operations(rfcomm_tty_driver, &rfcomm_ops); |
| 1102 | 1131 | ||
diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 4b07acb8293c..45007362683b 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c | |||
| @@ -53,8 +53,7 @@ static int smp_e(struct crypto_blkcipher *tfm, const u8 *k, u8 *r) | |||
| 53 | { | 53 | { |
| 54 | struct blkcipher_desc desc; | 54 | struct blkcipher_desc desc; |
| 55 | struct scatterlist sg; | 55 | struct scatterlist sg; |
| 56 | int err, iv_len; | 56 | int err; |
| 57 | unsigned char iv[128]; | ||
| 58 | 57 | ||
| 59 | if (tfm == NULL) { | 58 | if (tfm == NULL) { |
| 60 | BT_ERR("tfm %p", tfm); | 59 | BT_ERR("tfm %p", tfm); |
| @@ -72,12 +71,6 @@ static int smp_e(struct crypto_blkcipher *tfm, const u8 *k, u8 *r) | |||
| 72 | 71 | ||
| 73 | sg_init_one(&sg, r, 16); | 72 | sg_init_one(&sg, r, 16); |
| 74 | 73 | ||
| 75 | iv_len = crypto_blkcipher_ivsize(tfm); | ||
| 76 | if (iv_len) { | ||
| 77 | memset(&iv, 0xff, iv_len); | ||
| 78 | crypto_blkcipher_set_iv(tfm, iv, iv_len); | ||
| 79 | } | ||
| 80 | |||
| 81 | err = crypto_blkcipher_encrypt(&desc, &sg, &sg, 16); | 74 | err = crypto_blkcipher_encrypt(&desc, &sg, &sg, 16); |
| 82 | if (err) | 75 | if (err) |
| 83 | BT_ERR("Encrypt data error %d", err); | 76 | BT_ERR("Encrypt data error %d", err); |
| @@ -143,13 +136,6 @@ static int smp_s1(struct crypto_blkcipher *tfm, u8 k[16], u8 r1[16], | |||
| 143 | return err; | 136 | return err; |
| 144 | } | 137 | } |
| 145 | 138 | ||
| 146 | static int smp_rand(u8 *buf) | ||
| 147 | { | ||
| 148 | get_random_bytes(buf, 16); | ||
| 149 | |||
| 150 | return 0; | ||
| 151 | } | ||
| 152 | |||
| 153 | static struct sk_buff *smp_build_cmd(struct l2cap_conn *conn, u8 code, | 139 | static struct sk_buff *smp_build_cmd(struct l2cap_conn *conn, u8 code, |
| 154 | u16 dlen, void *data) | 140 | u16 dlen, void *data) |
| 155 | { | 141 | { |
| @@ -257,11 +243,11 @@ static u8 check_enc_key_size(struct l2cap_conn *conn, __u8 max_key_size) | |||
| 257 | return 0; | 243 | return 0; |
| 258 | } | 244 | } |
| 259 | 245 | ||
| 260 | static void smp_failure(struct l2cap_conn *conn, u8 reason, u8 send) | 246 | static void smp_failure(struct l2cap_conn *conn, u8 reason) |
| 261 | { | 247 | { |
| 262 | struct hci_conn *hcon = conn->hcon; | 248 | struct hci_conn *hcon = conn->hcon; |
| 263 | 249 | ||
| 264 | if (send) | 250 | if (reason) |
| 265 | smp_send_cmd(conn, SMP_CMD_PAIRING_FAIL, sizeof(reason), | 251 | smp_send_cmd(conn, SMP_CMD_PAIRING_FAIL, sizeof(reason), |
| 266 | &reason); | 252 | &reason); |
| 267 | 253 | ||
| @@ -406,7 +392,7 @@ static void confirm_work(struct work_struct *work) | |||
| 406 | return; | 392 | return; |
| 407 | 393 | ||
| 408 | error: | 394 | error: |
| 409 | smp_failure(conn, reason, 1); | 395 | smp_failure(conn, reason); |
| 410 | } | 396 | } |
| 411 | 397 | ||
| 412 | static void random_work(struct work_struct *work) | 398 | static void random_work(struct work_struct *work) |
| @@ -490,7 +476,7 @@ static void random_work(struct work_struct *work) | |||
| 490 | return; | 476 | return; |
| 491 | 477 | ||
| 492 | error: | 478 | error: |
| 493 | smp_failure(conn, reason, 1); | 479 | smp_failure(conn, reason); |
| 494 | } | 480 | } |
| 495 | 481 | ||
| 496 | static struct smp_chan *smp_chan_create(struct l2cap_conn *conn) | 482 | static struct smp_chan *smp_chan_create(struct l2cap_conn *conn) |
| @@ -555,10 +541,10 @@ int smp_user_confirm_reply(struct hci_conn *hcon, u16 mgmt_op, __le32 passkey) | |||
| 555 | break; | 541 | break; |
| 556 | case MGMT_OP_USER_PASSKEY_NEG_REPLY: | 542 | case MGMT_OP_USER_PASSKEY_NEG_REPLY: |
| 557 | case MGMT_OP_USER_CONFIRM_NEG_REPLY: | 543 | case MGMT_OP_USER_CONFIRM_NEG_REPLY: |
| 558 | smp_failure(conn, SMP_PASSKEY_ENTRY_FAILED, 1); | 544 | smp_failure(conn, SMP_PASSKEY_ENTRY_FAILED); |
| 559 | return 0; | 545 | return 0; |
| 560 | default: | 546 | default: |
| 561 | smp_failure(conn, SMP_PASSKEY_ENTRY_FAILED, 1); | 547 | smp_failure(conn, SMP_PASSKEY_ENTRY_FAILED); |
| 562 | return -EOPNOTSUPP; | 548 | return -EOPNOTSUPP; |
| 563 | } | 549 | } |
| 564 | 550 | ||
| @@ -606,9 +592,7 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) | |||
| 606 | if (check_enc_key_size(conn, key_size)) | 592 | if (check_enc_key_size(conn, key_size)) |
| 607 | return SMP_ENC_KEY_SIZE; | 593 | return SMP_ENC_KEY_SIZE; |
| 608 | 594 | ||
| 609 | ret = smp_rand(smp->prnd); | 595 | get_random_bytes(smp->prnd, sizeof(smp->prnd)); |
| 610 | if (ret) | ||
| 611 | return SMP_UNSPECIFIED; | ||
| 612 | 596 | ||
| 613 | smp->prsp[0] = SMP_CMD_PAIRING_RSP; | 597 | smp->prsp[0] = SMP_CMD_PAIRING_RSP; |
| 614 | memcpy(&smp->prsp[1], &rsp, sizeof(rsp)); | 598 | memcpy(&smp->prsp[1], &rsp, sizeof(rsp)); |
| @@ -644,9 +628,7 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb) | |||
| 644 | if (check_enc_key_size(conn, key_size)) | 628 | if (check_enc_key_size(conn, key_size)) |
| 645 | return SMP_ENC_KEY_SIZE; | 629 | return SMP_ENC_KEY_SIZE; |
| 646 | 630 | ||
| 647 | ret = smp_rand(smp->prnd); | 631 | get_random_bytes(smp->prnd, sizeof(smp->prnd)); |
| 648 | if (ret) | ||
| 649 | return SMP_UNSPECIFIED; | ||
| 650 | 632 | ||
| 651 | smp->prsp[0] = SMP_CMD_PAIRING_RSP; | 633 | smp->prsp[0] = SMP_CMD_PAIRING_RSP; |
| 652 | memcpy(&smp->prsp[1], rsp, sizeof(*rsp)); | 634 | memcpy(&smp->prsp[1], rsp, sizeof(*rsp)); |
| @@ -768,6 +750,17 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb) | |||
| 768 | return 0; | 750 | return 0; |
| 769 | } | 751 | } |
| 770 | 752 | ||
| 753 | bool smp_sufficient_security(struct hci_conn *hcon, u8 sec_level) | ||
| 754 | { | ||
| 755 | if (sec_level == BT_SECURITY_LOW) | ||
| 756 | return true; | ||
| 757 | |||
| 758 | if (hcon->sec_level >= sec_level) | ||
| 759 | return true; | ||
| 760 | |||
| 761 | return false; | ||
| 762 | } | ||
| 763 | |||
| 771 | int smp_conn_security(struct hci_conn *hcon, __u8 sec_level) | 764 | int smp_conn_security(struct hci_conn *hcon, __u8 sec_level) |
| 772 | { | 765 | { |
| 773 | struct l2cap_conn *conn = hcon->l2cap_data; | 766 | struct l2cap_conn *conn = hcon->l2cap_data; |
| @@ -779,10 +772,7 @@ int smp_conn_security(struct hci_conn *hcon, __u8 sec_level) | |||
| 779 | if (!test_bit(HCI_LE_ENABLED, &hcon->hdev->dev_flags)) | 772 | if (!test_bit(HCI_LE_ENABLED, &hcon->hdev->dev_flags)) |
| 780 | return 1; | 773 | return 1; |
| 781 | 774 | ||
| 782 | if (sec_level == BT_SECURITY_LOW) | 775 | if (smp_sufficient_security(hcon, sec_level)) |
| 783 | return 1; | ||
| 784 | |||
| 785 | if (hcon->sec_level >= sec_level) | ||
| 786 | return 1; | 776 | return 1; |
| 787 | 777 | ||
| 788 | if (hcon->link_mode & HCI_LM_MASTER) | 778 | if (hcon->link_mode & HCI_LM_MASTER) |
| @@ -895,7 +885,7 @@ int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb) | |||
| 895 | break; | 885 | break; |
| 896 | 886 | ||
| 897 | case SMP_CMD_PAIRING_FAIL: | 887 | case SMP_CMD_PAIRING_FAIL: |
| 898 | smp_failure(conn, skb->data[0], 0); | 888 | smp_failure(conn, 0); |
| 899 | reason = 0; | 889 | reason = 0; |
| 900 | err = -EPERM; | 890 | err = -EPERM; |
| 901 | break; | 891 | break; |
| @@ -941,7 +931,7 @@ int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb) | |||
| 941 | 931 | ||
| 942 | done: | 932 | done: |
| 943 | if (reason) | 933 | if (reason) |
| 944 | smp_failure(conn, reason, 1); | 934 | smp_failure(conn, reason); |
| 945 | 935 | ||
| 946 | kfree_skb(skb); | 936 | kfree_skb(skb); |
| 947 | return err; | 937 | return err; |
diff --git a/net/bluetooth/smp.h b/net/bluetooth/smp.h index f8ba07f3e5fa..a700bcb490d7 100644 --- a/net/bluetooth/smp.h +++ b/net/bluetooth/smp.h | |||
| @@ -136,6 +136,7 @@ struct smp_chan { | |||
| 136 | }; | 136 | }; |
| 137 | 137 | ||
| 138 | /* SMP Commands */ | 138 | /* SMP Commands */ |
| 139 | bool smp_sufficient_security(struct hci_conn *hcon, u8 sec_level); | ||
| 139 | int smp_conn_security(struct hci_conn *hcon, __u8 sec_level); | 140 | int smp_conn_security(struct hci_conn *hcon, __u8 sec_level); |
| 140 | int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb); | 141 | int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb); |
| 141 | int smp_distribute_keys(struct l2cap_conn *conn, __u8 force); | 142 | int smp_distribute_keys(struct l2cap_conn *conn, __u8 force); |
diff --git a/net/bridge/br.c b/net/bridge/br.c index ba780cc8e515..19311aafcf5a 100644 --- a/net/bridge/br.c +++ b/net/bridge/br.c | |||
| @@ -22,14 +22,29 @@ | |||
| 22 | 22 | ||
| 23 | #include "br_private.h" | 23 | #include "br_private.h" |
| 24 | 24 | ||
| 25 | static const struct stp_proto br_stp_proto = { | 25 | static void __net_exit br_net_exit(struct net *net) |
| 26 | .rcv = br_stp_rcv, | 26 | { |
| 27 | }; | 27 | struct net_device *dev; |
| 28 | LIST_HEAD(list); | ||
| 29 | |||
| 30 | rtnl_lock(); | ||
| 31 | for_each_netdev(net, dev) | ||
| 32 | if (dev->priv_flags & IFF_EBRIDGE) | ||
| 33 | br_dev_delete(dev, &list); | ||
| 34 | |||
| 35 | unregister_netdevice_many(&list); | ||
| 36 | rtnl_unlock(); | ||
| 37 | |||
| 38 | } | ||
| 28 | 39 | ||
| 29 | static struct pernet_operations br_net_ops = { | 40 | static struct pernet_operations br_net_ops = { |
| 30 | .exit = br_net_exit, | 41 | .exit = br_net_exit, |
| 31 | }; | 42 | }; |
| 32 | 43 | ||
| 44 | static const struct stp_proto br_stp_proto = { | ||
| 45 | .rcv = br_stp_rcv, | ||
| 46 | }; | ||
| 47 | |||
| 33 | static int __init br_init(void) | 48 | static int __init br_init(void) |
| 34 | { | 49 | { |
| 35 | int err; | 50 | int err; |
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c index f00cfd2a0143..e4401a531afb 100644 --- a/net/bridge/br_device.c +++ b/net/bridge/br_device.c | |||
| @@ -32,7 +32,7 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev) | |||
| 32 | const unsigned char *dest = skb->data; | 32 | const unsigned char *dest = skb->data; |
| 33 | struct net_bridge_fdb_entry *dst; | 33 | struct net_bridge_fdb_entry *dst; |
| 34 | struct net_bridge_mdb_entry *mdst; | 34 | struct net_bridge_mdb_entry *mdst; |
| 35 | struct br_cpu_netstats *brstats = this_cpu_ptr(br->stats); | 35 | struct pcpu_sw_netstats *brstats = this_cpu_ptr(br->stats); |
| 36 | u16 vid = 0; | 36 | u16 vid = 0; |
| 37 | 37 | ||
| 38 | rcu_read_lock(); | 38 | rcu_read_lock(); |
| @@ -90,12 +90,12 @@ static int br_dev_init(struct net_device *dev) | |||
| 90 | struct net_bridge *br = netdev_priv(dev); | 90 | struct net_bridge *br = netdev_priv(dev); |
| 91 | int i; | 91 | int i; |
| 92 | 92 | ||
| 93 | br->stats = alloc_percpu(struct br_cpu_netstats); | 93 | br->stats = alloc_percpu(struct pcpu_sw_netstats); |
| 94 | if (!br->stats) | 94 | if (!br->stats) |
| 95 | return -ENOMEM; | 95 | return -ENOMEM; |
| 96 | 96 | ||
| 97 | for_each_possible_cpu(i) { | 97 | for_each_possible_cpu(i) { |
| 98 | struct br_cpu_netstats *br_dev_stats; | 98 | struct pcpu_sw_netstats *br_dev_stats; |
| 99 | br_dev_stats = per_cpu_ptr(br->stats, i); | 99 | br_dev_stats = per_cpu_ptr(br->stats, i); |
| 100 | u64_stats_init(&br_dev_stats->syncp); | 100 | u64_stats_init(&br_dev_stats->syncp); |
| 101 | } | 101 | } |
| @@ -135,12 +135,12 @@ static struct rtnl_link_stats64 *br_get_stats64(struct net_device *dev, | |||
| 135 | struct rtnl_link_stats64 *stats) | 135 | struct rtnl_link_stats64 *stats) |
| 136 | { | 136 | { |
| 137 | struct net_bridge *br = netdev_priv(dev); | 137 | struct net_bridge *br = netdev_priv(dev); |
| 138 | struct br_cpu_netstats tmp, sum = { 0 }; | 138 | struct pcpu_sw_netstats tmp, sum = { 0 }; |
| 139 | unsigned int cpu; | 139 | unsigned int cpu; |
| 140 | 140 | ||
| 141 | for_each_possible_cpu(cpu) { | 141 | for_each_possible_cpu(cpu) { |
| 142 | unsigned int start; | 142 | unsigned int start; |
| 143 | const struct br_cpu_netstats *bstats | 143 | const struct pcpu_sw_netstats *bstats |
| 144 | = per_cpu_ptr(br->stats, cpu); | 144 | = per_cpu_ptr(br->stats, cpu); |
| 145 | do { | 145 | do { |
| 146 | start = u64_stats_fetch_begin_bh(&bstats->syncp); | 146 | start = u64_stats_fetch_begin_bh(&bstats->syncp); |
diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c index 33e8f23acddd..c5f5a4a933f4 100644 --- a/net/bridge/br_fdb.c +++ b/net/bridge/br_fdb.c | |||
| @@ -570,8 +570,7 @@ static void fdb_notify(struct net_bridge *br, | |||
| 570 | rtnl_notify(skb, net, 0, RTNLGRP_NEIGH, NULL, GFP_ATOMIC); | 570 | rtnl_notify(skb, net, 0, RTNLGRP_NEIGH, NULL, GFP_ATOMIC); |
| 571 | return; | 571 | return; |
| 572 | errout: | 572 | errout: |
| 573 | if (err < 0) | 573 | rtnl_set_sk_err(net, RTNLGRP_NEIGH, err); |
| 574 | rtnl_set_sk_err(net, RTNLGRP_NEIGH, err); | ||
| 575 | } | 574 | } |
| 576 | 575 | ||
| 577 | /* Dump information about entries, in response to GETNEIGH */ | 576 | /* Dump information about entries, in response to GETNEIGH */ |
diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c index 4b81b1471789..d3409e6b5453 100644 --- a/net/bridge/br_forward.c +++ b/net/bridge/br_forward.c | |||
| @@ -26,13 +26,13 @@ static int deliver_clone(const struct net_bridge_port *prev, | |||
| 26 | void (*__packet_hook)(const struct net_bridge_port *p, | 26 | void (*__packet_hook)(const struct net_bridge_port *p, |
| 27 | struct sk_buff *skb)); | 27 | struct sk_buff *skb)); |
| 28 | 28 | ||
| 29 | /* Don't forward packets to originating port or forwarding diasabled */ | 29 | /* Don't forward packets to originating port or forwarding disabled */ |
| 30 | static inline int should_deliver(const struct net_bridge_port *p, | 30 | static inline int should_deliver(const struct net_bridge_port *p, |
| 31 | const struct sk_buff *skb) | 31 | const struct sk_buff *skb) |
| 32 | { | 32 | { |
| 33 | return (((p->flags & BR_HAIRPIN_MODE) || skb->dev != p->dev) && | 33 | return ((p->flags & BR_HAIRPIN_MODE) || skb->dev != p->dev) && |
| 34 | br_allowed_egress(p->br, nbp_get_vlan_info(p), skb) && | 34 | br_allowed_egress(p->br, nbp_get_vlan_info(p), skb) && |
| 35 | p->state == BR_STATE_FORWARDING); | 35 | p->state == BR_STATE_FORWARDING; |
| 36 | } | 36 | } |
| 37 | 37 | ||
| 38 | static inline unsigned int packet_length(const struct sk_buff *skb) | 38 | static inline unsigned int packet_length(const struct sk_buff *skb) |
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index 4bf02adb5dc2..cffe1d666ba1 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c | |||
| @@ -61,7 +61,7 @@ static int port_cost(struct net_device *dev) | |||
| 61 | } | 61 | } |
| 62 | 62 | ||
| 63 | 63 | ||
| 64 | /* Check for port carrier transistions. */ | 64 | /* Check for port carrier transitions. */ |
| 65 | void br_port_carrier_check(struct net_bridge_port *p) | 65 | void br_port_carrier_check(struct net_bridge_port *p) |
| 66 | { | 66 | { |
| 67 | struct net_device *dev = p->dev; | 67 | struct net_device *dev = p->dev; |
| @@ -455,18 +455,3 @@ int br_del_if(struct net_bridge *br, struct net_device *dev) | |||
| 455 | 455 | ||
| 456 | return 0; | 456 | return 0; |
| 457 | } | 457 | } |
| 458 | |||
| 459 | void __net_exit br_net_exit(struct net *net) | ||
| 460 | { | ||
| 461 | struct net_device *dev; | ||
| 462 | LIST_HEAD(list); | ||
| 463 | |||
| 464 | rtnl_lock(); | ||
| 465 | for_each_netdev(net, dev) | ||
| 466 | if (dev->priv_flags & IFF_EBRIDGE) | ||
| 467 | br_dev_delete(dev, &list); | ||
| 468 | |||
| 469 | unregister_netdevice_many(&list); | ||
| 470 | rtnl_unlock(); | ||
| 471 | |||
| 472 | } | ||
diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c index 7e73c32e205d..bf8dc7d308d6 100644 --- a/net/bridge/br_input.c +++ b/net/bridge/br_input.c | |||
| @@ -28,7 +28,7 @@ static int br_pass_frame_up(struct sk_buff *skb) | |||
| 28 | { | 28 | { |
| 29 | struct net_device *indev, *brdev = BR_INPUT_SKB_CB(skb)->brdev; | 29 | struct net_device *indev, *brdev = BR_INPUT_SKB_CB(skb)->brdev; |
| 30 | struct net_bridge *br = netdev_priv(brdev); | 30 | struct net_bridge *br = netdev_priv(brdev); |
| 31 | struct br_cpu_netstats *brstats = this_cpu_ptr(br->stats); | 31 | struct pcpu_sw_netstats *brstats = this_cpu_ptr(br->stats); |
| 32 | 32 | ||
| 33 | u64_stats_update_begin(&brstats->syncp); | 33 | u64_stats_update_begin(&brstats->syncp); |
| 34 | brstats->rx_packets++; | 34 | brstats->rx_packets++; |
diff --git a/net/bridge/br_ioctl.c b/net/bridge/br_ioctl.c index cd8c3a44ab7d..a9a4a1b7863d 100644 --- a/net/bridge/br_ioctl.c +++ b/net/bridge/br_ioctl.c | |||
| @@ -381,7 +381,7 @@ int br_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) | |||
| 381 | { | 381 | { |
| 382 | struct net_bridge *br = netdev_priv(dev); | 382 | struct net_bridge *br = netdev_priv(dev); |
| 383 | 383 | ||
| 384 | switch(cmd) { | 384 | switch (cmd) { |
| 385 | case SIOCDEVPRIVATE: | 385 | case SIOCDEVPRIVATE: |
| 386 | return old_dev_ioctl(dev, rq, cmd); | 386 | return old_dev_ioctl(dev, rq, cmd); |
| 387 | 387 | ||
diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c index 80cad2cf02a7..b008c59a92c4 100644 --- a/net/bridge/br_netfilter.c +++ b/net/bridge/br_netfilter.c | |||
| @@ -1001,7 +1001,7 @@ static struct nf_hook_ops br_nf_ops[] __read_mostly = { | |||
| 1001 | #ifdef CONFIG_SYSCTL | 1001 | #ifdef CONFIG_SYSCTL |
| 1002 | static | 1002 | static |
| 1003 | int brnf_sysctl_call_tables(struct ctl_table *ctl, int write, | 1003 | int brnf_sysctl_call_tables(struct ctl_table *ctl, int write, |
| 1004 | void __user * buffer, size_t * lenp, loff_t * ppos) | 1004 | void __user *buffer, size_t *lenp, loff_t *ppos) |
| 1005 | { | 1005 | { |
| 1006 | int ret; | 1006 | int ret; |
| 1007 | 1007 | ||
diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index f75d92e4f96b..e74b6d530cb6 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c | |||
| @@ -195,8 +195,7 @@ void br_ifinfo_notify(int event, struct net_bridge_port *port) | |||
| 195 | rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC); | 195 | rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC); |
| 196 | return; | 196 | return; |
| 197 | errout: | 197 | errout: |
| 198 | if (err < 0) | 198 | rtnl_set_sk_err(net, RTNLGRP_LINK, err); |
| 199 | rtnl_set_sk_err(net, RTNLGRP_LINK, err); | ||
| 200 | } | 199 | } |
| 201 | 200 | ||
| 202 | 201 | ||
| @@ -373,7 +372,7 @@ int br_setlink(struct net_device *dev, struct nlmsghdr *nlh) | |||
| 373 | 372 | ||
| 374 | p = br_port_get_rtnl(dev); | 373 | p = br_port_get_rtnl(dev); |
| 375 | /* We want to accept dev as bridge itself if the AF_SPEC | 374 | /* We want to accept dev as bridge itself if the AF_SPEC |
| 376 | * is set to see if someone is setting vlan info on the brigde | 375 | * is set to see if someone is setting vlan info on the bridge |
| 377 | */ | 376 | */ |
| 378 | if (!p && !afspec) | 377 | if (!p && !afspec) |
| 379 | return -EINVAL; | 378 | return -EINVAL; |
| @@ -389,7 +388,7 @@ int br_setlink(struct net_device *dev, struct nlmsghdr *nlh) | |||
| 389 | err = br_setport(p, tb); | 388 | err = br_setport(p, tb); |
| 390 | spin_unlock_bh(&p->br->lock); | 389 | spin_unlock_bh(&p->br->lock); |
| 391 | } else { | 390 | } else { |
| 392 | /* Binary compatability with old RSTP */ | 391 | /* Binary compatibility with old RSTP */ |
| 393 | if (nla_len(protinfo) < sizeof(u8)) | 392 | if (nla_len(protinfo) < sizeof(u8)) |
| 394 | return -EINVAL; | 393 | return -EINVAL; |
| 395 | 394 | ||
| @@ -482,9 +481,7 @@ int __init br_netlink_init(void) | |||
| 482 | int err; | 481 | int err; |
| 483 | 482 | ||
| 484 | br_mdb_init(); | 483 | br_mdb_init(); |
| 485 | err = rtnl_af_register(&br_af_ops); | 484 | rtnl_af_register(&br_af_ops); |
| 486 | if (err) | ||
| 487 | goto out; | ||
| 488 | 485 | ||
| 489 | err = rtnl_link_register(&br_link_ops); | 486 | err = rtnl_link_register(&br_link_ops); |
| 490 | if (err) | 487 | if (err) |
| @@ -494,7 +491,6 @@ int __init br_netlink_init(void) | |||
| 494 | 491 | ||
| 495 | out_af: | 492 | out_af: |
| 496 | rtnl_af_unregister(&br_af_ops); | 493 | rtnl_af_unregister(&br_af_ops); |
| 497 | out: | ||
| 498 | br_mdb_uninit(); | 494 | br_mdb_uninit(); |
| 499 | return err; | 495 | return err; |
| 500 | } | 496 | } |
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index 045d56eaeca2..fcd12333c59b 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h | |||
| @@ -210,21 +210,13 @@ static inline struct net_bridge_port *br_port_get_rtnl(const struct net_device * | |||
| 210 | rtnl_dereference(dev->rx_handler_data) : NULL; | 210 | rtnl_dereference(dev->rx_handler_data) : NULL; |
| 211 | } | 211 | } |
| 212 | 212 | ||
| 213 | struct br_cpu_netstats { | ||
| 214 | u64 rx_packets; | ||
| 215 | u64 rx_bytes; | ||
| 216 | u64 tx_packets; | ||
| 217 | u64 tx_bytes; | ||
| 218 | struct u64_stats_sync syncp; | ||
| 219 | }; | ||
| 220 | |||
| 221 | struct net_bridge | 213 | struct net_bridge |
| 222 | { | 214 | { |
| 223 | spinlock_t lock; | 215 | spinlock_t lock; |
| 224 | struct list_head port_list; | 216 | struct list_head port_list; |
| 225 | struct net_device *dev; | 217 | struct net_device *dev; |
| 226 | 218 | ||
| 227 | struct br_cpu_netstats __percpu *stats; | 219 | struct pcpu_sw_netstats __percpu *stats; |
| 228 | spinlock_t hash_lock; | 220 | spinlock_t hash_lock; |
| 229 | struct hlist_head hash[BR_HASH_SIZE]; | 221 | struct hlist_head hash[BR_HASH_SIZE]; |
| 230 | #ifdef CONFIG_BRIDGE_NETFILTER | 222 | #ifdef CONFIG_BRIDGE_NETFILTER |
| @@ -415,7 +407,6 @@ void br_flood_forward(struct net_bridge *br, struct sk_buff *skb, | |||
| 415 | void br_port_carrier_check(struct net_bridge_port *p); | 407 | void br_port_carrier_check(struct net_bridge_port *p); |
| 416 | int br_add_bridge(struct net *net, const char *name); | 408 | int br_add_bridge(struct net *net, const char *name); |
| 417 | int br_del_bridge(struct net *net, const char *name); | 409 | int br_del_bridge(struct net *net, const char *name); |
| 418 | void br_net_exit(struct net *net); | ||
| 419 | int br_add_if(struct net_bridge *br, struct net_device *dev); | 410 | int br_add_if(struct net_bridge *br, struct net_device *dev); |
| 420 | int br_del_if(struct net_bridge *br, struct net_device *dev); | 411 | int br_del_if(struct net_bridge *br, struct net_device *dev); |
| 421 | int br_min_mtu(const struct net_bridge *br); | 412 | int br_min_mtu(const struct net_bridge *br); |
| @@ -721,7 +712,7 @@ void br_netfilter_fini(void); | |||
| 721 | void br_netfilter_rtable_init(struct net_bridge *); | 712 | void br_netfilter_rtable_init(struct net_bridge *); |
| 722 | #else | 713 | #else |
| 723 | #define br_netfilter_init() (0) | 714 | #define br_netfilter_init() (0) |
| 724 | #define br_netfilter_fini() do { } while(0) | 715 | #define br_netfilter_fini() do { } while (0) |
| 725 | #define br_netfilter_rtable_init(x) | 716 | #define br_netfilter_rtable_init(x) |
| 726 | #endif | 717 | #endif |
| 727 | 718 | ||
diff --git a/net/bridge/br_stp_timer.c b/net/bridge/br_stp_timer.c index 950663d4d330..558c46d19e05 100644 --- a/net/bridge/br_stp_timer.c +++ b/net/bridge/br_stp_timer.c | |||
| @@ -110,7 +110,7 @@ static void br_tcn_timer_expired(unsigned long arg) | |||
| 110 | if (!br_is_root_bridge(br) && (br->dev->flags & IFF_UP)) { | 110 | if (!br_is_root_bridge(br) && (br->dev->flags & IFF_UP)) { |
| 111 | br_transmit_tcn(br); | 111 | br_transmit_tcn(br); |
| 112 | 112 | ||
| 113 | mod_timer(&br->tcn_timer,jiffies + br->bridge_hello_time); | 113 | mod_timer(&br->tcn_timer, jiffies + br->bridge_hello_time); |
| 114 | } | 114 | } |
| 115 | spin_unlock(&br->lock); | 115 | spin_unlock(&br->lock); |
| 116 | } | 116 | } |
diff --git a/net/bridge/br_sysfs_br.c b/net/bridge/br_sysfs_br.c index 3b9637fb7939..8dac65552f19 100644 --- a/net/bridge/br_sysfs_br.c +++ b/net/bridge/br_sysfs_br.c | |||
| @@ -49,53 +49,51 @@ static ssize_t store_bridge_parm(struct device *d, | |||
| 49 | } | 49 | } |
| 50 | 50 | ||
| 51 | 51 | ||
| 52 | static ssize_t show_forward_delay(struct device *d, | 52 | static ssize_t forward_delay_show(struct device *d, |
| 53 | struct device_attribute *attr, char *buf) | 53 | struct device_attribute *attr, char *buf) |
| 54 | { | 54 | { |
| 55 | struct net_bridge *br = to_bridge(d); | 55 | struct net_bridge *br = to_bridge(d); |
| 56 | return sprintf(buf, "%lu\n", jiffies_to_clock_t(br->forward_delay)); | 56 | return sprintf(buf, "%lu\n", jiffies_to_clock_t(br->forward_delay)); |
| 57 | } | 57 | } |
| 58 | 58 | ||
| 59 | static ssize_t store_forward_delay(struct device *d, | 59 | static ssize_t forward_delay_store(struct device *d, |
| 60 | struct device_attribute *attr, | 60 | struct device_attribute *attr, |
| 61 | const char *buf, size_t len) | 61 | const char *buf, size_t len) |
| 62 | { | 62 | { |
| 63 | return store_bridge_parm(d, buf, len, br_set_forward_delay); | 63 | return store_bridge_parm(d, buf, len, br_set_forward_delay); |
| 64 | } | 64 | } |
| 65 | static DEVICE_ATTR(forward_delay, S_IRUGO | S_IWUSR, | 65 | static DEVICE_ATTR_RW(forward_delay); |
| 66 | show_forward_delay, store_forward_delay); | ||
| 67 | 66 | ||
| 68 | static ssize_t show_hello_time(struct device *d, struct device_attribute *attr, | 67 | static ssize_t hello_time_show(struct device *d, struct device_attribute *attr, |
| 69 | char *buf) | 68 | char *buf) |
| 70 | { | 69 | { |
| 71 | return sprintf(buf, "%lu\n", | 70 | return sprintf(buf, "%lu\n", |
| 72 | jiffies_to_clock_t(to_bridge(d)->hello_time)); | 71 | jiffies_to_clock_t(to_bridge(d)->hello_time)); |
| 73 | } | 72 | } |
| 74 | 73 | ||
| 75 | static ssize_t store_hello_time(struct device *d, | 74 | static ssize_t hello_time_store(struct device *d, |
| 76 | struct device_attribute *attr, const char *buf, | 75 | struct device_attribute *attr, const char *buf, |
| 77 | size_t len) | 76 | size_t len) |
| 78 | { | 77 | { |
| 79 | return store_bridge_parm(d, buf, len, br_set_hello_time); | 78 | return store_bridge_parm(d, buf, len, br_set_hello_time); |
| 80 | } | 79 | } |
| 81 | static DEVICE_ATTR(hello_time, S_IRUGO | S_IWUSR, show_hello_time, | 80 | static DEVICE_ATTR_RW(hello_time); |
| 82 | store_hello_time); | ||
| 83 | 81 | ||
| 84 | static ssize_t show_max_age(struct device *d, struct device_attribute *attr, | 82 | static ssize_t max_age_show(struct device *d, struct device_attribute *attr, |
| 85 | char *buf) | 83 | char *buf) |
| 86 | { | 84 | { |
| 87 | return sprintf(buf, "%lu\n", | 85 | return sprintf(buf, "%lu\n", |
| 88 | jiffies_to_clock_t(to_bridge(d)->max_age)); | 86 | jiffies_to_clock_t(to_bridge(d)->max_age)); |
| 89 | } | 87 | } |
| 90 | 88 | ||
| 91 | static ssize_t store_max_age(struct device *d, struct device_attribute *attr, | 89 | static ssize_t max_age_store(struct device *d, struct device_attribute *attr, |
| 92 | const char *buf, size_t len) | 90 | const char *buf, size_t len) |
| 93 | { | 91 | { |
| 94 | return store_bridge_parm(d, buf, len, br_set_max_age); | 92 | return store_bridge_parm(d, buf, len, br_set_max_age); |
| 95 | } | 93 | } |
| 96 | static DEVICE_ATTR(max_age, S_IRUGO | S_IWUSR, show_max_age, store_max_age); | 94 | static DEVICE_ATTR_RW(max_age); |
| 97 | 95 | ||
| 98 | static ssize_t show_ageing_time(struct device *d, | 96 | static ssize_t ageing_time_show(struct device *d, |
| 99 | struct device_attribute *attr, char *buf) | 97 | struct device_attribute *attr, char *buf) |
| 100 | { | 98 | { |
| 101 | struct net_bridge *br = to_bridge(d); | 99 | struct net_bridge *br = to_bridge(d); |
| @@ -108,16 +106,15 @@ static int set_ageing_time(struct net_bridge *br, unsigned long val) | |||
| 108 | return 0; | 106 | return 0; |
| 109 | } | 107 | } |
| 110 | 108 | ||
| 111 | static ssize_t store_ageing_time(struct device *d, | 109 | static ssize_t ageing_time_store(struct device *d, |
| 112 | struct device_attribute *attr, | 110 | struct device_attribute *attr, |
| 113 | const char *buf, size_t len) | 111 | const char *buf, size_t len) |
| 114 | { | 112 | { |
| 115 | return store_bridge_parm(d, buf, len, set_ageing_time); | 113 | return store_bridge_parm(d, buf, len, set_ageing_time); |
| 116 | } | 114 | } |
| 117 | static DEVICE_ATTR(ageing_time, S_IRUGO | S_IWUSR, show_ageing_time, | 115 | static DEVICE_ATTR_RW(ageing_time); |
| 118 | store_ageing_time); | ||
| 119 | 116 | ||
| 120 | static ssize_t show_stp_state(struct device *d, | 117 | static ssize_t stp_state_show(struct device *d, |
| 121 | struct device_attribute *attr, char *buf) | 118 | struct device_attribute *attr, char *buf) |
| 122 | { | 119 | { |
| 123 | struct net_bridge *br = to_bridge(d); | 120 | struct net_bridge *br = to_bridge(d); |
| @@ -125,7 +122,7 @@ static ssize_t show_stp_state(struct device *d, | |||
| 125 | } | 122 | } |
| 126 | 123 | ||
| 127 | 124 | ||
| 128 | static ssize_t store_stp_state(struct device *d, | 125 | static ssize_t stp_state_store(struct device *d, |
| 129 | struct device_attribute *attr, const char *buf, | 126 | struct device_attribute *attr, const char *buf, |
| 130 | size_t len) | 127 | size_t len) |
| 131 | { | 128 | { |
| @@ -147,20 +144,21 @@ static ssize_t store_stp_state(struct device *d, | |||
| 147 | 144 | ||
| 148 | return len; | 145 | return len; |
| 149 | } | 146 | } |
| 150 | static DEVICE_ATTR(stp_state, S_IRUGO | S_IWUSR, show_stp_state, | 147 | static DEVICE_ATTR_RW(stp_state); |
| 151 | store_stp_state); | ||
| 152 | 148 | ||
| 153 | static ssize_t show_group_fwd_mask(struct device *d, | 149 | static ssize_t group_fwd_mask_show(struct device *d, |
| 154 | struct device_attribute *attr, char *buf) | 150 | struct device_attribute *attr, |
| 151 | char *buf) | ||
| 155 | { | 152 | { |
| 156 | struct net_bridge *br = to_bridge(d); | 153 | struct net_bridge *br = to_bridge(d); |
| 157 | return sprintf(buf, "%#x\n", br->group_fwd_mask); | 154 | return sprintf(buf, "%#x\n", br->group_fwd_mask); |
| 158 | } | 155 | } |
| 159 | 156 | ||
| 160 | 157 | ||
| 161 | static ssize_t store_group_fwd_mask(struct device *d, | 158 | static ssize_t group_fwd_mask_store(struct device *d, |
| 162 | struct device_attribute *attr, const char *buf, | 159 | struct device_attribute *attr, |
| 163 | size_t len) | 160 | const char *buf, |
| 161 | size_t len) | ||
| 164 | { | 162 | { |
| 165 | struct net_bridge *br = to_bridge(d); | 163 | struct net_bridge *br = to_bridge(d); |
| 166 | char *endp; | 164 | char *endp; |
| @@ -180,10 +178,9 @@ static ssize_t store_group_fwd_mask(struct device *d, | |||
| 180 | 178 | ||
| 181 | return len; | 179 | return len; |
| 182 | } | 180 | } |
| 183 | static DEVICE_ATTR(group_fwd_mask, S_IRUGO | S_IWUSR, show_group_fwd_mask, | 181 | static DEVICE_ATTR_RW(group_fwd_mask); |
| 184 | store_group_fwd_mask); | ||
| 185 | 182 | ||
| 186 | static ssize_t show_priority(struct device *d, struct device_attribute *attr, | 183 | static ssize_t priority_show(struct device *d, struct device_attribute *attr, |
| 187 | char *buf) | 184 | char *buf) |
| 188 | { | 185 | { |
| 189 | struct net_bridge *br = to_bridge(d); | 186 | struct net_bridge *br = to_bridge(d); |
| @@ -197,93 +194,91 @@ static int set_priority(struct net_bridge *br, unsigned long val) | |||
| 197 | return 0; | 194 | return 0; |
| 198 | } | 195 | } |
| 199 | 196 | ||
| 200 | static ssize_t store_priority(struct device *d, struct device_attribute *attr, | 197 | static ssize_t priority_store(struct device *d, struct device_attribute *attr, |
| 201 | const char *buf, size_t len) | 198 | const char *buf, size_t len) |
| 202 | { | 199 | { |
| 203 | return store_bridge_parm(d, buf, len, set_priority); | 200 | return store_bridge_parm(d, buf, len, set_priority); |
| 204 | } | 201 | } |
| 205 | static DEVICE_ATTR(priority, S_IRUGO | S_IWUSR, show_priority, store_priority); | 202 | static DEVICE_ATTR_RW(priority); |
| 206 | 203 | ||
| 207 | static ssize_t show_root_id(struct device *d, struct device_attribute *attr, | 204 | static ssize_t root_id_show(struct device *d, struct device_attribute *attr, |
| 208 | char *buf) | 205 | char *buf) |
| 209 | { | 206 | { |
| 210 | return br_show_bridge_id(buf, &to_bridge(d)->designated_root); | 207 | return br_show_bridge_id(buf, &to_bridge(d)->designated_root); |
| 211 | } | 208 | } |
| 212 | static DEVICE_ATTR(root_id, S_IRUGO, show_root_id, NULL); | 209 | static DEVICE_ATTR_RO(root_id); |
| 213 | 210 | ||
| 214 | static ssize_t show_bridge_id(struct device *d, struct device_attribute *attr, | 211 | static ssize_t bridge_id_show(struct device *d, struct device_attribute *attr, |
| 215 | char *buf) | 212 | char *buf) |
| 216 | { | 213 | { |
| 217 | return br_show_bridge_id(buf, &to_bridge(d)->bridge_id); | 214 | return br_show_bridge_id(buf, &to_bridge(d)->bridge_id); |
| 218 | } | 215 | } |
| 219 | static DEVICE_ATTR(bridge_id, S_IRUGO, show_bridge_id, NULL); | 216 | static DEVICE_ATTR_RO(bridge_id); |
| 220 | 217 | ||
| 221 | static ssize_t show_root_port(struct device *d, struct device_attribute *attr, | 218 | static ssize_t root_port_show(struct device *d, struct device_attribute *attr, |
| 222 | char *buf) | 219 | char *buf) |
| 223 | { | 220 | { |
| 224 | return sprintf(buf, "%d\n", to_bridge(d)->root_port); | 221 | return sprintf(buf, "%d\n", to_bridge(d)->root_port); |
| 225 | } | 222 | } |
| 226 | static DEVICE_ATTR(root_port, S_IRUGO, show_root_port, NULL); | 223 | static DEVICE_ATTR_RO(root_port); |
| 227 | 224 | ||
| 228 | static ssize_t show_root_path_cost(struct device *d, | 225 | static ssize_t root_path_cost_show(struct device *d, |
| 229 | struct device_attribute *attr, char *buf) | 226 | struct device_attribute *attr, char *buf) |
| 230 | { | 227 | { |
| 231 | return sprintf(buf, "%d\n", to_bridge(d)->root_path_cost); | 228 | return sprintf(buf, "%d\n", to_bridge(d)->root_path_cost); |
| 232 | } | 229 | } |
| 233 | static DEVICE_ATTR(root_path_cost, S_IRUGO, show_root_path_cost, NULL); | 230 | static DEVICE_ATTR_RO(root_path_cost); |
| 234 | 231 | ||
| 235 | static ssize_t show_topology_change(struct device *d, | 232 | static ssize_t topology_change_show(struct device *d, |
| 236 | struct device_attribute *attr, char *buf) | 233 | struct device_attribute *attr, char *buf) |
| 237 | { | 234 | { |
| 238 | return sprintf(buf, "%d\n", to_bridge(d)->topology_change); | 235 | return sprintf(buf, "%d\n", to_bridge(d)->topology_change); |
| 239 | } | 236 | } |
| 240 | static DEVICE_ATTR(topology_change, S_IRUGO, show_topology_change, NULL); | 237 | static DEVICE_ATTR_RO(topology_change); |
| 241 | 238 | ||
| 242 | static ssize_t show_topology_change_detected(struct device *d, | 239 | static ssize_t topology_change_detected_show(struct device *d, |
| 243 | struct device_attribute *attr, | 240 | struct device_attribute *attr, |
| 244 | char *buf) | 241 | char *buf) |
| 245 | { | 242 | { |
| 246 | struct net_bridge *br = to_bridge(d); | 243 | struct net_bridge *br = to_bridge(d); |
| 247 | return sprintf(buf, "%d\n", br->topology_change_detected); | 244 | return sprintf(buf, "%d\n", br->topology_change_detected); |
| 248 | } | 245 | } |
| 249 | static DEVICE_ATTR(topology_change_detected, S_IRUGO, | 246 | static DEVICE_ATTR_RO(topology_change_detected); |
| 250 | show_topology_change_detected, NULL); | ||
| 251 | 247 | ||
| 252 | static ssize_t show_hello_timer(struct device *d, | 248 | static ssize_t hello_timer_show(struct device *d, |
| 253 | struct device_attribute *attr, char *buf) | 249 | struct device_attribute *attr, char *buf) |
| 254 | { | 250 | { |
| 255 | struct net_bridge *br = to_bridge(d); | 251 | struct net_bridge *br = to_bridge(d); |
| 256 | return sprintf(buf, "%ld\n", br_timer_value(&br->hello_timer)); | 252 | return sprintf(buf, "%ld\n", br_timer_value(&br->hello_timer)); |
| 257 | } | 253 | } |
| 258 | static DEVICE_ATTR(hello_timer, S_IRUGO, show_hello_timer, NULL); | 254 | static DEVICE_ATTR_RO(hello_timer); |
| 259 | 255 | ||
| 260 | static ssize_t show_tcn_timer(struct device *d, struct device_attribute *attr, | 256 | static ssize_t tcn_timer_show(struct device *d, struct device_attribute *attr, |
| 261 | char *buf) | 257 | char *buf) |
| 262 | { | 258 | { |
| 263 | struct net_bridge *br = to_bridge(d); | 259 | struct net_bridge *br = to_bridge(d); |
| 264 | return sprintf(buf, "%ld\n", br_timer_value(&br->tcn_timer)); | 260 | return sprintf(buf, "%ld\n", br_timer_value(&br->tcn_timer)); |
| 265 | } | 261 | } |
| 266 | static DEVICE_ATTR(tcn_timer, S_IRUGO, show_tcn_timer, NULL); | 262 | static DEVICE_ATTR_RO(tcn_timer); |
| 267 | 263 | ||
| 268 | static ssize_t show_topology_change_timer(struct device *d, | 264 | static ssize_t topology_change_timer_show(struct device *d, |
| 269 | struct device_attribute *attr, | 265 | struct device_attribute *attr, |
| 270 | char *buf) | 266 | char *buf) |
| 271 | { | 267 | { |
| 272 | struct net_bridge *br = to_bridge(d); | 268 | struct net_bridge *br = to_bridge(d); |
| 273 | return sprintf(buf, "%ld\n", br_timer_value(&br->topology_change_timer)); | 269 | return sprintf(buf, "%ld\n", br_timer_value(&br->topology_change_timer)); |
| 274 | } | 270 | } |
| 275 | static DEVICE_ATTR(topology_change_timer, S_IRUGO, show_topology_change_timer, | 271 | static DEVICE_ATTR_RO(topology_change_timer); |
| 276 | NULL); | ||
| 277 | 272 | ||
| 278 | static ssize_t show_gc_timer(struct device *d, struct device_attribute *attr, | 273 | static ssize_t gc_timer_show(struct device *d, struct device_attribute *attr, |
| 279 | char *buf) | 274 | char *buf) |
| 280 | { | 275 | { |
| 281 | struct net_bridge *br = to_bridge(d); | 276 | struct net_bridge *br = to_bridge(d); |
| 282 | return sprintf(buf, "%ld\n", br_timer_value(&br->gc_timer)); | 277 | return sprintf(buf, "%ld\n", br_timer_value(&br->gc_timer)); |
| 283 | } | 278 | } |
| 284 | static DEVICE_ATTR(gc_timer, S_IRUGO, show_gc_timer, NULL); | 279 | static DEVICE_ATTR_RO(gc_timer); |
| 285 | 280 | ||
| 286 | static ssize_t show_group_addr(struct device *d, | 281 | static ssize_t group_addr_show(struct device *d, |
| 287 | struct device_attribute *attr, char *buf) | 282 | struct device_attribute *attr, char *buf) |
| 288 | { | 283 | { |
| 289 | struct net_bridge *br = to_bridge(d); | 284 | struct net_bridge *br = to_bridge(d); |
| @@ -293,7 +288,7 @@ static ssize_t show_group_addr(struct device *d, | |||
| 293 | br->group_addr[4], br->group_addr[5]); | 288 | br->group_addr[4], br->group_addr[5]); |
| 294 | } | 289 | } |
| 295 | 290 | ||
| 296 | static ssize_t store_group_addr(struct device *d, | 291 | static ssize_t group_addr_store(struct device *d, |
| 297 | struct device_attribute *attr, | 292 | struct device_attribute *attr, |
| 298 | const char *buf, size_t len) | 293 | const char *buf, size_t len) |
| 299 | { | 294 | { |
| @@ -324,10 +319,9 @@ static ssize_t store_group_addr(struct device *d, | |||
| 324 | return len; | 319 | return len; |
| 325 | } | 320 | } |
| 326 | 321 | ||
| 327 | static DEVICE_ATTR(group_addr, S_IRUGO | S_IWUSR, | 322 | static DEVICE_ATTR_RW(group_addr); |
| 328 | show_group_addr, store_group_addr); | ||
| 329 | 323 | ||
| 330 | static ssize_t store_flush(struct device *d, | 324 | static ssize_t flush_store(struct device *d, |
| 331 | struct device_attribute *attr, | 325 | struct device_attribute *attr, |
| 332 | const char *buf, size_t len) | 326 | const char *buf, size_t len) |
| 333 | { | 327 | { |
| @@ -339,26 +333,25 @@ static ssize_t store_flush(struct device *d, | |||
| 339 | br_fdb_flush(br); | 333 | br_fdb_flush(br); |
| 340 | return len; | 334 | return len; |
| 341 | } | 335 | } |
| 342 | static DEVICE_ATTR(flush, S_IWUSR, NULL, store_flush); | 336 | static DEVICE_ATTR_WO(flush); |
| 343 | 337 | ||
| 344 | #ifdef CONFIG_BRIDGE_IGMP_SNOOPING | 338 | #ifdef CONFIG_BRIDGE_IGMP_SNOOPING |
| 345 | static ssize_t show_multicast_router(struct device *d, | 339 | static ssize_t multicast_router_show(struct device *d, |
| 346 | struct device_attribute *attr, char *buf) | 340 | struct device_attribute *attr, char *buf) |
| 347 | { | 341 | { |
| 348 | struct net_bridge *br = to_bridge(d); | 342 | struct net_bridge *br = to_bridge(d); |
| 349 | return sprintf(buf, "%d\n", br->multicast_router); | 343 | return sprintf(buf, "%d\n", br->multicast_router); |
| 350 | } | 344 | } |
| 351 | 345 | ||
| 352 | static ssize_t store_multicast_router(struct device *d, | 346 | static ssize_t multicast_router_store(struct device *d, |
| 353 | struct device_attribute *attr, | 347 | struct device_attribute *attr, |
| 354 | const char *buf, size_t len) | 348 | const char *buf, size_t len) |
| 355 | { | 349 | { |
| 356 | return store_bridge_parm(d, buf, len, br_multicast_set_router); | 350 | return store_bridge_parm(d, buf, len, br_multicast_set_router); |
| 357 | } | 351 | } |
| 358 | static DEVICE_ATTR(multicast_router, S_IRUGO | S_IWUSR, show_multicast_router, | 352 | static DEVICE_ATTR_RW(multicast_router); |
| 359 | store_multicast_router); | ||
| 360 | 353 | ||
| 361 | static ssize_t show_multicast_snooping(struct device *d, | 354 | static ssize_t multicast_snooping_show(struct device *d, |
| 362 | struct device_attribute *attr, | 355 | struct device_attribute *attr, |
| 363 | char *buf) | 356 | char *buf) |
| 364 | { | 357 | { |
| @@ -366,18 +359,17 @@ static ssize_t show_multicast_snooping(struct device *d, | |||
| 366 | return sprintf(buf, "%d\n", !br->multicast_disabled); | 359 | return sprintf(buf, "%d\n", !br->multicast_disabled); |
| 367 | } | 360 | } |
| 368 | 361 | ||
| 369 | static ssize_t store_multicast_snooping(struct device *d, | 362 | static ssize_t multicast_snooping_store(struct device *d, |
| 370 | struct device_attribute *attr, | 363 | struct device_attribute *attr, |
| 371 | const char *buf, size_t len) | 364 | const char *buf, size_t len) |
| 372 | { | 365 | { |
| 373 | return store_bridge_parm(d, buf, len, br_multicast_toggle); | 366 | return store_bridge_parm(d, buf, len, br_multicast_toggle); |
| 374 | } | 367 | } |
| 375 | static DEVICE_ATTR(multicast_snooping, S_IRUGO | S_IWUSR, | 368 | static DEVICE_ATTR_RW(multicast_snooping); |
| 376 | show_multicast_snooping, store_multicast_snooping); | ||
| 377 | 369 | ||
| 378 | static ssize_t show_multicast_query_use_ifaddr(struct device *d, | 370 | static ssize_t multicast_query_use_ifaddr_show(struct device *d, |
| 379 | struct device_attribute *attr, | 371 | struct device_attribute *attr, |
| 380 | char *buf) | 372 | char *buf) |
| 381 | { | 373 | { |
| 382 | struct net_bridge *br = to_bridge(d); | 374 | struct net_bridge *br = to_bridge(d); |
| 383 | return sprintf(buf, "%d\n", br->multicast_query_use_ifaddr); | 375 | return sprintf(buf, "%d\n", br->multicast_query_use_ifaddr); |
| @@ -390,17 +382,15 @@ static int set_query_use_ifaddr(struct net_bridge *br, unsigned long val) | |||
| 390 | } | 382 | } |
| 391 | 383 | ||
| 392 | static ssize_t | 384 | static ssize_t |
| 393 | store_multicast_query_use_ifaddr(struct device *d, | 385 | multicast_query_use_ifaddr_store(struct device *d, |
| 394 | struct device_attribute *attr, | 386 | struct device_attribute *attr, |
| 395 | const char *buf, size_t len) | 387 | const char *buf, size_t len) |
| 396 | { | 388 | { |
| 397 | return store_bridge_parm(d, buf, len, set_query_use_ifaddr); | 389 | return store_bridge_parm(d, buf, len, set_query_use_ifaddr); |
| 398 | } | 390 | } |
| 399 | static DEVICE_ATTR(multicast_query_use_ifaddr, S_IRUGO | S_IWUSR, | 391 | static DEVICE_ATTR_RW(multicast_query_use_ifaddr); |
| 400 | show_multicast_query_use_ifaddr, | ||
| 401 | store_multicast_query_use_ifaddr); | ||
| 402 | 392 | ||
| 403 | static ssize_t show_multicast_querier(struct device *d, | 393 | static ssize_t multicast_querier_show(struct device *d, |
| 404 | struct device_attribute *attr, | 394 | struct device_attribute *attr, |
| 405 | char *buf) | 395 | char *buf) |
| 406 | { | 396 | { |
| @@ -408,16 +398,15 @@ static ssize_t show_multicast_querier(struct device *d, | |||
| 408 | return sprintf(buf, "%d\n", br->multicast_querier); | 398 | return sprintf(buf, "%d\n", br->multicast_querier); |
| 409 | } | 399 | } |
| 410 | 400 | ||
| 411 | static ssize_t store_multicast_querier(struct device *d, | 401 | static ssize_t multicast_querier_store(struct device *d, |
| 412 | struct device_attribute *attr, | 402 | struct device_attribute *attr, |
| 413 | const char *buf, size_t len) | 403 | const char *buf, size_t len) |
| 414 | { | 404 | { |
| 415 | return store_bridge_parm(d, buf, len, br_multicast_set_querier); | 405 | return store_bridge_parm(d, buf, len, br_multicast_set_querier); |
| 416 | } | 406 | } |
| 417 | static DEVICE_ATTR(multicast_querier, S_IRUGO | S_IWUSR, | 407 | static DEVICE_ATTR_RW(multicast_querier); |
| 418 | show_multicast_querier, store_multicast_querier); | ||
| 419 | 408 | ||
| 420 | static ssize_t show_hash_elasticity(struct device *d, | 409 | static ssize_t hash_elasticity_show(struct device *d, |
| 421 | struct device_attribute *attr, char *buf) | 410 | struct device_attribute *attr, char *buf) |
| 422 | { | 411 | { |
| 423 | struct net_bridge *br = to_bridge(d); | 412 | struct net_bridge *br = to_bridge(d); |
| @@ -430,31 +419,29 @@ static int set_elasticity(struct net_bridge *br, unsigned long val) | |||
| 430 | return 0; | 419 | return 0; |
| 431 | } | 420 | } |
| 432 | 421 | ||
| 433 | static ssize_t store_hash_elasticity(struct device *d, | 422 | static ssize_t hash_elasticity_store(struct device *d, |
| 434 | struct device_attribute *attr, | 423 | struct device_attribute *attr, |
| 435 | const char *buf, size_t len) | 424 | const char *buf, size_t len) |
| 436 | { | 425 | { |
| 437 | return store_bridge_parm(d, buf, len, set_elasticity); | 426 | return store_bridge_parm(d, buf, len, set_elasticity); |
| 438 | } | 427 | } |
| 439 | static DEVICE_ATTR(hash_elasticity, S_IRUGO | S_IWUSR, show_hash_elasticity, | 428 | static DEVICE_ATTR_RW(hash_elasticity); |
| 440 | store_hash_elasticity); | ||
| 441 | 429 | ||
| 442 | static ssize_t show_hash_max(struct device *d, struct device_attribute *attr, | 430 | static ssize_t hash_max_show(struct device *d, struct device_attribute *attr, |
| 443 | char *buf) | 431 | char *buf) |
| 444 | { | 432 | { |
| 445 | struct net_bridge *br = to_bridge(d); | 433 | struct net_bridge *br = to_bridge(d); |
| 446 | return sprintf(buf, "%u\n", br->hash_max); | 434 | return sprintf(buf, "%u\n", br->hash_max); |
| 447 | } | 435 | } |
| 448 | 436 | ||
| 449 | static ssize_t store_hash_max(struct device *d, struct device_attribute *attr, | 437 | static ssize_t hash_max_store(struct device *d, struct device_attribute *attr, |
| 450 | const char *buf, size_t len) | 438 | const char *buf, size_t len) |
| 451 | { | 439 | { |
| 452 | return store_bridge_parm(d, buf, len, br_multicast_set_hash_max); | 440 | return store_bridge_parm(d, buf, len, br_multicast_set_hash_max); |
| 453 | } | 441 | } |
| 454 | static DEVICE_ATTR(hash_max, S_IRUGO | S_IWUSR, show_hash_max, | 442 | static DEVICE_ATTR_RW(hash_max); |
| 455 | store_hash_max); | ||
| 456 | 443 | ||
| 457 | static ssize_t show_multicast_last_member_count(struct device *d, | 444 | static ssize_t multicast_last_member_count_show(struct device *d, |
| 458 | struct device_attribute *attr, | 445 | struct device_attribute *attr, |
| 459 | char *buf) | 446 | char *buf) |
| 460 | { | 447 | { |
| @@ -468,17 +455,15 @@ static int set_last_member_count(struct net_bridge *br, unsigned long val) | |||
| 468 | return 0; | 455 | return 0; |
| 469 | } | 456 | } |
| 470 | 457 | ||
| 471 | static ssize_t store_multicast_last_member_count(struct device *d, | 458 | static ssize_t multicast_last_member_count_store(struct device *d, |
| 472 | struct device_attribute *attr, | 459 | struct device_attribute *attr, |
| 473 | const char *buf, size_t len) | 460 | const char *buf, size_t len) |
| 474 | { | 461 | { |
| 475 | return store_bridge_parm(d, buf, len, set_last_member_count); | 462 | return store_bridge_parm(d, buf, len, set_last_member_count); |
| 476 | } | 463 | } |
| 477 | static DEVICE_ATTR(multicast_last_member_count, S_IRUGO | S_IWUSR, | 464 | static DEVICE_ATTR_RW(multicast_last_member_count); |
| 478 | show_multicast_last_member_count, | ||
| 479 | store_multicast_last_member_count); | ||
| 480 | 465 | ||
| 481 | static ssize_t show_multicast_startup_query_count( | 466 | static ssize_t multicast_startup_query_count_show( |
| 482 | struct device *d, struct device_attribute *attr, char *buf) | 467 | struct device *d, struct device_attribute *attr, char *buf) |
| 483 | { | 468 | { |
| 484 | struct net_bridge *br = to_bridge(d); | 469 | struct net_bridge *br = to_bridge(d); |
| @@ -491,17 +476,15 @@ static int set_startup_query_count(struct net_bridge *br, unsigned long val) | |||
| 491 | return 0; | 476 | return 0; |
| 492 | } | 477 | } |
| 493 | 478 | ||
| 494 | static ssize_t store_multicast_startup_query_count( | 479 | static ssize_t multicast_startup_query_count_store( |
| 495 | struct device *d, struct device_attribute *attr, const char *buf, | 480 | struct device *d, struct device_attribute *attr, const char *buf, |
| 496 | size_t len) | 481 | size_t len) |
| 497 | { | 482 | { |
| 498 | return store_bridge_parm(d, buf, len, set_startup_query_count); | 483 | return store_bridge_parm(d, buf, len, set_startup_query_count); |
| 499 | } | 484 | } |
| 500 | static DEVICE_ATTR(multicast_startup_query_count, S_IRUGO | S_IWUSR, | 485 | static DEVICE_ATTR_RW(multicast_startup_query_count); |
| 501 | show_multicast_startup_query_count, | ||
| 502 | store_multicast_startup_query_count); | ||
| 503 | 486 | ||
| 504 | static ssize_t show_multicast_last_member_interval( | 487 | static ssize_t multicast_last_member_interval_show( |
| 505 | struct device *d, struct device_attribute *attr, char *buf) | 488 | struct device *d, struct device_attribute *attr, char *buf) |
| 506 | { | 489 | { |
| 507 | struct net_bridge *br = to_bridge(d); | 490 | struct net_bridge *br = to_bridge(d); |
| @@ -515,17 +498,15 @@ static int set_last_member_interval(struct net_bridge *br, unsigned long val) | |||
| 515 | return 0; | 498 | return 0; |
| 516 | } | 499 | } |
| 517 | 500 | ||
| 518 | static ssize_t store_multicast_last_member_interval( | 501 | static ssize_t multicast_last_member_interval_store( |
| 519 | struct device *d, struct device_attribute *attr, const char *buf, | 502 | struct device *d, struct device_attribute *attr, const char *buf, |
| 520 | size_t len) | 503 | size_t len) |
| 521 | { | 504 | { |
| 522 | return store_bridge_parm(d, buf, len, set_last_member_interval); | 505 | return store_bridge_parm(d, buf, len, set_last_member_interval); |
| 523 | } | 506 | } |
| 524 | static DEVICE_ATTR(multicast_last_member_interval, S_IRUGO | S_IWUSR, | 507 | static DEVICE_ATTR_RW(multicast_last_member_interval); |
| 525 | show_multicast_last_member_interval, | ||
| 526 | store_multicast_last_member_interval); | ||
| 527 | 508 | ||
| 528 | static ssize_t show_multicast_membership_interval( | 509 | static ssize_t multicast_membership_interval_show( |
| 529 | struct device *d, struct device_attribute *attr, char *buf) | 510 | struct device *d, struct device_attribute *attr, char *buf) |
| 530 | { | 511 | { |
| 531 | struct net_bridge *br = to_bridge(d); | 512 | struct net_bridge *br = to_bridge(d); |
| @@ -539,17 +520,15 @@ static int set_membership_interval(struct net_bridge *br, unsigned long val) | |||
| 539 | return 0; | 520 | return 0; |
| 540 | } | 521 | } |
| 541 | 522 | ||
| 542 | static ssize_t store_multicast_membership_interval( | 523 | static ssize_t multicast_membership_interval_store( |
| 543 | struct device *d, struct device_attribute *attr, const char *buf, | 524 | struct device *d, struct device_attribute *attr, const char *buf, |
| 544 | size_t len) | 525 | size_t len) |
| 545 | { | 526 | { |
| 546 | return store_bridge_parm(d, buf, len, set_membership_interval); | 527 | return store_bridge_parm(d, buf, len, set_membership_interval); |
| 547 | } | 528 | } |
| 548 | static DEVICE_ATTR(multicast_membership_interval, S_IRUGO | S_IWUSR, | 529 | static DEVICE_ATTR_RW(multicast_membership_interval); |
| 549 | show_multicast_membership_interval, | ||
| 550 | store_multicast_membership_interval); | ||
| 551 | 530 | ||
| 552 | static ssize_t show_multicast_querier_interval(struct device *d, | 531 | static ssize_t multicast_querier_interval_show(struct device *d, |
| 553 | struct device_attribute *attr, | 532 | struct device_attribute *attr, |
| 554 | char *buf) | 533 | char *buf) |
| 555 | { | 534 | { |
| @@ -564,17 +543,15 @@ static int set_querier_interval(struct net_bridge *br, unsigned long val) | |||
| 564 | return 0; | 543 | return 0; |
| 565 | } | 544 | } |
| 566 | 545 | ||
| 567 | static ssize_t store_multicast_querier_interval(struct device *d, | 546 | static ssize_t multicast_querier_interval_store(struct device *d, |
| 568 | struct device_attribute *attr, | 547 | struct device_attribute *attr, |
| 569 | const char *buf, size_t len) | 548 | const char *buf, size_t len) |
| 570 | { | 549 | { |
| 571 | return store_bridge_parm(d, buf, len, set_querier_interval); | 550 | return store_bridge_parm(d, buf, len, set_querier_interval); |
| 572 | } | 551 | } |
| 573 | static DEVICE_ATTR(multicast_querier_interval, S_IRUGO | S_IWUSR, | 552 | static DEVICE_ATTR_RW(multicast_querier_interval); |
| 574 | show_multicast_querier_interval, | ||
| 575 | store_multicast_querier_interval); | ||
| 576 | 553 | ||
| 577 | static ssize_t show_multicast_query_interval(struct device *d, | 554 | static ssize_t multicast_query_interval_show(struct device *d, |
| 578 | struct device_attribute *attr, | 555 | struct device_attribute *attr, |
| 579 | char *buf) | 556 | char *buf) |
| 580 | { | 557 | { |
| @@ -589,17 +566,15 @@ static int set_query_interval(struct net_bridge *br, unsigned long val) | |||
| 589 | return 0; | 566 | return 0; |
| 590 | } | 567 | } |
| 591 | 568 | ||
| 592 | static ssize_t store_multicast_query_interval(struct device *d, | 569 | static ssize_t multicast_query_interval_store(struct device *d, |
| 593 | struct device_attribute *attr, | 570 | struct device_attribute *attr, |
| 594 | const char *buf, size_t len) | 571 | const char *buf, size_t len) |
| 595 | { | 572 | { |
| 596 | return store_bridge_parm(d, buf, len, set_query_interval); | 573 | return store_bridge_parm(d, buf, len, set_query_interval); |
| 597 | } | 574 | } |
| 598 | static DEVICE_ATTR(multicast_query_interval, S_IRUGO | S_IWUSR, | 575 | static DEVICE_ATTR_RW(multicast_query_interval); |
| 599 | show_multicast_query_interval, | ||
| 600 | store_multicast_query_interval); | ||
| 601 | 576 | ||
| 602 | static ssize_t show_multicast_query_response_interval( | 577 | static ssize_t multicast_query_response_interval_show( |
| 603 | struct device *d, struct device_attribute *attr, char *buf) | 578 | struct device *d, struct device_attribute *attr, char *buf) |
| 604 | { | 579 | { |
| 605 | struct net_bridge *br = to_bridge(d); | 580 | struct net_bridge *br = to_bridge(d); |
| @@ -614,17 +589,15 @@ static int set_query_response_interval(struct net_bridge *br, unsigned long val) | |||
| 614 | return 0; | 589 | return 0; |
| 615 | } | 590 | } |
| 616 | 591 | ||
| 617 | static ssize_t store_multicast_query_response_interval( | 592 | static ssize_t multicast_query_response_interval_store( |
| 618 | struct device *d, struct device_attribute *attr, const char *buf, | 593 | struct device *d, struct device_attribute *attr, const char *buf, |
| 619 | size_t len) | 594 | size_t len) |
| 620 | { | 595 | { |
| 621 | return store_bridge_parm(d, buf, len, set_query_response_interval); | 596 | return store_bridge_parm(d, buf, len, set_query_response_interval); |
| 622 | } | 597 | } |
| 623 | static DEVICE_ATTR(multicast_query_response_interval, S_IRUGO | S_IWUSR, | 598 | static DEVICE_ATTR_RW(multicast_query_response_interval); |
| 624 | show_multicast_query_response_interval, | ||
| 625 | store_multicast_query_response_interval); | ||
| 626 | 599 | ||
| 627 | static ssize_t show_multicast_startup_query_interval( | 600 | static ssize_t multicast_startup_query_interval_show( |
| 628 | struct device *d, struct device_attribute *attr, char *buf) | 601 | struct device *d, struct device_attribute *attr, char *buf) |
| 629 | { | 602 | { |
| 630 | struct net_bridge *br = to_bridge(d); | 603 | struct net_bridge *br = to_bridge(d); |
| @@ -639,18 +612,16 @@ static int set_startup_query_interval(struct net_bridge *br, unsigned long val) | |||
| 639 | return 0; | 612 | return 0; |
| 640 | } | 613 | } |
| 641 | 614 | ||
| 642 | static ssize_t store_multicast_startup_query_interval( | 615 | static ssize_t multicast_startup_query_interval_store( |
| 643 | struct device *d, struct device_attribute *attr, const char *buf, | 616 | struct device *d, struct device_attribute *attr, const char *buf, |
| 644 | size_t len) | 617 | size_t len) |
| 645 | { | 618 | { |
| 646 | return store_bridge_parm(d, buf, len, set_startup_query_interval); | 619 | return store_bridge_parm(d, buf, len, set_startup_query_interval); |
| 647 | } | 620 | } |
| 648 | static DEVICE_ATTR(multicast_startup_query_interval, S_IRUGO | S_IWUSR, | 621 | static DEVICE_ATTR_RW(multicast_startup_query_interval); |
| 649 | show_multicast_startup_query_interval, | ||
| 650 | store_multicast_startup_query_interval); | ||
| 651 | #endif | 622 | #endif |
| 652 | #ifdef CONFIG_BRIDGE_NETFILTER | 623 | #ifdef CONFIG_BRIDGE_NETFILTER |
| 653 | static ssize_t show_nf_call_iptables( | 624 | static ssize_t nf_call_iptables_show( |
| 654 | struct device *d, struct device_attribute *attr, char *buf) | 625 | struct device *d, struct device_attribute *attr, char *buf) |
| 655 | { | 626 | { |
| 656 | struct net_bridge *br = to_bridge(d); | 627 | struct net_bridge *br = to_bridge(d); |
| @@ -663,16 +634,15 @@ static int set_nf_call_iptables(struct net_bridge *br, unsigned long val) | |||
| 663 | return 0; | 634 | return 0; |
| 664 | } | 635 | } |
| 665 | 636 | ||
| 666 | static ssize_t store_nf_call_iptables( | 637 | static ssize_t nf_call_iptables_store( |
| 667 | struct device *d, struct device_attribute *attr, const char *buf, | 638 | struct device *d, struct device_attribute *attr, const char *buf, |
| 668 | size_t len) | 639 | size_t len) |
| 669 | { | 640 | { |
| 670 | return store_bridge_parm(d, buf, len, set_nf_call_iptables); | 641 | return store_bridge_parm(d, buf, len, set_nf_call_iptables); |
| 671 | } | 642 | } |
| 672 | static DEVICE_ATTR(nf_call_iptables, S_IRUGO | S_IWUSR, | 643 | static DEVICE_ATTR_RW(nf_call_iptables); |
| 673 | show_nf_call_iptables, store_nf_call_iptables); | ||
| 674 | 644 | ||
| 675 | static ssize_t show_nf_call_ip6tables( | 645 | static ssize_t nf_call_ip6tables_show( |
| 676 | struct device *d, struct device_attribute *attr, char *buf) | 646 | struct device *d, struct device_attribute *attr, char *buf) |
| 677 | { | 647 | { |
| 678 | struct net_bridge *br = to_bridge(d); | 648 | struct net_bridge *br = to_bridge(d); |
| @@ -685,16 +655,15 @@ static int set_nf_call_ip6tables(struct net_bridge *br, unsigned long val) | |||
| 685 | return 0; | 655 | return 0; |
| 686 | } | 656 | } |
| 687 | 657 | ||
| 688 | static ssize_t store_nf_call_ip6tables( | 658 | static ssize_t nf_call_ip6tables_store( |
| 689 | struct device *d, struct device_attribute *attr, const char *buf, | 659 | struct device *d, struct device_attribute *attr, const char *buf, |
| 690 | size_t len) | 660 | size_t len) |
| 691 | { | 661 | { |
| 692 | return store_bridge_parm(d, buf, len, set_nf_call_ip6tables); | 662 | return store_bridge_parm(d, buf, len, set_nf_call_ip6tables); |
| 693 | } | 663 | } |
| 694 | static DEVICE_ATTR(nf_call_ip6tables, S_IRUGO | S_IWUSR, | 664 | static DEVICE_ATTR_RW(nf_call_ip6tables); |
| 695 | show_nf_call_ip6tables, store_nf_call_ip6tables); | ||
| 696 | 665 | ||
| 697 | static ssize_t show_nf_call_arptables( | 666 | static ssize_t nf_call_arptables_show( |
| 698 | struct device *d, struct device_attribute *attr, char *buf) | 667 | struct device *d, struct device_attribute *attr, char *buf) |
| 699 | { | 668 | { |
| 700 | struct net_bridge *br = to_bridge(d); | 669 | struct net_bridge *br = to_bridge(d); |
| @@ -707,17 +676,16 @@ static int set_nf_call_arptables(struct net_bridge *br, unsigned long val) | |||
| 707 | return 0; | 676 | return 0; |
| 708 | } | 677 | } |
| 709 | 678 | ||
| 710 | static ssize_t store_nf_call_arptables( | 679 | static ssize_t nf_call_arptables_store( |
| 711 | struct device *d, struct device_attribute *attr, const char *buf, | 680 | struct device *d, struct device_attribute *attr, const char *buf, |
| 712 | size_t len) | 681 | size_t len) |
| 713 | { | 682 | { |
| 714 | return store_bridge_parm(d, buf, len, set_nf_call_arptables); | 683 | return store_bridge_parm(d, buf, len, set_nf_call_arptables); |
| 715 | } | 684 | } |
| 716 | static DEVICE_ATTR(nf_call_arptables, S_IRUGO | S_IWUSR, | 685 | static DEVICE_ATTR_RW(nf_call_arptables); |
| 717 | show_nf_call_arptables, store_nf_call_arptables); | ||
| 718 | #endif | 686 | #endif |
| 719 | #ifdef CONFIG_BRIDGE_VLAN_FILTERING | 687 | #ifdef CONFIG_BRIDGE_VLAN_FILTERING |
| 720 | static ssize_t show_vlan_filtering(struct device *d, | 688 | static ssize_t vlan_filtering_show(struct device *d, |
| 721 | struct device_attribute *attr, | 689 | struct device_attribute *attr, |
| 722 | char *buf) | 690 | char *buf) |
| 723 | { | 691 | { |
| @@ -725,14 +693,13 @@ static ssize_t show_vlan_filtering(struct device *d, | |||
| 725 | return sprintf(buf, "%d\n", br->vlan_enabled); | 693 | return sprintf(buf, "%d\n", br->vlan_enabled); |
| 726 | } | 694 | } |
| 727 | 695 | ||
| 728 | static ssize_t store_vlan_filtering(struct device *d, | 696 | static ssize_t vlan_filtering_store(struct device *d, |
| 729 | struct device_attribute *attr, | 697 | struct device_attribute *attr, |
| 730 | const char *buf, size_t len) | 698 | const char *buf, size_t len) |
| 731 | { | 699 | { |
| 732 | return store_bridge_parm(d, buf, len, br_vlan_filter_toggle); | 700 | return store_bridge_parm(d, buf, len, br_vlan_filter_toggle); |
| 733 | } | 701 | } |
| 734 | static DEVICE_ATTR(vlan_filtering, S_IRUGO | S_IWUSR, | 702 | static DEVICE_ATTR_RW(vlan_filtering); |
| 735 | show_vlan_filtering, store_vlan_filtering); | ||
| 736 | #endif | 703 | #endif |
| 737 | 704 | ||
| 738 | static struct attribute *bridge_attrs[] = { | 705 | static struct attribute *bridge_attrs[] = { |
diff --git a/net/bridge/br_sysfs_if.c b/net/bridge/br_sysfs_if.c index 2a2cdb756d51..dd595bd7fa82 100644 --- a/net/bridge/br_sysfs_if.c +++ b/net/bridge/br_sysfs_if.c | |||
| @@ -26,7 +26,7 @@ struct brport_attribute { | |||
| 26 | int (*store)(struct net_bridge_port *, unsigned long); | 26 | int (*store)(struct net_bridge_port *, unsigned long); |
| 27 | }; | 27 | }; |
| 28 | 28 | ||
| 29 | #define BRPORT_ATTR(_name,_mode,_show,_store) \ | 29 | #define BRPORT_ATTR(_name, _mode, _show, _store) \ |
| 30 | const struct brport_attribute brport_attr_##_name = { \ | 30 | const struct brport_attribute brport_attr_##_name = { \ |
| 31 | .attr = {.name = __stringify(_name), \ | 31 | .attr = {.name = __stringify(_name), \ |
| 32 | .mode = _mode }, \ | 32 | .mode = _mode }, \ |
| @@ -209,21 +209,21 @@ static const struct brport_attribute *brport_attrs[] = { | |||
| 209 | #define to_brport_attr(_at) container_of(_at, struct brport_attribute, attr) | 209 | #define to_brport_attr(_at) container_of(_at, struct brport_attribute, attr) |
| 210 | #define to_brport(obj) container_of(obj, struct net_bridge_port, kobj) | 210 | #define to_brport(obj) container_of(obj, struct net_bridge_port, kobj) |
| 211 | 211 | ||
| 212 | static ssize_t brport_show(struct kobject * kobj, | 212 | static ssize_t brport_show(struct kobject *kobj, |
| 213 | struct attribute * attr, char * buf) | 213 | struct attribute *attr, char *buf) |
| 214 | { | 214 | { |
| 215 | struct brport_attribute * brport_attr = to_brport_attr(attr); | 215 | struct brport_attribute *brport_attr = to_brport_attr(attr); |
| 216 | struct net_bridge_port * p = to_brport(kobj); | 216 | struct net_bridge_port *p = to_brport(kobj); |
| 217 | 217 | ||
| 218 | return brport_attr->show(p, buf); | 218 | return brport_attr->show(p, buf); |
| 219 | } | 219 | } |
| 220 | 220 | ||
| 221 | static ssize_t brport_store(struct kobject * kobj, | 221 | static ssize_t brport_store(struct kobject *kobj, |
| 222 | struct attribute * attr, | 222 | struct attribute *attr, |
| 223 | const char * buf, size_t count) | 223 | const char *buf, size_t count) |
| 224 | { | 224 | { |
| 225 | struct brport_attribute * brport_attr = to_brport_attr(attr); | 225 | struct brport_attribute *brport_attr = to_brport_attr(attr); |
| 226 | struct net_bridge_port * p = to_brport(kobj); | 226 | struct net_bridge_port *p = to_brport(kobj); |
| 227 | ssize_t ret = -EINVAL; | 227 | ssize_t ret = -EINVAL; |
| 228 | char *endp; | 228 | char *endp; |
| 229 | unsigned long val; | 229 | unsigned long val; |
diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c index af5ebd18d705..4ca4d0a0151c 100644 --- a/net/bridge/br_vlan.c +++ b/net/bridge/br_vlan.c | |||
| @@ -146,32 +146,11 @@ struct sk_buff *br_handle_vlan(struct net_bridge *br, | |||
| 146 | 146 | ||
| 147 | /* At this point, we know that the frame was filtered and contains | 147 | /* At this point, we know that the frame was filtered and contains |
| 148 | * a valid vlan id. If the vlan id is set in the untagged bitmap, | 148 | * a valid vlan id. If the vlan id is set in the untagged bitmap, |
| 149 | * send untagged; otherwise, send taged. | 149 | * send untagged; otherwise, send tagged. |
| 150 | */ | 150 | */ |
| 151 | br_vlan_get_tag(skb, &vid); | 151 | br_vlan_get_tag(skb, &vid); |
| 152 | if (test_bit(vid, pv->untagged_bitmap)) | 152 | if (test_bit(vid, pv->untagged_bitmap)) |
| 153 | skb = br_vlan_untag(skb); | 153 | skb = br_vlan_untag(skb); |
| 154 | else { | ||
| 155 | /* Egress policy says "send tagged". If output device | ||
| 156 | * is the bridge, we need to add the VLAN header | ||
| 157 | * ourselves since we'll be going through the RX path. | ||
| 158 | * Sending to ports puts the frame on the TX path and | ||
| 159 | * we let dev_hard_start_xmit() add the header. | ||
| 160 | */ | ||
| 161 | if (skb->protocol != htons(ETH_P_8021Q) && | ||
| 162 | pv->port_idx == 0) { | ||
| 163 | /* vlan_put_tag expects skb->data to point to | ||
| 164 | * mac header. | ||
| 165 | */ | ||
| 166 | skb_push(skb, ETH_HLEN); | ||
| 167 | skb = __vlan_put_tag(skb, skb->vlan_proto, skb->vlan_tci); | ||
| 168 | if (!skb) | ||
| 169 | goto out; | ||
| 170 | /* put skb->data back to where it was */ | ||
| 171 | skb_pull(skb, ETH_HLEN); | ||
| 172 | skb->vlan_tci = 0; | ||
| 173 | } | ||
| 174 | } | ||
| 175 | 154 | ||
| 176 | out: | 155 | out: |
| 177 | return skb; | 156 | return skb; |
diff --git a/net/bridge/netfilter/ebt_log.c b/net/bridge/netfilter/ebt_log.c index 19c37a4929bc..5322a36867a3 100644 --- a/net/bridge/netfilter/ebt_log.c +++ b/net/bridge/netfilter/ebt_log.c | |||
| @@ -96,7 +96,7 @@ ebt_log_packet(struct net *net, u_int8_t pf, unsigned int hooknum, | |||
| 96 | bitmask = NF_LOG_MASK; | 96 | bitmask = NF_LOG_MASK; |
| 97 | 97 | ||
| 98 | if ((bitmask & EBT_LOG_IP) && eth_hdr(skb)->h_proto == | 98 | if ((bitmask & EBT_LOG_IP) && eth_hdr(skb)->h_proto == |
| 99 | htons(ETH_P_IP)){ | 99 | htons(ETH_P_IP)) { |
| 100 | const struct iphdr *ih; | 100 | const struct iphdr *ih; |
| 101 | struct iphdr _iph; | 101 | struct iphdr _iph; |
| 102 | 102 | ||
diff --git a/net/bridge/netfilter/ebt_snat.c b/net/bridge/netfilter/ebt_snat.c index f8f0bd1a1d51..0f6b118d6cb2 100644 --- a/net/bridge/netfilter/ebt_snat.c +++ b/net/bridge/netfilter/ebt_snat.c | |||
| @@ -35,7 +35,7 @@ ebt_snat_tg(struct sk_buff *skb, const struct xt_action_param *par) | |||
| 35 | return EBT_DROP; | 35 | return EBT_DROP; |
| 36 | if (ap->ar_hln != ETH_ALEN) | 36 | if (ap->ar_hln != ETH_ALEN) |
| 37 | goto out; | 37 | goto out; |
| 38 | if (skb_store_bits(skb, sizeof(_ah), info->mac,ETH_ALEN)) | 38 | if (skb_store_bits(skb, sizeof(_ah), info->mac, ETH_ALEN)) |
| 39 | return EBT_DROP; | 39 | return EBT_DROP; |
| 40 | } | 40 | } |
| 41 | out: | 41 | out: |
diff --git a/net/bridge/netfilter/ebt_vlan.c b/net/bridge/netfilter/ebt_vlan.c index eae67bf0446c..8d3f8c7651f0 100644 --- a/net/bridge/netfilter/ebt_vlan.c +++ b/net/bridge/netfilter/ebt_vlan.c | |||
| @@ -14,8 +14,7 @@ | |||
| 14 | * GNU General Public License for more details. | 14 | * GNU General Public License for more details. |
| 15 | * | 15 | * |
| 16 | * You should have received a copy of the GNU General Public License | 16 | * You should have received a copy of the GNU General Public License |
| 17 | * along with this program; if not, write to the Free Software | 17 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 19 | */ | 18 | */ |
| 20 | 19 | ||
| 21 | #include <linux/if_ether.h> | 20 | #include <linux/if_ether.h> |
diff --git a/net/bridge/netfilter/ebtable_broute.c b/net/bridge/netfilter/ebtable_broute.c index dbd1c783431b..d2cdf5d6e98c 100644 --- a/net/bridge/netfilter/ebtable_broute.c +++ b/net/bridge/netfilter/ebtable_broute.c | |||
| @@ -23,8 +23,7 @@ static struct ebt_entries initial_chain = { | |||
| 23 | .policy = EBT_ACCEPT, | 23 | .policy = EBT_ACCEPT, |
| 24 | }; | 24 | }; |
| 25 | 25 | ||
| 26 | static struct ebt_replace_kernel initial_table = | 26 | static struct ebt_replace_kernel initial_table = { |
| 27 | { | ||
| 28 | .name = "broute", | 27 | .name = "broute", |
| 29 | .valid_hooks = 1 << NF_BR_BROUTING, | 28 | .valid_hooks = 1 << NF_BR_BROUTING, |
| 30 | .entries_size = sizeof(struct ebt_entries), | 29 | .entries_size = sizeof(struct ebt_entries), |
| @@ -41,8 +40,7 @@ static int check(const struct ebt_table_info *info, unsigned int valid_hooks) | |||
| 41 | return 0; | 40 | return 0; |
| 42 | } | 41 | } |
| 43 | 42 | ||
| 44 | static const struct ebt_table broute_table = | 43 | static const struct ebt_table broute_table = { |
| 45 | { | ||
| 46 | .name = "broute", | 44 | .name = "broute", |
| 47 | .table = &initial_table, | 45 | .table = &initial_table, |
| 48 | .valid_hooks = 1 << NF_BR_BROUTING, | 46 | .valid_hooks = 1 << NF_BR_BROUTING, |
diff --git a/net/bridge/netfilter/ebtable_filter.c b/net/bridge/netfilter/ebtable_filter.c index bb2da7b706e7..ce205aabf9c5 100644 --- a/net/bridge/netfilter/ebtable_filter.c +++ b/net/bridge/netfilter/ebtable_filter.c | |||
| @@ -14,8 +14,7 @@ | |||
| 14 | #define FILTER_VALID_HOOKS ((1 << NF_BR_LOCAL_IN) | (1 << NF_BR_FORWARD) | \ | 14 | #define FILTER_VALID_HOOKS ((1 << NF_BR_LOCAL_IN) | (1 << NF_BR_FORWARD) | \ |
| 15 | (1 << NF_BR_LOCAL_OUT)) | 15 | (1 << NF_BR_LOCAL_OUT)) |
| 16 | 16 | ||
| 17 | static struct ebt_entries initial_chains[] = | 17 | static struct ebt_entries initial_chains[] = { |
| 18 | { | ||
| 19 | { | 18 | { |
| 20 | .name = "INPUT", | 19 | .name = "INPUT", |
| 21 | .policy = EBT_ACCEPT, | 20 | .policy = EBT_ACCEPT, |
| @@ -30,8 +29,7 @@ static struct ebt_entries initial_chains[] = | |||
| 30 | }, | 29 | }, |
| 31 | }; | 30 | }; |
| 32 | 31 | ||
| 33 | static struct ebt_replace_kernel initial_table = | 32 | static struct ebt_replace_kernel initial_table = { |
| 34 | { | ||
| 35 | .name = "filter", | 33 | .name = "filter", |
| 36 | .valid_hooks = FILTER_VALID_HOOKS, | 34 | .valid_hooks = FILTER_VALID_HOOKS, |
| 37 | .entries_size = 3 * sizeof(struct ebt_entries), | 35 | .entries_size = 3 * sizeof(struct ebt_entries), |
| @@ -50,8 +48,7 @@ static int check(const struct ebt_table_info *info, unsigned int valid_hooks) | |||
| 50 | return 0; | 48 | return 0; |
| 51 | } | 49 | } |
| 52 | 50 | ||
| 53 | static const struct ebt_table frame_filter = | 51 | static const struct ebt_table frame_filter = { |
| 54 | { | ||
| 55 | .name = "filter", | 52 | .name = "filter", |
| 56 | .table = &initial_table, | 53 | .table = &initial_table, |
| 57 | .valid_hooks = FILTER_VALID_HOOKS, | 54 | .valid_hooks = FILTER_VALID_HOOKS, |
diff --git a/net/bridge/netfilter/ebtable_nat.c b/net/bridge/netfilter/ebtable_nat.c index bd238f1f105b..a0ac2984fb6c 100644 --- a/net/bridge/netfilter/ebtable_nat.c +++ b/net/bridge/netfilter/ebtable_nat.c | |||
| @@ -14,8 +14,7 @@ | |||
| 14 | #define NAT_VALID_HOOKS ((1 << NF_BR_PRE_ROUTING) | (1 << NF_BR_LOCAL_OUT) | \ | 14 | #define NAT_VALID_HOOKS ((1 << NF_BR_PRE_ROUTING) | (1 << NF_BR_LOCAL_OUT) | \ |
| 15 | (1 << NF_BR_POST_ROUTING)) | 15 | (1 << NF_BR_POST_ROUTING)) |
| 16 | 16 | ||
| 17 | static struct ebt_entries initial_chains[] = | 17 | static struct ebt_entries initial_chains[] = { |
| 18 | { | ||
| 19 | { | 18 | { |
| 20 | .name = "PREROUTING", | 19 | .name = "PREROUTING", |
| 21 | .policy = EBT_ACCEPT, | 20 | .policy = EBT_ACCEPT, |
| @@ -30,8 +29,7 @@ static struct ebt_entries initial_chains[] = | |||
| 30 | } | 29 | } |
| 31 | }; | 30 | }; |
| 32 | 31 | ||
| 33 | static struct ebt_replace_kernel initial_table = | 32 | static struct ebt_replace_kernel initial_table = { |
| 34 | { | ||
| 35 | .name = "nat", | 33 | .name = "nat", |
| 36 | .valid_hooks = NAT_VALID_HOOKS, | 34 | .valid_hooks = NAT_VALID_HOOKS, |
| 37 | .entries_size = 3 * sizeof(struct ebt_entries), | 35 | .entries_size = 3 * sizeof(struct ebt_entries), |
| @@ -50,8 +48,7 @@ static int check(const struct ebt_table_info *info, unsigned int valid_hooks) | |||
| 50 | return 0; | 48 | return 0; |
| 51 | } | 49 | } |
| 52 | 50 | ||
| 53 | static struct ebt_table frame_nat = | 51 | static struct ebt_table frame_nat = { |
| 54 | { | ||
| 55 | .name = "nat", | 52 | .name = "nat", |
| 56 | .table = &initial_table, | 53 | .table = &initial_table, |
| 57 | .valid_hooks = NAT_VALID_HOOKS, | 54 | .valid_hooks = NAT_VALID_HOOKS, |
diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c index ac7802428384..0e474b13463b 100644 --- a/net/bridge/netfilter/ebtables.c +++ b/net/bridge/netfilter/ebtables.c | |||
| @@ -118,10 +118,10 @@ ebt_dev_check(const char *entry, const struct net_device *device) | |||
| 118 | /* 1 is the wildcard token */ | 118 | /* 1 is the wildcard token */ |
| 119 | while (entry[i] != '\0' && entry[i] != 1 && entry[i] == devname[i]) | 119 | while (entry[i] != '\0' && entry[i] != 1 && entry[i] == devname[i]) |
| 120 | i++; | 120 | i++; |
| 121 | return (devname[i] != entry[i] && entry[i] != 1); | 121 | return devname[i] != entry[i] && entry[i] != 1; |
| 122 | } | 122 | } |
| 123 | 123 | ||
| 124 | #define FWINV2(bool,invflg) ((bool) ^ !!(e->invflags & invflg)) | 124 | #define FWINV2(bool, invflg) ((bool) ^ !!(e->invflags & invflg)) |
| 125 | /* process standard matches */ | 125 | /* process standard matches */ |
| 126 | static inline int | 126 | static inline int |
| 127 | ebt_basic_match(const struct ebt_entry *e, const struct sk_buff *skb, | 127 | ebt_basic_match(const struct ebt_entry *e, const struct sk_buff *skb, |
| @@ -1441,7 +1441,7 @@ static int copy_everything_to_user(struct ebt_table *t, void __user *user, | |||
| 1441 | return -EFAULT; | 1441 | return -EFAULT; |
| 1442 | 1442 | ||
| 1443 | if (*len != sizeof(struct ebt_replace) + entries_size + | 1443 | if (*len != sizeof(struct ebt_replace) + entries_size + |
| 1444 | (tmp.num_counters? nentries * sizeof(struct ebt_counter): 0)) | 1444 | (tmp.num_counters ? nentries * sizeof(struct ebt_counter) : 0)) |
| 1445 | return -EINVAL; | 1445 | return -EINVAL; |
| 1446 | 1446 | ||
| 1447 | if (tmp.nentries != nentries) { | 1447 | if (tmp.nentries != nentries) { |
| @@ -1477,7 +1477,7 @@ static int do_ebt_set_ctl(struct sock *sk, | |||
| 1477 | if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) | 1477 | if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) |
| 1478 | return -EPERM; | 1478 | return -EPERM; |
| 1479 | 1479 | ||
| 1480 | switch(cmd) { | 1480 | switch (cmd) { |
| 1481 | case EBT_SO_SET_ENTRIES: | 1481 | case EBT_SO_SET_ENTRIES: |
| 1482 | ret = do_replace(net, user, len); | 1482 | ret = do_replace(net, user, len); |
| 1483 | break; | 1483 | break; |
| @@ -1507,10 +1507,10 @@ static int do_ebt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) | |||
| 1507 | if (!t) | 1507 | if (!t) |
| 1508 | return ret; | 1508 | return ret; |
| 1509 | 1509 | ||
| 1510 | switch(cmd) { | 1510 | switch (cmd) { |
| 1511 | case EBT_SO_GET_INFO: | 1511 | case EBT_SO_GET_INFO: |
| 1512 | case EBT_SO_GET_INIT_INFO: | 1512 | case EBT_SO_GET_INIT_INFO: |
| 1513 | if (*len != sizeof(struct ebt_replace)){ | 1513 | if (*len != sizeof(struct ebt_replace)) { |
| 1514 | ret = -EINVAL; | 1514 | ret = -EINVAL; |
| 1515 | mutex_unlock(&ebt_mutex); | 1515 | mutex_unlock(&ebt_mutex); |
| 1516 | break; | 1516 | break; |
| @@ -1525,7 +1525,7 @@ static int do_ebt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) | |||
| 1525 | tmp.valid_hooks = t->table->valid_hooks; | 1525 | tmp.valid_hooks = t->table->valid_hooks; |
| 1526 | } | 1526 | } |
| 1527 | mutex_unlock(&ebt_mutex); | 1527 | mutex_unlock(&ebt_mutex); |
| 1528 | if (copy_to_user(user, &tmp, *len) != 0){ | 1528 | if (copy_to_user(user, &tmp, *len) != 0) { |
| 1529 | BUGPRINT("c2u Didn't work\n"); | 1529 | BUGPRINT("c2u Didn't work\n"); |
| 1530 | ret = -EFAULT; | 1530 | ret = -EFAULT; |
| 1531 | break; | 1531 | break; |
| @@ -2375,8 +2375,7 @@ static int compat_do_ebt_get_ctl(struct sock *sk, int cmd, | |||
| 2375 | } | 2375 | } |
| 2376 | #endif | 2376 | #endif |
| 2377 | 2377 | ||
| 2378 | static struct nf_sockopt_ops ebt_sockopts = | 2378 | static struct nf_sockopt_ops ebt_sockopts = { |
| 2379 | { | ||
| 2380 | .pf = PF_INET, | 2379 | .pf = PF_INET, |
| 2381 | .set_optmin = EBT_BASE_CTL, | 2380 | .set_optmin = EBT_BASE_CTL, |
| 2382 | .set_optmax = EBT_SO_SET_MAX + 1, | 2381 | .set_optmax = EBT_SO_SET_MAX + 1, |
diff --git a/net/bridge/netfilter/nf_tables_bridge.c b/net/bridge/netfilter/nf_tables_bridge.c index cf54b22818c8..5bcc0d8b31f2 100644 --- a/net/bridge/netfilter/nf_tables_bridge.c +++ b/net/bridge/netfilter/nf_tables_bridge.c | |||
| @@ -14,10 +14,30 @@ | |||
| 14 | #include <linux/netfilter_bridge.h> | 14 | #include <linux/netfilter_bridge.h> |
| 15 | #include <net/netfilter/nf_tables.h> | 15 | #include <net/netfilter/nf_tables.h> |
| 16 | 16 | ||
| 17 | static unsigned int | ||
| 18 | nft_do_chain_bridge(const struct nf_hook_ops *ops, | ||
| 19 | struct sk_buff *skb, | ||
| 20 | const struct net_device *in, | ||
| 21 | const struct net_device *out, | ||
| 22 | int (*okfn)(struct sk_buff *)) | ||
| 23 | { | ||
| 24 | struct nft_pktinfo pkt; | ||
| 25 | |||
| 26 | nft_set_pktinfo(&pkt, ops, skb, in, out); | ||
| 27 | |||
| 28 | return nft_do_chain(&pkt, ops); | ||
| 29 | } | ||
| 30 | |||
| 17 | static struct nft_af_info nft_af_bridge __read_mostly = { | 31 | static struct nft_af_info nft_af_bridge __read_mostly = { |
| 18 | .family = NFPROTO_BRIDGE, | 32 | .family = NFPROTO_BRIDGE, |
| 19 | .nhooks = NF_BR_NUMHOOKS, | 33 | .nhooks = NF_BR_NUMHOOKS, |
| 20 | .owner = THIS_MODULE, | 34 | .owner = THIS_MODULE, |
| 35 | .nops = 1, | ||
| 36 | .hooks = { | ||
| 37 | [NF_BR_LOCAL_IN] = nft_do_chain_bridge, | ||
| 38 | [NF_BR_FORWARD] = nft_do_chain_bridge, | ||
| 39 | [NF_BR_LOCAL_OUT] = nft_do_chain_bridge, | ||
| 40 | }, | ||
| 21 | }; | 41 | }; |
| 22 | 42 | ||
| 23 | static int nf_tables_bridge_init_net(struct net *net) | 43 | static int nf_tables_bridge_init_net(struct net *net) |
| @@ -48,32 +68,14 @@ static struct pernet_operations nf_tables_bridge_net_ops = { | |||
| 48 | .exit = nf_tables_bridge_exit_net, | 68 | .exit = nf_tables_bridge_exit_net, |
| 49 | }; | 69 | }; |
| 50 | 70 | ||
| 51 | static unsigned int | 71 | static const struct nf_chain_type filter_bridge = { |
| 52 | nft_do_chain_bridge(const struct nf_hook_ops *ops, | ||
| 53 | struct sk_buff *skb, | ||
| 54 | const struct net_device *in, | ||
| 55 | const struct net_device *out, | ||
| 56 | int (*okfn)(struct sk_buff *)) | ||
| 57 | { | ||
| 58 | struct nft_pktinfo pkt; | ||
| 59 | |||
| 60 | nft_set_pktinfo(&pkt, ops, skb, in, out); | ||
| 61 | |||
| 62 | return nft_do_chain_pktinfo(&pkt, ops); | ||
| 63 | } | ||
| 64 | |||
| 65 | static struct nf_chain_type filter_bridge = { | ||
| 66 | .family = NFPROTO_BRIDGE, | ||
| 67 | .name = "filter", | 72 | .name = "filter", |
| 68 | .type = NFT_CHAIN_T_DEFAULT, | 73 | .type = NFT_CHAIN_T_DEFAULT, |
| 74 | .family = NFPROTO_BRIDGE, | ||
| 75 | .owner = THIS_MODULE, | ||
| 69 | .hook_mask = (1 << NF_BR_LOCAL_IN) | | 76 | .hook_mask = (1 << NF_BR_LOCAL_IN) | |
| 70 | (1 << NF_BR_FORWARD) | | 77 | (1 << NF_BR_FORWARD) | |
| 71 | (1 << NF_BR_LOCAL_OUT), | 78 | (1 << NF_BR_LOCAL_OUT), |
| 72 | .fn = { | ||
| 73 | [NF_BR_LOCAL_IN] = nft_do_chain_bridge, | ||
| 74 | [NF_BR_FORWARD] = nft_do_chain_bridge, | ||
| 75 | [NF_BR_LOCAL_OUT] = nft_do_chain_bridge, | ||
| 76 | }, | ||
| 77 | }; | 79 | }; |
| 78 | 80 | ||
| 79 | static int __init nf_tables_bridge_init(void) | 81 | static int __init nf_tables_bridge_init(void) |
diff --git a/net/caif/caif_usb.c b/net/caif/caif_usb.c index 75ed04b78fa4..ba02db022900 100644 --- a/net/caif/caif_usb.c +++ b/net/caif/caif_usb.c | |||
| @@ -14,6 +14,7 @@ | |||
| 14 | #include <linux/mii.h> | 14 | #include <linux/mii.h> |
| 15 | #include <linux/usb.h> | 15 | #include <linux/usb.h> |
| 16 | #include <linux/usb/usbnet.h> | 16 | #include <linux/usb/usbnet.h> |
| 17 | #include <linux/etherdevice.h> | ||
| 17 | #include <net/netns/generic.h> | 18 | #include <net/netns/generic.h> |
| 18 | #include <net/caif/caif_dev.h> | 19 | #include <net/caif/caif_dev.h> |
| 19 | #include <net/caif/caif_layer.h> | 20 | #include <net/caif/caif_layer.h> |
| @@ -105,8 +106,8 @@ static struct cflayer *cfusbl_create(int phyid, u8 ethaddr[ETH_ALEN], | |||
| 105 | * 5-11 source address | 106 | * 5-11 source address |
| 106 | * 12-13 protocol type | 107 | * 12-13 protocol type |
| 107 | */ | 108 | */ |
| 108 | memcpy(&this->tx_eth_hdr[ETH_ALEN], braddr, ETH_ALEN); | 109 | ether_addr_copy(&this->tx_eth_hdr[ETH_ALEN], braddr); |
| 109 | memcpy(&this->tx_eth_hdr[ETH_ALEN], ethaddr, ETH_ALEN); | 110 | ether_addr_copy(&this->tx_eth_hdr[ETH_ALEN], ethaddr); |
| 110 | this->tx_eth_hdr[12] = cpu_to_be16(ETH_P_802_EX1) & 0xff; | 111 | this->tx_eth_hdr[12] = cpu_to_be16(ETH_P_802_EX1) & 0xff; |
| 111 | this->tx_eth_hdr[13] = (cpu_to_be16(ETH_P_802_EX1) >> 8) & 0xff; | 112 | this->tx_eth_hdr[13] = (cpu_to_be16(ETH_P_802_EX1) >> 8) & 0xff; |
| 112 | pr_debug("caif ethernet TX-header dst:%pM src:%pM type:%02x%02x\n", | 113 | pr_debug("caif ethernet TX-header dst:%pM src:%pM type:%02x%02x\n", |
diff --git a/net/caif/chnl_net.c b/net/caif/chnl_net.c index 7344a8fa1bb0..4589ff67bfa9 100644 --- a/net/caif/chnl_net.c +++ b/net/caif/chnl_net.c | |||
| @@ -285,7 +285,7 @@ static int chnl_net_open(struct net_device *dev) | |||
| 285 | goto error; | 285 | goto error; |
| 286 | } | 286 | } |
| 287 | 287 | ||
| 288 | lldev = dev_get_by_index(dev_net(dev), llifindex); | 288 | lldev = __dev_get_by_index(dev_net(dev), llifindex); |
| 289 | 289 | ||
| 290 | if (lldev == NULL) { | 290 | if (lldev == NULL) { |
| 291 | pr_debug("no interface?\n"); | 291 | pr_debug("no interface?\n"); |
| @@ -307,7 +307,6 @@ static int chnl_net_open(struct net_device *dev) | |||
| 307 | mtu = min_t(int, dev->mtu, lldev->mtu - (headroom + tailroom)); | 307 | mtu = min_t(int, dev->mtu, lldev->mtu - (headroom + tailroom)); |
| 308 | mtu = min_t(int, GPRS_PDP_MTU, mtu); | 308 | mtu = min_t(int, GPRS_PDP_MTU, mtu); |
| 309 | dev_set_mtu(dev, mtu); | 309 | dev_set_mtu(dev, mtu); |
| 310 | dev_put(lldev); | ||
| 311 | 310 | ||
| 312 | if (mtu < 100) { | 311 | if (mtu < 100) { |
| 313 | pr_warn("CAIF Interface MTU too small (%d)\n", mtu); | 312 | pr_warn("CAIF Interface MTU too small (%d)\n", mtu); |
diff --git a/net/can/bcm.c b/net/can/bcm.c index 46f20bfafc0e..3fc737b214c7 100644 --- a/net/can/bcm.c +++ b/net/can/bcm.c | |||
| @@ -1256,8 +1256,7 @@ static int bcm_sendmsg(struct kiocb *iocb, struct socket *sock, | |||
| 1256 | 1256 | ||
| 1257 | if (!ifindex && msg->msg_name) { | 1257 | if (!ifindex && msg->msg_name) { |
| 1258 | /* no bound device as default => check msg_name */ | 1258 | /* no bound device as default => check msg_name */ |
| 1259 | struct sockaddr_can *addr = | 1259 | DECLARE_SOCKADDR(struct sockaddr_can *, addr, msg->msg_name); |
| 1260 | (struct sockaddr_can *)msg->msg_name; | ||
| 1261 | 1260 | ||
| 1262 | if (msg->msg_namelen < sizeof(*addr)) | 1261 | if (msg->msg_namelen < sizeof(*addr)) |
| 1263 | return -EINVAL; | 1262 | return -EINVAL; |
| @@ -1568,6 +1567,7 @@ static int bcm_recvmsg(struct kiocb *iocb, struct socket *sock, | |||
| 1568 | sock_recv_ts_and_drops(msg, sk, skb); | 1567 | sock_recv_ts_and_drops(msg, sk, skb); |
| 1569 | 1568 | ||
| 1570 | if (msg->msg_name) { | 1569 | if (msg->msg_name) { |
| 1570 | __sockaddr_check_size(sizeof(struct sockaddr_can)); | ||
| 1571 | msg->msg_namelen = sizeof(struct sockaddr_can); | 1571 | msg->msg_namelen = sizeof(struct sockaddr_can); |
| 1572 | memcpy(msg->msg_name, skb->cb, msg->msg_namelen); | 1572 | memcpy(msg->msg_name, skb->cb, msg->msg_namelen); |
| 1573 | } | 1573 | } |
diff --git a/net/can/gw.c b/net/can/gw.c index 3f9b0f3a2818..ac31891967da 100644 --- a/net/can/gw.c +++ b/net/can/gw.c | |||
| @@ -839,23 +839,21 @@ static int cgw_create_job(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
| 839 | if (!gwj->ccgw.src_idx || !gwj->ccgw.dst_idx) | 839 | if (!gwj->ccgw.src_idx || !gwj->ccgw.dst_idx) |
| 840 | goto out; | 840 | goto out; |
| 841 | 841 | ||
| 842 | gwj->src.dev = dev_get_by_index(&init_net, gwj->ccgw.src_idx); | 842 | gwj->src.dev = __dev_get_by_index(&init_net, gwj->ccgw.src_idx); |
| 843 | 843 | ||
| 844 | if (!gwj->src.dev) | 844 | if (!gwj->src.dev) |
| 845 | goto out; | 845 | goto out; |
| 846 | 846 | ||
| 847 | /* check for CAN netdev not using header_ops - see gw_rcv() */ | 847 | if (gwj->src.dev->type != ARPHRD_CAN) |
| 848 | if (gwj->src.dev->type != ARPHRD_CAN || gwj->src.dev->header_ops) | 848 | goto out; |
| 849 | goto put_src_out; | ||
| 850 | 849 | ||
| 851 | gwj->dst.dev = dev_get_by_index(&init_net, gwj->ccgw.dst_idx); | 850 | gwj->dst.dev = __dev_get_by_index(&init_net, gwj->ccgw.dst_idx); |
| 852 | 851 | ||
| 853 | if (!gwj->dst.dev) | 852 | if (!gwj->dst.dev) |
| 854 | goto put_src_out; | 853 | goto out; |
| 855 | 854 | ||
| 856 | /* check for CAN netdev not using header_ops - see gw_rcv() */ | 855 | if (gwj->dst.dev->type != ARPHRD_CAN) |
| 857 | if (gwj->dst.dev->type != ARPHRD_CAN || gwj->dst.dev->header_ops) | 856 | goto out; |
| 858 | goto put_src_dst_out; | ||
| 859 | 857 | ||
| 860 | gwj->limit_hops = limhops; | 858 | gwj->limit_hops = limhops; |
| 861 | 859 | ||
| @@ -864,11 +862,6 @@ static int cgw_create_job(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
| 864 | err = cgw_register_filter(gwj); | 862 | err = cgw_register_filter(gwj); |
| 865 | if (!err) | 863 | if (!err) |
| 866 | hlist_add_head_rcu(&gwj->list, &cgw_list); | 864 | hlist_add_head_rcu(&gwj->list, &cgw_list); |
| 867 | |||
| 868 | put_src_dst_out: | ||
| 869 | dev_put(gwj->dst.dev); | ||
| 870 | put_src_out: | ||
| 871 | dev_put(gwj->src.dev); | ||
| 872 | out: | 865 | out: |
| 873 | if (err) | 866 | if (err) |
| 874 | kmem_cache_free(cgw_cache, gwj); | 867 | kmem_cache_free(cgw_cache, gwj); |
diff --git a/net/can/raw.c b/net/can/raw.c index 641e1c895123..07d72d852324 100644 --- a/net/can/raw.c +++ b/net/can/raw.c | |||
| @@ -675,8 +675,7 @@ static int raw_sendmsg(struct kiocb *iocb, struct socket *sock, | |||
| 675 | int err; | 675 | int err; |
| 676 | 676 | ||
| 677 | if (msg->msg_name) { | 677 | if (msg->msg_name) { |
| 678 | struct sockaddr_can *addr = | 678 | DECLARE_SOCKADDR(struct sockaddr_can *, addr, msg->msg_name); |
| 679 | (struct sockaddr_can *)msg->msg_name; | ||
| 680 | 679 | ||
| 681 | if (msg->msg_namelen < sizeof(*addr)) | 680 | if (msg->msg_namelen < sizeof(*addr)) |
| 682 | return -EINVAL; | 681 | return -EINVAL; |
| @@ -775,6 +774,7 @@ static int raw_recvmsg(struct kiocb *iocb, struct socket *sock, | |||
| 775 | sock_recv_ts_and_drops(msg, sk, skb); | 774 | sock_recv_ts_and_drops(msg, sk, skb); |
| 776 | 775 | ||
| 777 | if (msg->msg_name) { | 776 | if (msg->msg_name) { |
| 777 | __sockaddr_check_size(sizeof(struct sockaddr_can)); | ||
| 778 | msg->msg_namelen = sizeof(struct sockaddr_can); | 778 | msg->msg_namelen = sizeof(struct sockaddr_can); |
| 779 | memcpy(msg->msg_name, skb->cb, msg->msg_namelen); | 779 | memcpy(msg->msg_name, skb->cb, msg->msg_namelen); |
| 780 | } | 780 | } |
diff --git a/net/ceph/buffer.c b/net/ceph/buffer.c index bf3e6a13c215..621b5f65407f 100644 --- a/net/ceph/buffer.c +++ b/net/ceph/buffer.c | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | 6 | ||
| 7 | #include <linux/ceph/buffer.h> | 7 | #include <linux/ceph/buffer.h> |
| 8 | #include <linux/ceph/decode.h> | 8 | #include <linux/ceph/decode.h> |
| 9 | #include <linux/ceph/libceph.h> /* for ceph_kv{malloc,free} */ | ||
| 9 | 10 | ||
| 10 | struct ceph_buffer *ceph_buffer_new(size_t len, gfp_t gfp) | 11 | struct ceph_buffer *ceph_buffer_new(size_t len, gfp_t gfp) |
| 11 | { | 12 | { |
| @@ -15,16 +16,10 @@ struct ceph_buffer *ceph_buffer_new(size_t len, gfp_t gfp) | |||
| 15 | if (!b) | 16 | if (!b) |
| 16 | return NULL; | 17 | return NULL; |
| 17 | 18 | ||
| 18 | b->vec.iov_base = kmalloc(len, gfp | __GFP_NOWARN); | 19 | b->vec.iov_base = ceph_kvmalloc(len, gfp); |
| 19 | if (b->vec.iov_base) { | 20 | if (!b->vec.iov_base) { |
| 20 | b->is_vmalloc = false; | 21 | kfree(b); |
| 21 | } else { | 22 | return NULL; |
| 22 | b->vec.iov_base = __vmalloc(len, gfp | __GFP_HIGHMEM, PAGE_KERNEL); | ||
| 23 | if (!b->vec.iov_base) { | ||
| 24 | kfree(b); | ||
| 25 | return NULL; | ||
| 26 | } | ||
| 27 | b->is_vmalloc = true; | ||
| 28 | } | 23 | } |
| 29 | 24 | ||
| 30 | kref_init(&b->kref); | 25 | kref_init(&b->kref); |
| @@ -40,12 +35,7 @@ void ceph_buffer_release(struct kref *kref) | |||
| 40 | struct ceph_buffer *b = container_of(kref, struct ceph_buffer, kref); | 35 | struct ceph_buffer *b = container_of(kref, struct ceph_buffer, kref); |
| 41 | 36 | ||
| 42 | dout("buffer_release %p\n", b); | 37 | dout("buffer_release %p\n", b); |
| 43 | if (b->vec.iov_base) { | 38 | ceph_kvfree(b->vec.iov_base); |
| 44 | if (b->is_vmalloc) | ||
| 45 | vfree(b->vec.iov_base); | ||
| 46 | else | ||
| 47 | kfree(b->vec.iov_base); | ||
| 48 | } | ||
| 49 | kfree(b); | 39 | kfree(b); |
| 50 | } | 40 | } |
| 51 | EXPORT_SYMBOL(ceph_buffer_release); | 41 | EXPORT_SYMBOL(ceph_buffer_release); |
diff --git a/net/ceph/ceph_common.c b/net/ceph/ceph_common.c index 34b11ee8124e..67d7721d237e 100644 --- a/net/ceph/ceph_common.c +++ b/net/ceph/ceph_common.c | |||
| @@ -15,6 +15,7 @@ | |||
| 15 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
| 16 | #include <linux/statfs.h> | 16 | #include <linux/statfs.h> |
| 17 | #include <linux/string.h> | 17 | #include <linux/string.h> |
| 18 | #include <linux/vmalloc.h> | ||
| 18 | #include <linux/nsproxy.h> | 19 | #include <linux/nsproxy.h> |
| 19 | #include <net/net_namespace.h> | 20 | #include <net/net_namespace.h> |
| 20 | 21 | ||
| @@ -170,6 +171,25 @@ int ceph_compare_options(struct ceph_options *new_opt, | |||
| 170 | } | 171 | } |
| 171 | EXPORT_SYMBOL(ceph_compare_options); | 172 | EXPORT_SYMBOL(ceph_compare_options); |
| 172 | 173 | ||
| 174 | void *ceph_kvmalloc(size_t size, gfp_t flags) | ||
| 175 | { | ||
| 176 | if (size <= (PAGE_SIZE << PAGE_ALLOC_COSTLY_ORDER)) { | ||
| 177 | void *ptr = kmalloc(size, flags | __GFP_NOWARN); | ||
| 178 | if (ptr) | ||
| 179 | return ptr; | ||
| 180 | } | ||
| 181 | |||
| 182 | return __vmalloc(size, flags | __GFP_HIGHMEM, PAGE_KERNEL); | ||
| 183 | } | ||
| 184 | |||
| 185 | void ceph_kvfree(const void *ptr) | ||
| 186 | { | ||
| 187 | if (is_vmalloc_addr(ptr)) | ||
| 188 | vfree(ptr); | ||
| 189 | else | ||
| 190 | kfree(ptr); | ||
| 191 | } | ||
| 192 | |||
| 173 | 193 | ||
| 174 | static int parse_fsid(const char *str, struct ceph_fsid *fsid) | 194 | static int parse_fsid(const char *str, struct ceph_fsid *fsid) |
| 175 | { | 195 | { |
| @@ -461,8 +481,8 @@ EXPORT_SYMBOL(ceph_client_id); | |||
| 461 | * create a fresh client instance | 481 | * create a fresh client instance |
| 462 | */ | 482 | */ |
| 463 | struct ceph_client *ceph_create_client(struct ceph_options *opt, void *private, | 483 | struct ceph_client *ceph_create_client(struct ceph_options *opt, void *private, |
| 464 | unsigned int supported_features, | 484 | u64 supported_features, |
| 465 | unsigned int required_features) | 485 | u64 required_features) |
| 466 | { | 486 | { |
| 467 | struct ceph_client *client; | 487 | struct ceph_client *client; |
| 468 | struct ceph_entity_addr *myaddr = NULL; | 488 | struct ceph_entity_addr *myaddr = NULL; |
diff --git a/net/ceph/crush/crush.c b/net/ceph/crush/crush.c index 089613234f03..16bc199d9a62 100644 --- a/net/ceph/crush/crush.c +++ b/net/ceph/crush/crush.c | |||
| @@ -116,11 +116,14 @@ void crush_destroy(struct crush_map *map) | |||
| 116 | if (map->rules) { | 116 | if (map->rules) { |
| 117 | __u32 b; | 117 | __u32 b; |
| 118 | for (b = 0; b < map->max_rules; b++) | 118 | for (b = 0; b < map->max_rules; b++) |
| 119 | kfree(map->rules[b]); | 119 | crush_destroy_rule(map->rules[b]); |
| 120 | kfree(map->rules); | 120 | kfree(map->rules); |
| 121 | } | 121 | } |
| 122 | 122 | ||
| 123 | kfree(map); | 123 | kfree(map); |
| 124 | } | 124 | } |
| 125 | 125 | ||
| 126 | 126 | void crush_destroy_rule(struct crush_rule *rule) | |
| 127 | { | ||
| 128 | kfree(rule); | ||
| 129 | } | ||
diff --git a/net/ceph/crush/mapper.c b/net/ceph/crush/mapper.c index cbd06a91941c..b703790b4e44 100644 --- a/net/ceph/crush/mapper.c +++ b/net/ceph/crush/mapper.c | |||
| @@ -189,7 +189,7 @@ static int terminal(int x) | |||
| 189 | static int bucket_tree_choose(struct crush_bucket_tree *bucket, | 189 | static int bucket_tree_choose(struct crush_bucket_tree *bucket, |
| 190 | int x, int r) | 190 | int x, int r) |
| 191 | { | 191 | { |
| 192 | int n, l; | 192 | int n; |
| 193 | __u32 w; | 193 | __u32 w; |
| 194 | __u64 t; | 194 | __u64 t; |
| 195 | 195 | ||
| @@ -197,6 +197,7 @@ static int bucket_tree_choose(struct crush_bucket_tree *bucket, | |||
| 197 | n = bucket->num_nodes >> 1; | 197 | n = bucket->num_nodes >> 1; |
| 198 | 198 | ||
| 199 | while (!terminal(n)) { | 199 | while (!terminal(n)) { |
| 200 | int l; | ||
| 200 | /* pick point in [0, w) */ | 201 | /* pick point in [0, w) */ |
| 201 | w = bucket->node_weights[n]; | 202 | w = bucket->node_weights[n]; |
| 202 | t = (__u64)crush_hash32_4(bucket->h.hash, x, n, r, | 203 | t = (__u64)crush_hash32_4(bucket->h.hash, x, n, r, |
| @@ -264,8 +265,12 @@ static int crush_bucket_choose(struct crush_bucket *in, int x, int r) | |||
| 264 | * true if device is marked "out" (failed, fully offloaded) | 265 | * true if device is marked "out" (failed, fully offloaded) |
| 265 | * of the cluster | 266 | * of the cluster |
| 266 | */ | 267 | */ |
| 267 | static int is_out(const struct crush_map *map, const __u32 *weight, int item, int x) | 268 | static int is_out(const struct crush_map *map, |
| 269 | const __u32 *weight, int weight_max, | ||
| 270 | int item, int x) | ||
| 268 | { | 271 | { |
| 272 | if (item >= weight_max) | ||
| 273 | return 1; | ||
| 269 | if (weight[item] >= 0x10000) | 274 | if (weight[item] >= 0x10000) |
| 270 | return 0; | 275 | return 0; |
| 271 | if (weight[item] == 0) | 276 | if (weight[item] == 0) |
| @@ -277,7 +282,7 @@ static int is_out(const struct crush_map *map, const __u32 *weight, int item, in | |||
| 277 | } | 282 | } |
| 278 | 283 | ||
| 279 | /** | 284 | /** |
| 280 | * crush_choose - choose numrep distinct items of given type | 285 | * crush_choose_firstn - choose numrep distinct items of given type |
| 281 | * @map: the crush_map | 286 | * @map: the crush_map |
| 282 | * @bucket: the bucket we are choose an item from | 287 | * @bucket: the bucket we are choose an item from |
| 283 | * @x: crush input value | 288 | * @x: crush input value |
| @@ -285,18 +290,24 @@ static int is_out(const struct crush_map *map, const __u32 *weight, int item, in | |||
| 285 | * @type: the type of item to choose | 290 | * @type: the type of item to choose |
| 286 | * @out: pointer to output vector | 291 | * @out: pointer to output vector |
| 287 | * @outpos: our position in that vector | 292 | * @outpos: our position in that vector |
| 288 | * @firstn: true if choosing "first n" items, false if choosing "indep" | 293 | * @tries: number of attempts to make |
| 289 | * @recurse_to_leaf: true if we want one device under each item of given type | 294 | * @recurse_tries: number of attempts to have recursive chooseleaf make |
| 290 | * @descend_once: true if we should only try one descent before giving up | 295 | * @local_tries: localized retries |
| 296 | * @local_fallback_tries: localized fallback retries | ||
| 297 | * @recurse_to_leaf: true if we want one device under each item of given type (chooseleaf instead of choose) | ||
| 291 | * @out2: second output vector for leaf items (if @recurse_to_leaf) | 298 | * @out2: second output vector for leaf items (if @recurse_to_leaf) |
| 292 | */ | 299 | */ |
| 293 | static int crush_choose(const struct crush_map *map, | 300 | static int crush_choose_firstn(const struct crush_map *map, |
| 294 | struct crush_bucket *bucket, | 301 | struct crush_bucket *bucket, |
| 295 | const __u32 *weight, | 302 | const __u32 *weight, int weight_max, |
| 296 | int x, int numrep, int type, | 303 | int x, int numrep, int type, |
| 297 | int *out, int outpos, | 304 | int *out, int outpos, |
| 298 | int firstn, int recurse_to_leaf, | 305 | unsigned int tries, |
| 299 | int descend_once, int *out2) | 306 | unsigned int recurse_tries, |
| 307 | unsigned int local_tries, | ||
| 308 | unsigned int local_fallback_tries, | ||
| 309 | int recurse_to_leaf, | ||
| 310 | int *out2) | ||
| 300 | { | 311 | { |
| 301 | int rep; | 312 | int rep; |
| 302 | unsigned int ftotal, flocal; | 313 | unsigned int ftotal, flocal; |
| @@ -325,35 +336,17 @@ static int crush_choose(const struct crush_map *map, | |||
| 325 | collide = 0; | 336 | collide = 0; |
| 326 | retry_bucket = 0; | 337 | retry_bucket = 0; |
| 327 | r = rep; | 338 | r = rep; |
| 328 | if (in->alg == CRUSH_BUCKET_UNIFORM) { | 339 | /* r' = r + f_total */ |
| 329 | /* be careful */ | 340 | r += ftotal; |
| 330 | if (firstn || (__u32)numrep >= in->size) | ||
| 331 | /* r' = r + f_total */ | ||
| 332 | r += ftotal; | ||
| 333 | else if (in->size % numrep == 0) | ||
| 334 | /* r'=r+(n+1)*f_local */ | ||
| 335 | r += (numrep+1) * | ||
| 336 | (flocal+ftotal); | ||
| 337 | else | ||
| 338 | /* r' = r + n*f_local */ | ||
| 339 | r += numrep * (flocal+ftotal); | ||
| 340 | } else { | ||
| 341 | if (firstn) | ||
| 342 | /* r' = r + f_total */ | ||
| 343 | r += ftotal; | ||
| 344 | else | ||
| 345 | /* r' = r + n*f_local */ | ||
| 346 | r += numrep * (flocal+ftotal); | ||
| 347 | } | ||
| 348 | 341 | ||
| 349 | /* bucket choose */ | 342 | /* bucket choose */ |
| 350 | if (in->size == 0) { | 343 | if (in->size == 0) { |
| 351 | reject = 1; | 344 | reject = 1; |
| 352 | goto reject; | 345 | goto reject; |
| 353 | } | 346 | } |
| 354 | if (map->choose_local_fallback_tries > 0 && | 347 | if (local_fallback_tries > 0 && |
| 355 | flocal >= (in->size>>1) && | 348 | flocal >= (in->size>>1) && |
| 356 | flocal > map->choose_local_fallback_tries) | 349 | flocal > local_fallback_tries) |
| 357 | item = bucket_perm_choose(in, x, r); | 350 | item = bucket_perm_choose(in, x, r); |
| 358 | else | 351 | else |
| 359 | item = crush_bucket_choose(in, x, r); | 352 | item = crush_bucket_choose(in, x, r); |
| @@ -394,13 +387,15 @@ static int crush_choose(const struct crush_map *map, | |||
| 394 | reject = 0; | 387 | reject = 0; |
| 395 | if (!collide && recurse_to_leaf) { | 388 | if (!collide && recurse_to_leaf) { |
| 396 | if (item < 0) { | 389 | if (item < 0) { |
| 397 | if (crush_choose(map, | 390 | if (crush_choose_firstn(map, |
| 398 | map->buckets[-1-item], | 391 | map->buckets[-1-item], |
| 399 | weight, | 392 | weight, weight_max, |
| 400 | x, outpos+1, 0, | 393 | x, outpos+1, 0, |
| 401 | out2, outpos, | 394 | out2, outpos, |
| 402 | firstn, 0, | 395 | recurse_tries, 0, |
| 403 | map->chooseleaf_descend_once, | 396 | local_tries, |
| 397 | local_fallback_tries, | ||
| 398 | 0, | ||
| 404 | NULL) <= outpos) | 399 | NULL) <= outpos) |
| 405 | /* didn't get leaf */ | 400 | /* didn't get leaf */ |
| 406 | reject = 1; | 401 | reject = 1; |
| @@ -414,6 +409,7 @@ static int crush_choose(const struct crush_map *map, | |||
| 414 | /* out? */ | 409 | /* out? */ |
| 415 | if (itemtype == 0) | 410 | if (itemtype == 0) |
| 416 | reject = is_out(map, weight, | 411 | reject = is_out(map, weight, |
| 412 | weight_max, | ||
| 417 | item, x); | 413 | item, x); |
| 418 | else | 414 | else |
| 419 | reject = 0; | 415 | reject = 0; |
| @@ -424,17 +420,14 @@ reject: | |||
| 424 | ftotal++; | 420 | ftotal++; |
| 425 | flocal++; | 421 | flocal++; |
| 426 | 422 | ||
| 427 | if (reject && descend_once) | 423 | if (collide && flocal <= local_tries) |
| 428 | /* let outer call try again */ | ||
| 429 | skip_rep = 1; | ||
| 430 | else if (collide && flocal <= map->choose_local_tries) | ||
| 431 | /* retry locally a few times */ | 424 | /* retry locally a few times */ |
| 432 | retry_bucket = 1; | 425 | retry_bucket = 1; |
| 433 | else if (map->choose_local_fallback_tries > 0 && | 426 | else if (local_fallback_tries > 0 && |
| 434 | flocal <= in->size + map->choose_local_fallback_tries) | 427 | flocal <= in->size + local_fallback_tries) |
| 435 | /* exhaustive bucket search */ | 428 | /* exhaustive bucket search */ |
| 436 | retry_bucket = 1; | 429 | retry_bucket = 1; |
| 437 | else if (ftotal <= map->choose_total_tries) | 430 | else if (ftotal <= tries) |
| 438 | /* then retry descent */ | 431 | /* then retry descent */ |
| 439 | retry_descent = 1; | 432 | retry_descent = 1; |
| 440 | else | 433 | else |
| @@ -464,21 +457,179 @@ reject: | |||
| 464 | 457 | ||
| 465 | 458 | ||
| 466 | /** | 459 | /** |
| 460 | * crush_choose_indep: alternative breadth-first positionally stable mapping | ||
| 461 | * | ||
| 462 | */ | ||
| 463 | static void crush_choose_indep(const struct crush_map *map, | ||
| 464 | struct crush_bucket *bucket, | ||
| 465 | const __u32 *weight, int weight_max, | ||
| 466 | int x, int left, int numrep, int type, | ||
| 467 | int *out, int outpos, | ||
| 468 | unsigned int tries, | ||
| 469 | unsigned int recurse_tries, | ||
| 470 | int recurse_to_leaf, | ||
| 471 | int *out2, | ||
| 472 | int parent_r) | ||
| 473 | { | ||
| 474 | struct crush_bucket *in = bucket; | ||
| 475 | int endpos = outpos + left; | ||
| 476 | int rep; | ||
| 477 | unsigned int ftotal; | ||
| 478 | int r; | ||
| 479 | int i; | ||
| 480 | int item = 0; | ||
| 481 | int itemtype; | ||
| 482 | int collide; | ||
| 483 | |||
| 484 | dprintk("CHOOSE%s INDEP bucket %d x %d outpos %d numrep %d\n", recurse_to_leaf ? "_LEAF" : "", | ||
| 485 | bucket->id, x, outpos, numrep); | ||
| 486 | |||
| 487 | /* initially my result is undefined */ | ||
| 488 | for (rep = outpos; rep < endpos; rep++) { | ||
| 489 | out[rep] = CRUSH_ITEM_UNDEF; | ||
| 490 | if (out2) | ||
| 491 | out2[rep] = CRUSH_ITEM_UNDEF; | ||
| 492 | } | ||
| 493 | |||
| 494 | for (ftotal = 0; left > 0 && ftotal < tries; ftotal++) { | ||
| 495 | for (rep = outpos; rep < endpos; rep++) { | ||
| 496 | if (out[rep] != CRUSH_ITEM_UNDEF) | ||
| 497 | continue; | ||
| 498 | |||
| 499 | in = bucket; /* initial bucket */ | ||
| 500 | |||
| 501 | /* choose through intervening buckets */ | ||
| 502 | for (;;) { | ||
| 503 | /* note: we base the choice on the position | ||
| 504 | * even in the nested call. that means that | ||
| 505 | * if the first layer chooses the same bucket | ||
| 506 | * in a different position, we will tend to | ||
| 507 | * choose a different item in that bucket. | ||
| 508 | * this will involve more devices in data | ||
| 509 | * movement and tend to distribute the load. | ||
| 510 | */ | ||
| 511 | r = rep + parent_r; | ||
| 512 | |||
| 513 | /* be careful */ | ||
| 514 | if (in->alg == CRUSH_BUCKET_UNIFORM && | ||
| 515 | in->size % numrep == 0) | ||
| 516 | /* r'=r+(n+1)*f_total */ | ||
| 517 | r += (numrep+1) * ftotal; | ||
| 518 | else | ||
| 519 | /* r' = r + n*f_total */ | ||
| 520 | r += numrep * ftotal; | ||
| 521 | |||
| 522 | /* bucket choose */ | ||
| 523 | if (in->size == 0) { | ||
| 524 | dprintk(" empty bucket\n"); | ||
| 525 | break; | ||
| 526 | } | ||
| 527 | |||
| 528 | item = crush_bucket_choose(in, x, r); | ||
| 529 | if (item >= map->max_devices) { | ||
| 530 | dprintk(" bad item %d\n", item); | ||
| 531 | out[rep] = CRUSH_ITEM_NONE; | ||
| 532 | if (out2) | ||
| 533 | out2[rep] = CRUSH_ITEM_NONE; | ||
| 534 | left--; | ||
| 535 | break; | ||
| 536 | } | ||
| 537 | |||
| 538 | /* desired type? */ | ||
| 539 | if (item < 0) | ||
| 540 | itemtype = map->buckets[-1-item]->type; | ||
| 541 | else | ||
| 542 | itemtype = 0; | ||
| 543 | dprintk(" item %d type %d\n", item, itemtype); | ||
| 544 | |||
| 545 | /* keep going? */ | ||
| 546 | if (itemtype != type) { | ||
| 547 | if (item >= 0 || | ||
| 548 | (-1-item) >= map->max_buckets) { | ||
| 549 | dprintk(" bad item type %d\n", type); | ||
| 550 | out[rep] = CRUSH_ITEM_NONE; | ||
| 551 | if (out2) | ||
| 552 | out2[rep] = | ||
| 553 | CRUSH_ITEM_NONE; | ||
| 554 | left--; | ||
| 555 | break; | ||
| 556 | } | ||
| 557 | in = map->buckets[-1-item]; | ||
| 558 | continue; | ||
| 559 | } | ||
| 560 | |||
| 561 | /* collision? */ | ||
| 562 | collide = 0; | ||
| 563 | for (i = outpos; i < endpos; i++) { | ||
| 564 | if (out[i] == item) { | ||
| 565 | collide = 1; | ||
| 566 | break; | ||
| 567 | } | ||
| 568 | } | ||
| 569 | if (collide) | ||
| 570 | break; | ||
| 571 | |||
| 572 | if (recurse_to_leaf) { | ||
| 573 | if (item < 0) { | ||
| 574 | crush_choose_indep(map, | ||
| 575 | map->buckets[-1-item], | ||
| 576 | weight, weight_max, | ||
| 577 | x, 1, numrep, 0, | ||
| 578 | out2, rep, | ||
| 579 | recurse_tries, 0, | ||
| 580 | 0, NULL, r); | ||
| 581 | if (out2[rep] == CRUSH_ITEM_NONE) { | ||
| 582 | /* placed nothing; no leaf */ | ||
| 583 | break; | ||
| 584 | } | ||
| 585 | } else { | ||
| 586 | /* we already have a leaf! */ | ||
| 587 | out2[rep] = item; | ||
| 588 | } | ||
| 589 | } | ||
| 590 | |||
| 591 | /* out? */ | ||
| 592 | if (itemtype == 0 && | ||
| 593 | is_out(map, weight, weight_max, item, x)) | ||
| 594 | break; | ||
| 595 | |||
| 596 | /* yay! */ | ||
| 597 | out[rep] = item; | ||
| 598 | left--; | ||
| 599 | break; | ||
| 600 | } | ||
| 601 | } | ||
| 602 | } | ||
| 603 | for (rep = outpos; rep < endpos; rep++) { | ||
| 604 | if (out[rep] == CRUSH_ITEM_UNDEF) { | ||
| 605 | out[rep] = CRUSH_ITEM_NONE; | ||
| 606 | } | ||
| 607 | if (out2 && out2[rep] == CRUSH_ITEM_UNDEF) { | ||
| 608 | out2[rep] = CRUSH_ITEM_NONE; | ||
| 609 | } | ||
| 610 | } | ||
| 611 | } | ||
| 612 | |||
| 613 | /** | ||
| 467 | * crush_do_rule - calculate a mapping with the given input and rule | 614 | * crush_do_rule - calculate a mapping with the given input and rule |
| 468 | * @map: the crush_map | 615 | * @map: the crush_map |
| 469 | * @ruleno: the rule id | 616 | * @ruleno: the rule id |
| 470 | * @x: hash input | 617 | * @x: hash input |
| 471 | * @result: pointer to result vector | 618 | * @result: pointer to result vector |
| 472 | * @result_max: maximum result size | 619 | * @result_max: maximum result size |
| 620 | * @weight: weight vector (for map leaves) | ||
| 621 | * @weight_max: size of weight vector | ||
| 622 | * @scratch: scratch vector for private use; must be >= 3 * result_max | ||
| 473 | */ | 623 | */ |
| 474 | int crush_do_rule(const struct crush_map *map, | 624 | int crush_do_rule(const struct crush_map *map, |
| 475 | int ruleno, int x, int *result, int result_max, | 625 | int ruleno, int x, int *result, int result_max, |
| 476 | const __u32 *weight) | 626 | const __u32 *weight, int weight_max, |
| 627 | int *scratch) | ||
| 477 | { | 628 | { |
| 478 | int result_len; | 629 | int result_len; |
| 479 | int a[CRUSH_MAX_SET]; | 630 | int *a = scratch; |
| 480 | int b[CRUSH_MAX_SET]; | 631 | int *b = scratch + result_max; |
| 481 | int c[CRUSH_MAX_SET]; | 632 | int *c = scratch + result_max*2; |
| 482 | int recurse_to_leaf; | 633 | int recurse_to_leaf; |
| 483 | int *w; | 634 | int *w; |
| 484 | int wsize = 0; | 635 | int wsize = 0; |
| @@ -489,8 +640,10 @@ int crush_do_rule(const struct crush_map *map, | |||
| 489 | __u32 step; | 640 | __u32 step; |
| 490 | int i, j; | 641 | int i, j; |
| 491 | int numrep; | 642 | int numrep; |
| 492 | int firstn; | 643 | int choose_tries = map->choose_total_tries; |
| 493 | const int descend_once = 0; | 644 | int choose_local_tries = map->choose_local_tries; |
| 645 | int choose_local_fallback_tries = map->choose_local_fallback_tries; | ||
| 646 | int choose_leaf_tries = 0; | ||
| 494 | 647 | ||
| 495 | if ((__u32)ruleno >= map->max_rules) { | 648 | if ((__u32)ruleno >= map->max_rules) { |
| 496 | dprintk(" bad ruleno %d\n", ruleno); | 649 | dprintk(" bad ruleno %d\n", ruleno); |
| @@ -503,29 +656,49 @@ int crush_do_rule(const struct crush_map *map, | |||
| 503 | o = b; | 656 | o = b; |
| 504 | 657 | ||
| 505 | for (step = 0; step < rule->len; step++) { | 658 | for (step = 0; step < rule->len; step++) { |
| 659 | int firstn = 0; | ||
| 506 | struct crush_rule_step *curstep = &rule->steps[step]; | 660 | struct crush_rule_step *curstep = &rule->steps[step]; |
| 507 | 661 | ||
| 508 | firstn = 0; | ||
| 509 | switch (curstep->op) { | 662 | switch (curstep->op) { |
| 510 | case CRUSH_RULE_TAKE: | 663 | case CRUSH_RULE_TAKE: |
| 511 | w[0] = curstep->arg1; | 664 | w[0] = curstep->arg1; |
| 512 | wsize = 1; | 665 | wsize = 1; |
| 513 | break; | 666 | break; |
| 514 | 667 | ||
| 515 | case CRUSH_RULE_CHOOSE_LEAF_FIRSTN: | 668 | case CRUSH_RULE_SET_CHOOSE_TRIES: |
| 669 | if (curstep->arg1 > 0) | ||
| 670 | choose_tries = curstep->arg1; | ||
| 671 | break; | ||
| 672 | |||
| 673 | case CRUSH_RULE_SET_CHOOSELEAF_TRIES: | ||
| 674 | if (curstep->arg1 > 0) | ||
| 675 | choose_leaf_tries = curstep->arg1; | ||
| 676 | break; | ||
| 677 | |||
| 678 | case CRUSH_RULE_SET_CHOOSE_LOCAL_TRIES: | ||
| 679 | if (curstep->arg1 > 0) | ||
| 680 | choose_local_tries = curstep->arg1; | ||
| 681 | break; | ||
| 682 | |||
| 683 | case CRUSH_RULE_SET_CHOOSE_LOCAL_FALLBACK_TRIES: | ||
| 684 | if (curstep->arg1 > 0) | ||
| 685 | choose_local_fallback_tries = curstep->arg1; | ||
| 686 | break; | ||
| 687 | |||
| 688 | case CRUSH_RULE_CHOOSELEAF_FIRSTN: | ||
| 516 | case CRUSH_RULE_CHOOSE_FIRSTN: | 689 | case CRUSH_RULE_CHOOSE_FIRSTN: |
| 517 | firstn = 1; | 690 | firstn = 1; |
| 518 | /* fall through */ | 691 | /* fall through */ |
| 519 | case CRUSH_RULE_CHOOSE_LEAF_INDEP: | 692 | case CRUSH_RULE_CHOOSELEAF_INDEP: |
| 520 | case CRUSH_RULE_CHOOSE_INDEP: | 693 | case CRUSH_RULE_CHOOSE_INDEP: |
| 521 | if (wsize == 0) | 694 | if (wsize == 0) |
| 522 | break; | 695 | break; |
| 523 | 696 | ||
| 524 | recurse_to_leaf = | 697 | recurse_to_leaf = |
| 525 | curstep->op == | 698 | curstep->op == |
| 526 | CRUSH_RULE_CHOOSE_LEAF_FIRSTN || | 699 | CRUSH_RULE_CHOOSELEAF_FIRSTN || |
| 527 | curstep->op == | 700 | curstep->op == |
| 528 | CRUSH_RULE_CHOOSE_LEAF_INDEP; | 701 | CRUSH_RULE_CHOOSELEAF_INDEP; |
| 529 | 702 | ||
| 530 | /* reset output */ | 703 | /* reset output */ |
| 531 | osize = 0; | 704 | osize = 0; |
| @@ -543,22 +716,51 @@ int crush_do_rule(const struct crush_map *map, | |||
| 543 | continue; | 716 | continue; |
| 544 | } | 717 | } |
| 545 | j = 0; | 718 | j = 0; |
| 546 | osize += crush_choose(map, | 719 | if (firstn) { |
| 547 | map->buckets[-1-w[i]], | 720 | int recurse_tries; |
| 548 | weight, | 721 | if (choose_leaf_tries) |
| 549 | x, numrep, | 722 | recurse_tries = |
| 550 | curstep->arg2, | 723 | choose_leaf_tries; |
| 551 | o+osize, j, | 724 | else if (map->chooseleaf_descend_once) |
| 552 | firstn, | 725 | recurse_tries = 1; |
| 553 | recurse_to_leaf, | 726 | else |
| 554 | descend_once, c+osize); | 727 | recurse_tries = choose_tries; |
| 728 | osize += crush_choose_firstn( | ||
| 729 | map, | ||
| 730 | map->buckets[-1-w[i]], | ||
| 731 | weight, weight_max, | ||
| 732 | x, numrep, | ||
| 733 | curstep->arg2, | ||
| 734 | o+osize, j, | ||
| 735 | choose_tries, | ||
| 736 | recurse_tries, | ||
| 737 | choose_local_tries, | ||
| 738 | choose_local_fallback_tries, | ||
| 739 | recurse_to_leaf, | ||
| 740 | c+osize); | ||
| 741 | } else { | ||
| 742 | crush_choose_indep( | ||
| 743 | map, | ||
| 744 | map->buckets[-1-w[i]], | ||
| 745 | weight, weight_max, | ||
| 746 | x, numrep, numrep, | ||
| 747 | curstep->arg2, | ||
| 748 | o+osize, j, | ||
| 749 | choose_tries, | ||
| 750 | choose_leaf_tries ? | ||
| 751 | choose_leaf_tries : 1, | ||
| 752 | recurse_to_leaf, | ||
| 753 | c+osize, | ||
| 754 | 0); | ||
| 755 | osize += numrep; | ||
| 756 | } | ||
| 555 | } | 757 | } |
| 556 | 758 | ||
| 557 | if (recurse_to_leaf) | 759 | if (recurse_to_leaf) |
| 558 | /* copy final _leaf_ values to output set */ | 760 | /* copy final _leaf_ values to output set */ |
| 559 | memcpy(o, c, osize*sizeof(*o)); | 761 | memcpy(o, c, osize*sizeof(*o)); |
| 560 | 762 | ||
| 561 | /* swap t and w arrays */ | 763 | /* swap o and w arrays */ |
| 562 | tmp = o; | 764 | tmp = o; |
| 563 | o = w; | 765 | o = w; |
| 564 | w = tmp; | 766 | w = tmp; |
diff --git a/net/ceph/debugfs.c b/net/ceph/debugfs.c index 83661cdc0766..258a382e75ed 100644 --- a/net/ceph/debugfs.c +++ b/net/ceph/debugfs.c | |||
| @@ -132,7 +132,8 @@ static int osdc_show(struct seq_file *s, void *pp) | |||
| 132 | req->r_osd ? req->r_osd->o_osd : -1, | 132 | req->r_osd ? req->r_osd->o_osd : -1, |
| 133 | req->r_pgid.pool, req->r_pgid.seed); | 133 | req->r_pgid.pool, req->r_pgid.seed); |
| 134 | 134 | ||
| 135 | seq_printf(s, "%.*s", req->r_oid_len, req->r_oid); | 135 | seq_printf(s, "%.*s", req->r_base_oid.name_len, |
| 136 | req->r_base_oid.name); | ||
| 136 | 137 | ||
| 137 | if (req->r_reassert_version.epoch) | 138 | if (req->r_reassert_version.epoch) |
| 138 | seq_printf(s, "\t%u'%llu", | 139 | seq_printf(s, "\t%u'%llu", |
diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 4a5df7b1cc9f..0e478a0f4204 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c | |||
| @@ -15,6 +15,7 @@ | |||
| 15 | #include <linux/dns_resolver.h> | 15 | #include <linux/dns_resolver.h> |
| 16 | #include <net/tcp.h> | 16 | #include <net/tcp.h> |
| 17 | 17 | ||
| 18 | #include <linux/ceph/ceph_features.h> | ||
| 18 | #include <linux/ceph/libceph.h> | 19 | #include <linux/ceph/libceph.h> |
| 19 | #include <linux/ceph/messenger.h> | 20 | #include <linux/ceph/messenger.h> |
| 20 | #include <linux/ceph/decode.h> | 21 | #include <linux/ceph/decode.h> |
| @@ -777,13 +778,12 @@ static void ceph_msg_data_bio_cursor_init(struct ceph_msg_data_cursor *cursor, | |||
| 777 | 778 | ||
| 778 | bio = data->bio; | 779 | bio = data->bio; |
| 779 | BUG_ON(!bio); | 780 | BUG_ON(!bio); |
| 780 | BUG_ON(!bio->bi_vcnt); | ||
| 781 | 781 | ||
| 782 | cursor->resid = min(length, data->bio_length); | 782 | cursor->resid = min(length, data->bio_length); |
| 783 | cursor->bio = bio; | 783 | cursor->bio = bio; |
| 784 | cursor->vector_index = 0; | 784 | cursor->bvec_iter = bio->bi_iter; |
| 785 | cursor->vector_offset = 0; | 785 | cursor->last_piece = |
| 786 | cursor->last_piece = length <= bio->bi_io_vec[0].bv_len; | 786 | cursor->resid <= bio_iter_len(bio, cursor->bvec_iter); |
| 787 | } | 787 | } |
| 788 | 788 | ||
| 789 | static struct page *ceph_msg_data_bio_next(struct ceph_msg_data_cursor *cursor, | 789 | static struct page *ceph_msg_data_bio_next(struct ceph_msg_data_cursor *cursor, |
| @@ -792,71 +792,63 @@ static struct page *ceph_msg_data_bio_next(struct ceph_msg_data_cursor *cursor, | |||
| 792 | { | 792 | { |
| 793 | struct ceph_msg_data *data = cursor->data; | 793 | struct ceph_msg_data *data = cursor->data; |
| 794 | struct bio *bio; | 794 | struct bio *bio; |
| 795 | struct bio_vec *bio_vec; | 795 | struct bio_vec bio_vec; |
| 796 | unsigned int index; | ||
| 797 | 796 | ||
| 798 | BUG_ON(data->type != CEPH_MSG_DATA_BIO); | 797 | BUG_ON(data->type != CEPH_MSG_DATA_BIO); |
| 799 | 798 | ||
| 800 | bio = cursor->bio; | 799 | bio = cursor->bio; |
| 801 | BUG_ON(!bio); | 800 | BUG_ON(!bio); |
| 802 | 801 | ||
| 803 | index = cursor->vector_index; | 802 | bio_vec = bio_iter_iovec(bio, cursor->bvec_iter); |
| 804 | BUG_ON(index >= (unsigned int) bio->bi_vcnt); | ||
| 805 | 803 | ||
| 806 | bio_vec = &bio->bi_io_vec[index]; | 804 | *page_offset = (size_t) bio_vec.bv_offset; |
| 807 | BUG_ON(cursor->vector_offset >= bio_vec->bv_len); | ||
| 808 | *page_offset = (size_t) (bio_vec->bv_offset + cursor->vector_offset); | ||
| 809 | BUG_ON(*page_offset >= PAGE_SIZE); | 805 | BUG_ON(*page_offset >= PAGE_SIZE); |
| 810 | if (cursor->last_piece) /* pagelist offset is always 0 */ | 806 | if (cursor->last_piece) /* pagelist offset is always 0 */ |
| 811 | *length = cursor->resid; | 807 | *length = cursor->resid; |
| 812 | else | 808 | else |
| 813 | *length = (size_t) (bio_vec->bv_len - cursor->vector_offset); | 809 | *length = (size_t) bio_vec.bv_len; |
| 814 | BUG_ON(*length > cursor->resid); | 810 | BUG_ON(*length > cursor->resid); |
| 815 | BUG_ON(*page_offset + *length > PAGE_SIZE); | 811 | BUG_ON(*page_offset + *length > PAGE_SIZE); |
| 816 | 812 | ||
| 817 | return bio_vec->bv_page; | 813 | return bio_vec.bv_page; |
| 818 | } | 814 | } |
| 819 | 815 | ||
| 820 | static bool ceph_msg_data_bio_advance(struct ceph_msg_data_cursor *cursor, | 816 | static bool ceph_msg_data_bio_advance(struct ceph_msg_data_cursor *cursor, |
| 821 | size_t bytes) | 817 | size_t bytes) |
| 822 | { | 818 | { |
| 823 | struct bio *bio; | 819 | struct bio *bio; |
| 824 | struct bio_vec *bio_vec; | 820 | struct bio_vec bio_vec; |
| 825 | unsigned int index; | ||
| 826 | 821 | ||
| 827 | BUG_ON(cursor->data->type != CEPH_MSG_DATA_BIO); | 822 | BUG_ON(cursor->data->type != CEPH_MSG_DATA_BIO); |
| 828 | 823 | ||
| 829 | bio = cursor->bio; | 824 | bio = cursor->bio; |
| 830 | BUG_ON(!bio); | 825 | BUG_ON(!bio); |
| 831 | 826 | ||
| 832 | index = cursor->vector_index; | 827 | bio_vec = bio_iter_iovec(bio, cursor->bvec_iter); |
| 833 | BUG_ON(index >= (unsigned int) bio->bi_vcnt); | ||
| 834 | bio_vec = &bio->bi_io_vec[index]; | ||
| 835 | 828 | ||
| 836 | /* Advance the cursor offset */ | 829 | /* Advance the cursor offset */ |
| 837 | 830 | ||
| 838 | BUG_ON(cursor->resid < bytes); | 831 | BUG_ON(cursor->resid < bytes); |
| 839 | cursor->resid -= bytes; | 832 | cursor->resid -= bytes; |
| 840 | cursor->vector_offset += bytes; | 833 | |
| 841 | if (cursor->vector_offset < bio_vec->bv_len) | 834 | bio_advance_iter(bio, &cursor->bvec_iter, bytes); |
| 835 | |||
| 836 | if (bytes < bio_vec.bv_len) | ||
| 842 | return false; /* more bytes to process in this segment */ | 837 | return false; /* more bytes to process in this segment */ |
| 843 | BUG_ON(cursor->vector_offset != bio_vec->bv_len); | ||
| 844 | 838 | ||
| 845 | /* Move on to the next segment, and possibly the next bio */ | 839 | /* Move on to the next segment, and possibly the next bio */ |
| 846 | 840 | ||
| 847 | if (++index == (unsigned int) bio->bi_vcnt) { | 841 | if (!cursor->bvec_iter.bi_size) { |
| 848 | bio = bio->bi_next; | 842 | bio = bio->bi_next; |
| 849 | index = 0; | 843 | cursor->bvec_iter = bio->bi_iter; |
| 850 | } | 844 | } |
| 851 | cursor->bio = bio; | 845 | cursor->bio = bio; |
| 852 | cursor->vector_index = index; | ||
| 853 | cursor->vector_offset = 0; | ||
| 854 | 846 | ||
| 855 | if (!cursor->last_piece) { | 847 | if (!cursor->last_piece) { |
| 856 | BUG_ON(!cursor->resid); | 848 | BUG_ON(!cursor->resid); |
| 857 | BUG_ON(!bio); | 849 | BUG_ON(!bio); |
| 858 | /* A short read is OK, so use <= rather than == */ | 850 | /* A short read is OK, so use <= rather than == */ |
| 859 | if (cursor->resid <= bio->bi_io_vec[index].bv_len) | 851 | if (cursor->resid <= bio_iter_len(bio, cursor->bvec_iter)) |
| 860 | cursor->last_piece = true; | 852 | cursor->last_piece = true; |
| 861 | } | 853 | } |
| 862 | 854 | ||
| @@ -1865,7 +1857,9 @@ int ceph_parse_ips(const char *c, const char *end, | |||
| 1865 | port = (port * 10) + (*p - '0'); | 1857 | port = (port * 10) + (*p - '0'); |
| 1866 | p++; | 1858 | p++; |
| 1867 | } | 1859 | } |
| 1868 | if (port > 65535 || port == 0) | 1860 | if (port == 0) |
| 1861 | port = CEPH_MON_PORT; | ||
| 1862 | else if (port > 65535) | ||
| 1869 | goto bad; | 1863 | goto bad; |
| 1870 | } else { | 1864 | } else { |
| 1871 | port = CEPH_MON_PORT; | 1865 | port = CEPH_MON_PORT; |
| @@ -1945,7 +1939,8 @@ static int process_connect(struct ceph_connection *con) | |||
| 1945 | { | 1939 | { |
| 1946 | u64 sup_feat = con->msgr->supported_features; | 1940 | u64 sup_feat = con->msgr->supported_features; |
| 1947 | u64 req_feat = con->msgr->required_features; | 1941 | u64 req_feat = con->msgr->required_features; |
| 1948 | u64 server_feat = le64_to_cpu(con->in_reply.features); | 1942 | u64 server_feat = ceph_sanitize_features( |
| 1943 | le64_to_cpu(con->in_reply.features)); | ||
| 1949 | int ret; | 1944 | int ret; |
| 1950 | 1945 | ||
| 1951 | dout("process_connect on %p tag %d\n", con, (int)con->in_tag); | 1946 | dout("process_connect on %p tag %d\n", con, (int)con->in_tag); |
| @@ -2853,8 +2848,8 @@ static void con_fault(struct ceph_connection *con) | |||
| 2853 | */ | 2848 | */ |
| 2854 | void ceph_messenger_init(struct ceph_messenger *msgr, | 2849 | void ceph_messenger_init(struct ceph_messenger *msgr, |
| 2855 | struct ceph_entity_addr *myaddr, | 2850 | struct ceph_entity_addr *myaddr, |
| 2856 | u32 supported_features, | 2851 | u64 supported_features, |
| 2857 | u32 required_features, | 2852 | u64 required_features, |
| 2858 | bool nocrc) | 2853 | bool nocrc) |
| 2859 | { | 2854 | { |
| 2860 | msgr->supported_features = supported_features; | 2855 | msgr->supported_features = supported_features; |
| @@ -3126,15 +3121,8 @@ struct ceph_msg *ceph_msg_new(int type, int front_len, gfp_t flags, | |||
| 3126 | INIT_LIST_HEAD(&m->data); | 3121 | INIT_LIST_HEAD(&m->data); |
| 3127 | 3122 | ||
| 3128 | /* front */ | 3123 | /* front */ |
| 3129 | m->front_max = front_len; | ||
| 3130 | if (front_len) { | 3124 | if (front_len) { |
| 3131 | if (front_len > PAGE_CACHE_SIZE) { | 3125 | m->front.iov_base = ceph_kvmalloc(front_len, flags); |
| 3132 | m->front.iov_base = __vmalloc(front_len, flags, | ||
| 3133 | PAGE_KERNEL); | ||
| 3134 | m->front_is_vmalloc = true; | ||
| 3135 | } else { | ||
| 3136 | m->front.iov_base = kmalloc(front_len, flags); | ||
| 3137 | } | ||
| 3138 | if (m->front.iov_base == NULL) { | 3126 | if (m->front.iov_base == NULL) { |
| 3139 | dout("ceph_msg_new can't allocate %d bytes\n", | 3127 | dout("ceph_msg_new can't allocate %d bytes\n", |
| 3140 | front_len); | 3128 | front_len); |
| @@ -3143,7 +3131,7 @@ struct ceph_msg *ceph_msg_new(int type, int front_len, gfp_t flags, | |||
| 3143 | } else { | 3131 | } else { |
| 3144 | m->front.iov_base = NULL; | 3132 | m->front.iov_base = NULL; |
| 3145 | } | 3133 | } |
| 3146 | m->front.iov_len = front_len; | 3134 | m->front_alloc_len = m->front.iov_len = front_len; |
| 3147 | 3135 | ||
| 3148 | dout("ceph_msg_new %p front %d\n", m, front_len); | 3136 | dout("ceph_msg_new %p front %d\n", m, front_len); |
| 3149 | return m; | 3137 | return m; |
| @@ -3256,10 +3244,7 @@ static int ceph_con_in_msg_alloc(struct ceph_connection *con, int *skip) | |||
| 3256 | void ceph_msg_kfree(struct ceph_msg *m) | 3244 | void ceph_msg_kfree(struct ceph_msg *m) |
| 3257 | { | 3245 | { |
| 3258 | dout("msg_kfree %p\n", m); | 3246 | dout("msg_kfree %p\n", m); |
| 3259 | if (m->front_is_vmalloc) | 3247 | ceph_kvfree(m->front.iov_base); |
| 3260 | vfree(m->front.iov_base); | ||
| 3261 | else | ||
| 3262 | kfree(m->front.iov_base); | ||
| 3263 | kmem_cache_free(ceph_msg_cache, m); | 3248 | kmem_cache_free(ceph_msg_cache, m); |
| 3264 | } | 3249 | } |
| 3265 | 3250 | ||
| @@ -3301,8 +3286,8 @@ EXPORT_SYMBOL(ceph_msg_last_put); | |||
| 3301 | 3286 | ||
| 3302 | void ceph_msg_dump(struct ceph_msg *msg) | 3287 | void ceph_msg_dump(struct ceph_msg *msg) |
| 3303 | { | 3288 | { |
| 3304 | pr_debug("msg_dump %p (front_max %d length %zd)\n", msg, | 3289 | pr_debug("msg_dump %p (front_alloc_len %d length %zd)\n", msg, |
| 3305 | msg->front_max, msg->data_length); | 3290 | msg->front_alloc_len, msg->data_length); |
| 3306 | print_hex_dump(KERN_DEBUG, "header: ", | 3291 | print_hex_dump(KERN_DEBUG, "header: ", |
| 3307 | DUMP_PREFIX_OFFSET, 16, 1, | 3292 | DUMP_PREFIX_OFFSET, 16, 1, |
| 3308 | &msg->hdr, sizeof(msg->hdr), true); | 3293 | &msg->hdr, sizeof(msg->hdr), true); |
diff --git a/net/ceph/mon_client.c b/net/ceph/mon_client.c index 1fe25cd29d0e..2ac9ef35110b 100644 --- a/net/ceph/mon_client.c +++ b/net/ceph/mon_client.c | |||
| @@ -152,7 +152,7 @@ static int __open_session(struct ceph_mon_client *monc) | |||
| 152 | /* initiatiate authentication handshake */ | 152 | /* initiatiate authentication handshake */ |
| 153 | ret = ceph_auth_build_hello(monc->auth, | 153 | ret = ceph_auth_build_hello(monc->auth, |
| 154 | monc->m_auth->front.iov_base, | 154 | monc->m_auth->front.iov_base, |
| 155 | monc->m_auth->front_max); | 155 | monc->m_auth->front_alloc_len); |
| 156 | __send_prepared_auth_request(monc, ret); | 156 | __send_prepared_auth_request(monc, ret); |
| 157 | } else { | 157 | } else { |
| 158 | dout("open_session mon%d already open\n", monc->cur_mon); | 158 | dout("open_session mon%d already open\n", monc->cur_mon); |
| @@ -196,7 +196,7 @@ static void __send_subscribe(struct ceph_mon_client *monc) | |||
| 196 | int num; | 196 | int num; |
| 197 | 197 | ||
| 198 | p = msg->front.iov_base; | 198 | p = msg->front.iov_base; |
| 199 | end = p + msg->front_max; | 199 | end = p + msg->front_alloc_len; |
| 200 | 200 | ||
| 201 | num = 1 + !!monc->want_next_osdmap + !!monc->want_mdsmap; | 201 | num = 1 + !!monc->want_next_osdmap + !!monc->want_mdsmap; |
| 202 | ceph_encode_32(&p, num); | 202 | ceph_encode_32(&p, num); |
| @@ -897,7 +897,7 @@ static void handle_auth_reply(struct ceph_mon_client *monc, | |||
| 897 | ret = ceph_handle_auth_reply(monc->auth, msg->front.iov_base, | 897 | ret = ceph_handle_auth_reply(monc->auth, msg->front.iov_base, |
| 898 | msg->front.iov_len, | 898 | msg->front.iov_len, |
| 899 | monc->m_auth->front.iov_base, | 899 | monc->m_auth->front.iov_base, |
| 900 | monc->m_auth->front_max); | 900 | monc->m_auth->front_alloc_len); |
| 901 | if (ret < 0) { | 901 | if (ret < 0) { |
| 902 | monc->client->auth_err = ret; | 902 | monc->client->auth_err = ret; |
| 903 | wake_up_all(&monc->client->auth_wq); | 903 | wake_up_all(&monc->client->auth_wq); |
| @@ -939,7 +939,7 @@ static int __validate_auth(struct ceph_mon_client *monc) | |||
| 939 | return 0; | 939 | return 0; |
| 940 | 940 | ||
| 941 | ret = ceph_build_auth(monc->auth, monc->m_auth->front.iov_base, | 941 | ret = ceph_build_auth(monc->auth, monc->m_auth->front.iov_base, |
| 942 | monc->m_auth->front_max); | 942 | monc->m_auth->front_alloc_len); |
| 943 | if (ret <= 0) | 943 | if (ret <= 0) |
| 944 | return ret; /* either an error, or no need to authenticate */ | 944 | return ret; /* either an error, or no need to authenticate */ |
| 945 | __send_prepared_auth_request(monc, ret); | 945 | __send_prepared_auth_request(monc, ret); |
diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c index 2b4b32aaa893..010ff3bd58ad 100644 --- a/net/ceph/osd_client.c +++ b/net/ceph/osd_client.c | |||
| @@ -338,7 +338,7 @@ struct ceph_osd_request *ceph_osdc_alloc_request(struct ceph_osd_client *osdc, | |||
| 338 | msg_size = 4 + 4 + 8 + 8 + 4+8; | 338 | msg_size = 4 + 4 + 8 + 8 + 4+8; |
| 339 | msg_size += 2 + 4 + 8 + 4 + 4; /* oloc */ | 339 | msg_size += 2 + 4 + 8 + 4 + 4; /* oloc */ |
| 340 | msg_size += 1 + 8 + 4 + 4; /* pg_t */ | 340 | msg_size += 1 + 8 + 4 + 4; /* pg_t */ |
| 341 | msg_size += 4 + MAX_OBJ_NAME_SIZE; | 341 | msg_size += 4 + CEPH_MAX_OID_NAME_LEN; /* oid */ |
| 342 | msg_size += 2 + num_ops*sizeof(struct ceph_osd_op); | 342 | msg_size += 2 + num_ops*sizeof(struct ceph_osd_op); |
| 343 | msg_size += 8; /* snapid */ | 343 | msg_size += 8; /* snapid */ |
| 344 | msg_size += 8; /* snap_seq */ | 344 | msg_size += 8; /* snap_seq */ |
| @@ -368,6 +368,9 @@ struct ceph_osd_request *ceph_osdc_alloc_request(struct ceph_osd_client *osdc, | |||
| 368 | INIT_LIST_HEAD(&req->r_req_lru_item); | 368 | INIT_LIST_HEAD(&req->r_req_lru_item); |
| 369 | INIT_LIST_HEAD(&req->r_osd_item); | 369 | INIT_LIST_HEAD(&req->r_osd_item); |
| 370 | 370 | ||
| 371 | req->r_base_oloc.pool = -1; | ||
| 372 | req->r_target_oloc.pool = -1; | ||
| 373 | |||
| 371 | /* create reply message */ | 374 | /* create reply message */ |
| 372 | if (use_mempool) | 375 | if (use_mempool) |
| 373 | msg = ceph_msgpool_get(&osdc->msgpool_op_reply, 0); | 376 | msg = ceph_msgpool_get(&osdc->msgpool_op_reply, 0); |
| @@ -761,11 +764,11 @@ struct ceph_osd_request *ceph_osdc_new_request(struct ceph_osd_client *osdc, | |||
| 761 | if (num_ops > 1) | 764 | if (num_ops > 1) |
| 762 | osd_req_op_init(req, 1, CEPH_OSD_OP_STARTSYNC); | 765 | osd_req_op_init(req, 1, CEPH_OSD_OP_STARTSYNC); |
| 763 | 766 | ||
| 764 | req->r_file_layout = *layout; /* keep a copy */ | 767 | req->r_base_oloc.pool = ceph_file_layout_pg_pool(*layout); |
| 765 | 768 | ||
| 766 | snprintf(req->r_oid, sizeof(req->r_oid), "%llx.%08llx", | 769 | snprintf(req->r_base_oid.name, sizeof(req->r_base_oid.name), |
| 767 | vino.ino, objnum); | 770 | "%llx.%08llx", vino.ino, objnum); |
| 768 | req->r_oid_len = strlen(req->r_oid); | 771 | req->r_base_oid.name_len = strlen(req->r_base_oid.name); |
| 769 | 772 | ||
| 770 | return req; | 773 | return req; |
| 771 | } | 774 | } |
| @@ -1044,8 +1047,8 @@ static int __reset_osd(struct ceph_osd_client *osdc, struct ceph_osd *osd) | |||
| 1044 | !ceph_con_opened(&osd->o_con)) { | 1047 | !ceph_con_opened(&osd->o_con)) { |
| 1045 | struct ceph_osd_request *req; | 1048 | struct ceph_osd_request *req; |
| 1046 | 1049 | ||
| 1047 | dout(" osd addr hasn't changed and connection never opened," | 1050 | dout("osd addr hasn't changed and connection never opened, " |
| 1048 | " letting msgr retry"); | 1051 | "letting msgr retry\n"); |
| 1049 | /* touch each r_stamp for handle_timeout()'s benfit */ | 1052 | /* touch each r_stamp for handle_timeout()'s benfit */ |
| 1050 | list_for_each_entry(req, &osd->o_requests, r_osd_item) | 1053 | list_for_each_entry(req, &osd->o_requests, r_osd_item) |
| 1051 | req->r_stamp = jiffies; | 1054 | req->r_stamp = jiffies; |
| @@ -1232,6 +1235,61 @@ void ceph_osdc_set_request_linger(struct ceph_osd_client *osdc, | |||
| 1232 | EXPORT_SYMBOL(ceph_osdc_set_request_linger); | 1235 | EXPORT_SYMBOL(ceph_osdc_set_request_linger); |
| 1233 | 1236 | ||
| 1234 | /* | 1237 | /* |
| 1238 | * Returns whether a request should be blocked from being sent | ||
| 1239 | * based on the current osdmap and osd_client settings. | ||
| 1240 | * | ||
| 1241 | * Caller should hold map_sem for read. | ||
| 1242 | */ | ||
| 1243 | static bool __req_should_be_paused(struct ceph_osd_client *osdc, | ||
| 1244 | struct ceph_osd_request *req) | ||
| 1245 | { | ||
| 1246 | bool pauserd = ceph_osdmap_flag(osdc->osdmap, CEPH_OSDMAP_PAUSERD); | ||
| 1247 | bool pausewr = ceph_osdmap_flag(osdc->osdmap, CEPH_OSDMAP_PAUSEWR) || | ||
| 1248 | ceph_osdmap_flag(osdc->osdmap, CEPH_OSDMAP_FULL); | ||
| 1249 | return (req->r_flags & CEPH_OSD_FLAG_READ && pauserd) || | ||
| 1250 | (req->r_flags & CEPH_OSD_FLAG_WRITE && pausewr); | ||
| 1251 | } | ||
| 1252 | |||
| 1253 | /* | ||
| 1254 | * Calculate mapping of a request to a PG. Takes tiering into account. | ||
| 1255 | */ | ||
| 1256 | static int __calc_request_pg(struct ceph_osdmap *osdmap, | ||
| 1257 | struct ceph_osd_request *req, | ||
| 1258 | struct ceph_pg *pg_out) | ||
| 1259 | { | ||
| 1260 | bool need_check_tiering; | ||
| 1261 | |||
| 1262 | need_check_tiering = false; | ||
| 1263 | if (req->r_target_oloc.pool == -1) { | ||
| 1264 | req->r_target_oloc = req->r_base_oloc; /* struct */ | ||
| 1265 | need_check_tiering = true; | ||
| 1266 | } | ||
| 1267 | if (req->r_target_oid.name_len == 0) { | ||
| 1268 | ceph_oid_copy(&req->r_target_oid, &req->r_base_oid); | ||
| 1269 | need_check_tiering = true; | ||
| 1270 | } | ||
| 1271 | |||
| 1272 | if (need_check_tiering && | ||
| 1273 | (req->r_flags & CEPH_OSD_FLAG_IGNORE_OVERLAY) == 0) { | ||
| 1274 | struct ceph_pg_pool_info *pi; | ||
| 1275 | |||
| 1276 | pi = ceph_pg_pool_by_id(osdmap, req->r_target_oloc.pool); | ||
| 1277 | if (pi) { | ||
| 1278 | if ((req->r_flags & CEPH_OSD_FLAG_READ) && | ||
| 1279 | pi->read_tier >= 0) | ||
| 1280 | req->r_target_oloc.pool = pi->read_tier; | ||
| 1281 | if ((req->r_flags & CEPH_OSD_FLAG_WRITE) && | ||
| 1282 | pi->write_tier >= 0) | ||
| 1283 | req->r_target_oloc.pool = pi->write_tier; | ||
| 1284 | } | ||
| 1285 | /* !pi is caught in ceph_oloc_oid_to_pg() */ | ||
| 1286 | } | ||
| 1287 | |||
| 1288 | return ceph_oloc_oid_to_pg(osdmap, &req->r_target_oloc, | ||
| 1289 | &req->r_target_oid, pg_out); | ||
| 1290 | } | ||
| 1291 | |||
| 1292 | /* | ||
| 1235 | * Pick an osd (the first 'up' osd in the pg), allocate the osd struct | 1293 | * Pick an osd (the first 'up' osd in the pg), allocate the osd struct |
| 1236 | * (as needed), and set the request r_osd appropriately. If there is | 1294 | * (as needed), and set the request r_osd appropriately. If there is |
| 1237 | * no up osd, set r_osd to NULL. Move the request to the appropriate list | 1295 | * no up osd, set r_osd to NULL. Move the request to the appropriate list |
| @@ -1248,10 +1306,11 @@ static int __map_request(struct ceph_osd_client *osdc, | |||
| 1248 | int acting[CEPH_PG_MAX_SIZE]; | 1306 | int acting[CEPH_PG_MAX_SIZE]; |
| 1249 | int o = -1, num = 0; | 1307 | int o = -1, num = 0; |
| 1250 | int err; | 1308 | int err; |
| 1309 | bool was_paused; | ||
| 1251 | 1310 | ||
| 1252 | dout("map_request %p tid %lld\n", req, req->r_tid); | 1311 | dout("map_request %p tid %lld\n", req, req->r_tid); |
| 1253 | err = ceph_calc_ceph_pg(&pgid, req->r_oid, osdc->osdmap, | 1312 | |
| 1254 | ceph_file_layout_pg_pool(req->r_file_layout)); | 1313 | err = __calc_request_pg(osdc->osdmap, req, &pgid); |
| 1255 | if (err) { | 1314 | if (err) { |
| 1256 | list_move(&req->r_req_lru_item, &osdc->req_notarget); | 1315 | list_move(&req->r_req_lru_item, &osdc->req_notarget); |
| 1257 | return err; | 1316 | return err; |
| @@ -1264,12 +1323,18 @@ static int __map_request(struct ceph_osd_client *osdc, | |||
| 1264 | num = err; | 1323 | num = err; |
| 1265 | } | 1324 | } |
| 1266 | 1325 | ||
| 1326 | was_paused = req->r_paused; | ||
| 1327 | req->r_paused = __req_should_be_paused(osdc, req); | ||
| 1328 | if (was_paused && !req->r_paused) | ||
| 1329 | force_resend = 1; | ||
| 1330 | |||
| 1267 | if ((!force_resend && | 1331 | if ((!force_resend && |
| 1268 | req->r_osd && req->r_osd->o_osd == o && | 1332 | req->r_osd && req->r_osd->o_osd == o && |
| 1269 | req->r_sent >= req->r_osd->o_incarnation && | 1333 | req->r_sent >= req->r_osd->o_incarnation && |
| 1270 | req->r_num_pg_osds == num && | 1334 | req->r_num_pg_osds == num && |
| 1271 | memcmp(req->r_pg_osds, acting, sizeof(acting[0])*num) == 0) || | 1335 | memcmp(req->r_pg_osds, acting, sizeof(acting[0])*num) == 0) || |
| 1272 | (req->r_osd == NULL && o == -1)) | 1336 | (req->r_osd == NULL && o == -1) || |
| 1337 | req->r_paused) | ||
| 1273 | return 0; /* no change */ | 1338 | return 0; /* no change */ |
| 1274 | 1339 | ||
| 1275 | dout("map_request tid %llu pgid %lld.%x osd%d (was osd%d)\n", | 1340 | dout("map_request tid %llu pgid %lld.%x osd%d (was osd%d)\n", |
| @@ -1331,7 +1396,7 @@ static void __send_request(struct ceph_osd_client *osdc, | |||
| 1331 | /* fill in message content that changes each time we send it */ | 1396 | /* fill in message content that changes each time we send it */ |
| 1332 | put_unaligned_le32(osdc->osdmap->epoch, req->r_request_osdmap_epoch); | 1397 | put_unaligned_le32(osdc->osdmap->epoch, req->r_request_osdmap_epoch); |
| 1333 | put_unaligned_le32(req->r_flags, req->r_request_flags); | 1398 | put_unaligned_le32(req->r_flags, req->r_request_flags); |
| 1334 | put_unaligned_le64(req->r_pgid.pool, req->r_request_pool); | 1399 | put_unaligned_le64(req->r_target_oloc.pool, req->r_request_pool); |
| 1335 | p = req->r_request_pgid; | 1400 | p = req->r_request_pgid; |
| 1336 | ceph_encode_64(&p, req->r_pgid.pool); | 1401 | ceph_encode_64(&p, req->r_pgid.pool); |
| 1337 | ceph_encode_32(&p, req->r_pgid.seed); | 1402 | ceph_encode_32(&p, req->r_pgid.seed); |
| @@ -1432,6 +1497,109 @@ static void handle_osds_timeout(struct work_struct *work) | |||
| 1432 | round_jiffies_relative(delay)); | 1497 | round_jiffies_relative(delay)); |
| 1433 | } | 1498 | } |
| 1434 | 1499 | ||
| 1500 | static int ceph_oloc_decode(void **p, void *end, | ||
| 1501 | struct ceph_object_locator *oloc) | ||
| 1502 | { | ||
| 1503 | u8 struct_v, struct_cv; | ||
| 1504 | u32 len; | ||
| 1505 | void *struct_end; | ||
| 1506 | int ret = 0; | ||
| 1507 | |||
| 1508 | ceph_decode_need(p, end, 1 + 1 + 4, e_inval); | ||
| 1509 | struct_v = ceph_decode_8(p); | ||
| 1510 | struct_cv = ceph_decode_8(p); | ||
| 1511 | if (struct_v < 3) { | ||
| 1512 | pr_warn("got v %d < 3 cv %d of ceph_object_locator\n", | ||
| 1513 | struct_v, struct_cv); | ||
| 1514 | goto e_inval; | ||
| 1515 | } | ||
| 1516 | if (struct_cv > 6) { | ||
| 1517 | pr_warn("got v %d cv %d > 6 of ceph_object_locator\n", | ||
| 1518 | struct_v, struct_cv); | ||
| 1519 | goto e_inval; | ||
| 1520 | } | ||
| 1521 | len = ceph_decode_32(p); | ||
| 1522 | ceph_decode_need(p, end, len, e_inval); | ||
| 1523 | struct_end = *p + len; | ||
| 1524 | |||
| 1525 | oloc->pool = ceph_decode_64(p); | ||
| 1526 | *p += 4; /* skip preferred */ | ||
| 1527 | |||
| 1528 | len = ceph_decode_32(p); | ||
| 1529 | if (len > 0) { | ||
| 1530 | pr_warn("ceph_object_locator::key is set\n"); | ||
| 1531 | goto e_inval; | ||
| 1532 | } | ||
| 1533 | |||
| 1534 | if (struct_v >= 5) { | ||
| 1535 | len = ceph_decode_32(p); | ||
| 1536 | if (len > 0) { | ||
| 1537 | pr_warn("ceph_object_locator::nspace is set\n"); | ||
| 1538 | goto e_inval; | ||
| 1539 | } | ||
| 1540 | } | ||
| 1541 | |||
| 1542 | if (struct_v >= 6) { | ||
| 1543 | s64 hash = ceph_decode_64(p); | ||
| 1544 | if (hash != -1) { | ||
| 1545 | pr_warn("ceph_object_locator::hash is set\n"); | ||
| 1546 | goto e_inval; | ||
| 1547 | } | ||
| 1548 | } | ||
| 1549 | |||
| 1550 | /* skip the rest */ | ||
| 1551 | *p = struct_end; | ||
| 1552 | out: | ||
| 1553 | return ret; | ||
| 1554 | |||
| 1555 | e_inval: | ||
| 1556 | ret = -EINVAL; | ||
| 1557 | goto out; | ||
| 1558 | } | ||
| 1559 | |||
| 1560 | static int ceph_redirect_decode(void **p, void *end, | ||
| 1561 | struct ceph_request_redirect *redir) | ||
| 1562 | { | ||
| 1563 | u8 struct_v, struct_cv; | ||
| 1564 | u32 len; | ||
| 1565 | void *struct_end; | ||
| 1566 | int ret; | ||
| 1567 | |||
| 1568 | ceph_decode_need(p, end, 1 + 1 + 4, e_inval); | ||
| 1569 | struct_v = ceph_decode_8(p); | ||
| 1570 | struct_cv = ceph_decode_8(p); | ||
| 1571 | if (struct_cv > 1) { | ||
| 1572 | pr_warn("got v %d cv %d > 1 of ceph_request_redirect\n", | ||
| 1573 | struct_v, struct_cv); | ||
| 1574 | goto e_inval; | ||
| 1575 | } | ||
| 1576 | len = ceph_decode_32(p); | ||
| 1577 | ceph_decode_need(p, end, len, e_inval); | ||
| 1578 | struct_end = *p + len; | ||
| 1579 | |||
| 1580 | ret = ceph_oloc_decode(p, end, &redir->oloc); | ||
| 1581 | if (ret) | ||
| 1582 | goto out; | ||
| 1583 | |||
| 1584 | len = ceph_decode_32(p); | ||
| 1585 | if (len > 0) { | ||
| 1586 | pr_warn("ceph_request_redirect::object_name is set\n"); | ||
| 1587 | goto e_inval; | ||
| 1588 | } | ||
| 1589 | |||
| 1590 | len = ceph_decode_32(p); | ||
| 1591 | *p += len; /* skip osd_instructions */ | ||
| 1592 | |||
| 1593 | /* skip the rest */ | ||
| 1594 | *p = struct_end; | ||
| 1595 | out: | ||
| 1596 | return ret; | ||
| 1597 | |||
| 1598 | e_inval: | ||
| 1599 | ret = -EINVAL; | ||
| 1600 | goto out; | ||
| 1601 | } | ||
| 1602 | |||
| 1435 | static void complete_request(struct ceph_osd_request *req) | 1603 | static void complete_request(struct ceph_osd_request *req) |
| 1436 | { | 1604 | { |
| 1437 | complete_all(&req->r_safe_completion); /* fsync waiter */ | 1605 | complete_all(&req->r_safe_completion); /* fsync waiter */ |
| @@ -1446,6 +1614,7 @@ static void handle_reply(struct ceph_osd_client *osdc, struct ceph_msg *msg, | |||
| 1446 | { | 1614 | { |
| 1447 | void *p, *end; | 1615 | void *p, *end; |
| 1448 | struct ceph_osd_request *req; | 1616 | struct ceph_osd_request *req; |
| 1617 | struct ceph_request_redirect redir; | ||
| 1449 | u64 tid; | 1618 | u64 tid; |
| 1450 | int object_len; | 1619 | int object_len; |
| 1451 | unsigned int numops; | 1620 | unsigned int numops; |
| @@ -1525,10 +1694,41 @@ static void handle_reply(struct ceph_osd_client *osdc, struct ceph_msg *msg, | |||
| 1525 | for (i = 0; i < numops; i++) | 1694 | for (i = 0; i < numops; i++) |
| 1526 | req->r_reply_op_result[i] = ceph_decode_32(&p); | 1695 | req->r_reply_op_result[i] = ceph_decode_32(&p); |
| 1527 | 1696 | ||
| 1528 | already_completed = req->r_got_reply; | 1697 | if (le16_to_cpu(msg->hdr.version) >= 6) { |
| 1698 | p += 8 + 4; /* skip replay_version */ | ||
| 1699 | p += 8; /* skip user_version */ | ||
| 1529 | 1700 | ||
| 1530 | if (!req->r_got_reply) { | 1701 | err = ceph_redirect_decode(&p, end, &redir); |
| 1702 | if (err) | ||
| 1703 | goto bad_put; | ||
| 1704 | } else { | ||
| 1705 | redir.oloc.pool = -1; | ||
| 1706 | } | ||
| 1707 | |||
| 1708 | if (redir.oloc.pool != -1) { | ||
| 1709 | dout("redirect pool %lld\n", redir.oloc.pool); | ||
| 1710 | |||
| 1711 | __unregister_request(osdc, req); | ||
| 1712 | mutex_unlock(&osdc->request_mutex); | ||
| 1713 | |||
| 1714 | req->r_target_oloc = redir.oloc; /* struct */ | ||
| 1715 | |||
| 1716 | /* | ||
| 1717 | * Start redirect requests with nofail=true. If | ||
| 1718 | * mapping fails, request will end up on the notarget | ||
| 1719 | * list, waiting for the new osdmap (which can take | ||
| 1720 | * a while), even though the original request mapped | ||
| 1721 | * successfully. In the future we might want to follow | ||
| 1722 | * original request's nofail setting here. | ||
| 1723 | */ | ||
| 1724 | err = ceph_osdc_start_request(osdc, req, true); | ||
| 1725 | BUG_ON(err); | ||
| 1531 | 1726 | ||
| 1727 | goto done; | ||
| 1728 | } | ||
| 1729 | |||
| 1730 | already_completed = req->r_got_reply; | ||
| 1731 | if (!req->r_got_reply) { | ||
| 1532 | req->r_result = result; | 1732 | req->r_result = result; |
| 1533 | dout("handle_reply result %d bytes %d\n", req->r_result, | 1733 | dout("handle_reply result %d bytes %d\n", req->r_result, |
| 1534 | bytes); | 1734 | bytes); |
| @@ -1581,6 +1781,13 @@ done: | |||
| 1581 | return; | 1781 | return; |
| 1582 | 1782 | ||
| 1583 | bad_put: | 1783 | bad_put: |
| 1784 | req->r_result = -EIO; | ||
| 1785 | __unregister_request(osdc, req); | ||
| 1786 | if (req->r_callback) | ||
| 1787 | req->r_callback(req, msg); | ||
| 1788 | else | ||
| 1789 | complete_all(&req->r_completion); | ||
| 1790 | complete_request(req); | ||
| 1584 | ceph_osdc_put_request(req); | 1791 | ceph_osdc_put_request(req); |
| 1585 | bad_mutex: | 1792 | bad_mutex: |
| 1586 | mutex_unlock(&osdc->request_mutex); | 1793 | mutex_unlock(&osdc->request_mutex); |
| @@ -1613,14 +1820,17 @@ static void reset_changed_osds(struct ceph_osd_client *osdc) | |||
| 1613 | * | 1820 | * |
| 1614 | * Caller should hold map_sem for read. | 1821 | * Caller should hold map_sem for read. |
| 1615 | */ | 1822 | */ |
| 1616 | static void kick_requests(struct ceph_osd_client *osdc, int force_resend) | 1823 | static void kick_requests(struct ceph_osd_client *osdc, bool force_resend, |
| 1824 | bool force_resend_writes) | ||
| 1617 | { | 1825 | { |
| 1618 | struct ceph_osd_request *req, *nreq; | 1826 | struct ceph_osd_request *req, *nreq; |
| 1619 | struct rb_node *p; | 1827 | struct rb_node *p; |
| 1620 | int needmap = 0; | 1828 | int needmap = 0; |
| 1621 | int err; | 1829 | int err; |
| 1830 | bool force_resend_req; | ||
| 1622 | 1831 | ||
| 1623 | dout("kick_requests %s\n", force_resend ? " (force resend)" : ""); | 1832 | dout("kick_requests %s %s\n", force_resend ? " (force resend)" : "", |
| 1833 | force_resend_writes ? " (force resend writes)" : ""); | ||
| 1624 | mutex_lock(&osdc->request_mutex); | 1834 | mutex_lock(&osdc->request_mutex); |
| 1625 | for (p = rb_first(&osdc->requests); p; ) { | 1835 | for (p = rb_first(&osdc->requests); p; ) { |
| 1626 | req = rb_entry(p, struct ceph_osd_request, r_node); | 1836 | req = rb_entry(p, struct ceph_osd_request, r_node); |
| @@ -1645,7 +1855,10 @@ static void kick_requests(struct ceph_osd_client *osdc, int force_resend) | |||
| 1645 | continue; | 1855 | continue; |
| 1646 | } | 1856 | } |
| 1647 | 1857 | ||
| 1648 | err = __map_request(osdc, req, force_resend); | 1858 | force_resend_req = force_resend || |
| 1859 | (force_resend_writes && | ||
| 1860 | req->r_flags & CEPH_OSD_FLAG_WRITE); | ||
| 1861 | err = __map_request(osdc, req, force_resend_req); | ||
| 1649 | if (err < 0) | 1862 | if (err < 0) |
| 1650 | continue; /* error */ | 1863 | continue; /* error */ |
| 1651 | if (req->r_osd == NULL) { | 1864 | if (req->r_osd == NULL) { |
| @@ -1665,7 +1878,8 @@ static void kick_requests(struct ceph_osd_client *osdc, int force_resend) | |||
| 1665 | r_linger_item) { | 1878 | r_linger_item) { |
| 1666 | dout("linger req=%p req->r_osd=%p\n", req, req->r_osd); | 1879 | dout("linger req=%p req->r_osd=%p\n", req, req->r_osd); |
| 1667 | 1880 | ||
| 1668 | err = __map_request(osdc, req, force_resend); | 1881 | err = __map_request(osdc, req, |
| 1882 | force_resend || force_resend_writes); | ||
| 1669 | dout("__map_request returned %d\n", err); | 1883 | dout("__map_request returned %d\n", err); |
| 1670 | if (err == 0) | 1884 | if (err == 0) |
| 1671 | continue; /* no change and no osd was specified */ | 1885 | continue; /* no change and no osd was specified */ |
| @@ -1707,6 +1921,7 @@ void ceph_osdc_handle_map(struct ceph_osd_client *osdc, struct ceph_msg *msg) | |||
| 1707 | struct ceph_osdmap *newmap = NULL, *oldmap; | 1921 | struct ceph_osdmap *newmap = NULL, *oldmap; |
| 1708 | int err; | 1922 | int err; |
| 1709 | struct ceph_fsid fsid; | 1923 | struct ceph_fsid fsid; |
| 1924 | bool was_full; | ||
| 1710 | 1925 | ||
| 1711 | dout("handle_map have %u\n", osdc->osdmap ? osdc->osdmap->epoch : 0); | 1926 | dout("handle_map have %u\n", osdc->osdmap ? osdc->osdmap->epoch : 0); |
| 1712 | p = msg->front.iov_base; | 1927 | p = msg->front.iov_base; |
| @@ -1720,6 +1935,8 @@ void ceph_osdc_handle_map(struct ceph_osd_client *osdc, struct ceph_msg *msg) | |||
| 1720 | 1935 | ||
| 1721 | down_write(&osdc->map_sem); | 1936 | down_write(&osdc->map_sem); |
| 1722 | 1937 | ||
| 1938 | was_full = ceph_osdmap_flag(osdc->osdmap, CEPH_OSDMAP_FULL); | ||
| 1939 | |||
| 1723 | /* incremental maps */ | 1940 | /* incremental maps */ |
| 1724 | ceph_decode_32_safe(&p, end, nr_maps, bad); | 1941 | ceph_decode_32_safe(&p, end, nr_maps, bad); |
| 1725 | dout(" %d inc maps\n", nr_maps); | 1942 | dout(" %d inc maps\n", nr_maps); |
| @@ -1744,7 +1961,10 @@ void ceph_osdc_handle_map(struct ceph_osd_client *osdc, struct ceph_msg *msg) | |||
| 1744 | ceph_osdmap_destroy(osdc->osdmap); | 1961 | ceph_osdmap_destroy(osdc->osdmap); |
| 1745 | osdc->osdmap = newmap; | 1962 | osdc->osdmap = newmap; |
| 1746 | } | 1963 | } |
| 1747 | kick_requests(osdc, 0); | 1964 | was_full = was_full || |
| 1965 | ceph_osdmap_flag(osdc->osdmap, | ||
| 1966 | CEPH_OSDMAP_FULL); | ||
| 1967 | kick_requests(osdc, 0, was_full); | ||
| 1748 | } else { | 1968 | } else { |
| 1749 | dout("ignoring incremental map %u len %d\n", | 1969 | dout("ignoring incremental map %u len %d\n", |
| 1750 | epoch, maplen); | 1970 | epoch, maplen); |
| @@ -1787,7 +2007,10 @@ void ceph_osdc_handle_map(struct ceph_osd_client *osdc, struct ceph_msg *msg) | |||
| 1787 | skipped_map = 1; | 2007 | skipped_map = 1; |
| 1788 | ceph_osdmap_destroy(oldmap); | 2008 | ceph_osdmap_destroy(oldmap); |
| 1789 | } | 2009 | } |
| 1790 | kick_requests(osdc, skipped_map); | 2010 | was_full = was_full || |
| 2011 | ceph_osdmap_flag(osdc->osdmap, | ||
| 2012 | CEPH_OSDMAP_FULL); | ||
| 2013 | kick_requests(osdc, skipped_map, was_full); | ||
| 1791 | } | 2014 | } |
| 1792 | p += maplen; | 2015 | p += maplen; |
| 1793 | nr_maps--; | 2016 | nr_maps--; |
| @@ -1804,7 +2027,9 @@ done: | |||
| 1804 | * we find out when we are no longer full and stop returning | 2027 | * we find out when we are no longer full and stop returning |
| 1805 | * ENOSPC. | 2028 | * ENOSPC. |
| 1806 | */ | 2029 | */ |
| 1807 | if (ceph_osdmap_flag(osdc->osdmap, CEPH_OSDMAP_FULL)) | 2030 | if (ceph_osdmap_flag(osdc->osdmap, CEPH_OSDMAP_FULL) || |
| 2031 | ceph_osdmap_flag(osdc->osdmap, CEPH_OSDMAP_PAUSERD) || | ||
| 2032 | ceph_osdmap_flag(osdc->osdmap, CEPH_OSDMAP_PAUSEWR)) | ||
| 1808 | ceph_monc_request_next_osdmap(&osdc->client->monc); | 2033 | ceph_monc_request_next_osdmap(&osdc->client->monc); |
| 1809 | 2034 | ||
| 1810 | mutex_lock(&osdc->request_mutex); | 2035 | mutex_lock(&osdc->request_mutex); |
| @@ -2068,10 +2293,11 @@ void ceph_osdc_build_request(struct ceph_osd_request *req, u64 off, | |||
| 2068 | ceph_encode_32(&p, -1); /* preferred */ | 2293 | ceph_encode_32(&p, -1); /* preferred */ |
| 2069 | 2294 | ||
| 2070 | /* oid */ | 2295 | /* oid */ |
| 2071 | ceph_encode_32(&p, req->r_oid_len); | 2296 | ceph_encode_32(&p, req->r_base_oid.name_len); |
| 2072 | memcpy(p, req->r_oid, req->r_oid_len); | 2297 | memcpy(p, req->r_base_oid.name, req->r_base_oid.name_len); |
| 2073 | dout("oid '%.*s' len %d\n", req->r_oid_len, req->r_oid, req->r_oid_len); | 2298 | dout("oid '%.*s' len %d\n", req->r_base_oid.name_len, |
| 2074 | p += req->r_oid_len; | 2299 | req->r_base_oid.name, req->r_base_oid.name_len); |
| 2300 | p += req->r_base_oid.name_len; | ||
| 2075 | 2301 | ||
| 2076 | /* ops--can imply data */ | 2302 | /* ops--can imply data */ |
| 2077 | ceph_encode_16(&p, (u16)req->r_num_ops); | 2303 | ceph_encode_16(&p, (u16)req->r_num_ops); |
| @@ -2454,7 +2680,7 @@ static struct ceph_msg *get_reply(struct ceph_connection *con, | |||
| 2454 | struct ceph_osd_client *osdc = osd->o_osdc; | 2680 | struct ceph_osd_client *osdc = osd->o_osdc; |
| 2455 | struct ceph_msg *m; | 2681 | struct ceph_msg *m; |
| 2456 | struct ceph_osd_request *req; | 2682 | struct ceph_osd_request *req; |
| 2457 | int front = le32_to_cpu(hdr->front_len); | 2683 | int front_len = le32_to_cpu(hdr->front_len); |
| 2458 | int data_len = le32_to_cpu(hdr->data_len); | 2684 | int data_len = le32_to_cpu(hdr->data_len); |
| 2459 | u64 tid; | 2685 | u64 tid; |
| 2460 | 2686 | ||
| @@ -2474,12 +2700,13 @@ static struct ceph_msg *get_reply(struct ceph_connection *con, | |||
| 2474 | req->r_reply, req->r_reply->con); | 2700 | req->r_reply, req->r_reply->con); |
| 2475 | ceph_msg_revoke_incoming(req->r_reply); | 2701 | ceph_msg_revoke_incoming(req->r_reply); |
| 2476 | 2702 | ||
| 2477 | if (front > req->r_reply->front.iov_len) { | 2703 | if (front_len > req->r_reply->front_alloc_len) { |
| 2478 | pr_warning("get_reply front %d > preallocated %d (%u#%llu)\n", | 2704 | pr_warning("get_reply front %d > preallocated %d (%u#%llu)\n", |
| 2479 | front, (int)req->r_reply->front.iov_len, | 2705 | front_len, req->r_reply->front_alloc_len, |
| 2480 | (unsigned int)con->peer_name.type, | 2706 | (unsigned int)con->peer_name.type, |
| 2481 | le64_to_cpu(con->peer_name.num)); | 2707 | le64_to_cpu(con->peer_name.num)); |
| 2482 | m = ceph_msg_new(CEPH_MSG_OSD_OPREPLY, front, GFP_NOFS, false); | 2708 | m = ceph_msg_new(CEPH_MSG_OSD_OPREPLY, front_len, GFP_NOFS, |
| 2709 | false); | ||
| 2483 | if (!m) | 2710 | if (!m) |
| 2484 | goto out; | 2711 | goto out; |
| 2485 | ceph_msg_put(req->r_reply); | 2712 | ceph_msg_put(req->r_reply); |
diff --git a/net/ceph/osdmap.c b/net/ceph/osdmap.c index dbd9a4792427..aade4a5c1c07 100644 --- a/net/ceph/osdmap.c +++ b/net/ceph/osdmap.c | |||
| @@ -464,6 +464,11 @@ static struct ceph_pg_pool_info *__lookup_pg_pool(struct rb_root *root, u64 id) | |||
| 464 | return NULL; | 464 | return NULL; |
| 465 | } | 465 | } |
| 466 | 466 | ||
| 467 | struct ceph_pg_pool_info *ceph_pg_pool_by_id(struct ceph_osdmap *map, u64 id) | ||
| 468 | { | ||
| 469 | return __lookup_pg_pool(&map->pg_pools, id); | ||
| 470 | } | ||
| 471 | |||
| 467 | const char *ceph_pg_pool_name_by_id(struct ceph_osdmap *map, u64 id) | 472 | const char *ceph_pg_pool_name_by_id(struct ceph_osdmap *map, u64 id) |
| 468 | { | 473 | { |
| 469 | struct ceph_pg_pool_info *pi; | 474 | struct ceph_pg_pool_info *pi; |
| @@ -514,8 +519,8 @@ static int __decode_pool(void **p, void *end, struct ceph_pg_pool_info *pi) | |||
| 514 | pr_warning("got v %d < 5 cv %d of ceph_pg_pool\n", ev, cv); | 519 | pr_warning("got v %d < 5 cv %d of ceph_pg_pool\n", ev, cv); |
| 515 | return -EINVAL; | 520 | return -EINVAL; |
| 516 | } | 521 | } |
| 517 | if (cv > 7) { | 522 | if (cv > 9) { |
| 518 | pr_warning("got v %d cv %d > 7 of ceph_pg_pool\n", ev, cv); | 523 | pr_warning("got v %d cv %d > 9 of ceph_pg_pool\n", ev, cv); |
| 519 | return -EINVAL; | 524 | return -EINVAL; |
| 520 | } | 525 | } |
| 521 | len = ceph_decode_32(p); | 526 | len = ceph_decode_32(p); |
| @@ -543,12 +548,34 @@ static int __decode_pool(void **p, void *end, struct ceph_pg_pool_info *pi) | |||
| 543 | *p += len; | 548 | *p += len; |
| 544 | } | 549 | } |
| 545 | 550 | ||
| 546 | /* skip removed snaps */ | 551 | /* skip removed_snaps */ |
| 547 | num = ceph_decode_32(p); | 552 | num = ceph_decode_32(p); |
| 548 | *p += num * (8 + 8); | 553 | *p += num * (8 + 8); |
| 549 | 554 | ||
| 550 | *p += 8; /* skip auid */ | 555 | *p += 8; /* skip auid */ |
| 551 | pi->flags = ceph_decode_64(p); | 556 | pi->flags = ceph_decode_64(p); |
| 557 | *p += 4; /* skip crash_replay_interval */ | ||
| 558 | |||
| 559 | if (ev >= 7) | ||
| 560 | *p += 1; /* skip min_size */ | ||
| 561 | |||
| 562 | if (ev >= 8) | ||
| 563 | *p += 8 + 8; /* skip quota_max_* */ | ||
| 564 | |||
| 565 | if (ev >= 9) { | ||
| 566 | /* skip tiers */ | ||
| 567 | num = ceph_decode_32(p); | ||
| 568 | *p += num * 8; | ||
| 569 | |||
| 570 | *p += 8; /* skip tier_of */ | ||
| 571 | *p += 1; /* skip cache_mode */ | ||
| 572 | |||
| 573 | pi->read_tier = ceph_decode_64(p); | ||
| 574 | pi->write_tier = ceph_decode_64(p); | ||
| 575 | } else { | ||
| 576 | pi->read_tier = -1; | ||
| 577 | pi->write_tier = -1; | ||
| 578 | } | ||
| 552 | 579 | ||
| 553 | /* ignore the rest */ | 580 | /* ignore the rest */ |
| 554 | 581 | ||
| @@ -1090,25 +1117,40 @@ invalid: | |||
| 1090 | EXPORT_SYMBOL(ceph_calc_file_object_mapping); | 1117 | EXPORT_SYMBOL(ceph_calc_file_object_mapping); |
| 1091 | 1118 | ||
| 1092 | /* | 1119 | /* |
| 1093 | * calculate an object layout (i.e. pgid) from an oid, | 1120 | * Calculate mapping of a (oloc, oid) pair to a PG. Should only be |
| 1094 | * file_layout, and osdmap | 1121 | * called with target's (oloc, oid), since tiering isn't taken into |
| 1122 | * account. | ||
| 1095 | */ | 1123 | */ |
| 1096 | int ceph_calc_ceph_pg(struct ceph_pg *pg, const char *oid, | 1124 | int ceph_oloc_oid_to_pg(struct ceph_osdmap *osdmap, |
| 1097 | struct ceph_osdmap *osdmap, uint64_t pool) | 1125 | struct ceph_object_locator *oloc, |
| 1126 | struct ceph_object_id *oid, | ||
| 1127 | struct ceph_pg *pg_out) | ||
| 1098 | { | 1128 | { |
| 1099 | struct ceph_pg_pool_info *pool_info; | 1129 | struct ceph_pg_pool_info *pi; |
| 1100 | 1130 | ||
| 1101 | BUG_ON(!osdmap); | 1131 | pi = __lookup_pg_pool(&osdmap->pg_pools, oloc->pool); |
| 1102 | pool_info = __lookup_pg_pool(&osdmap->pg_pools, pool); | 1132 | if (!pi) |
| 1103 | if (!pool_info) | ||
| 1104 | return -EIO; | 1133 | return -EIO; |
| 1105 | pg->pool = pool; | ||
| 1106 | pg->seed = ceph_str_hash(pool_info->object_hash, oid, strlen(oid)); | ||
| 1107 | 1134 | ||
| 1108 | dout("%s '%s' pgid %lld.%x\n", __func__, oid, pg->pool, pg->seed); | 1135 | pg_out->pool = oloc->pool; |
| 1136 | pg_out->seed = ceph_str_hash(pi->object_hash, oid->name, | ||
| 1137 | oid->name_len); | ||
| 1138 | |||
| 1139 | dout("%s '%.*s' pgid %llu.%x\n", __func__, oid->name_len, oid->name, | ||
| 1140 | pg_out->pool, pg_out->seed); | ||
| 1109 | return 0; | 1141 | return 0; |
| 1110 | } | 1142 | } |
| 1111 | EXPORT_SYMBOL(ceph_calc_ceph_pg); | 1143 | EXPORT_SYMBOL(ceph_oloc_oid_to_pg); |
| 1144 | |||
| 1145 | static int crush_do_rule_ary(const struct crush_map *map, int ruleno, int x, | ||
| 1146 | int *result, int result_max, | ||
| 1147 | const __u32 *weight, int weight_max) | ||
| 1148 | { | ||
| 1149 | int scratch[result_max * 3]; | ||
| 1150 | |||
| 1151 | return crush_do_rule(map, ruleno, x, result, result_max, | ||
| 1152 | weight, weight_max, scratch); | ||
| 1153 | } | ||
| 1112 | 1154 | ||
| 1113 | /* | 1155 | /* |
| 1114 | * Calculate raw osd vector for the given pgid. Return pointer to osd | 1156 | * Calculate raw osd vector for the given pgid. Return pointer to osd |
| @@ -1163,9 +1205,9 @@ static int *calc_pg_raw(struct ceph_osdmap *osdmap, struct ceph_pg pgid, | |||
| 1163 | pool->pgp_num_mask) + | 1205 | pool->pgp_num_mask) + |
| 1164 | (unsigned)pgid.pool; | 1206 | (unsigned)pgid.pool; |
| 1165 | } | 1207 | } |
| 1166 | r = crush_do_rule(osdmap->crush, ruleno, pps, osds, | 1208 | r = crush_do_rule_ary(osdmap->crush, ruleno, pps, |
| 1167 | min_t(int, pool->size, *num), | 1209 | osds, min_t(int, pool->size, *num), |
| 1168 | osdmap->osd_weight); | 1210 | osdmap->osd_weight, osdmap->max_osd); |
| 1169 | if (r < 0) { | 1211 | if (r < 0) { |
| 1170 | pr_err("error %d from crush rule: pool %lld ruleset %d type %d" | 1212 | pr_err("error %d from crush rule: pool %lld ruleset %d type %d" |
| 1171 | " size %d\n", r, pgid.pool, pool->crush_ruleset, | 1213 | " size %d\n", r, pgid.pool, pool->crush_ruleset, |
diff --git a/net/compat.c b/net/compat.c index dd32e34c1e2c..f50161fb812e 100644 --- a/net/compat.c +++ b/net/compat.c | |||
| @@ -780,21 +780,16 @@ asmlinkage long compat_sys_recvmmsg(int fd, struct compat_mmsghdr __user *mmsg, | |||
| 780 | if (flags & MSG_CMSG_COMPAT) | 780 | if (flags & MSG_CMSG_COMPAT) |
| 781 | return -EINVAL; | 781 | return -EINVAL; |
| 782 | 782 | ||
| 783 | if (COMPAT_USE_64BIT_TIME) | ||
| 784 | return __sys_recvmmsg(fd, (struct mmsghdr __user *)mmsg, vlen, | ||
| 785 | flags | MSG_CMSG_COMPAT, | ||
| 786 | (struct timespec *) timeout); | ||
| 787 | |||
| 788 | if (timeout == NULL) | 783 | if (timeout == NULL) |
| 789 | return __sys_recvmmsg(fd, (struct mmsghdr __user *)mmsg, vlen, | 784 | return __sys_recvmmsg(fd, (struct mmsghdr __user *)mmsg, vlen, |
| 790 | flags | MSG_CMSG_COMPAT, NULL); | 785 | flags | MSG_CMSG_COMPAT, NULL); |
| 791 | 786 | ||
| 792 | if (get_compat_timespec(&ktspec, timeout)) | 787 | if (compat_get_timespec(&ktspec, timeout)) |
| 793 | return -EFAULT; | 788 | return -EFAULT; |
| 794 | 789 | ||
| 795 | datagrams = __sys_recvmmsg(fd, (struct mmsghdr __user *)mmsg, vlen, | 790 | datagrams = __sys_recvmmsg(fd, (struct mmsghdr __user *)mmsg, vlen, |
| 796 | flags | MSG_CMSG_COMPAT, &ktspec); | 791 | flags | MSG_CMSG_COMPAT, &ktspec); |
| 797 | if (datagrams > 0 && put_compat_timespec(&ktspec, timeout)) | 792 | if (datagrams > 0 && compat_put_timespec(&ktspec, timeout)) |
| 798 | datagrams = -EFAULT; | 793 | datagrams = -EFAULT; |
| 799 | 794 | ||
| 800 | return datagrams; | 795 | return datagrams; |
diff --git a/net/core/Makefile b/net/core/Makefile index b33b996f5dd6..9628c20acff6 100644 --- a/net/core/Makefile +++ b/net/core/Makefile | |||
| @@ -21,4 +21,5 @@ obj-$(CONFIG_FIB_RULES) += fib_rules.o | |||
| 21 | obj-$(CONFIG_TRACEPOINTS) += net-traces.o | 21 | obj-$(CONFIG_TRACEPOINTS) += net-traces.o |
| 22 | obj-$(CONFIG_NET_DROP_MONITOR) += drop_monitor.o | 22 | obj-$(CONFIG_NET_DROP_MONITOR) += drop_monitor.o |
| 23 | obj-$(CONFIG_NETWORK_PHY_TIMESTAMPING) += timestamping.o | 23 | obj-$(CONFIG_NETWORK_PHY_TIMESTAMPING) += timestamping.o |
| 24 | obj-$(CONFIG_NETPRIO_CGROUP) += netprio_cgroup.o | 24 | obj-$(CONFIG_CGROUP_NET_PRIO) += netprio_cgroup.o |
| 25 | obj-$(CONFIG_CGROUP_NET_CLASSID) += netclassid_cgroup.o | ||
diff --git a/net/core/dev.c b/net/core/dev.c index 0ce469e5ec80..3721db716350 100644 --- a/net/core/dev.c +++ b/net/core/dev.c | |||
| @@ -147,6 +147,8 @@ struct list_head ptype_base[PTYPE_HASH_SIZE] __read_mostly; | |||
| 147 | struct list_head ptype_all __read_mostly; /* Taps */ | 147 | struct list_head ptype_all __read_mostly; /* Taps */ |
| 148 | static struct list_head offload_base __read_mostly; | 148 | static struct list_head offload_base __read_mostly; |
| 149 | 149 | ||
| 150 | static int netif_rx_internal(struct sk_buff *skb); | ||
| 151 | |||
| 150 | /* | 152 | /* |
| 151 | * The @dev_base_head list is protected by @dev_base_lock and the rtnl | 153 | * The @dev_base_head list is protected by @dev_base_lock and the rtnl |
| 152 | * semaphore. | 154 | * semaphore. |
| @@ -480,7 +482,7 @@ EXPORT_SYMBOL(dev_add_offload); | |||
| 480 | * and must not be freed until after all the CPU's have gone | 482 | * and must not be freed until after all the CPU's have gone |
| 481 | * through a quiescent state. | 483 | * through a quiescent state. |
| 482 | */ | 484 | */ |
| 483 | void __dev_remove_offload(struct packet_offload *po) | 485 | static void __dev_remove_offload(struct packet_offload *po) |
| 484 | { | 486 | { |
| 485 | struct list_head *head = &offload_base; | 487 | struct list_head *head = &offload_base; |
| 486 | struct packet_offload *po1; | 488 | struct packet_offload *po1; |
| @@ -498,7 +500,6 @@ void __dev_remove_offload(struct packet_offload *po) | |||
| 498 | out: | 500 | out: |
| 499 | spin_unlock(&offload_lock); | 501 | spin_unlock(&offload_lock); |
| 500 | } | 502 | } |
| 501 | EXPORT_SYMBOL(__dev_remove_offload); | ||
| 502 | 503 | ||
| 503 | /** | 504 | /** |
| 504 | * dev_remove_offload - remove packet offload handler | 505 | * dev_remove_offload - remove packet offload handler |
| @@ -1118,6 +1119,8 @@ rollback: | |||
| 1118 | 1119 | ||
| 1119 | write_seqcount_end(&devnet_rename_seq); | 1120 | write_seqcount_end(&devnet_rename_seq); |
| 1120 | 1121 | ||
| 1122 | netdev_adjacent_rename_links(dev, oldname); | ||
| 1123 | |||
| 1121 | write_lock_bh(&dev_base_lock); | 1124 | write_lock_bh(&dev_base_lock); |
| 1122 | hlist_del_rcu(&dev->name_hlist); | 1125 | hlist_del_rcu(&dev->name_hlist); |
| 1123 | write_unlock_bh(&dev_base_lock); | 1126 | write_unlock_bh(&dev_base_lock); |
| @@ -1137,6 +1140,7 @@ rollback: | |||
| 1137 | err = ret; | 1140 | err = ret; |
| 1138 | write_seqcount_begin(&devnet_rename_seq); | 1141 | write_seqcount_begin(&devnet_rename_seq); |
| 1139 | memcpy(dev->name, oldname, IFNAMSIZ); | 1142 | memcpy(dev->name, oldname, IFNAMSIZ); |
| 1143 | memcpy(oldname, newname, IFNAMSIZ); | ||
| 1140 | goto rollback; | 1144 | goto rollback; |
| 1141 | } else { | 1145 | } else { |
| 1142 | pr_err("%s: name change rollback failed: %d\n", | 1146 | pr_err("%s: name change rollback failed: %d\n", |
| @@ -1566,14 +1570,14 @@ EXPORT_SYMBOL(unregister_netdevice_notifier); | |||
| 1566 | * are as for raw_notifier_call_chain(). | 1570 | * are as for raw_notifier_call_chain(). |
| 1567 | */ | 1571 | */ |
| 1568 | 1572 | ||
| 1569 | int call_netdevice_notifiers_info(unsigned long val, struct net_device *dev, | 1573 | static int call_netdevice_notifiers_info(unsigned long val, |
| 1570 | struct netdev_notifier_info *info) | 1574 | struct net_device *dev, |
| 1575 | struct netdev_notifier_info *info) | ||
| 1571 | { | 1576 | { |
| 1572 | ASSERT_RTNL(); | 1577 | ASSERT_RTNL(); |
| 1573 | netdev_notifier_info_init(info, dev); | 1578 | netdev_notifier_info_init(info, dev); |
| 1574 | return raw_notifier_call_chain(&netdev_chain, val, info); | 1579 | return raw_notifier_call_chain(&netdev_chain, val, info); |
| 1575 | } | 1580 | } |
| 1576 | EXPORT_SYMBOL(call_netdevice_notifiers_info); | ||
| 1577 | 1581 | ||
| 1578 | /** | 1582 | /** |
| 1579 | * call_netdevice_notifiers - call all network notifier blocks | 1583 | * call_netdevice_notifiers - call all network notifier blocks |
| @@ -1699,7 +1703,7 @@ int dev_forward_skb(struct net_device *dev, struct sk_buff *skb) | |||
| 1699 | skb_scrub_packet(skb, true); | 1703 | skb_scrub_packet(skb, true); |
| 1700 | skb->protocol = eth_type_trans(skb, dev); | 1704 | skb->protocol = eth_type_trans(skb, dev); |
| 1701 | 1705 | ||
| 1702 | return netif_rx(skb); | 1706 | return netif_rx_internal(skb); |
| 1703 | } | 1707 | } |
| 1704 | EXPORT_SYMBOL_GPL(dev_forward_skb); | 1708 | EXPORT_SYMBOL_GPL(dev_forward_skb); |
| 1705 | 1709 | ||
| @@ -2079,7 +2083,7 @@ int netif_set_real_num_tx_queues(struct net_device *dev, unsigned int txq) | |||
| 2079 | } | 2083 | } |
| 2080 | EXPORT_SYMBOL(netif_set_real_num_tx_queues); | 2084 | EXPORT_SYMBOL(netif_set_real_num_tx_queues); |
| 2081 | 2085 | ||
| 2082 | #ifdef CONFIG_RPS | 2086 | #ifdef CONFIG_SYSFS |
| 2083 | /** | 2087 | /** |
| 2084 | * netif_set_real_num_rx_queues - set actual number of RX queues used | 2088 | * netif_set_real_num_rx_queues - set actual number of RX queues used |
| 2085 | * @dev: Network device | 2089 | * @dev: Network device |
| @@ -2145,30 +2149,42 @@ void __netif_schedule(struct Qdisc *q) | |||
| 2145 | } | 2149 | } |
| 2146 | EXPORT_SYMBOL(__netif_schedule); | 2150 | EXPORT_SYMBOL(__netif_schedule); |
| 2147 | 2151 | ||
| 2148 | void dev_kfree_skb_irq(struct sk_buff *skb) | 2152 | struct dev_kfree_skb_cb { |
| 2153 | enum skb_free_reason reason; | ||
| 2154 | }; | ||
| 2155 | |||
| 2156 | static struct dev_kfree_skb_cb *get_kfree_skb_cb(const struct sk_buff *skb) | ||
| 2149 | { | 2157 | { |
| 2150 | if (atomic_dec_and_test(&skb->users)) { | 2158 | return (struct dev_kfree_skb_cb *)skb->cb; |
| 2151 | struct softnet_data *sd; | 2159 | } |
| 2152 | unsigned long flags; | 2160 | |
| 2161 | void __dev_kfree_skb_irq(struct sk_buff *skb, enum skb_free_reason reason) | ||
| 2162 | { | ||
| 2163 | unsigned long flags; | ||
| 2153 | 2164 | ||
| 2154 | local_irq_save(flags); | 2165 | if (likely(atomic_read(&skb->users) == 1)) { |
| 2155 | sd = &__get_cpu_var(softnet_data); | 2166 | smp_rmb(); |
| 2156 | skb->next = sd->completion_queue; | 2167 | atomic_set(&skb->users, 0); |
| 2157 | sd->completion_queue = skb; | 2168 | } else if (likely(!atomic_dec_and_test(&skb->users))) { |
| 2158 | raise_softirq_irqoff(NET_TX_SOFTIRQ); | 2169 | return; |
| 2159 | local_irq_restore(flags); | ||
| 2160 | } | 2170 | } |
| 2171 | get_kfree_skb_cb(skb)->reason = reason; | ||
| 2172 | local_irq_save(flags); | ||
| 2173 | skb->next = __this_cpu_read(softnet_data.completion_queue); | ||
| 2174 | __this_cpu_write(softnet_data.completion_queue, skb); | ||
| 2175 | raise_softirq_irqoff(NET_TX_SOFTIRQ); | ||
| 2176 | local_irq_restore(flags); | ||
| 2161 | } | 2177 | } |
| 2162 | EXPORT_SYMBOL(dev_kfree_skb_irq); | 2178 | EXPORT_SYMBOL(__dev_kfree_skb_irq); |
| 2163 | 2179 | ||
| 2164 | void dev_kfree_skb_any(struct sk_buff *skb) | 2180 | void __dev_kfree_skb_any(struct sk_buff *skb, enum skb_free_reason reason) |
| 2165 | { | 2181 | { |
| 2166 | if (in_irq() || irqs_disabled()) | 2182 | if (in_irq() || irqs_disabled()) |
| 2167 | dev_kfree_skb_irq(skb); | 2183 | __dev_kfree_skb_irq(skb, reason); |
| 2168 | else | 2184 | else |
| 2169 | dev_kfree_skb(skb); | 2185 | dev_kfree_skb(skb); |
| 2170 | } | 2186 | } |
| 2171 | EXPORT_SYMBOL(dev_kfree_skb_any); | 2187 | EXPORT_SYMBOL(__dev_kfree_skb_any); |
| 2172 | 2188 | ||
| 2173 | 2189 | ||
| 2174 | /** | 2190 | /** |
| @@ -2442,13 +2458,8 @@ static void dev_gso_skb_destructor(struct sk_buff *skb) | |||
| 2442 | { | 2458 | { |
| 2443 | struct dev_gso_cb *cb; | 2459 | struct dev_gso_cb *cb; |
| 2444 | 2460 | ||
| 2445 | do { | 2461 | kfree_skb_list(skb->next); |
| 2446 | struct sk_buff *nskb = skb->next; | 2462 | skb->next = NULL; |
| 2447 | |||
| 2448 | skb->next = nskb->next; | ||
| 2449 | nskb->next = NULL; | ||
| 2450 | kfree_skb(nskb); | ||
| 2451 | } while (skb->next); | ||
| 2452 | 2463 | ||
| 2453 | cb = DEV_GSO_CB(skb); | 2464 | cb = DEV_GSO_CB(skb); |
| 2454 | if (cb->destructor) | 2465 | if (cb->destructor) |
| @@ -2523,21 +2534,6 @@ netdev_features_t netif_skb_features(struct sk_buff *skb) | |||
| 2523 | } | 2534 | } |
| 2524 | EXPORT_SYMBOL(netif_skb_features); | 2535 | EXPORT_SYMBOL(netif_skb_features); |
| 2525 | 2536 | ||
| 2526 | /* | ||
| 2527 | * Returns true if either: | ||
| 2528 | * 1. skb has frag_list and the device doesn't support FRAGLIST, or | ||
| 2529 | * 2. skb is fragmented and the device does not support SG. | ||
| 2530 | */ | ||
| 2531 | static inline int skb_needs_linearize(struct sk_buff *skb, | ||
| 2532 | netdev_features_t features) | ||
| 2533 | { | ||
| 2534 | return skb_is_nonlinear(skb) && | ||
| 2535 | ((skb_has_frag_list(skb) && | ||
| 2536 | !(features & NETIF_F_FRAGLIST)) || | ||
| 2537 | (skb_shinfo(skb)->nr_frags && | ||
| 2538 | !(features & NETIF_F_SG))); | ||
| 2539 | } | ||
| 2540 | |||
| 2541 | int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev, | 2537 | int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev, |
| 2542 | struct netdev_queue *txq) | 2538 | struct netdev_queue *txq) |
| 2543 | { | 2539 | { |
| @@ -2605,8 +2601,8 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev, | |||
| 2605 | dev_queue_xmit_nit(skb, dev); | 2601 | dev_queue_xmit_nit(skb, dev); |
| 2606 | 2602 | ||
| 2607 | skb_len = skb->len; | 2603 | skb_len = skb->len; |
| 2608 | rc = ops->ndo_start_xmit(skb, dev); | 2604 | trace_net_dev_start_xmit(skb, dev); |
| 2609 | 2605 | rc = ops->ndo_start_xmit(skb, dev); | |
| 2610 | trace_net_dev_xmit(skb, rc, dev, skb_len); | 2606 | trace_net_dev_xmit(skb, rc, dev, skb_len); |
| 2611 | if (rc == NETDEV_TX_OK) | 2607 | if (rc == NETDEV_TX_OK) |
| 2612 | txq_trans_update(txq); | 2608 | txq_trans_update(txq); |
| @@ -2624,6 +2620,7 @@ gso: | |||
| 2624 | dev_queue_xmit_nit(nskb, dev); | 2620 | dev_queue_xmit_nit(nskb, dev); |
| 2625 | 2621 | ||
| 2626 | skb_len = nskb->len; | 2622 | skb_len = nskb->len; |
| 2623 | trace_net_dev_start_xmit(nskb, dev); | ||
| 2627 | rc = ops->ndo_start_xmit(nskb, dev); | 2624 | rc = ops->ndo_start_xmit(nskb, dev); |
| 2628 | trace_net_dev_xmit(nskb, rc, dev, skb_len); | 2625 | trace_net_dev_xmit(nskb, rc, dev, skb_len); |
| 2629 | if (unlikely(rc != NETDEV_TX_OK)) { | 2626 | if (unlikely(rc != NETDEV_TX_OK)) { |
| @@ -2744,7 +2741,7 @@ static inline int __dev_xmit_skb(struct sk_buff *skb, struct Qdisc *q, | |||
| 2744 | return rc; | 2741 | return rc; |
| 2745 | } | 2742 | } |
| 2746 | 2743 | ||
| 2747 | #if IS_ENABLED(CONFIG_NETPRIO_CGROUP) | 2744 | #if IS_ENABLED(CONFIG_CGROUP_NET_PRIO) |
| 2748 | static void skb_update_prio(struct sk_buff *skb) | 2745 | static void skb_update_prio(struct sk_buff *skb) |
| 2749 | { | 2746 | { |
| 2750 | struct netprio_map *map = rcu_dereference_bh(skb->dev->priomap); | 2747 | struct netprio_map *map = rcu_dereference_bh(skb->dev->priomap); |
| @@ -2781,8 +2778,9 @@ int dev_loopback_xmit(struct sk_buff *skb) | |||
| 2781 | EXPORT_SYMBOL(dev_loopback_xmit); | 2778 | EXPORT_SYMBOL(dev_loopback_xmit); |
| 2782 | 2779 | ||
| 2783 | /** | 2780 | /** |
| 2784 | * dev_queue_xmit - transmit a buffer | 2781 | * __dev_queue_xmit - transmit a buffer |
| 2785 | * @skb: buffer to transmit | 2782 | * @skb: buffer to transmit |
| 2783 | * @accel_priv: private data used for L2 forwarding offload | ||
| 2786 | * | 2784 | * |
| 2787 | * Queue a buffer for transmission to a network device. The caller must | 2785 | * Queue a buffer for transmission to a network device. The caller must |
| 2788 | * have set the device and priority and built the buffer before calling | 2786 | * have set the device and priority and built the buffer before calling |
| @@ -3014,7 +3012,7 @@ static int get_rps_cpu(struct net_device *dev, struct sk_buff *skb, | |||
| 3014 | } | 3012 | } |
| 3015 | 3013 | ||
| 3016 | skb_reset_network_header(skb); | 3014 | skb_reset_network_header(skb); |
| 3017 | if (!skb_get_rxhash(skb)) | 3015 | if (!skb_get_hash(skb)) |
| 3018 | goto done; | 3016 | goto done; |
| 3019 | 3017 | ||
| 3020 | flow_table = rcu_dereference(rxqueue->rps_flow_table); | 3018 | flow_table = rcu_dereference(rxqueue->rps_flow_table); |
| @@ -3159,7 +3157,7 @@ static bool skb_flow_limit(struct sk_buff *skb, unsigned int qlen) | |||
| 3159 | rcu_read_lock(); | 3157 | rcu_read_lock(); |
| 3160 | fl = rcu_dereference(sd->flow_limit); | 3158 | fl = rcu_dereference(sd->flow_limit); |
| 3161 | if (fl) { | 3159 | if (fl) { |
| 3162 | new_flow = skb_get_rxhash(skb) & (fl->num_buckets - 1); | 3160 | new_flow = skb_get_hash(skb) & (fl->num_buckets - 1); |
| 3163 | old_flow = fl->history[fl->history_head]; | 3161 | old_flow = fl->history[fl->history_head]; |
| 3164 | fl->history[fl->history_head] = new_flow; | 3162 | fl->history[fl->history_head] = new_flow; |
| 3165 | 3163 | ||
| @@ -3227,22 +3225,7 @@ enqueue: | |||
| 3227 | return NET_RX_DROP; | 3225 | return NET_RX_DROP; |
| 3228 | } | 3226 | } |
| 3229 | 3227 | ||
| 3230 | /** | 3228 | static int netif_rx_internal(struct sk_buff *skb) |
| 3231 | * netif_rx - post buffer to the network code | ||
| 3232 | * @skb: buffer to post | ||
| 3233 | * | ||
| 3234 | * This function receives a packet from a device driver and queues it for | ||
| 3235 | * the upper (protocol) levels to process. It always succeeds. The buffer | ||
| 3236 | * may be dropped during processing for congestion control or by the | ||
| 3237 | * protocol layers. | ||
| 3238 | * | ||
| 3239 | * return values: | ||
| 3240 | * NET_RX_SUCCESS (no congestion) | ||
| 3241 | * NET_RX_DROP (packet was dropped) | ||
| 3242 | * | ||
| 3243 | */ | ||
| 3244 | |||
| 3245 | int netif_rx(struct sk_buff *skb) | ||
| 3246 | { | 3229 | { |
| 3247 | int ret; | 3230 | int ret; |
| 3248 | 3231 | ||
| @@ -3278,14 +3261,38 @@ int netif_rx(struct sk_buff *skb) | |||
| 3278 | } | 3261 | } |
| 3279 | return ret; | 3262 | return ret; |
| 3280 | } | 3263 | } |
| 3264 | |||
| 3265 | /** | ||
| 3266 | * netif_rx - post buffer to the network code | ||
| 3267 | * @skb: buffer to post | ||
| 3268 | * | ||
| 3269 | * This function receives a packet from a device driver and queues it for | ||
| 3270 | * the upper (protocol) levels to process. It always succeeds. The buffer | ||
| 3271 | * may be dropped during processing for congestion control or by the | ||
| 3272 | * protocol layers. | ||
| 3273 | * | ||
| 3274 | * return values: | ||
| 3275 | * NET_RX_SUCCESS (no congestion) | ||
| 3276 | * NET_RX_DROP (packet was dropped) | ||
| 3277 | * | ||
| 3278 | */ | ||
| 3279 | |||
| 3280 | int netif_rx(struct sk_buff *skb) | ||
| 3281 | { | ||
| 3282 | trace_netif_rx_entry(skb); | ||
| 3283 | |||
| 3284 | return netif_rx_internal(skb); | ||
| 3285 | } | ||
| 3281 | EXPORT_SYMBOL(netif_rx); | 3286 | EXPORT_SYMBOL(netif_rx); |
| 3282 | 3287 | ||
| 3283 | int netif_rx_ni(struct sk_buff *skb) | 3288 | int netif_rx_ni(struct sk_buff *skb) |
| 3284 | { | 3289 | { |
| 3285 | int err; | 3290 | int err; |
| 3286 | 3291 | ||
| 3292 | trace_netif_rx_ni_entry(skb); | ||
| 3293 | |||
| 3287 | preempt_disable(); | 3294 | preempt_disable(); |
| 3288 | err = netif_rx(skb); | 3295 | err = netif_rx_internal(skb); |
| 3289 | if (local_softirq_pending()) | 3296 | if (local_softirq_pending()) |
| 3290 | do_softirq(); | 3297 | do_softirq(); |
| 3291 | preempt_enable(); | 3298 | preempt_enable(); |
| @@ -3311,7 +3318,10 @@ static void net_tx_action(struct softirq_action *h) | |||
| 3311 | clist = clist->next; | 3318 | clist = clist->next; |
| 3312 | 3319 | ||
| 3313 | WARN_ON(atomic_read(&skb->users)); | 3320 | WARN_ON(atomic_read(&skb->users)); |
| 3314 | trace_kfree_skb(skb, net_tx_action); | 3321 | if (likely(get_kfree_skb_cb(skb)->reason == SKB_REASON_CONSUMED)) |
| 3322 | trace_consume_skb(skb); | ||
| 3323 | else | ||
| 3324 | trace_kfree_skb(skb, net_tx_action); | ||
| 3315 | __kfree_skb(skb); | 3325 | __kfree_skb(skb); |
| 3316 | } | 3326 | } |
| 3317 | } | 3327 | } |
| @@ -3667,22 +3677,7 @@ static int __netif_receive_skb(struct sk_buff *skb) | |||
| 3667 | return ret; | 3677 | return ret; |
| 3668 | } | 3678 | } |
| 3669 | 3679 | ||
| 3670 | /** | 3680 | static int netif_receive_skb_internal(struct sk_buff *skb) |
| 3671 | * netif_receive_skb - process receive buffer from network | ||
| 3672 | * @skb: buffer to process | ||
| 3673 | * | ||
| 3674 | * netif_receive_skb() is the main receive data processing function. | ||
| 3675 | * It always succeeds. The buffer may be dropped during processing | ||
| 3676 | * for congestion control or by the protocol layers. | ||
| 3677 | * | ||
| 3678 | * This function may only be called from softirq context and interrupts | ||
| 3679 | * should be enabled. | ||
| 3680 | * | ||
| 3681 | * Return values (usually ignored): | ||
| 3682 | * NET_RX_SUCCESS: no congestion | ||
| 3683 | * NET_RX_DROP: packet was dropped | ||
| 3684 | */ | ||
| 3685 | int netif_receive_skb(struct sk_buff *skb) | ||
| 3686 | { | 3681 | { |
| 3687 | net_timestamp_check(netdev_tstamp_prequeue, skb); | 3682 | net_timestamp_check(netdev_tstamp_prequeue, skb); |
| 3688 | 3683 | ||
| @@ -3708,6 +3703,28 @@ int netif_receive_skb(struct sk_buff *skb) | |||
| 3708 | #endif | 3703 | #endif |
| 3709 | return __netif_receive_skb(skb); | 3704 | return __netif_receive_skb(skb); |
| 3710 | } | 3705 | } |
| 3706 | |||
| 3707 | /** | ||
| 3708 | * netif_receive_skb - process receive buffer from network | ||
| 3709 | * @skb: buffer to process | ||
| 3710 | * | ||
| 3711 | * netif_receive_skb() is the main receive data processing function. | ||
| 3712 | * It always succeeds. The buffer may be dropped during processing | ||
| 3713 | * for congestion control or by the protocol layers. | ||
| 3714 | * | ||
| 3715 | * This function may only be called from softirq context and interrupts | ||
| 3716 | * should be enabled. | ||
| 3717 | * | ||
| 3718 | * Return values (usually ignored): | ||
| 3719 | * NET_RX_SUCCESS: no congestion | ||
| 3720 | * NET_RX_DROP: packet was dropped | ||
| 3721 | */ | ||
| 3722 | int netif_receive_skb(struct sk_buff *skb) | ||
| 3723 | { | ||
| 3724 | trace_netif_receive_skb_entry(skb); | ||
| 3725 | |||
| 3726 | return netif_receive_skb_internal(skb); | ||
| 3727 | } | ||
| 3711 | EXPORT_SYMBOL(netif_receive_skb); | 3728 | EXPORT_SYMBOL(netif_receive_skb); |
| 3712 | 3729 | ||
| 3713 | /* Network device is going away, flush any packets still pending | 3730 | /* Network device is going away, flush any packets still pending |
| @@ -3757,7 +3774,7 @@ static int napi_gro_complete(struct sk_buff *skb) | |||
| 3757 | if (ptype->type != type || !ptype->callbacks.gro_complete) | 3774 | if (ptype->type != type || !ptype->callbacks.gro_complete) |
| 3758 | continue; | 3775 | continue; |
| 3759 | 3776 | ||
| 3760 | err = ptype->callbacks.gro_complete(skb); | 3777 | err = ptype->callbacks.gro_complete(skb, 0); |
| 3761 | break; | 3778 | break; |
| 3762 | } | 3779 | } |
| 3763 | rcu_read_unlock(); | 3780 | rcu_read_unlock(); |
| @@ -3769,7 +3786,7 @@ static int napi_gro_complete(struct sk_buff *skb) | |||
| 3769 | } | 3786 | } |
| 3770 | 3787 | ||
| 3771 | out: | 3788 | out: |
| 3772 | return netif_receive_skb(skb); | 3789 | return netif_receive_skb_internal(skb); |
| 3773 | } | 3790 | } |
| 3774 | 3791 | ||
| 3775 | /* napi->gro_list contains packets ordered by age. | 3792 | /* napi->gro_list contains packets ordered by age. |
| @@ -3805,10 +3822,18 @@ static void gro_list_prepare(struct napi_struct *napi, struct sk_buff *skb) | |||
| 3805 | { | 3822 | { |
| 3806 | struct sk_buff *p; | 3823 | struct sk_buff *p; |
| 3807 | unsigned int maclen = skb->dev->hard_header_len; | 3824 | unsigned int maclen = skb->dev->hard_header_len; |
| 3825 | u32 hash = skb_get_hash_raw(skb); | ||
| 3808 | 3826 | ||
| 3809 | for (p = napi->gro_list; p; p = p->next) { | 3827 | for (p = napi->gro_list; p; p = p->next) { |
| 3810 | unsigned long diffs; | 3828 | unsigned long diffs; |
| 3811 | 3829 | ||
| 3830 | NAPI_GRO_CB(p)->flush = 0; | ||
| 3831 | |||
| 3832 | if (hash != skb_get_hash_raw(p)) { | ||
| 3833 | NAPI_GRO_CB(p)->same_flow = 0; | ||
| 3834 | continue; | ||
| 3835 | } | ||
| 3836 | |||
| 3812 | diffs = (unsigned long)p->dev ^ (unsigned long)skb->dev; | 3837 | diffs = (unsigned long)p->dev ^ (unsigned long)skb->dev; |
| 3813 | diffs |= p->vlan_tci ^ skb->vlan_tci; | 3838 | diffs |= p->vlan_tci ^ skb->vlan_tci; |
| 3814 | if (maclen == ETH_HLEN) | 3839 | if (maclen == ETH_HLEN) |
| @@ -3819,7 +3844,23 @@ static void gro_list_prepare(struct napi_struct *napi, struct sk_buff *skb) | |||
| 3819 | skb_gro_mac_header(skb), | 3844 | skb_gro_mac_header(skb), |
| 3820 | maclen); | 3845 | maclen); |
| 3821 | NAPI_GRO_CB(p)->same_flow = !diffs; | 3846 | NAPI_GRO_CB(p)->same_flow = !diffs; |
| 3822 | NAPI_GRO_CB(p)->flush = 0; | 3847 | } |
| 3848 | } | ||
| 3849 | |||
| 3850 | static void skb_gro_reset_offset(struct sk_buff *skb) | ||
| 3851 | { | ||
| 3852 | const struct skb_shared_info *pinfo = skb_shinfo(skb); | ||
| 3853 | const skb_frag_t *frag0 = &pinfo->frags[0]; | ||
| 3854 | |||
| 3855 | NAPI_GRO_CB(skb)->data_offset = 0; | ||
| 3856 | NAPI_GRO_CB(skb)->frag0 = NULL; | ||
| 3857 | NAPI_GRO_CB(skb)->frag0_len = 0; | ||
| 3858 | |||
| 3859 | if (skb_mac_header(skb) == skb_tail_pointer(skb) && | ||
| 3860 | pinfo->nr_frags && | ||
| 3861 | !PageHighMem(skb_frag_page(frag0))) { | ||
| 3862 | NAPI_GRO_CB(skb)->frag0 = skb_frag_address(frag0); | ||
| 3863 | NAPI_GRO_CB(skb)->frag0_len = skb_frag_size(frag0); | ||
| 3823 | } | 3864 | } |
| 3824 | } | 3865 | } |
| 3825 | 3866 | ||
| @@ -3838,7 +3879,9 @@ static enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff | |||
| 3838 | if (skb_is_gso(skb) || skb_has_frag_list(skb)) | 3879 | if (skb_is_gso(skb) || skb_has_frag_list(skb)) |
| 3839 | goto normal; | 3880 | goto normal; |
| 3840 | 3881 | ||
| 3882 | skb_gro_reset_offset(skb); | ||
| 3841 | gro_list_prepare(napi, skb); | 3883 | gro_list_prepare(napi, skb); |
| 3884 | NAPI_GRO_CB(skb)->csum = skb->csum; /* Needed for CHECKSUM_COMPLETE */ | ||
| 3842 | 3885 | ||
| 3843 | rcu_read_lock(); | 3886 | rcu_read_lock(); |
| 3844 | list_for_each_entry_rcu(ptype, head, list) { | 3887 | list_for_each_entry_rcu(ptype, head, list) { |
| @@ -3850,6 +3893,7 @@ static enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff | |||
| 3850 | NAPI_GRO_CB(skb)->same_flow = 0; | 3893 | NAPI_GRO_CB(skb)->same_flow = 0; |
| 3851 | NAPI_GRO_CB(skb)->flush = 0; | 3894 | NAPI_GRO_CB(skb)->flush = 0; |
| 3852 | NAPI_GRO_CB(skb)->free = 0; | 3895 | NAPI_GRO_CB(skb)->free = 0; |
| 3896 | NAPI_GRO_CB(skb)->udp_mark = 0; | ||
| 3853 | 3897 | ||
| 3854 | pp = ptype->callbacks.gro_receive(&napi->gro_list, skb); | 3898 | pp = ptype->callbacks.gro_receive(&napi->gro_list, skb); |
| 3855 | break; | 3899 | break; |
| @@ -3874,10 +3918,23 @@ static enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff | |||
| 3874 | if (same_flow) | 3918 | if (same_flow) |
| 3875 | goto ok; | 3919 | goto ok; |
| 3876 | 3920 | ||
| 3877 | if (NAPI_GRO_CB(skb)->flush || napi->gro_count >= MAX_GRO_SKBS) | 3921 | if (NAPI_GRO_CB(skb)->flush) |
| 3878 | goto normal; | 3922 | goto normal; |
| 3879 | 3923 | ||
| 3880 | napi->gro_count++; | 3924 | if (unlikely(napi->gro_count >= MAX_GRO_SKBS)) { |
| 3925 | struct sk_buff *nskb = napi->gro_list; | ||
| 3926 | |||
| 3927 | /* locate the end of the list to select the 'oldest' flow */ | ||
| 3928 | while (nskb->next) { | ||
| 3929 | pp = &nskb->next; | ||
| 3930 | nskb = *pp; | ||
| 3931 | } | ||
| 3932 | *pp = NULL; | ||
| 3933 | nskb->next = NULL; | ||
| 3934 | napi_gro_complete(nskb); | ||
| 3935 | } else { | ||
| 3936 | napi->gro_count++; | ||
| 3937 | } | ||
| 3881 | NAPI_GRO_CB(skb)->count = 1; | 3938 | NAPI_GRO_CB(skb)->count = 1; |
| 3882 | NAPI_GRO_CB(skb)->age = jiffies; | 3939 | NAPI_GRO_CB(skb)->age = jiffies; |
| 3883 | skb_shinfo(skb)->gso_size = skb_gro_len(skb); | 3940 | skb_shinfo(skb)->gso_size = skb_gro_len(skb); |
| @@ -3915,12 +3972,39 @@ normal: | |||
| 3915 | goto pull; | 3972 | goto pull; |
| 3916 | } | 3973 | } |
| 3917 | 3974 | ||
| 3975 | struct packet_offload *gro_find_receive_by_type(__be16 type) | ||
| 3976 | { | ||
| 3977 | struct list_head *offload_head = &offload_base; | ||
| 3978 | struct packet_offload *ptype; | ||
| 3979 | |||
| 3980 | list_for_each_entry_rcu(ptype, offload_head, list) { | ||
| 3981 | if (ptype->type != type || !ptype->callbacks.gro_receive) | ||
| 3982 | continue; | ||
| 3983 | return ptype; | ||
| 3984 | } | ||
| 3985 | return NULL; | ||
| 3986 | } | ||
| 3987 | EXPORT_SYMBOL(gro_find_receive_by_type); | ||
| 3988 | |||
| 3989 | struct packet_offload *gro_find_complete_by_type(__be16 type) | ||
| 3990 | { | ||
| 3991 | struct list_head *offload_head = &offload_base; | ||
| 3992 | struct packet_offload *ptype; | ||
| 3993 | |||
| 3994 | list_for_each_entry_rcu(ptype, offload_head, list) { | ||
| 3995 | if (ptype->type != type || !ptype->callbacks.gro_complete) | ||
| 3996 | continue; | ||
| 3997 | return ptype; | ||
| 3998 | } | ||
| 3999 | return NULL; | ||
| 4000 | } | ||
| 4001 | EXPORT_SYMBOL(gro_find_complete_by_type); | ||
| 3918 | 4002 | ||
| 3919 | static gro_result_t napi_skb_finish(gro_result_t ret, struct sk_buff *skb) | 4003 | static gro_result_t napi_skb_finish(gro_result_t ret, struct sk_buff *skb) |
| 3920 | { | 4004 | { |
| 3921 | switch (ret) { | 4005 | switch (ret) { |
| 3922 | case GRO_NORMAL: | 4006 | case GRO_NORMAL: |
| 3923 | if (netif_receive_skb(skb)) | 4007 | if (netif_receive_skb_internal(skb)) |
| 3924 | ret = GRO_DROP; | 4008 | ret = GRO_DROP; |
| 3925 | break; | 4009 | break; |
| 3926 | 4010 | ||
| @@ -3943,26 +4027,9 @@ static gro_result_t napi_skb_finish(gro_result_t ret, struct sk_buff *skb) | |||
| 3943 | return ret; | 4027 | return ret; |
| 3944 | } | 4028 | } |
| 3945 | 4029 | ||
| 3946 | static void skb_gro_reset_offset(struct sk_buff *skb) | ||
| 3947 | { | ||
| 3948 | const struct skb_shared_info *pinfo = skb_shinfo(skb); | ||
| 3949 | const skb_frag_t *frag0 = &pinfo->frags[0]; | ||
| 3950 | |||
| 3951 | NAPI_GRO_CB(skb)->data_offset = 0; | ||
| 3952 | NAPI_GRO_CB(skb)->frag0 = NULL; | ||
| 3953 | NAPI_GRO_CB(skb)->frag0_len = 0; | ||
| 3954 | |||
| 3955 | if (skb_mac_header(skb) == skb_tail_pointer(skb) && | ||
| 3956 | pinfo->nr_frags && | ||
| 3957 | !PageHighMem(skb_frag_page(frag0))) { | ||
| 3958 | NAPI_GRO_CB(skb)->frag0 = skb_frag_address(frag0); | ||
| 3959 | NAPI_GRO_CB(skb)->frag0_len = skb_frag_size(frag0); | ||
| 3960 | } | ||
| 3961 | } | ||
| 3962 | |||
| 3963 | gro_result_t napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb) | 4030 | gro_result_t napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb) |
| 3964 | { | 4031 | { |
| 3965 | skb_gro_reset_offset(skb); | 4032 | trace_napi_gro_receive_entry(skb); |
| 3966 | 4033 | ||
| 3967 | return napi_skb_finish(dev_gro_receive(napi, skb), skb); | 4034 | return napi_skb_finish(dev_gro_receive(napi, skb), skb); |
| 3968 | } | 4035 | } |
| @@ -3986,8 +4053,7 @@ struct sk_buff *napi_get_frags(struct napi_struct *napi) | |||
| 3986 | 4053 | ||
| 3987 | if (!skb) { | 4054 | if (!skb) { |
| 3988 | skb = netdev_alloc_skb_ip_align(napi->dev, GRO_MAX_HEAD); | 4055 | skb = netdev_alloc_skb_ip_align(napi->dev, GRO_MAX_HEAD); |
| 3989 | if (skb) | 4056 | napi->skb = skb; |
| 3990 | napi->skb = skb; | ||
| 3991 | } | 4057 | } |
| 3992 | return skb; | 4058 | return skb; |
| 3993 | } | 4059 | } |
| @@ -3998,12 +4064,7 @@ static gro_result_t napi_frags_finish(struct napi_struct *napi, struct sk_buff * | |||
| 3998 | { | 4064 | { |
| 3999 | switch (ret) { | 4065 | switch (ret) { |
| 4000 | case GRO_NORMAL: | 4066 | case GRO_NORMAL: |
| 4001 | case GRO_HELD: | 4067 | if (netif_receive_skb_internal(skb)) |
| 4002 | skb->protocol = eth_type_trans(skb, skb->dev); | ||
| 4003 | |||
| 4004 | if (ret == GRO_HELD) | ||
| 4005 | skb_gro_pull(skb, -ETH_HLEN); | ||
| 4006 | else if (netif_receive_skb(skb)) | ||
| 4007 | ret = GRO_DROP; | 4068 | ret = GRO_DROP; |
| 4008 | break; | 4069 | break; |
| 4009 | 4070 | ||
| @@ -4012,6 +4073,7 @@ static gro_result_t napi_frags_finish(struct napi_struct *napi, struct sk_buff * | |||
| 4012 | napi_reuse_skb(napi, skb); | 4073 | napi_reuse_skb(napi, skb); |
| 4013 | break; | 4074 | break; |
| 4014 | 4075 | ||
| 4076 | case GRO_HELD: | ||
| 4015 | case GRO_MERGED: | 4077 | case GRO_MERGED: |
| 4016 | break; | 4078 | break; |
| 4017 | } | 4079 | } |
| @@ -4022,36 +4084,15 @@ static gro_result_t napi_frags_finish(struct napi_struct *napi, struct sk_buff * | |||
| 4022 | static struct sk_buff *napi_frags_skb(struct napi_struct *napi) | 4084 | static struct sk_buff *napi_frags_skb(struct napi_struct *napi) |
| 4023 | { | 4085 | { |
| 4024 | struct sk_buff *skb = napi->skb; | 4086 | struct sk_buff *skb = napi->skb; |
| 4025 | struct ethhdr *eth; | ||
| 4026 | unsigned int hlen; | ||
| 4027 | unsigned int off; | ||
| 4028 | 4087 | ||
| 4029 | napi->skb = NULL; | 4088 | napi->skb = NULL; |
| 4030 | 4089 | ||
| 4031 | skb_reset_mac_header(skb); | 4090 | if (unlikely(!pskb_may_pull(skb, sizeof(struct ethhdr)))) { |
| 4032 | skb_gro_reset_offset(skb); | 4091 | napi_reuse_skb(napi, skb); |
| 4033 | 4092 | return NULL; | |
| 4034 | off = skb_gro_offset(skb); | ||
| 4035 | hlen = off + sizeof(*eth); | ||
| 4036 | eth = skb_gro_header_fast(skb, off); | ||
| 4037 | if (skb_gro_header_hard(skb, hlen)) { | ||
| 4038 | eth = skb_gro_header_slow(skb, hlen, off); | ||
| 4039 | if (unlikely(!eth)) { | ||
| 4040 | napi_reuse_skb(napi, skb); | ||
| 4041 | skb = NULL; | ||
| 4042 | goto out; | ||
| 4043 | } | ||
| 4044 | } | 4093 | } |
| 4094 | skb->protocol = eth_type_trans(skb, skb->dev); | ||
| 4045 | 4095 | ||
| 4046 | skb_gro_pull(skb, sizeof(*eth)); | ||
| 4047 | |||
| 4048 | /* | ||
| 4049 | * This works because the only protocols we care about don't require | ||
| 4050 | * special handling. We'll fix it up properly at the end. | ||
| 4051 | */ | ||
| 4052 | skb->protocol = eth->h_proto; | ||
| 4053 | |||
| 4054 | out: | ||
| 4055 | return skb; | 4096 | return skb; |
| 4056 | } | 4097 | } |
| 4057 | 4098 | ||
| @@ -4062,12 +4103,14 @@ gro_result_t napi_gro_frags(struct napi_struct *napi) | |||
| 4062 | if (!skb) | 4103 | if (!skb) |
| 4063 | return GRO_DROP; | 4104 | return GRO_DROP; |
| 4064 | 4105 | ||
| 4106 | trace_napi_gro_frags_entry(skb); | ||
| 4107 | |||
| 4065 | return napi_frags_finish(napi, skb, dev_gro_receive(napi, skb)); | 4108 | return napi_frags_finish(napi, skb, dev_gro_receive(napi, skb)); |
| 4066 | } | 4109 | } |
| 4067 | EXPORT_SYMBOL(napi_gro_frags); | 4110 | EXPORT_SYMBOL(napi_gro_frags); |
| 4068 | 4111 | ||
| 4069 | /* | 4112 | /* |
| 4070 | * net_rps_action sends any pending IPI's for rps. | 4113 | * net_rps_action_and_irq_enable sends any pending IPI's for rps. |
| 4071 | * Note: called with local irq disabled, but exits with local irq enabled. | 4114 | * Note: called with local irq disabled, but exits with local irq enabled. |
| 4072 | */ | 4115 | */ |
| 4073 | static void net_rps_action_and_irq_enable(struct softnet_data *sd) | 4116 | static void net_rps_action_and_irq_enable(struct softnet_data *sd) |
| @@ -4272,17 +4315,10 @@ EXPORT_SYMBOL(netif_napi_add); | |||
| 4272 | 4315 | ||
| 4273 | void netif_napi_del(struct napi_struct *napi) | 4316 | void netif_napi_del(struct napi_struct *napi) |
| 4274 | { | 4317 | { |
| 4275 | struct sk_buff *skb, *next; | ||
| 4276 | |||
| 4277 | list_del_init(&napi->dev_list); | 4318 | list_del_init(&napi->dev_list); |
| 4278 | napi_free_frags(napi); | 4319 | napi_free_frags(napi); |
| 4279 | 4320 | ||
| 4280 | for (skb = napi->gro_list; skb; skb = next) { | 4321 | kfree_skb_list(napi->gro_list); |
| 4281 | next = skb->next; | ||
| 4282 | skb->next = NULL; | ||
| 4283 | kfree_skb(skb); | ||
| 4284 | } | ||
| 4285 | |||
| 4286 | napi->gro_list = NULL; | 4322 | napi->gro_list = NULL; |
| 4287 | napi->gro_count = 0; | 4323 | napi->gro_count = 0; |
| 4288 | } | 4324 | } |
| @@ -4399,19 +4435,6 @@ struct netdev_adjacent { | |||
| 4399 | struct rcu_head rcu; | 4435 | struct rcu_head rcu; |
| 4400 | }; | 4436 | }; |
| 4401 | 4437 | ||
| 4402 | static struct netdev_adjacent *__netdev_find_adj_rcu(struct net_device *dev, | ||
| 4403 | struct net_device *adj_dev, | ||
| 4404 | struct list_head *adj_list) | ||
| 4405 | { | ||
| 4406 | struct netdev_adjacent *adj; | ||
| 4407 | |||
| 4408 | list_for_each_entry_rcu(adj, adj_list, list) { | ||
| 4409 | if (adj->dev == adj_dev) | ||
| 4410 | return adj; | ||
| 4411 | } | ||
| 4412 | return NULL; | ||
| 4413 | } | ||
| 4414 | |||
| 4415 | static struct netdev_adjacent *__netdev_find_adj(struct net_device *dev, | 4438 | static struct netdev_adjacent *__netdev_find_adj(struct net_device *dev, |
| 4416 | struct net_device *adj_dev, | 4439 | struct net_device *adj_dev, |
| 4417 | struct list_head *adj_list) | 4440 | struct list_head *adj_list) |
| @@ -4450,13 +4473,12 @@ EXPORT_SYMBOL(netdev_has_upper_dev); | |||
| 4450 | * Find out if a device is linked to an upper device and return true in case | 4473 | * Find out if a device is linked to an upper device and return true in case |
| 4451 | * it is. The caller must hold the RTNL lock. | 4474 | * it is. The caller must hold the RTNL lock. |
| 4452 | */ | 4475 | */ |
| 4453 | bool netdev_has_any_upper_dev(struct net_device *dev) | 4476 | static bool netdev_has_any_upper_dev(struct net_device *dev) |
| 4454 | { | 4477 | { |
| 4455 | ASSERT_RTNL(); | 4478 | ASSERT_RTNL(); |
| 4456 | 4479 | ||
| 4457 | return !list_empty(&dev->all_adj_list.upper); | 4480 | return !list_empty(&dev->all_adj_list.upper); |
| 4458 | } | 4481 | } |
| 4459 | EXPORT_SYMBOL(netdev_has_any_upper_dev); | ||
| 4460 | 4482 | ||
| 4461 | /** | 4483 | /** |
| 4462 | * netdev_master_upper_dev_get - Get master upper device | 4484 | * netdev_master_upper_dev_get - Get master upper device |
| @@ -4576,6 +4598,27 @@ void *netdev_lower_get_next_private_rcu(struct net_device *dev, | |||
| 4576 | EXPORT_SYMBOL(netdev_lower_get_next_private_rcu); | 4598 | EXPORT_SYMBOL(netdev_lower_get_next_private_rcu); |
| 4577 | 4599 | ||
| 4578 | /** | 4600 | /** |
| 4601 | * netdev_lower_get_first_private_rcu - Get the first ->private from the | ||
| 4602 | * lower neighbour list, RCU | ||
| 4603 | * variant | ||
| 4604 | * @dev: device | ||
| 4605 | * | ||
| 4606 | * Gets the first netdev_adjacent->private from the dev's lower neighbour | ||
| 4607 | * list. The caller must hold RCU read lock. | ||
| 4608 | */ | ||
| 4609 | void *netdev_lower_get_first_private_rcu(struct net_device *dev) | ||
| 4610 | { | ||
| 4611 | struct netdev_adjacent *lower; | ||
| 4612 | |||
| 4613 | lower = list_first_or_null_rcu(&dev->adj_list.lower, | ||
| 4614 | struct netdev_adjacent, list); | ||
| 4615 | if (lower) | ||
| 4616 | return lower->private; | ||
| 4617 | return NULL; | ||
| 4618 | } | ||
| 4619 | EXPORT_SYMBOL(netdev_lower_get_first_private_rcu); | ||
| 4620 | |||
| 4621 | /** | ||
| 4579 | * netdev_master_upper_dev_get_rcu - Get master upper device | 4622 | * netdev_master_upper_dev_get_rcu - Get master upper device |
| 4580 | * @dev: device | 4623 | * @dev: device |
| 4581 | * | 4624 | * |
| @@ -4594,13 +4637,36 @@ struct net_device *netdev_master_upper_dev_get_rcu(struct net_device *dev) | |||
| 4594 | } | 4637 | } |
| 4595 | EXPORT_SYMBOL(netdev_master_upper_dev_get_rcu); | 4638 | EXPORT_SYMBOL(netdev_master_upper_dev_get_rcu); |
| 4596 | 4639 | ||
| 4640 | int netdev_adjacent_sysfs_add(struct net_device *dev, | ||
| 4641 | struct net_device *adj_dev, | ||
| 4642 | struct list_head *dev_list) | ||
| 4643 | { | ||
| 4644 | char linkname[IFNAMSIZ+7]; | ||
| 4645 | sprintf(linkname, dev_list == &dev->adj_list.upper ? | ||
| 4646 | "upper_%s" : "lower_%s", adj_dev->name); | ||
| 4647 | return sysfs_create_link(&(dev->dev.kobj), &(adj_dev->dev.kobj), | ||
| 4648 | linkname); | ||
| 4649 | } | ||
| 4650 | void netdev_adjacent_sysfs_del(struct net_device *dev, | ||
| 4651 | char *name, | ||
| 4652 | struct list_head *dev_list) | ||
| 4653 | { | ||
| 4654 | char linkname[IFNAMSIZ+7]; | ||
| 4655 | sprintf(linkname, dev_list == &dev->adj_list.upper ? | ||
| 4656 | "upper_%s" : "lower_%s", name); | ||
| 4657 | sysfs_remove_link(&(dev->dev.kobj), linkname); | ||
| 4658 | } | ||
| 4659 | |||
| 4660 | #define netdev_adjacent_is_neigh_list(dev, dev_list) \ | ||
| 4661 | (dev_list == &dev->adj_list.upper || \ | ||
| 4662 | dev_list == &dev->adj_list.lower) | ||
| 4663 | |||
| 4597 | static int __netdev_adjacent_dev_insert(struct net_device *dev, | 4664 | static int __netdev_adjacent_dev_insert(struct net_device *dev, |
| 4598 | struct net_device *adj_dev, | 4665 | struct net_device *adj_dev, |
| 4599 | struct list_head *dev_list, | 4666 | struct list_head *dev_list, |
| 4600 | void *private, bool master) | 4667 | void *private, bool master) |
| 4601 | { | 4668 | { |
| 4602 | struct netdev_adjacent *adj; | 4669 | struct netdev_adjacent *adj; |
| 4603 | char linkname[IFNAMSIZ+7]; | ||
| 4604 | int ret; | 4670 | int ret; |
| 4605 | 4671 | ||
| 4606 | adj = __netdev_find_adj(dev, adj_dev, dev_list); | 4672 | adj = __netdev_find_adj(dev, adj_dev, dev_list); |
| @@ -4623,16 +4689,8 @@ static int __netdev_adjacent_dev_insert(struct net_device *dev, | |||
| 4623 | pr_debug("dev_hold for %s, because of link added from %s to %s\n", | 4689 | pr_debug("dev_hold for %s, because of link added from %s to %s\n", |
| 4624 | adj_dev->name, dev->name, adj_dev->name); | 4690 | adj_dev->name, dev->name, adj_dev->name); |
| 4625 | 4691 | ||
| 4626 | if (dev_list == &dev->adj_list.lower) { | 4692 | if (netdev_adjacent_is_neigh_list(dev, dev_list)) { |
| 4627 | sprintf(linkname, "lower_%s", adj_dev->name); | 4693 | ret = netdev_adjacent_sysfs_add(dev, adj_dev, dev_list); |
| 4628 | ret = sysfs_create_link(&(dev->dev.kobj), | ||
| 4629 | &(adj_dev->dev.kobj), linkname); | ||
| 4630 | if (ret) | ||
| 4631 | goto free_adj; | ||
| 4632 | } else if (dev_list == &dev->adj_list.upper) { | ||
| 4633 | sprintf(linkname, "upper_%s", adj_dev->name); | ||
| 4634 | ret = sysfs_create_link(&(dev->dev.kobj), | ||
| 4635 | &(adj_dev->dev.kobj), linkname); | ||
| 4636 | if (ret) | 4694 | if (ret) |
| 4637 | goto free_adj; | 4695 | goto free_adj; |
| 4638 | } | 4696 | } |
| @@ -4652,14 +4710,8 @@ static int __netdev_adjacent_dev_insert(struct net_device *dev, | |||
| 4652 | return 0; | 4710 | return 0; |
| 4653 | 4711 | ||
| 4654 | remove_symlinks: | 4712 | remove_symlinks: |
| 4655 | if (dev_list == &dev->adj_list.lower) { | 4713 | if (netdev_adjacent_is_neigh_list(dev, dev_list)) |
| 4656 | sprintf(linkname, "lower_%s", adj_dev->name); | 4714 | netdev_adjacent_sysfs_del(dev, adj_dev->name, dev_list); |
| 4657 | sysfs_remove_link(&(dev->dev.kobj), linkname); | ||
| 4658 | } else if (dev_list == &dev->adj_list.upper) { | ||
| 4659 | sprintf(linkname, "upper_%s", adj_dev->name); | ||
| 4660 | sysfs_remove_link(&(dev->dev.kobj), linkname); | ||
| 4661 | } | ||
| 4662 | |||
| 4663 | free_adj: | 4715 | free_adj: |
| 4664 | kfree(adj); | 4716 | kfree(adj); |
| 4665 | dev_put(adj_dev); | 4717 | dev_put(adj_dev); |
| @@ -4667,12 +4719,11 @@ free_adj: | |||
| 4667 | return ret; | 4719 | return ret; |
| 4668 | } | 4720 | } |
| 4669 | 4721 | ||
| 4670 | void __netdev_adjacent_dev_remove(struct net_device *dev, | 4722 | static void __netdev_adjacent_dev_remove(struct net_device *dev, |
| 4671 | struct net_device *adj_dev, | 4723 | struct net_device *adj_dev, |
| 4672 | struct list_head *dev_list) | 4724 | struct list_head *dev_list) |
| 4673 | { | 4725 | { |
| 4674 | struct netdev_adjacent *adj; | 4726 | struct netdev_adjacent *adj; |
| 4675 | char linkname[IFNAMSIZ+7]; | ||
| 4676 | 4727 | ||
| 4677 | adj = __netdev_find_adj(dev, adj_dev, dev_list); | 4728 | adj = __netdev_find_adj(dev, adj_dev, dev_list); |
| 4678 | 4729 | ||
| @@ -4692,13 +4743,8 @@ void __netdev_adjacent_dev_remove(struct net_device *dev, | |||
| 4692 | if (adj->master) | 4743 | if (adj->master) |
| 4693 | sysfs_remove_link(&(dev->dev.kobj), "master"); | 4744 | sysfs_remove_link(&(dev->dev.kobj), "master"); |
| 4694 | 4745 | ||
| 4695 | if (dev_list == &dev->adj_list.lower) { | 4746 | if (netdev_adjacent_is_neigh_list(dev, dev_list)) |
| 4696 | sprintf(linkname, "lower_%s", adj_dev->name); | 4747 | netdev_adjacent_sysfs_del(dev, adj_dev->name, dev_list); |
| 4697 | sysfs_remove_link(&(dev->dev.kobj), linkname); | ||
| 4698 | } else if (dev_list == &dev->adj_list.upper) { | ||
| 4699 | sprintf(linkname, "upper_%s", adj_dev->name); | ||
| 4700 | sysfs_remove_link(&(dev->dev.kobj), linkname); | ||
| 4701 | } | ||
| 4702 | 4748 | ||
| 4703 | list_del_rcu(&adj->list); | 4749 | list_del_rcu(&adj->list); |
| 4704 | pr_debug("dev_put for %s, because link removed from %s to %s\n", | 4750 | pr_debug("dev_put for %s, because link removed from %s to %s\n", |
| @@ -4707,11 +4753,11 @@ void __netdev_adjacent_dev_remove(struct net_device *dev, | |||
| 4707 | kfree_rcu(adj, rcu); | 4753 | kfree_rcu(adj, rcu); |
| 4708 | } | 4754 | } |
| 4709 | 4755 | ||
| 4710 | int __netdev_adjacent_dev_link_lists(struct net_device *dev, | 4756 | static int __netdev_adjacent_dev_link_lists(struct net_device *dev, |
| 4711 | struct net_device *upper_dev, | 4757 | struct net_device *upper_dev, |
| 4712 | struct list_head *up_list, | 4758 | struct list_head *up_list, |
| 4713 | struct list_head *down_list, | 4759 | struct list_head *down_list, |
| 4714 | void *private, bool master) | 4760 | void *private, bool master) |
| 4715 | { | 4761 | { |
| 4716 | int ret; | 4762 | int ret; |
| 4717 | 4763 | ||
| @@ -4730,8 +4776,8 @@ int __netdev_adjacent_dev_link_lists(struct net_device *dev, | |||
| 4730 | return 0; | 4776 | return 0; |
| 4731 | } | 4777 | } |
| 4732 | 4778 | ||
| 4733 | int __netdev_adjacent_dev_link(struct net_device *dev, | 4779 | static int __netdev_adjacent_dev_link(struct net_device *dev, |
| 4734 | struct net_device *upper_dev) | 4780 | struct net_device *upper_dev) |
| 4735 | { | 4781 | { |
| 4736 | return __netdev_adjacent_dev_link_lists(dev, upper_dev, | 4782 | return __netdev_adjacent_dev_link_lists(dev, upper_dev, |
| 4737 | &dev->all_adj_list.upper, | 4783 | &dev->all_adj_list.upper, |
| @@ -4739,26 +4785,26 @@ int __netdev_adjacent_dev_link(struct net_device *dev, | |||
| 4739 | NULL, false); | 4785 | NULL, false); |
| 4740 | } | 4786 | } |
| 4741 | 4787 | ||
| 4742 | void __netdev_adjacent_dev_unlink_lists(struct net_device *dev, | 4788 | static void __netdev_adjacent_dev_unlink_lists(struct net_device *dev, |
| 4743 | struct net_device *upper_dev, | 4789 | struct net_device *upper_dev, |
| 4744 | struct list_head *up_list, | 4790 | struct list_head *up_list, |
| 4745 | struct list_head *down_list) | 4791 | struct list_head *down_list) |
| 4746 | { | 4792 | { |
| 4747 | __netdev_adjacent_dev_remove(dev, upper_dev, up_list); | 4793 | __netdev_adjacent_dev_remove(dev, upper_dev, up_list); |
| 4748 | __netdev_adjacent_dev_remove(upper_dev, dev, down_list); | 4794 | __netdev_adjacent_dev_remove(upper_dev, dev, down_list); |
| 4749 | } | 4795 | } |
| 4750 | 4796 | ||
| 4751 | void __netdev_adjacent_dev_unlink(struct net_device *dev, | 4797 | static void __netdev_adjacent_dev_unlink(struct net_device *dev, |
| 4752 | struct net_device *upper_dev) | 4798 | struct net_device *upper_dev) |
| 4753 | { | 4799 | { |
| 4754 | __netdev_adjacent_dev_unlink_lists(dev, upper_dev, | 4800 | __netdev_adjacent_dev_unlink_lists(dev, upper_dev, |
| 4755 | &dev->all_adj_list.upper, | 4801 | &dev->all_adj_list.upper, |
| 4756 | &upper_dev->all_adj_list.lower); | 4802 | &upper_dev->all_adj_list.lower); |
| 4757 | } | 4803 | } |
| 4758 | 4804 | ||
| 4759 | int __netdev_adjacent_dev_link_neighbour(struct net_device *dev, | 4805 | static int __netdev_adjacent_dev_link_neighbour(struct net_device *dev, |
| 4760 | struct net_device *upper_dev, | 4806 | struct net_device *upper_dev, |
| 4761 | void *private, bool master) | 4807 | void *private, bool master) |
| 4762 | { | 4808 | { |
| 4763 | int ret = __netdev_adjacent_dev_link(dev, upper_dev); | 4809 | int ret = __netdev_adjacent_dev_link(dev, upper_dev); |
| 4764 | 4810 | ||
| @@ -4777,8 +4823,8 @@ int __netdev_adjacent_dev_link_neighbour(struct net_device *dev, | |||
| 4777 | return 0; | 4823 | return 0; |
| 4778 | } | 4824 | } |
| 4779 | 4825 | ||
| 4780 | void __netdev_adjacent_dev_unlink_neighbour(struct net_device *dev, | 4826 | static void __netdev_adjacent_dev_unlink_neighbour(struct net_device *dev, |
| 4781 | struct net_device *upper_dev) | 4827 | struct net_device *upper_dev) |
| 4782 | { | 4828 | { |
| 4783 | __netdev_adjacent_dev_unlink(dev, upper_dev); | 4829 | __netdev_adjacent_dev_unlink(dev, upper_dev); |
| 4784 | __netdev_adjacent_dev_unlink_lists(dev, upper_dev, | 4830 | __netdev_adjacent_dev_unlink_lists(dev, upper_dev, |
| @@ -4967,20 +5013,24 @@ void netdev_upper_dev_unlink(struct net_device *dev, | |||
| 4967 | } | 5013 | } |
| 4968 | EXPORT_SYMBOL(netdev_upper_dev_unlink); | 5014 | EXPORT_SYMBOL(netdev_upper_dev_unlink); |
| 4969 | 5015 | ||
| 4970 | void *netdev_lower_dev_get_private_rcu(struct net_device *dev, | 5016 | void netdev_adjacent_rename_links(struct net_device *dev, char *oldname) |
| 4971 | struct net_device *lower_dev) | ||
| 4972 | { | 5017 | { |
| 4973 | struct netdev_adjacent *lower; | 5018 | struct netdev_adjacent *iter; |
| 4974 | 5019 | ||
| 4975 | if (!lower_dev) | 5020 | list_for_each_entry(iter, &dev->adj_list.upper, list) { |
| 4976 | return NULL; | 5021 | netdev_adjacent_sysfs_del(iter->dev, oldname, |
| 4977 | lower = __netdev_find_adj_rcu(dev, lower_dev, &dev->adj_list.lower); | 5022 | &iter->dev->adj_list.lower); |
| 4978 | if (!lower) | 5023 | netdev_adjacent_sysfs_add(iter->dev, dev, |
| 4979 | return NULL; | 5024 | &iter->dev->adj_list.lower); |
| 5025 | } | ||
| 4980 | 5026 | ||
| 4981 | return lower->private; | 5027 | list_for_each_entry(iter, &dev->adj_list.lower, list) { |
| 5028 | netdev_adjacent_sysfs_del(iter->dev, oldname, | ||
| 5029 | &iter->dev->adj_list.upper); | ||
| 5030 | netdev_adjacent_sysfs_add(iter->dev, dev, | ||
| 5031 | &iter->dev->adj_list.upper); | ||
| 5032 | } | ||
| 4982 | } | 5033 | } |
| 4983 | EXPORT_SYMBOL(netdev_lower_dev_get_private_rcu); | ||
| 4984 | 5034 | ||
| 4985 | void *netdev_lower_dev_get_private(struct net_device *dev, | 5035 | void *netdev_lower_dev_get_private(struct net_device *dev, |
| 4986 | struct net_device *lower_dev) | 5036 | struct net_device *lower_dev) |
| @@ -5314,6 +5364,17 @@ int dev_change_flags(struct net_device *dev, unsigned int flags) | |||
| 5314 | } | 5364 | } |
| 5315 | EXPORT_SYMBOL(dev_change_flags); | 5365 | EXPORT_SYMBOL(dev_change_flags); |
| 5316 | 5366 | ||
| 5367 | static int __dev_set_mtu(struct net_device *dev, int new_mtu) | ||
| 5368 | { | ||
| 5369 | const struct net_device_ops *ops = dev->netdev_ops; | ||
| 5370 | |||
| 5371 | if (ops->ndo_change_mtu) | ||
| 5372 | return ops->ndo_change_mtu(dev, new_mtu); | ||
| 5373 | |||
| 5374 | dev->mtu = new_mtu; | ||
| 5375 | return 0; | ||
| 5376 | } | ||
| 5377 | |||
| 5317 | /** | 5378 | /** |
| 5318 | * dev_set_mtu - Change maximum transfer unit | 5379 | * dev_set_mtu - Change maximum transfer unit |
| 5319 | * @dev: device | 5380 | * @dev: device |
| @@ -5323,8 +5384,7 @@ EXPORT_SYMBOL(dev_change_flags); | |||
| 5323 | */ | 5384 | */ |
| 5324 | int dev_set_mtu(struct net_device *dev, int new_mtu) | 5385 | int dev_set_mtu(struct net_device *dev, int new_mtu) |
| 5325 | { | 5386 | { |
| 5326 | const struct net_device_ops *ops = dev->netdev_ops; | 5387 | int err, orig_mtu; |
| 5327 | int err; | ||
| 5328 | 5388 | ||
| 5329 | if (new_mtu == dev->mtu) | 5389 | if (new_mtu == dev->mtu) |
| 5330 | return 0; | 5390 | return 0; |
| @@ -5336,14 +5396,25 @@ int dev_set_mtu(struct net_device *dev, int new_mtu) | |||
| 5336 | if (!netif_device_present(dev)) | 5396 | if (!netif_device_present(dev)) |
| 5337 | return -ENODEV; | 5397 | return -ENODEV; |
| 5338 | 5398 | ||
| 5339 | err = 0; | 5399 | err = call_netdevice_notifiers(NETDEV_PRECHANGEMTU, dev); |
| 5340 | if (ops->ndo_change_mtu) | 5400 | err = notifier_to_errno(err); |
| 5341 | err = ops->ndo_change_mtu(dev, new_mtu); | 5401 | if (err) |
| 5342 | else | 5402 | return err; |
| 5343 | dev->mtu = new_mtu; | ||
| 5344 | 5403 | ||
| 5345 | if (!err) | 5404 | orig_mtu = dev->mtu; |
| 5346 | call_netdevice_notifiers(NETDEV_CHANGEMTU, dev); | 5405 | err = __dev_set_mtu(dev, new_mtu); |
| 5406 | |||
| 5407 | if (!err) { | ||
| 5408 | err = call_netdevice_notifiers(NETDEV_CHANGEMTU, dev); | ||
| 5409 | err = notifier_to_errno(err); | ||
| 5410 | if (err) { | ||
| 5411 | /* setting mtu back and notifying everyone again, | ||
| 5412 | * so that they have a chance to revert changes. | ||
| 5413 | */ | ||
| 5414 | __dev_set_mtu(dev, orig_mtu); | ||
| 5415 | call_netdevice_notifiers(NETDEV_CHANGEMTU, dev); | ||
| 5416 | } | ||
| 5417 | } | ||
| 5347 | return err; | 5418 | return err; |
| 5348 | } | 5419 | } |
| 5349 | EXPORT_SYMBOL(dev_set_mtu); | 5420 | EXPORT_SYMBOL(dev_set_mtu); |
| @@ -5697,7 +5768,7 @@ void netif_stacked_transfer_operstate(const struct net_device *rootdev, | |||
| 5697 | } | 5768 | } |
| 5698 | EXPORT_SYMBOL(netif_stacked_transfer_operstate); | 5769 | EXPORT_SYMBOL(netif_stacked_transfer_operstate); |
| 5699 | 5770 | ||
| 5700 | #ifdef CONFIG_RPS | 5771 | #ifdef CONFIG_SYSFS |
| 5701 | static int netif_alloc_rx_queues(struct net_device *dev) | 5772 | static int netif_alloc_rx_queues(struct net_device *dev) |
| 5702 | { | 5773 | { |
| 5703 | unsigned int i, count = dev->num_rx_queues; | 5774 | unsigned int i, count = dev->num_rx_queues; |
| @@ -5836,13 +5907,8 @@ int register_netdevice(struct net_device *dev) | |||
| 5836 | dev->features |= NETIF_F_SOFT_FEATURES; | 5907 | dev->features |= NETIF_F_SOFT_FEATURES; |
| 5837 | dev->wanted_features = dev->features & dev->hw_features; | 5908 | dev->wanted_features = dev->features & dev->hw_features; |
| 5838 | 5909 | ||
| 5839 | /* Turn on no cache copy if HW is doing checksum */ | ||
| 5840 | if (!(dev->flags & IFF_LOOPBACK)) { | 5910 | if (!(dev->flags & IFF_LOOPBACK)) { |
| 5841 | dev->hw_features |= NETIF_F_NOCACHE_COPY; | 5911 | dev->hw_features |= NETIF_F_NOCACHE_COPY; |
| 5842 | if (dev->features & NETIF_F_ALL_CSUM) { | ||
| 5843 | dev->wanted_features |= NETIF_F_NOCACHE_COPY; | ||
| 5844 | dev->features |= NETIF_F_NOCACHE_COPY; | ||
| 5845 | } | ||
| 5846 | } | 5912 | } |
| 5847 | 5913 | ||
| 5848 | /* Make NETIF_F_HIGHDMA inheritable to VLAN devices. | 5914 | /* Make NETIF_F_HIGHDMA inheritable to VLAN devices. |
| @@ -6229,7 +6295,7 @@ void netdev_freemem(struct net_device *dev) | |||
| 6229 | * @rxqs: the number of RX subqueues to allocate | 6295 | * @rxqs: the number of RX subqueues to allocate |
| 6230 | * | 6296 | * |
| 6231 | * Allocates a struct net_device with private data area for driver use | 6297 | * Allocates a struct net_device with private data area for driver use |
| 6232 | * and performs basic initialization. Also allocates subquue structs | 6298 | * and performs basic initialization. Also allocates subqueue structs |
| 6233 | * for each queue on the device. | 6299 | * for each queue on the device. |
| 6234 | */ | 6300 | */ |
| 6235 | struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name, | 6301 | struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name, |
| @@ -6247,7 +6313,7 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name, | |||
| 6247 | return NULL; | 6313 | return NULL; |
| 6248 | } | 6314 | } |
| 6249 | 6315 | ||
| 6250 | #ifdef CONFIG_RPS | 6316 | #ifdef CONFIG_SYSFS |
| 6251 | if (rxqs < 1) { | 6317 | if (rxqs < 1) { |
| 6252 | pr_err("alloc_netdev: Unable to allocate device with zero RX queues\n"); | 6318 | pr_err("alloc_netdev: Unable to allocate device with zero RX queues\n"); |
| 6253 | return NULL; | 6319 | return NULL; |
| @@ -6303,7 +6369,7 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name, | |||
| 6303 | if (netif_alloc_netdev_queues(dev)) | 6369 | if (netif_alloc_netdev_queues(dev)) |
| 6304 | goto free_all; | 6370 | goto free_all; |
| 6305 | 6371 | ||
| 6306 | #ifdef CONFIG_RPS | 6372 | #ifdef CONFIG_SYSFS |
| 6307 | dev->num_rx_queues = rxqs; | 6373 | dev->num_rx_queues = rxqs; |
| 6308 | dev->real_num_rx_queues = rxqs; | 6374 | dev->real_num_rx_queues = rxqs; |
| 6309 | if (netif_alloc_rx_queues(dev)) | 6375 | if (netif_alloc_rx_queues(dev)) |
| @@ -6323,7 +6389,7 @@ free_all: | |||
| 6323 | free_pcpu: | 6389 | free_pcpu: |
| 6324 | free_percpu(dev->pcpu_refcnt); | 6390 | free_percpu(dev->pcpu_refcnt); |
| 6325 | netif_free_tx_queues(dev); | 6391 | netif_free_tx_queues(dev); |
| 6326 | #ifdef CONFIG_RPS | 6392 | #ifdef CONFIG_SYSFS |
| 6327 | kfree(dev->_rx); | 6393 | kfree(dev->_rx); |
| 6328 | #endif | 6394 | #endif |
| 6329 | 6395 | ||
| @@ -6348,7 +6414,7 @@ void free_netdev(struct net_device *dev) | |||
| 6348 | release_net(dev_net(dev)); | 6414 | release_net(dev_net(dev)); |
| 6349 | 6415 | ||
| 6350 | netif_free_tx_queues(dev); | 6416 | netif_free_tx_queues(dev); |
| 6351 | #ifdef CONFIG_RPS | 6417 | #ifdef CONFIG_SYSFS |
| 6352 | kfree(dev->_rx); | 6418 | kfree(dev->_rx); |
| 6353 | #endif | 6419 | #endif |
| 6354 | 6420 | ||
| @@ -6618,11 +6684,11 @@ static int dev_cpu_callback(struct notifier_block *nfb, | |||
| 6618 | 6684 | ||
| 6619 | /* Process offline CPU's input_pkt_queue */ | 6685 | /* Process offline CPU's input_pkt_queue */ |
| 6620 | while ((skb = __skb_dequeue(&oldsd->process_queue))) { | 6686 | while ((skb = __skb_dequeue(&oldsd->process_queue))) { |
| 6621 | netif_rx(skb); | 6687 | netif_rx_internal(skb); |
| 6622 | input_queue_head_incr(oldsd); | 6688 | input_queue_head_incr(oldsd); |
| 6623 | } | 6689 | } |
| 6624 | while ((skb = __skb_dequeue(&oldsd->input_pkt_queue))) { | 6690 | while ((skb = __skb_dequeue(&oldsd->input_pkt_queue))) { |
| 6625 | netif_rx(skb); | 6691 | netif_rx_internal(skb); |
| 6626 | input_queue_head_incr(oldsd); | 6692 | input_queue_head_incr(oldsd); |
| 6627 | } | 6693 | } |
| 6628 | 6694 | ||
| @@ -6935,28 +7001,18 @@ static int __init net_dev_init(void) | |||
| 6935 | for_each_possible_cpu(i) { | 7001 | for_each_possible_cpu(i) { |
| 6936 | struct softnet_data *sd = &per_cpu(softnet_data, i); | 7002 | struct softnet_data *sd = &per_cpu(softnet_data, i); |
| 6937 | 7003 | ||
| 6938 | memset(sd, 0, sizeof(*sd)); | ||
| 6939 | skb_queue_head_init(&sd->input_pkt_queue); | 7004 | skb_queue_head_init(&sd->input_pkt_queue); |
| 6940 | skb_queue_head_init(&sd->process_queue); | 7005 | skb_queue_head_init(&sd->process_queue); |
| 6941 | sd->completion_queue = NULL; | ||
| 6942 | INIT_LIST_HEAD(&sd->poll_list); | 7006 | INIT_LIST_HEAD(&sd->poll_list); |
| 6943 | sd->output_queue = NULL; | ||
| 6944 | sd->output_queue_tailp = &sd->output_queue; | 7007 | sd->output_queue_tailp = &sd->output_queue; |
| 6945 | #ifdef CONFIG_RPS | 7008 | #ifdef CONFIG_RPS |
| 6946 | sd->csd.func = rps_trigger_softirq; | 7009 | sd->csd.func = rps_trigger_softirq; |
| 6947 | sd->csd.info = sd; | 7010 | sd->csd.info = sd; |
| 6948 | sd->csd.flags = 0; | ||
| 6949 | sd->cpu = i; | 7011 | sd->cpu = i; |
| 6950 | #endif | 7012 | #endif |
| 6951 | 7013 | ||
| 6952 | sd->backlog.poll = process_backlog; | 7014 | sd->backlog.poll = process_backlog; |
| 6953 | sd->backlog.weight = weight_p; | 7015 | sd->backlog.weight = weight_p; |
| 6954 | sd->backlog.gro_list = NULL; | ||
| 6955 | sd->backlog.gro_count = 0; | ||
| 6956 | |||
| 6957 | #ifdef CONFIG_NET_FLOW_LIMIT | ||
| 6958 | sd->flow_limit = NULL; | ||
| 6959 | #endif | ||
| 6960 | } | 7016 | } |
| 6961 | 7017 | ||
| 6962 | dev_boot_phase = 0; | 7018 | dev_boot_phase = 0; |
diff --git a/net/core/dev_addr_lists.c b/net/core/dev_addr_lists.c index ec40a849fc42..329d5794e7dc 100644 --- a/net/core/dev_addr_lists.c +++ b/net/core/dev_addr_lists.c | |||
| @@ -38,7 +38,7 @@ static int __hw_addr_create_ex(struct netdev_hw_addr_list *list, | |||
| 38 | ha->type = addr_type; | 38 | ha->type = addr_type; |
| 39 | ha->refcount = 1; | 39 | ha->refcount = 1; |
| 40 | ha->global_use = global; | 40 | ha->global_use = global; |
| 41 | ha->synced = sync; | 41 | ha->synced = sync ? 1 : 0; |
| 42 | ha->sync_cnt = 0; | 42 | ha->sync_cnt = 0; |
| 43 | list_add_tail_rcu(&ha->list, &list->list); | 43 | list_add_tail_rcu(&ha->list, &list->list); |
| 44 | list->count++; | 44 | list->count++; |
| @@ -48,7 +48,8 @@ static int __hw_addr_create_ex(struct netdev_hw_addr_list *list, | |||
| 48 | 48 | ||
| 49 | static int __hw_addr_add_ex(struct netdev_hw_addr_list *list, | 49 | static int __hw_addr_add_ex(struct netdev_hw_addr_list *list, |
| 50 | const unsigned char *addr, int addr_len, | 50 | const unsigned char *addr, int addr_len, |
| 51 | unsigned char addr_type, bool global, bool sync) | 51 | unsigned char addr_type, bool global, bool sync, |
| 52 | int sync_count) | ||
| 52 | { | 53 | { |
| 53 | struct netdev_hw_addr *ha; | 54 | struct netdev_hw_addr *ha; |
| 54 | 55 | ||
| @@ -66,10 +67,10 @@ static int __hw_addr_add_ex(struct netdev_hw_addr_list *list, | |||
| 66 | ha->global_use = true; | 67 | ha->global_use = true; |
| 67 | } | 68 | } |
| 68 | if (sync) { | 69 | if (sync) { |
| 69 | if (ha->synced) | 70 | if (ha->synced && sync_count) |
| 70 | return -EEXIST; | 71 | return -EEXIST; |
| 71 | else | 72 | else |
| 72 | ha->synced = true; | 73 | ha->synced++; |
| 73 | } | 74 | } |
| 74 | ha->refcount++; | 75 | ha->refcount++; |
| 75 | return 0; | 76 | return 0; |
| @@ -84,7 +85,8 @@ static int __hw_addr_add(struct netdev_hw_addr_list *list, | |||
| 84 | const unsigned char *addr, int addr_len, | 85 | const unsigned char *addr, int addr_len, |
| 85 | unsigned char addr_type) | 86 | unsigned char addr_type) |
| 86 | { | 87 | { |
| 87 | return __hw_addr_add_ex(list, addr, addr_len, addr_type, false, false); | 88 | return __hw_addr_add_ex(list, addr, addr_len, addr_type, false, false, |
| 89 | 0); | ||
| 88 | } | 90 | } |
| 89 | 91 | ||
| 90 | static int __hw_addr_del_entry(struct netdev_hw_addr_list *list, | 92 | static int __hw_addr_del_entry(struct netdev_hw_addr_list *list, |
| @@ -101,7 +103,7 @@ static int __hw_addr_del_entry(struct netdev_hw_addr_list *list, | |||
| 101 | ha->global_use = false; | 103 | ha->global_use = false; |
| 102 | 104 | ||
| 103 | if (sync) | 105 | if (sync) |
| 104 | ha->synced = false; | 106 | ha->synced--; |
| 105 | 107 | ||
| 106 | if (--ha->refcount) | 108 | if (--ha->refcount) |
| 107 | return 0; | 109 | return 0; |
| @@ -139,7 +141,7 @@ static int __hw_addr_sync_one(struct netdev_hw_addr_list *to_list, | |||
| 139 | int err; | 141 | int err; |
| 140 | 142 | ||
| 141 | err = __hw_addr_add_ex(to_list, ha->addr, addr_len, ha->type, | 143 | err = __hw_addr_add_ex(to_list, ha->addr, addr_len, ha->type, |
| 142 | false, true); | 144 | false, true, ha->sync_cnt); |
| 143 | if (err && err != -EEXIST) | 145 | if (err && err != -EEXIST) |
| 144 | return err; | 146 | return err; |
| 145 | 147 | ||
| @@ -186,47 +188,6 @@ static int __hw_addr_sync_multiple(struct netdev_hw_addr_list *to_list, | |||
| 186 | return err; | 188 | return err; |
| 187 | } | 189 | } |
| 188 | 190 | ||
| 189 | int __hw_addr_add_multiple(struct netdev_hw_addr_list *to_list, | ||
| 190 | struct netdev_hw_addr_list *from_list, | ||
| 191 | int addr_len, unsigned char addr_type) | ||
| 192 | { | ||
| 193 | int err; | ||
| 194 | struct netdev_hw_addr *ha, *ha2; | ||
| 195 | unsigned char type; | ||
| 196 | |||
| 197 | list_for_each_entry(ha, &from_list->list, list) { | ||
| 198 | type = addr_type ? addr_type : ha->type; | ||
| 199 | err = __hw_addr_add(to_list, ha->addr, addr_len, type); | ||
| 200 | if (err) | ||
| 201 | goto unroll; | ||
| 202 | } | ||
| 203 | return 0; | ||
| 204 | |||
| 205 | unroll: | ||
| 206 | list_for_each_entry(ha2, &from_list->list, list) { | ||
| 207 | if (ha2 == ha) | ||
| 208 | break; | ||
| 209 | type = addr_type ? addr_type : ha2->type; | ||
| 210 | __hw_addr_del(to_list, ha2->addr, addr_len, type); | ||
| 211 | } | ||
| 212 | return err; | ||
| 213 | } | ||
| 214 | EXPORT_SYMBOL(__hw_addr_add_multiple); | ||
| 215 | |||
| 216 | void __hw_addr_del_multiple(struct netdev_hw_addr_list *to_list, | ||
| 217 | struct netdev_hw_addr_list *from_list, | ||
| 218 | int addr_len, unsigned char addr_type) | ||
| 219 | { | ||
| 220 | struct netdev_hw_addr *ha; | ||
| 221 | unsigned char type; | ||
| 222 | |||
| 223 | list_for_each_entry(ha, &from_list->list, list) { | ||
| 224 | type = addr_type ? addr_type : ha->type; | ||
| 225 | __hw_addr_del(to_list, ha->addr, addr_len, type); | ||
| 226 | } | ||
| 227 | } | ||
| 228 | EXPORT_SYMBOL(__hw_addr_del_multiple); | ||
| 229 | |||
| 230 | /* This function only works where there is a strict 1-1 relationship | 191 | /* This function only works where there is a strict 1-1 relationship |
| 231 | * between source and destionation of they synch. If you ever need to | 192 | * between source and destionation of they synch. If you ever need to |
| 232 | * sync addresses to more then 1 destination, you need to use | 193 | * sync addresses to more then 1 destination, you need to use |
| @@ -264,7 +225,7 @@ void __hw_addr_unsync(struct netdev_hw_addr_list *to_list, | |||
| 264 | } | 225 | } |
| 265 | EXPORT_SYMBOL(__hw_addr_unsync); | 226 | EXPORT_SYMBOL(__hw_addr_unsync); |
| 266 | 227 | ||
| 267 | void __hw_addr_flush(struct netdev_hw_addr_list *list) | 228 | static void __hw_addr_flush(struct netdev_hw_addr_list *list) |
| 268 | { | 229 | { |
| 269 | struct netdev_hw_addr *ha, *tmp; | 230 | struct netdev_hw_addr *ha, *tmp; |
| 270 | 231 | ||
| @@ -274,7 +235,6 @@ void __hw_addr_flush(struct netdev_hw_addr_list *list) | |||
| 274 | } | 235 | } |
| 275 | list->count = 0; | 236 | list->count = 0; |
| 276 | } | 237 | } |
| 277 | EXPORT_SYMBOL(__hw_addr_flush); | ||
| 278 | 238 | ||
| 279 | void __hw_addr_init(struct netdev_hw_addr_list *list) | 239 | void __hw_addr_init(struct netdev_hw_addr_list *list) |
| 280 | { | 240 | { |
| @@ -400,59 +360,6 @@ int dev_addr_del(struct net_device *dev, const unsigned char *addr, | |||
| 400 | } | 360 | } |
| 401 | EXPORT_SYMBOL(dev_addr_del); | 361 | EXPORT_SYMBOL(dev_addr_del); |
| 402 | 362 | ||
| 403 | /** | ||
| 404 | * dev_addr_add_multiple - Add device addresses from another device | ||
| 405 | * @to_dev: device to which addresses will be added | ||
| 406 | * @from_dev: device from which addresses will be added | ||
| 407 | * @addr_type: address type - 0 means type will be used from from_dev | ||
| 408 | * | ||
| 409 | * Add device addresses of the one device to another. | ||
| 410 | ** | ||
| 411 | * The caller must hold the rtnl_mutex. | ||
| 412 | */ | ||
| 413 | int dev_addr_add_multiple(struct net_device *to_dev, | ||
| 414 | struct net_device *from_dev, | ||
| 415 | unsigned char addr_type) | ||
| 416 | { | ||
| 417 | int err; | ||
| 418 | |||
| 419 | ASSERT_RTNL(); | ||
| 420 | |||
| 421 | if (from_dev->addr_len != to_dev->addr_len) | ||
| 422 | return -EINVAL; | ||
| 423 | err = __hw_addr_add_multiple(&to_dev->dev_addrs, &from_dev->dev_addrs, | ||
| 424 | to_dev->addr_len, addr_type); | ||
| 425 | if (!err) | ||
| 426 | call_netdevice_notifiers(NETDEV_CHANGEADDR, to_dev); | ||
| 427 | return err; | ||
| 428 | } | ||
| 429 | EXPORT_SYMBOL(dev_addr_add_multiple); | ||
| 430 | |||
| 431 | /** | ||
| 432 | * dev_addr_del_multiple - Delete device addresses by another device | ||
| 433 | * @to_dev: device where the addresses will be deleted | ||
| 434 | * @from_dev: device supplying the addresses to be deleted | ||
| 435 | * @addr_type: address type - 0 means type will be used from from_dev | ||
| 436 | * | ||
| 437 | * Deletes addresses in to device by the list of addresses in from device. | ||
| 438 | * | ||
| 439 | * The caller must hold the rtnl_mutex. | ||
| 440 | */ | ||
| 441 | int dev_addr_del_multiple(struct net_device *to_dev, | ||
| 442 | struct net_device *from_dev, | ||
| 443 | unsigned char addr_type) | ||
| 444 | { | ||
| 445 | ASSERT_RTNL(); | ||
| 446 | |||
| 447 | if (from_dev->addr_len != to_dev->addr_len) | ||
| 448 | return -EINVAL; | ||
| 449 | __hw_addr_del_multiple(&to_dev->dev_addrs, &from_dev->dev_addrs, | ||
| 450 | to_dev->addr_len, addr_type); | ||
| 451 | call_netdevice_notifiers(NETDEV_CHANGEADDR, to_dev); | ||
| 452 | return 0; | ||
| 453 | } | ||
| 454 | EXPORT_SYMBOL(dev_addr_del_multiple); | ||
| 455 | |||
| 456 | /* | 363 | /* |
| 457 | * Unicast list handling functions | 364 | * Unicast list handling functions |
| 458 | */ | 365 | */ |
| @@ -676,7 +583,7 @@ static int __dev_mc_add(struct net_device *dev, const unsigned char *addr, | |||
| 676 | 583 | ||
| 677 | netif_addr_lock_bh(dev); | 584 | netif_addr_lock_bh(dev); |
| 678 | err = __hw_addr_add_ex(&dev->mc, addr, dev->addr_len, | 585 | err = __hw_addr_add_ex(&dev->mc, addr, dev->addr_len, |
| 679 | NETDEV_HW_ADDR_T_MULTICAST, global, false); | 586 | NETDEV_HW_ADDR_T_MULTICAST, global, false, 0); |
| 680 | if (!err) | 587 | if (!err) |
| 681 | __dev_set_rx_mode(dev); | 588 | __dev_set_rx_mode(dev); |
| 682 | netif_addr_unlock_bh(dev); | 589 | netif_addr_unlock_bh(dev); |
diff --git a/net/core/dev_ioctl.c b/net/core/dev_ioctl.c index 5b7d0e1d0664..cf999e09bcd2 100644 --- a/net/core/dev_ioctl.c +++ b/net/core/dev_ioctl.c | |||
| @@ -327,6 +327,7 @@ static int dev_ifsioc(struct net *net, struct ifreq *ifr, unsigned int cmd) | |||
| 327 | cmd == SIOCBRADDIF || | 327 | cmd == SIOCBRADDIF || |
| 328 | cmd == SIOCBRDELIF || | 328 | cmd == SIOCBRDELIF || |
| 329 | cmd == SIOCSHWTSTAMP || | 329 | cmd == SIOCSHWTSTAMP || |
| 330 | cmd == SIOCGHWTSTAMP || | ||
| 330 | cmd == SIOCWANDEV) { | 331 | cmd == SIOCWANDEV) { |
| 331 | err = -EOPNOTSUPP; | 332 | err = -EOPNOTSUPP; |
| 332 | if (ops->ndo_do_ioctl) { | 333 | if (ops->ndo_do_ioctl) { |
| @@ -546,6 +547,7 @@ int dev_ioctl(struct net *net, unsigned int cmd, void __user *arg) | |||
| 546 | */ | 547 | */ |
| 547 | default: | 548 | default: |
| 548 | if (cmd == SIOCWANDEV || | 549 | if (cmd == SIOCWANDEV || |
| 550 | cmd == SIOCGHWTSTAMP || | ||
| 549 | (cmd >= SIOCDEVPRIVATE && | 551 | (cmd >= SIOCDEVPRIVATE && |
| 550 | cmd <= SIOCDEVPRIVATE + 15)) { | 552 | cmd <= SIOCDEVPRIVATE + 15)) { |
| 551 | dev_load(net, ifr.ifr_name); | 553 | dev_load(net, ifr.ifr_name); |
diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index 2fc5beaf5783..87577d447554 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c | |||
| @@ -202,12 +202,12 @@ static __always_inline u32 __flow_hash_1word(u32 a) | |||
| 202 | } | 202 | } |
| 203 | 203 | ||
| 204 | /* | 204 | /* |
| 205 | * __skb_get_rxhash: calculate a flow hash based on src/dst addresses | 205 | * __skb_get_hash: calculate a flow hash based on src/dst addresses |
| 206 | * and src/dst port numbers. Sets rxhash in skb to non-zero hash value | 206 | * and src/dst port numbers. Sets rxhash in skb to non-zero hash value |
| 207 | * on success, zero indicates no valid hash. Also, sets l4_rxhash in skb | 207 | * on success, zero indicates no valid hash. Also, sets l4_rxhash in skb |
| 208 | * if hash is a canonical 4-tuple hash over transport ports. | 208 | * if hash is a canonical 4-tuple hash over transport ports. |
| 209 | */ | 209 | */ |
| 210 | void __skb_get_rxhash(struct sk_buff *skb) | 210 | void __skb_get_hash(struct sk_buff *skb) |
| 211 | { | 211 | { |
| 212 | struct flow_keys keys; | 212 | struct flow_keys keys; |
| 213 | u32 hash; | 213 | u32 hash; |
| @@ -234,7 +234,7 @@ void __skb_get_rxhash(struct sk_buff *skb) | |||
| 234 | 234 | ||
| 235 | skb->rxhash = hash; | 235 | skb->rxhash = hash; |
| 236 | } | 236 | } |
| 237 | EXPORT_SYMBOL(__skb_get_rxhash); | 237 | EXPORT_SYMBOL(__skb_get_hash); |
| 238 | 238 | ||
| 239 | /* | 239 | /* |
| 240 | * Returns a Tx hash based on the given packet descriptor a Tx queues' number | 240 | * Returns a Tx hash based on the given packet descriptor a Tx queues' number |
diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 932c6d7cf666..b9e9e0d38672 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c | |||
| @@ -38,6 +38,8 @@ | |||
| 38 | #include <linux/random.h> | 38 | #include <linux/random.h> |
| 39 | #include <linux/string.h> | 39 | #include <linux/string.h> |
| 40 | #include <linux/log2.h> | 40 | #include <linux/log2.h> |
| 41 | #include <linux/inetdevice.h> | ||
| 42 | #include <net/addrconf.h> | ||
| 41 | 43 | ||
| 42 | #define DEBUG | 44 | #define DEBUG |
| 43 | #define NEIGH_DEBUG 1 | 45 | #define NEIGH_DEBUG 1 |
| @@ -115,7 +117,7 @@ static void neigh_cleanup_and_release(struct neighbour *neigh) | |||
| 115 | 117 | ||
| 116 | unsigned long neigh_rand_reach_time(unsigned long base) | 118 | unsigned long neigh_rand_reach_time(unsigned long base) |
| 117 | { | 119 | { |
| 118 | return base ? (net_random() % base) + (base >> 1) : 0; | 120 | return base ? (prandom_u32() % base) + (base >> 1) : 0; |
| 119 | } | 121 | } |
| 120 | EXPORT_SYMBOL(neigh_rand_reach_time); | 122 | EXPORT_SYMBOL(neigh_rand_reach_time); |
| 121 | 123 | ||
| @@ -497,7 +499,7 @@ struct neighbour *__neigh_create(struct neigh_table *tbl, const void *pkey, | |||
| 497 | goto out_neigh_release; | 499 | goto out_neigh_release; |
| 498 | } | 500 | } |
| 499 | 501 | ||
| 500 | n->confirmed = jiffies - (n->parms->base_reachable_time << 1); | 502 | n->confirmed = jiffies - (NEIGH_VAR(n->parms, BASE_REACHABLE_TIME) << 1); |
| 501 | 503 | ||
| 502 | write_lock_bh(&tbl->lock); | 504 | write_lock_bh(&tbl->lock); |
| 503 | nht = rcu_dereference_protected(tbl->nht, | 505 | nht = rcu_dereference_protected(tbl->nht, |
| @@ -776,7 +778,7 @@ static void neigh_periodic_work(struct work_struct *work) | |||
| 776 | tbl->last_rand = jiffies; | 778 | tbl->last_rand = jiffies; |
| 777 | for (p = &tbl->parms; p; p = p->next) | 779 | for (p = &tbl->parms; p; p = p->next) |
| 778 | p->reachable_time = | 780 | p->reachable_time = |
| 779 | neigh_rand_reach_time(p->base_reachable_time); | 781 | neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME)); |
| 780 | } | 782 | } |
| 781 | 783 | ||
| 782 | for (i = 0 ; i < (1 << nht->hash_shift); i++) { | 784 | for (i = 0 ; i < (1 << nht->hash_shift); i++) { |
| @@ -799,7 +801,7 @@ static void neigh_periodic_work(struct work_struct *work) | |||
| 799 | 801 | ||
| 800 | if (atomic_read(&n->refcnt) == 1 && | 802 | if (atomic_read(&n->refcnt) == 1 && |
| 801 | (state == NUD_FAILED || | 803 | (state == NUD_FAILED || |
| 802 | time_after(jiffies, n->used + n->parms->gc_staletime))) { | 804 | time_after(jiffies, n->used + NEIGH_VAR(n->parms, GC_STALETIME)))) { |
| 803 | *np = n->next; | 805 | *np = n->next; |
| 804 | n->dead = 1; | 806 | n->dead = 1; |
| 805 | write_unlock(&n->lock); | 807 | write_unlock(&n->lock); |
| @@ -822,12 +824,12 @@ next_elt: | |||
| 822 | lockdep_is_held(&tbl->lock)); | 824 | lockdep_is_held(&tbl->lock)); |
| 823 | } | 825 | } |
| 824 | out: | 826 | out: |
| 825 | /* Cycle through all hash buckets every base_reachable_time/2 ticks. | 827 | /* Cycle through all hash buckets every BASE_REACHABLE_TIME/2 ticks. |
| 826 | * ARP entry timeouts range from 1/2 base_reachable_time to 3/2 | 828 | * ARP entry timeouts range from 1/2 BASE_REACHABLE_TIME to 3/2 |
| 827 | * base_reachable_time. | 829 | * BASE_REACHABLE_TIME. |
| 828 | */ | 830 | */ |
| 829 | schedule_delayed_work(&tbl->gc_work, | 831 | queue_delayed_work(system_power_efficient_wq, &tbl->gc_work, |
| 830 | tbl->parms.base_reachable_time >> 1); | 832 | NEIGH_VAR(&tbl->parms, BASE_REACHABLE_TIME) >> 1); |
| 831 | write_unlock_bh(&tbl->lock); | 833 | write_unlock_bh(&tbl->lock); |
| 832 | } | 834 | } |
| 833 | 835 | ||
| @@ -835,8 +837,9 @@ static __inline__ int neigh_max_probes(struct neighbour *n) | |||
| 835 | { | 837 | { |
| 836 | struct neigh_parms *p = n->parms; | 838 | struct neigh_parms *p = n->parms; |
| 837 | return (n->nud_state & NUD_PROBE) ? | 839 | return (n->nud_state & NUD_PROBE) ? |
| 838 | p->ucast_probes : | 840 | NEIGH_VAR(p, UCAST_PROBES) : |
| 839 | p->ucast_probes + p->app_probes + p->mcast_probes; | 841 | NEIGH_VAR(p, UCAST_PROBES) + NEIGH_VAR(p, APP_PROBES) + |
| 842 | NEIGH_VAR(p, MCAST_PROBES); | ||
| 840 | } | 843 | } |
| 841 | 844 | ||
| 842 | static void neigh_invalidate(struct neighbour *neigh) | 845 | static void neigh_invalidate(struct neighbour *neigh) |
| @@ -901,12 +904,13 @@ static void neigh_timer_handler(unsigned long arg) | |||
| 901 | neigh_dbg(2, "neigh %p is still alive\n", neigh); | 904 | neigh_dbg(2, "neigh %p is still alive\n", neigh); |
| 902 | next = neigh->confirmed + neigh->parms->reachable_time; | 905 | next = neigh->confirmed + neigh->parms->reachable_time; |
| 903 | } else if (time_before_eq(now, | 906 | } else if (time_before_eq(now, |
| 904 | neigh->used + neigh->parms->delay_probe_time)) { | 907 | neigh->used + |
| 908 | NEIGH_VAR(neigh->parms, DELAY_PROBE_TIME))) { | ||
| 905 | neigh_dbg(2, "neigh %p is delayed\n", neigh); | 909 | neigh_dbg(2, "neigh %p is delayed\n", neigh); |
| 906 | neigh->nud_state = NUD_DELAY; | 910 | neigh->nud_state = NUD_DELAY; |
| 907 | neigh->updated = jiffies; | 911 | neigh->updated = jiffies; |
| 908 | neigh_suspect(neigh); | 912 | neigh_suspect(neigh); |
| 909 | next = now + neigh->parms->delay_probe_time; | 913 | next = now + NEIGH_VAR(neigh->parms, DELAY_PROBE_TIME); |
| 910 | } else { | 914 | } else { |
| 911 | neigh_dbg(2, "neigh %p is suspected\n", neigh); | 915 | neigh_dbg(2, "neigh %p is suspected\n", neigh); |
| 912 | neigh->nud_state = NUD_STALE; | 916 | neigh->nud_state = NUD_STALE; |
| @@ -916,7 +920,8 @@ static void neigh_timer_handler(unsigned long arg) | |||
| 916 | } | 920 | } |
| 917 | } else if (state & NUD_DELAY) { | 921 | } else if (state & NUD_DELAY) { |
| 918 | if (time_before_eq(now, | 922 | if (time_before_eq(now, |
| 919 | neigh->confirmed + neigh->parms->delay_probe_time)) { | 923 | neigh->confirmed + |
| 924 | NEIGH_VAR(neigh->parms, DELAY_PROBE_TIME))) { | ||
| 920 | neigh_dbg(2, "neigh %p is now reachable\n", neigh); | 925 | neigh_dbg(2, "neigh %p is now reachable\n", neigh); |
| 921 | neigh->nud_state = NUD_REACHABLE; | 926 | neigh->nud_state = NUD_REACHABLE; |
| 922 | neigh->updated = jiffies; | 927 | neigh->updated = jiffies; |
| @@ -928,11 +933,11 @@ static void neigh_timer_handler(unsigned long arg) | |||
| 928 | neigh->nud_state = NUD_PROBE; | 933 | neigh->nud_state = NUD_PROBE; |
| 929 | neigh->updated = jiffies; | 934 | neigh->updated = jiffies; |
| 930 | atomic_set(&neigh->probes, 0); | 935 | atomic_set(&neigh->probes, 0); |
| 931 | next = now + neigh->parms->retrans_time; | 936 | next = now + NEIGH_VAR(neigh->parms, RETRANS_TIME); |
| 932 | } | 937 | } |
| 933 | } else { | 938 | } else { |
| 934 | /* NUD_PROBE|NUD_INCOMPLETE */ | 939 | /* NUD_PROBE|NUD_INCOMPLETE */ |
| 935 | next = now + neigh->parms->retrans_time; | 940 | next = now + NEIGH_VAR(neigh->parms, RETRANS_TIME); |
| 936 | } | 941 | } |
| 937 | 942 | ||
| 938 | if ((neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) && | 943 | if ((neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) && |
| @@ -973,13 +978,16 @@ int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb) | |||
| 973 | goto out_unlock_bh; | 978 | goto out_unlock_bh; |
| 974 | 979 | ||
| 975 | if (!(neigh->nud_state & (NUD_STALE | NUD_INCOMPLETE))) { | 980 | if (!(neigh->nud_state & (NUD_STALE | NUD_INCOMPLETE))) { |
| 976 | if (neigh->parms->mcast_probes + neigh->parms->app_probes) { | 981 | if (NEIGH_VAR(neigh->parms, MCAST_PROBES) + |
| 982 | NEIGH_VAR(neigh->parms, APP_PROBES)) { | ||
| 977 | unsigned long next, now = jiffies; | 983 | unsigned long next, now = jiffies; |
| 978 | 984 | ||
| 979 | atomic_set(&neigh->probes, neigh->parms->ucast_probes); | 985 | atomic_set(&neigh->probes, |
| 986 | NEIGH_VAR(neigh->parms, UCAST_PROBES)); | ||
| 980 | neigh->nud_state = NUD_INCOMPLETE; | 987 | neigh->nud_state = NUD_INCOMPLETE; |
| 981 | neigh->updated = now; | 988 | neigh->updated = now; |
| 982 | next = now + max(neigh->parms->retrans_time, HZ/2); | 989 | next = now + max(NEIGH_VAR(neigh->parms, RETRANS_TIME), |
| 990 | HZ/2); | ||
| 983 | neigh_add_timer(neigh, next); | 991 | neigh_add_timer(neigh, next); |
| 984 | immediate_probe = true; | 992 | immediate_probe = true; |
| 985 | } else { | 993 | } else { |
| @@ -994,14 +1002,14 @@ int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb) | |||
| 994 | neigh_dbg(2, "neigh %p is delayed\n", neigh); | 1002 | neigh_dbg(2, "neigh %p is delayed\n", neigh); |
| 995 | neigh->nud_state = NUD_DELAY; | 1003 | neigh->nud_state = NUD_DELAY; |
| 996 | neigh->updated = jiffies; | 1004 | neigh->updated = jiffies; |
| 997 | neigh_add_timer(neigh, | 1005 | neigh_add_timer(neigh, jiffies + |
| 998 | jiffies + neigh->parms->delay_probe_time); | 1006 | NEIGH_VAR(neigh->parms, DELAY_PROBE_TIME)); |
| 999 | } | 1007 | } |
| 1000 | 1008 | ||
| 1001 | if (neigh->nud_state == NUD_INCOMPLETE) { | 1009 | if (neigh->nud_state == NUD_INCOMPLETE) { |
| 1002 | if (skb) { | 1010 | if (skb) { |
| 1003 | while (neigh->arp_queue_len_bytes + skb->truesize > | 1011 | while (neigh->arp_queue_len_bytes + skb->truesize > |
| 1004 | neigh->parms->queue_len_bytes) { | 1012 | NEIGH_VAR(neigh->parms, QUEUE_LEN_BYTES)) { |
| 1005 | struct sk_buff *buff; | 1013 | struct sk_buff *buff; |
| 1006 | 1014 | ||
| 1007 | buff = __skb_dequeue(&neigh->arp_queue); | 1015 | buff = __skb_dequeue(&neigh->arp_queue); |
| @@ -1171,7 +1179,7 @@ int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new, | |||
| 1171 | neigh_update_hhs(neigh); | 1179 | neigh_update_hhs(neigh); |
| 1172 | if (!(new & NUD_CONNECTED)) | 1180 | if (!(new & NUD_CONNECTED)) |
| 1173 | neigh->confirmed = jiffies - | 1181 | neigh->confirmed = jiffies - |
| 1174 | (neigh->parms->base_reachable_time << 1); | 1182 | (NEIGH_VAR(neigh->parms, BASE_REACHABLE_TIME) << 1); |
| 1175 | notify = 1; | 1183 | notify = 1; |
| 1176 | } | 1184 | } |
| 1177 | if (new == old) | 1185 | if (new == old) |
| @@ -1231,6 +1239,21 @@ out: | |||
| 1231 | } | 1239 | } |
| 1232 | EXPORT_SYMBOL(neigh_update); | 1240 | EXPORT_SYMBOL(neigh_update); |
| 1233 | 1241 | ||
| 1242 | /* Update the neigh to listen temporarily for probe responses, even if it is | ||
| 1243 | * in a NUD_FAILED state. The caller has to hold neigh->lock for writing. | ||
| 1244 | */ | ||
| 1245 | void __neigh_set_probe_once(struct neighbour *neigh) | ||
| 1246 | { | ||
| 1247 | neigh->updated = jiffies; | ||
| 1248 | if (!(neigh->nud_state & NUD_FAILED)) | ||
| 1249 | return; | ||
| 1250 | neigh->nud_state = NUD_PROBE; | ||
| 1251 | atomic_set(&neigh->probes, NEIGH_VAR(neigh->parms, UCAST_PROBES)); | ||
| 1252 | neigh_add_timer(neigh, | ||
| 1253 | jiffies + NEIGH_VAR(neigh->parms, RETRANS_TIME)); | ||
| 1254 | } | ||
| 1255 | EXPORT_SYMBOL(__neigh_set_probe_once); | ||
| 1256 | |||
| 1234 | struct neighbour *neigh_event_ns(struct neigh_table *tbl, | 1257 | struct neighbour *neigh_event_ns(struct neigh_table *tbl, |
| 1235 | u8 *lladdr, void *saddr, | 1258 | u8 *lladdr, void *saddr, |
| 1236 | struct net_device *dev) | 1259 | struct net_device *dev) |
| @@ -1392,9 +1415,11 @@ void pneigh_enqueue(struct neigh_table *tbl, struct neigh_parms *p, | |||
| 1392 | struct sk_buff *skb) | 1415 | struct sk_buff *skb) |
| 1393 | { | 1416 | { |
| 1394 | unsigned long now = jiffies; | 1417 | unsigned long now = jiffies; |
| 1395 | unsigned long sched_next = now + (net_random() % p->proxy_delay); | ||
| 1396 | 1418 | ||
| 1397 | if (tbl->proxy_queue.qlen > p->proxy_qlen) { | 1419 | unsigned long sched_next = now + (prandom_u32() % |
| 1420 | NEIGH_VAR(p, PROXY_DELAY)); | ||
| 1421 | |||
| 1422 | if (tbl->proxy_queue.qlen > NEIGH_VAR(p, PROXY_QLEN)) { | ||
| 1398 | kfree_skb(skb); | 1423 | kfree_skb(skb); |
| 1399 | return; | 1424 | return; |
| 1400 | } | 1425 | } |
| @@ -1441,7 +1466,7 @@ struct neigh_parms *neigh_parms_alloc(struct net_device *dev, | |||
| 1441 | p->tbl = tbl; | 1466 | p->tbl = tbl; |
| 1442 | atomic_set(&p->refcnt, 1); | 1467 | atomic_set(&p->refcnt, 1); |
| 1443 | p->reachable_time = | 1468 | p->reachable_time = |
| 1444 | neigh_rand_reach_time(p->base_reachable_time); | 1469 | neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME)); |
| 1445 | dev_hold(dev); | 1470 | dev_hold(dev); |
| 1446 | p->dev = dev; | 1471 | p->dev = dev; |
| 1447 | write_pnet(&p->net, hold_net(net)); | 1472 | write_pnet(&p->net, hold_net(net)); |
| @@ -1458,6 +1483,8 @@ struct neigh_parms *neigh_parms_alloc(struct net_device *dev, | |||
| 1458 | p->next = tbl->parms.next; | 1483 | p->next = tbl->parms.next; |
| 1459 | tbl->parms.next = p; | 1484 | tbl->parms.next = p; |
| 1460 | write_unlock_bh(&tbl->lock); | 1485 | write_unlock_bh(&tbl->lock); |
| 1486 | |||
| 1487 | neigh_parms_data_state_cleanall(p); | ||
| 1461 | } | 1488 | } |
| 1462 | return p; | 1489 | return p; |
| 1463 | } | 1490 | } |
| @@ -1510,7 +1537,7 @@ static void neigh_table_init_no_netlink(struct neigh_table *tbl) | |||
| 1510 | write_pnet(&tbl->parms.net, &init_net); | 1537 | write_pnet(&tbl->parms.net, &init_net); |
| 1511 | atomic_set(&tbl->parms.refcnt, 1); | 1538 | atomic_set(&tbl->parms.refcnt, 1); |
| 1512 | tbl->parms.reachable_time = | 1539 | tbl->parms.reachable_time = |
| 1513 | neigh_rand_reach_time(tbl->parms.base_reachable_time); | 1540 | neigh_rand_reach_time(NEIGH_VAR(&tbl->parms, BASE_REACHABLE_TIME)); |
| 1514 | 1541 | ||
| 1515 | tbl->stats = alloc_percpu(struct neigh_statistics); | 1542 | tbl->stats = alloc_percpu(struct neigh_statistics); |
| 1516 | if (!tbl->stats) | 1543 | if (!tbl->stats) |
| @@ -1538,7 +1565,8 @@ static void neigh_table_init_no_netlink(struct neigh_table *tbl) | |||
| 1538 | 1565 | ||
| 1539 | rwlock_init(&tbl->lock); | 1566 | rwlock_init(&tbl->lock); |
| 1540 | INIT_DEFERRABLE_WORK(&tbl->gc_work, neigh_periodic_work); | 1567 | INIT_DEFERRABLE_WORK(&tbl->gc_work, neigh_periodic_work); |
| 1541 | schedule_delayed_work(&tbl->gc_work, tbl->parms.reachable_time); | 1568 | queue_delayed_work(system_power_efficient_wq, &tbl->gc_work, |
| 1569 | tbl->parms.reachable_time); | ||
| 1542 | setup_timer(&tbl->proxy_timer, neigh_proxy_process, (unsigned long)tbl); | 1570 | setup_timer(&tbl->proxy_timer, neigh_proxy_process, (unsigned long)tbl); |
| 1543 | skb_queue_head_init_class(&tbl->proxy_queue, | 1571 | skb_queue_head_init_class(&tbl->proxy_queue, |
| 1544 | &neigh_table_proxy_queue_class); | 1572 | &neigh_table_proxy_queue_class); |
| @@ -1778,24 +1806,32 @@ static int neightbl_fill_parms(struct sk_buff *skb, struct neigh_parms *parms) | |||
| 1778 | if ((parms->dev && | 1806 | if ((parms->dev && |
| 1779 | nla_put_u32(skb, NDTPA_IFINDEX, parms->dev->ifindex)) || | 1807 | nla_put_u32(skb, NDTPA_IFINDEX, parms->dev->ifindex)) || |
| 1780 | nla_put_u32(skb, NDTPA_REFCNT, atomic_read(&parms->refcnt)) || | 1808 | nla_put_u32(skb, NDTPA_REFCNT, atomic_read(&parms->refcnt)) || |
| 1781 | nla_put_u32(skb, NDTPA_QUEUE_LENBYTES, parms->queue_len_bytes) || | 1809 | nla_put_u32(skb, NDTPA_QUEUE_LENBYTES, |
| 1810 | NEIGH_VAR(parms, QUEUE_LEN_BYTES)) || | ||
| 1782 | /* approximative value for deprecated QUEUE_LEN (in packets) */ | 1811 | /* approximative value for deprecated QUEUE_LEN (in packets) */ |
| 1783 | nla_put_u32(skb, NDTPA_QUEUE_LEN, | 1812 | nla_put_u32(skb, NDTPA_QUEUE_LEN, |
| 1784 | parms->queue_len_bytes / SKB_TRUESIZE(ETH_FRAME_LEN)) || | 1813 | NEIGH_VAR(parms, QUEUE_LEN_BYTES) / SKB_TRUESIZE(ETH_FRAME_LEN)) || |
| 1785 | nla_put_u32(skb, NDTPA_PROXY_QLEN, parms->proxy_qlen) || | 1814 | nla_put_u32(skb, NDTPA_PROXY_QLEN, NEIGH_VAR(parms, PROXY_QLEN)) || |
| 1786 | nla_put_u32(skb, NDTPA_APP_PROBES, parms->app_probes) || | 1815 | nla_put_u32(skb, NDTPA_APP_PROBES, NEIGH_VAR(parms, APP_PROBES)) || |
| 1787 | nla_put_u32(skb, NDTPA_UCAST_PROBES, parms->ucast_probes) || | 1816 | nla_put_u32(skb, NDTPA_UCAST_PROBES, |
| 1788 | nla_put_u32(skb, NDTPA_MCAST_PROBES, parms->mcast_probes) || | 1817 | NEIGH_VAR(parms, UCAST_PROBES)) || |
| 1818 | nla_put_u32(skb, NDTPA_MCAST_PROBES, | ||
| 1819 | NEIGH_VAR(parms, MCAST_PROBES)) || | ||
| 1789 | nla_put_msecs(skb, NDTPA_REACHABLE_TIME, parms->reachable_time) || | 1820 | nla_put_msecs(skb, NDTPA_REACHABLE_TIME, parms->reachable_time) || |
| 1790 | nla_put_msecs(skb, NDTPA_BASE_REACHABLE_TIME, | 1821 | nla_put_msecs(skb, NDTPA_BASE_REACHABLE_TIME, |
| 1791 | parms->base_reachable_time) || | 1822 | NEIGH_VAR(parms, BASE_REACHABLE_TIME)) || |
| 1792 | nla_put_msecs(skb, NDTPA_GC_STALETIME, parms->gc_staletime) || | 1823 | nla_put_msecs(skb, NDTPA_GC_STALETIME, |
| 1824 | NEIGH_VAR(parms, GC_STALETIME)) || | ||
| 1793 | nla_put_msecs(skb, NDTPA_DELAY_PROBE_TIME, | 1825 | nla_put_msecs(skb, NDTPA_DELAY_PROBE_TIME, |
| 1794 | parms->delay_probe_time) || | 1826 | NEIGH_VAR(parms, DELAY_PROBE_TIME)) || |
| 1795 | nla_put_msecs(skb, NDTPA_RETRANS_TIME, parms->retrans_time) || | 1827 | nla_put_msecs(skb, NDTPA_RETRANS_TIME, |
| 1796 | nla_put_msecs(skb, NDTPA_ANYCAST_DELAY, parms->anycast_delay) || | 1828 | NEIGH_VAR(parms, RETRANS_TIME)) || |
| 1797 | nla_put_msecs(skb, NDTPA_PROXY_DELAY, parms->proxy_delay) || | 1829 | nla_put_msecs(skb, NDTPA_ANYCAST_DELAY, |
| 1798 | nla_put_msecs(skb, NDTPA_LOCKTIME, parms->locktime)) | 1830 | NEIGH_VAR(parms, ANYCAST_DELAY)) || |
| 1831 | nla_put_msecs(skb, NDTPA_PROXY_DELAY, | ||
| 1832 | NEIGH_VAR(parms, PROXY_DELAY)) || | ||
| 1833 | nla_put_msecs(skb, NDTPA_LOCKTIME, | ||
| 1834 | NEIGH_VAR(parms, LOCKTIME))) | ||
| 1799 | goto nla_put_failure; | 1835 | goto nla_put_failure; |
| 1800 | return nla_nest_end(skb, nest); | 1836 | return nla_nest_end(skb, nest); |
| 1801 | 1837 | ||
| @@ -2011,44 +2047,57 @@ static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
| 2011 | 2047 | ||
| 2012 | switch (i) { | 2048 | switch (i) { |
| 2013 | case NDTPA_QUEUE_LEN: | 2049 | case NDTPA_QUEUE_LEN: |
| 2014 | p->queue_len_bytes = nla_get_u32(tbp[i]) * | 2050 | NEIGH_VAR_SET(p, QUEUE_LEN_BYTES, |
| 2015 | SKB_TRUESIZE(ETH_FRAME_LEN); | 2051 | nla_get_u32(tbp[i]) * |
| 2052 | SKB_TRUESIZE(ETH_FRAME_LEN)); | ||
| 2016 | break; | 2053 | break; |
| 2017 | case NDTPA_QUEUE_LENBYTES: | 2054 | case NDTPA_QUEUE_LENBYTES: |
| 2018 | p->queue_len_bytes = nla_get_u32(tbp[i]); | 2055 | NEIGH_VAR_SET(p, QUEUE_LEN_BYTES, |
| 2056 | nla_get_u32(tbp[i])); | ||
| 2019 | break; | 2057 | break; |
| 2020 | case NDTPA_PROXY_QLEN: | 2058 | case NDTPA_PROXY_QLEN: |
| 2021 | p->proxy_qlen = nla_get_u32(tbp[i]); | 2059 | NEIGH_VAR_SET(p, PROXY_QLEN, |
| 2060 | nla_get_u32(tbp[i])); | ||
| 2022 | break; | 2061 | break; |
| 2023 | case NDTPA_APP_PROBES: | 2062 | case NDTPA_APP_PROBES: |
| 2024 | p->app_probes = nla_get_u32(tbp[i]); | 2063 | NEIGH_VAR_SET(p, APP_PROBES, |
| 2064 | nla_get_u32(tbp[i])); | ||
| 2025 | break; | 2065 | break; |
| 2026 | case NDTPA_UCAST_PROBES: | 2066 | case NDTPA_UCAST_PROBES: |
| 2027 | p->ucast_probes = nla_get_u32(tbp[i]); | 2067 | NEIGH_VAR_SET(p, UCAST_PROBES, |
| 2068 | nla_get_u32(tbp[i])); | ||
| 2028 | break; | 2069 | break; |
| 2029 | case NDTPA_MCAST_PROBES: | 2070 | case NDTPA_MCAST_PROBES: |
| 2030 | p->mcast_probes = nla_get_u32(tbp[i]); | 2071 | NEIGH_VAR_SET(p, MCAST_PROBES, |
| 2072 | nla_get_u32(tbp[i])); | ||
| 2031 | break; | 2073 | break; |
| 2032 | case NDTPA_BASE_REACHABLE_TIME: | 2074 | case NDTPA_BASE_REACHABLE_TIME: |
| 2033 | p->base_reachable_time = nla_get_msecs(tbp[i]); | 2075 | NEIGH_VAR_SET(p, BASE_REACHABLE_TIME, |
| 2076 | nla_get_msecs(tbp[i])); | ||
| 2034 | break; | 2077 | break; |
| 2035 | case NDTPA_GC_STALETIME: | 2078 | case NDTPA_GC_STALETIME: |
| 2036 | p->gc_staletime = nla_get_msecs(tbp[i]); | 2079 | NEIGH_VAR_SET(p, GC_STALETIME, |
| 2080 | nla_get_msecs(tbp[i])); | ||
| 2037 | break; | 2081 | break; |
| 2038 | case NDTPA_DELAY_PROBE_TIME: | 2082 | case NDTPA_DELAY_PROBE_TIME: |
| 2039 | p->delay_probe_time = nla_get_msecs(tbp[i]); | 2083 | NEIGH_VAR_SET(p, DELAY_PROBE_TIME, |
| 2084 | nla_get_msecs(tbp[i])); | ||
| 2040 | break; | 2085 | break; |
| 2041 | case NDTPA_RETRANS_TIME: | 2086 | case NDTPA_RETRANS_TIME: |
| 2042 | p->retrans_time = nla_get_msecs(tbp[i]); | 2087 | NEIGH_VAR_SET(p, RETRANS_TIME, |
| 2088 | nla_get_msecs(tbp[i])); | ||
| 2043 | break; | 2089 | break; |
| 2044 | case NDTPA_ANYCAST_DELAY: | 2090 | case NDTPA_ANYCAST_DELAY: |
| 2045 | p->anycast_delay = nla_get_msecs(tbp[i]); | 2091 | NEIGH_VAR_SET(p, ANYCAST_DELAY, |
| 2092 | nla_get_msecs(tbp[i])); | ||
| 2046 | break; | 2093 | break; |
| 2047 | case NDTPA_PROXY_DELAY: | 2094 | case NDTPA_PROXY_DELAY: |
| 2048 | p->proxy_delay = nla_get_msecs(tbp[i]); | 2095 | NEIGH_VAR_SET(p, PROXY_DELAY, |
| 2096 | nla_get_msecs(tbp[i])); | ||
| 2049 | break; | 2097 | break; |
| 2050 | case NDTPA_LOCKTIME: | 2098 | case NDTPA_LOCKTIME: |
| 2051 | p->locktime = nla_get_msecs(tbp[i]); | 2099 | NEIGH_VAR_SET(p, LOCKTIME, |
| 2100 | nla_get_msecs(tbp[i])); | ||
| 2052 | break; | 2101 | break; |
| 2053 | } | 2102 | } |
| 2054 | } | 2103 | } |
| @@ -2789,133 +2838,167 @@ static int proc_unres_qlen(struct ctl_table *ctl, int write, | |||
| 2789 | return ret; | 2838 | return ret; |
| 2790 | } | 2839 | } |
| 2791 | 2840 | ||
| 2792 | enum { | 2841 | static struct neigh_parms *neigh_get_dev_parms_rcu(struct net_device *dev, |
| 2793 | NEIGH_VAR_MCAST_PROBE, | 2842 | int family) |
| 2794 | NEIGH_VAR_UCAST_PROBE, | 2843 | { |
| 2795 | NEIGH_VAR_APP_PROBE, | 2844 | switch (family) { |
| 2796 | NEIGH_VAR_RETRANS_TIME, | 2845 | case AF_INET: |
| 2797 | NEIGH_VAR_BASE_REACHABLE_TIME, | 2846 | return __in_dev_arp_parms_get_rcu(dev); |
| 2798 | NEIGH_VAR_DELAY_PROBE_TIME, | 2847 | case AF_INET6: |
| 2799 | NEIGH_VAR_GC_STALETIME, | 2848 | return __in6_dev_nd_parms_get_rcu(dev); |
| 2800 | NEIGH_VAR_QUEUE_LEN, | 2849 | } |
| 2801 | NEIGH_VAR_QUEUE_LEN_BYTES, | 2850 | return NULL; |
| 2802 | NEIGH_VAR_PROXY_QLEN, | 2851 | } |
| 2803 | NEIGH_VAR_ANYCAST_DELAY, | 2852 | |
| 2804 | NEIGH_VAR_PROXY_DELAY, | 2853 | static void neigh_copy_dflt_parms(struct net *net, struct neigh_parms *p, |
| 2805 | NEIGH_VAR_LOCKTIME, | 2854 | int index) |
| 2806 | NEIGH_VAR_RETRANS_TIME_MS, | 2855 | { |
| 2807 | NEIGH_VAR_BASE_REACHABLE_TIME_MS, | 2856 | struct net_device *dev; |
| 2808 | NEIGH_VAR_GC_INTERVAL, | 2857 | int family = neigh_parms_family(p); |
| 2809 | NEIGH_VAR_GC_THRESH1, | 2858 | |
| 2810 | NEIGH_VAR_GC_THRESH2, | 2859 | rcu_read_lock(); |
| 2811 | NEIGH_VAR_GC_THRESH3, | 2860 | for_each_netdev_rcu(net, dev) { |
| 2812 | NEIGH_VAR_MAX | 2861 | struct neigh_parms *dst_p = |
| 2813 | }; | 2862 | neigh_get_dev_parms_rcu(dev, family); |
| 2863 | |||
| 2864 | if (dst_p && !test_bit(index, dst_p->data_state)) | ||
| 2865 | dst_p->data[index] = p->data[index]; | ||
| 2866 | } | ||
| 2867 | rcu_read_unlock(); | ||
| 2868 | } | ||
| 2869 | |||
| 2870 | static void neigh_proc_update(struct ctl_table *ctl, int write) | ||
| 2871 | { | ||
| 2872 | struct net_device *dev = ctl->extra1; | ||
| 2873 | struct neigh_parms *p = ctl->extra2; | ||
| 2874 | struct net *net = neigh_parms_net(p); | ||
| 2875 | int index = (int *) ctl->data - p->data; | ||
| 2876 | |||
| 2877 | if (!write) | ||
| 2878 | return; | ||
| 2879 | |||
| 2880 | set_bit(index, p->data_state); | ||
| 2881 | if (!dev) /* NULL dev means this is default value */ | ||
| 2882 | neigh_copy_dflt_parms(net, p, index); | ||
| 2883 | } | ||
| 2884 | |||
| 2885 | static int neigh_proc_dointvec_zero_intmax(struct ctl_table *ctl, int write, | ||
| 2886 | void __user *buffer, | ||
| 2887 | size_t *lenp, loff_t *ppos) | ||
| 2888 | { | ||
| 2889 | struct ctl_table tmp = *ctl; | ||
| 2890 | int ret; | ||
| 2891 | |||
| 2892 | tmp.extra1 = &zero; | ||
| 2893 | tmp.extra2 = &int_max; | ||
| 2894 | |||
| 2895 | ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos); | ||
| 2896 | neigh_proc_update(ctl, write); | ||
| 2897 | return ret; | ||
| 2898 | } | ||
| 2899 | |||
| 2900 | int neigh_proc_dointvec(struct ctl_table *ctl, int write, | ||
| 2901 | void __user *buffer, size_t *lenp, loff_t *ppos) | ||
| 2902 | { | ||
| 2903 | int ret = proc_dointvec(ctl, write, buffer, lenp, ppos); | ||
| 2904 | |||
| 2905 | neigh_proc_update(ctl, write); | ||
| 2906 | return ret; | ||
| 2907 | } | ||
| 2908 | EXPORT_SYMBOL(neigh_proc_dointvec); | ||
| 2909 | |||
| 2910 | int neigh_proc_dointvec_jiffies(struct ctl_table *ctl, int write, | ||
| 2911 | void __user *buffer, | ||
| 2912 | size_t *lenp, loff_t *ppos) | ||
| 2913 | { | ||
| 2914 | int ret = proc_dointvec_jiffies(ctl, write, buffer, lenp, ppos); | ||
| 2915 | |||
| 2916 | neigh_proc_update(ctl, write); | ||
| 2917 | return ret; | ||
| 2918 | } | ||
| 2919 | EXPORT_SYMBOL(neigh_proc_dointvec_jiffies); | ||
| 2920 | |||
| 2921 | static int neigh_proc_dointvec_userhz_jiffies(struct ctl_table *ctl, int write, | ||
| 2922 | void __user *buffer, | ||
| 2923 | size_t *lenp, loff_t *ppos) | ||
| 2924 | { | ||
| 2925 | int ret = proc_dointvec_userhz_jiffies(ctl, write, buffer, lenp, ppos); | ||
| 2926 | |||
| 2927 | neigh_proc_update(ctl, write); | ||
| 2928 | return ret; | ||
| 2929 | } | ||
| 2930 | |||
| 2931 | int neigh_proc_dointvec_ms_jiffies(struct ctl_table *ctl, int write, | ||
| 2932 | void __user *buffer, | ||
| 2933 | size_t *lenp, loff_t *ppos) | ||
| 2934 | { | ||
| 2935 | int ret = proc_dointvec_ms_jiffies(ctl, write, buffer, lenp, ppos); | ||
| 2936 | |||
| 2937 | neigh_proc_update(ctl, write); | ||
| 2938 | return ret; | ||
| 2939 | } | ||
| 2940 | EXPORT_SYMBOL(neigh_proc_dointvec_ms_jiffies); | ||
| 2941 | |||
| 2942 | static int neigh_proc_dointvec_unres_qlen(struct ctl_table *ctl, int write, | ||
| 2943 | void __user *buffer, | ||
| 2944 | size_t *lenp, loff_t *ppos) | ||
| 2945 | { | ||
| 2946 | int ret = proc_unres_qlen(ctl, write, buffer, lenp, ppos); | ||
| 2947 | |||
| 2948 | neigh_proc_update(ctl, write); | ||
| 2949 | return ret; | ||
| 2950 | } | ||
| 2951 | |||
| 2952 | #define NEIGH_PARMS_DATA_OFFSET(index) \ | ||
| 2953 | (&((struct neigh_parms *) 0)->data[index]) | ||
| 2954 | |||
| 2955 | #define NEIGH_SYSCTL_ENTRY(attr, data_attr, name, mval, proc) \ | ||
| 2956 | [NEIGH_VAR_ ## attr] = { \ | ||
| 2957 | .procname = name, \ | ||
| 2958 | .data = NEIGH_PARMS_DATA_OFFSET(NEIGH_VAR_ ## data_attr), \ | ||
| 2959 | .maxlen = sizeof(int), \ | ||
| 2960 | .mode = mval, \ | ||
| 2961 | .proc_handler = proc, \ | ||
| 2962 | } | ||
| 2963 | |||
| 2964 | #define NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(attr, name) \ | ||
| 2965 | NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, neigh_proc_dointvec_zero_intmax) | ||
| 2966 | |||
| 2967 | #define NEIGH_SYSCTL_JIFFIES_ENTRY(attr, name) \ | ||
| 2968 | NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, neigh_proc_dointvec_jiffies) | ||
| 2969 | |||
| 2970 | #define NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(attr, name) \ | ||
| 2971 | NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, neigh_proc_dointvec_userhz_jiffies) | ||
| 2972 | |||
| 2973 | #define NEIGH_SYSCTL_MS_JIFFIES_ENTRY(attr, name) \ | ||
| 2974 | NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, neigh_proc_dointvec_ms_jiffies) | ||
| 2975 | |||
| 2976 | #define NEIGH_SYSCTL_MS_JIFFIES_REUSED_ENTRY(attr, data_attr, name) \ | ||
| 2977 | NEIGH_SYSCTL_ENTRY(attr, data_attr, name, 0644, neigh_proc_dointvec_ms_jiffies) | ||
| 2978 | |||
| 2979 | #define NEIGH_SYSCTL_UNRES_QLEN_REUSED_ENTRY(attr, data_attr, name) \ | ||
| 2980 | NEIGH_SYSCTL_ENTRY(attr, data_attr, name, 0644, neigh_proc_dointvec_unres_qlen) | ||
| 2814 | 2981 | ||
| 2815 | static struct neigh_sysctl_table { | 2982 | static struct neigh_sysctl_table { |
| 2816 | struct ctl_table_header *sysctl_header; | 2983 | struct ctl_table_header *sysctl_header; |
| 2817 | struct ctl_table neigh_vars[NEIGH_VAR_MAX + 1]; | 2984 | struct ctl_table neigh_vars[NEIGH_VAR_MAX + 1]; |
| 2818 | } neigh_sysctl_template __read_mostly = { | 2985 | } neigh_sysctl_template __read_mostly = { |
| 2819 | .neigh_vars = { | 2986 | .neigh_vars = { |
| 2820 | [NEIGH_VAR_MCAST_PROBE] = { | 2987 | NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(MCAST_PROBES, "mcast_solicit"), |
| 2821 | .procname = "mcast_solicit", | 2988 | NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(UCAST_PROBES, "ucast_solicit"), |
| 2822 | .maxlen = sizeof(int), | 2989 | NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(APP_PROBES, "app_solicit"), |
| 2823 | .mode = 0644, | 2990 | NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(RETRANS_TIME, "retrans_time"), |
| 2824 | .extra1 = &zero, | 2991 | NEIGH_SYSCTL_JIFFIES_ENTRY(BASE_REACHABLE_TIME, "base_reachable_time"), |
| 2825 | .extra2 = &int_max, | 2992 | NEIGH_SYSCTL_JIFFIES_ENTRY(DELAY_PROBE_TIME, "delay_first_probe_time"), |
| 2826 | .proc_handler = proc_dointvec_minmax, | 2993 | NEIGH_SYSCTL_JIFFIES_ENTRY(GC_STALETIME, "gc_stale_time"), |
| 2827 | }, | 2994 | NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(QUEUE_LEN_BYTES, "unres_qlen_bytes"), |
| 2828 | [NEIGH_VAR_UCAST_PROBE] = { | 2995 | NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(PROXY_QLEN, "proxy_qlen"), |
| 2829 | .procname = "ucast_solicit", | 2996 | NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(ANYCAST_DELAY, "anycast_delay"), |
| 2830 | .maxlen = sizeof(int), | 2997 | NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(PROXY_DELAY, "proxy_delay"), |
| 2831 | .mode = 0644, | 2998 | NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(LOCKTIME, "locktime"), |
| 2832 | .extra1 = &zero, | 2999 | NEIGH_SYSCTL_UNRES_QLEN_REUSED_ENTRY(QUEUE_LEN, QUEUE_LEN_BYTES, "unres_qlen"), |
| 2833 | .extra2 = &int_max, | 3000 | NEIGH_SYSCTL_MS_JIFFIES_REUSED_ENTRY(RETRANS_TIME_MS, RETRANS_TIME, "retrans_time_ms"), |
| 2834 | .proc_handler = proc_dointvec_minmax, | 3001 | NEIGH_SYSCTL_MS_JIFFIES_REUSED_ENTRY(BASE_REACHABLE_TIME_MS, BASE_REACHABLE_TIME, "base_reachable_time_ms"), |
| 2835 | }, | ||
| 2836 | [NEIGH_VAR_APP_PROBE] = { | ||
| 2837 | .procname = "app_solicit", | ||
| 2838 | .maxlen = sizeof(int), | ||
| 2839 | .mode = 0644, | ||
| 2840 | .extra1 = &zero, | ||
| 2841 | .extra2 = &int_max, | ||
| 2842 | .proc_handler = proc_dointvec_minmax, | ||
| 2843 | }, | ||
| 2844 | [NEIGH_VAR_RETRANS_TIME] = { | ||
| 2845 | .procname = "retrans_time", | ||
| 2846 | .maxlen = sizeof(int), | ||
| 2847 | .mode = 0644, | ||
| 2848 | .proc_handler = proc_dointvec_userhz_jiffies, | ||
| 2849 | }, | ||
| 2850 | [NEIGH_VAR_BASE_REACHABLE_TIME] = { | ||
| 2851 | .procname = "base_reachable_time", | ||
| 2852 | .maxlen = sizeof(int), | ||
| 2853 | .mode = 0644, | ||
| 2854 | .proc_handler = proc_dointvec_jiffies, | ||
| 2855 | }, | ||
| 2856 | [NEIGH_VAR_DELAY_PROBE_TIME] = { | ||
| 2857 | .procname = "delay_first_probe_time", | ||
| 2858 | .maxlen = sizeof(int), | ||
| 2859 | .mode = 0644, | ||
| 2860 | .proc_handler = proc_dointvec_jiffies, | ||
| 2861 | }, | ||
| 2862 | [NEIGH_VAR_GC_STALETIME] = { | ||
| 2863 | .procname = "gc_stale_time", | ||
| 2864 | .maxlen = sizeof(int), | ||
| 2865 | .mode = 0644, | ||
| 2866 | .proc_handler = proc_dointvec_jiffies, | ||
| 2867 | }, | ||
| 2868 | [NEIGH_VAR_QUEUE_LEN] = { | ||
| 2869 | .procname = "unres_qlen", | ||
| 2870 | .maxlen = sizeof(int), | ||
| 2871 | .mode = 0644, | ||
| 2872 | .proc_handler = proc_unres_qlen, | ||
| 2873 | }, | ||
| 2874 | [NEIGH_VAR_QUEUE_LEN_BYTES] = { | ||
| 2875 | .procname = "unres_qlen_bytes", | ||
| 2876 | .maxlen = sizeof(int), | ||
| 2877 | .mode = 0644, | ||
| 2878 | .extra1 = &zero, | ||
| 2879 | .proc_handler = proc_dointvec_minmax, | ||
| 2880 | }, | ||
| 2881 | [NEIGH_VAR_PROXY_QLEN] = { | ||
| 2882 | .procname = "proxy_qlen", | ||
| 2883 | .maxlen = sizeof(int), | ||
| 2884 | .mode = 0644, | ||
| 2885 | .extra1 = &zero, | ||
| 2886 | .extra2 = &int_max, | ||
| 2887 | .proc_handler = proc_dointvec_minmax, | ||
| 2888 | }, | ||
| 2889 | [NEIGH_VAR_ANYCAST_DELAY] = { | ||
| 2890 | .procname = "anycast_delay", | ||
| 2891 | .maxlen = sizeof(int), | ||
| 2892 | .mode = 0644, | ||
| 2893 | .proc_handler = proc_dointvec_userhz_jiffies, | ||
| 2894 | }, | ||
| 2895 | [NEIGH_VAR_PROXY_DELAY] = { | ||
| 2896 | .procname = "proxy_delay", | ||
| 2897 | .maxlen = sizeof(int), | ||
| 2898 | .mode = 0644, | ||
| 2899 | .proc_handler = proc_dointvec_userhz_jiffies, | ||
| 2900 | }, | ||
| 2901 | [NEIGH_VAR_LOCKTIME] = { | ||
| 2902 | .procname = "locktime", | ||
| 2903 | .maxlen = sizeof(int), | ||
| 2904 | .mode = 0644, | ||
| 2905 | .proc_handler = proc_dointvec_userhz_jiffies, | ||
| 2906 | }, | ||
| 2907 | [NEIGH_VAR_RETRANS_TIME_MS] = { | ||
| 2908 | .procname = "retrans_time_ms", | ||
| 2909 | .maxlen = sizeof(int), | ||
| 2910 | .mode = 0644, | ||
| 2911 | .proc_handler = proc_dointvec_ms_jiffies, | ||
| 2912 | }, | ||
| 2913 | [NEIGH_VAR_BASE_REACHABLE_TIME_MS] = { | ||
| 2914 | .procname = "base_reachable_time_ms", | ||
| 2915 | .maxlen = sizeof(int), | ||
| 2916 | .mode = 0644, | ||
| 2917 | .proc_handler = proc_dointvec_ms_jiffies, | ||
| 2918 | }, | ||
| 2919 | [NEIGH_VAR_GC_INTERVAL] = { | 3002 | [NEIGH_VAR_GC_INTERVAL] = { |
| 2920 | .procname = "gc_interval", | 3003 | .procname = "gc_interval", |
| 2921 | .maxlen = sizeof(int), | 3004 | .maxlen = sizeof(int), |
| @@ -2951,31 +3034,23 @@ static struct neigh_sysctl_table { | |||
| 2951 | }; | 3034 | }; |
| 2952 | 3035 | ||
| 2953 | int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p, | 3036 | int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p, |
| 2954 | char *p_name, proc_handler *handler) | 3037 | proc_handler *handler) |
| 2955 | { | 3038 | { |
| 3039 | int i; | ||
| 2956 | struct neigh_sysctl_table *t; | 3040 | struct neigh_sysctl_table *t; |
| 2957 | const char *dev_name_source = NULL; | 3041 | const char *dev_name_source; |
| 2958 | char neigh_path[ sizeof("net//neigh/") + IFNAMSIZ + IFNAMSIZ ]; | 3042 | char neigh_path[ sizeof("net//neigh/") + IFNAMSIZ + IFNAMSIZ ]; |
| 3043 | char *p_name; | ||
| 2959 | 3044 | ||
| 2960 | t = kmemdup(&neigh_sysctl_template, sizeof(*t), GFP_KERNEL); | 3045 | t = kmemdup(&neigh_sysctl_template, sizeof(*t), GFP_KERNEL); |
| 2961 | if (!t) | 3046 | if (!t) |
| 2962 | goto err; | 3047 | goto err; |
| 2963 | 3048 | ||
| 2964 | t->neigh_vars[NEIGH_VAR_MCAST_PROBE].data = &p->mcast_probes; | 3049 | for (i = 0; i < ARRAY_SIZE(t->neigh_vars); i++) { |
| 2965 | t->neigh_vars[NEIGH_VAR_UCAST_PROBE].data = &p->ucast_probes; | 3050 | t->neigh_vars[i].data += (long) p; |
| 2966 | t->neigh_vars[NEIGH_VAR_APP_PROBE].data = &p->app_probes; | 3051 | t->neigh_vars[i].extra1 = dev; |
| 2967 | t->neigh_vars[NEIGH_VAR_RETRANS_TIME].data = &p->retrans_time; | 3052 | t->neigh_vars[i].extra2 = p; |
| 2968 | t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME].data = &p->base_reachable_time; | 3053 | } |
| 2969 | t->neigh_vars[NEIGH_VAR_DELAY_PROBE_TIME].data = &p->delay_probe_time; | ||
| 2970 | t->neigh_vars[NEIGH_VAR_GC_STALETIME].data = &p->gc_staletime; | ||
| 2971 | t->neigh_vars[NEIGH_VAR_QUEUE_LEN].data = &p->queue_len_bytes; | ||
| 2972 | t->neigh_vars[NEIGH_VAR_QUEUE_LEN_BYTES].data = &p->queue_len_bytes; | ||
| 2973 | t->neigh_vars[NEIGH_VAR_PROXY_QLEN].data = &p->proxy_qlen; | ||
| 2974 | t->neigh_vars[NEIGH_VAR_ANYCAST_DELAY].data = &p->anycast_delay; | ||
| 2975 | t->neigh_vars[NEIGH_VAR_PROXY_DELAY].data = &p->proxy_delay; | ||
| 2976 | t->neigh_vars[NEIGH_VAR_LOCKTIME].data = &p->locktime; | ||
| 2977 | t->neigh_vars[NEIGH_VAR_RETRANS_TIME_MS].data = &p->retrans_time; | ||
| 2978 | t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME_MS].data = &p->base_reachable_time; | ||
| 2979 | 3054 | ||
| 2980 | if (dev) { | 3055 | if (dev) { |
| 2981 | dev_name_source = dev->name; | 3056 | dev_name_source = dev->name; |
| @@ -2990,26 +3065,32 @@ int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p, | |||
| 2990 | t->neigh_vars[NEIGH_VAR_GC_THRESH3].data = (int *)(p + 1) + 3; | 3065 | t->neigh_vars[NEIGH_VAR_GC_THRESH3].data = (int *)(p + 1) + 3; |
| 2991 | } | 3066 | } |
| 2992 | 3067 | ||
| 2993 | |||
| 2994 | if (handler) { | 3068 | if (handler) { |
| 2995 | /* RetransTime */ | 3069 | /* RetransTime */ |
| 2996 | t->neigh_vars[NEIGH_VAR_RETRANS_TIME].proc_handler = handler; | 3070 | t->neigh_vars[NEIGH_VAR_RETRANS_TIME].proc_handler = handler; |
| 2997 | t->neigh_vars[NEIGH_VAR_RETRANS_TIME].extra1 = dev; | ||
| 2998 | /* ReachableTime */ | 3071 | /* ReachableTime */ |
| 2999 | t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME].proc_handler = handler; | 3072 | t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME].proc_handler = handler; |
| 3000 | t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME].extra1 = dev; | ||
| 3001 | /* RetransTime (in milliseconds)*/ | 3073 | /* RetransTime (in milliseconds)*/ |
| 3002 | t->neigh_vars[NEIGH_VAR_RETRANS_TIME_MS].proc_handler = handler; | 3074 | t->neigh_vars[NEIGH_VAR_RETRANS_TIME_MS].proc_handler = handler; |
| 3003 | t->neigh_vars[NEIGH_VAR_RETRANS_TIME_MS].extra1 = dev; | ||
| 3004 | /* ReachableTime (in milliseconds) */ | 3075 | /* ReachableTime (in milliseconds) */ |
| 3005 | t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME_MS].proc_handler = handler; | 3076 | t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME_MS].proc_handler = handler; |
| 3006 | t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME_MS].extra1 = dev; | ||
| 3007 | } | 3077 | } |
| 3008 | 3078 | ||
| 3009 | /* Don't export sysctls to unprivileged users */ | 3079 | /* Don't export sysctls to unprivileged users */ |
| 3010 | if (neigh_parms_net(p)->user_ns != &init_user_ns) | 3080 | if (neigh_parms_net(p)->user_ns != &init_user_ns) |
| 3011 | t->neigh_vars[0].procname = NULL; | 3081 | t->neigh_vars[0].procname = NULL; |
| 3012 | 3082 | ||
| 3083 | switch (neigh_parms_family(p)) { | ||
| 3084 | case AF_INET: | ||
| 3085 | p_name = "ipv4"; | ||
| 3086 | break; | ||
| 3087 | case AF_INET6: | ||
| 3088 | p_name = "ipv6"; | ||
| 3089 | break; | ||
| 3090 | default: | ||
| 3091 | BUG(); | ||
| 3092 | } | ||
| 3093 | |||
| 3013 | snprintf(neigh_path, sizeof(neigh_path), "net/%s/neigh/%s", | 3094 | snprintf(neigh_path, sizeof(neigh_path), "net/%s/neigh/%s", |
| 3014 | p_name, dev_name_source); | 3095 | p_name, dev_name_source); |
| 3015 | t->sysctl_header = | 3096 | t->sysctl_header = |
diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index f3edf9635e02..93886246a0b4 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c | |||
| @@ -498,17 +498,7 @@ static struct attribute_group wireless_group = { | |||
| 498 | #define net_class_groups NULL | 498 | #define net_class_groups NULL |
| 499 | #endif /* CONFIG_SYSFS */ | 499 | #endif /* CONFIG_SYSFS */ |
| 500 | 500 | ||
| 501 | #ifdef CONFIG_RPS | 501 | #ifdef CONFIG_SYSFS |
| 502 | /* | ||
| 503 | * RX queue sysfs structures and functions. | ||
| 504 | */ | ||
| 505 | struct rx_queue_attribute { | ||
| 506 | struct attribute attr; | ||
| 507 | ssize_t (*show)(struct netdev_rx_queue *queue, | ||
| 508 | struct rx_queue_attribute *attr, char *buf); | ||
| 509 | ssize_t (*store)(struct netdev_rx_queue *queue, | ||
| 510 | struct rx_queue_attribute *attr, const char *buf, size_t len); | ||
| 511 | }; | ||
| 512 | #define to_rx_queue_attr(_attr) container_of(_attr, \ | 502 | #define to_rx_queue_attr(_attr) container_of(_attr, \ |
| 513 | struct rx_queue_attribute, attr) | 503 | struct rx_queue_attribute, attr) |
| 514 | 504 | ||
| @@ -543,6 +533,7 @@ static const struct sysfs_ops rx_queue_sysfs_ops = { | |||
| 543 | .store = rx_queue_attr_store, | 533 | .store = rx_queue_attr_store, |
| 544 | }; | 534 | }; |
| 545 | 535 | ||
| 536 | #ifdef CONFIG_RPS | ||
| 546 | static ssize_t show_rps_map(struct netdev_rx_queue *queue, | 537 | static ssize_t show_rps_map(struct netdev_rx_queue *queue, |
| 547 | struct rx_queue_attribute *attribute, char *buf) | 538 | struct rx_queue_attribute *attribute, char *buf) |
| 548 | { | 539 | { |
| @@ -676,8 +667,8 @@ static ssize_t store_rps_dev_flow_table_cnt(struct netdev_rx_queue *queue, | |||
| 676 | while ((mask | (mask >> 1)) != mask) | 667 | while ((mask | (mask >> 1)) != mask) |
| 677 | mask |= (mask >> 1); | 668 | mask |= (mask >> 1); |
| 678 | /* On 64 bit arches, must check mask fits in table->mask (u32), | 669 | /* On 64 bit arches, must check mask fits in table->mask (u32), |
| 679 | * and on 32bit arches, must check RPS_DEV_FLOW_TABLE_SIZE(mask + 1) | 670 | * and on 32bit arches, must check |
| 680 | * doesnt overflow. | 671 | * RPS_DEV_FLOW_TABLE_SIZE(mask + 1) doesn't overflow. |
| 681 | */ | 672 | */ |
| 682 | #if BITS_PER_LONG > 32 | 673 | #if BITS_PER_LONG > 32 |
| 683 | if (mask > (unsigned long)(u32)mask) | 674 | if (mask > (unsigned long)(u32)mask) |
| @@ -718,16 +709,20 @@ static struct rx_queue_attribute rps_cpus_attribute = | |||
| 718 | static struct rx_queue_attribute rps_dev_flow_table_cnt_attribute = | 709 | static struct rx_queue_attribute rps_dev_flow_table_cnt_attribute = |
| 719 | __ATTR(rps_flow_cnt, S_IRUGO | S_IWUSR, | 710 | __ATTR(rps_flow_cnt, S_IRUGO | S_IWUSR, |
| 720 | show_rps_dev_flow_table_cnt, store_rps_dev_flow_table_cnt); | 711 | show_rps_dev_flow_table_cnt, store_rps_dev_flow_table_cnt); |
| 712 | #endif /* CONFIG_RPS */ | ||
| 721 | 713 | ||
| 722 | static struct attribute *rx_queue_default_attrs[] = { | 714 | static struct attribute *rx_queue_default_attrs[] = { |
| 715 | #ifdef CONFIG_RPS | ||
| 723 | &rps_cpus_attribute.attr, | 716 | &rps_cpus_attribute.attr, |
| 724 | &rps_dev_flow_table_cnt_attribute.attr, | 717 | &rps_dev_flow_table_cnt_attribute.attr, |
| 718 | #endif | ||
| 725 | NULL | 719 | NULL |
| 726 | }; | 720 | }; |
| 727 | 721 | ||
| 728 | static void rx_queue_release(struct kobject *kobj) | 722 | static void rx_queue_release(struct kobject *kobj) |
| 729 | { | 723 | { |
| 730 | struct netdev_rx_queue *queue = to_rx_queue(kobj); | 724 | struct netdev_rx_queue *queue = to_rx_queue(kobj); |
| 725 | #ifdef CONFIG_RPS | ||
| 731 | struct rps_map *map; | 726 | struct rps_map *map; |
| 732 | struct rps_dev_flow_table *flow_table; | 727 | struct rps_dev_flow_table *flow_table; |
| 733 | 728 | ||
| @@ -743,15 +738,29 @@ static void rx_queue_release(struct kobject *kobj) | |||
| 743 | RCU_INIT_POINTER(queue->rps_flow_table, NULL); | 738 | RCU_INIT_POINTER(queue->rps_flow_table, NULL); |
| 744 | call_rcu(&flow_table->rcu, rps_dev_flow_table_release); | 739 | call_rcu(&flow_table->rcu, rps_dev_flow_table_release); |
| 745 | } | 740 | } |
| 741 | #endif | ||
| 746 | 742 | ||
| 747 | memset(kobj, 0, sizeof(*kobj)); | 743 | memset(kobj, 0, sizeof(*kobj)); |
| 748 | dev_put(queue->dev); | 744 | dev_put(queue->dev); |
| 749 | } | 745 | } |
| 750 | 746 | ||
| 747 | static const void *rx_queue_namespace(struct kobject *kobj) | ||
| 748 | { | ||
| 749 | struct netdev_rx_queue *queue = to_rx_queue(kobj); | ||
| 750 | struct device *dev = &queue->dev->dev; | ||
| 751 | const void *ns = NULL; | ||
| 752 | |||
| 753 | if (dev->class && dev->class->ns_type) | ||
| 754 | ns = dev->class->namespace(dev); | ||
| 755 | |||
| 756 | return ns; | ||
| 757 | } | ||
| 758 | |||
| 751 | static struct kobj_type rx_queue_ktype = { | 759 | static struct kobj_type rx_queue_ktype = { |
| 752 | .sysfs_ops = &rx_queue_sysfs_ops, | 760 | .sysfs_ops = &rx_queue_sysfs_ops, |
| 753 | .release = rx_queue_release, | 761 | .release = rx_queue_release, |
| 754 | .default_attrs = rx_queue_default_attrs, | 762 | .default_attrs = rx_queue_default_attrs, |
| 763 | .namespace = rx_queue_namespace | ||
| 755 | }; | 764 | }; |
| 756 | 765 | ||
| 757 | static int rx_queue_add_kobject(struct net_device *net, int index) | 766 | static int rx_queue_add_kobject(struct net_device *net, int index) |
| @@ -763,25 +772,36 @@ static int rx_queue_add_kobject(struct net_device *net, int index) | |||
| 763 | kobj->kset = net->queues_kset; | 772 | kobj->kset = net->queues_kset; |
| 764 | error = kobject_init_and_add(kobj, &rx_queue_ktype, NULL, | 773 | error = kobject_init_and_add(kobj, &rx_queue_ktype, NULL, |
| 765 | "rx-%u", index); | 774 | "rx-%u", index); |
| 766 | if (error) { | 775 | if (error) |
| 767 | kobject_put(kobj); | 776 | goto exit; |
| 768 | return error; | 777 | |
| 778 | if (net->sysfs_rx_queue_group) { | ||
| 779 | error = sysfs_create_group(kobj, net->sysfs_rx_queue_group); | ||
| 780 | if (error) | ||
| 781 | goto exit; | ||
| 769 | } | 782 | } |
| 770 | 783 | ||
| 771 | kobject_uevent(kobj, KOBJ_ADD); | 784 | kobject_uevent(kobj, KOBJ_ADD); |
| 772 | dev_hold(queue->dev); | 785 | dev_hold(queue->dev); |
| 773 | 786 | ||
| 774 | return error; | 787 | return error; |
| 788 | exit: | ||
| 789 | kobject_put(kobj); | ||
| 790 | return error; | ||
| 775 | } | 791 | } |
| 776 | #endif /* CONFIG_RPS */ | 792 | #endif /* CONFIG_SYFS */ |
| 777 | 793 | ||
| 778 | int | 794 | int |
| 779 | net_rx_queue_update_kobjects(struct net_device *net, int old_num, int new_num) | 795 | net_rx_queue_update_kobjects(struct net_device *net, int old_num, int new_num) |
| 780 | { | 796 | { |
| 781 | #ifdef CONFIG_RPS | 797 | #ifdef CONFIG_SYSFS |
| 782 | int i; | 798 | int i; |
| 783 | int error = 0; | 799 | int error = 0; |
| 784 | 800 | ||
| 801 | #ifndef CONFIG_RPS | ||
| 802 | if (!net->sysfs_rx_queue_group) | ||
| 803 | return 0; | ||
| 804 | #endif | ||
| 785 | for (i = old_num; i < new_num; i++) { | 805 | for (i = old_num; i < new_num; i++) { |
| 786 | error = rx_queue_add_kobject(net, i); | 806 | error = rx_queue_add_kobject(net, i); |
| 787 | if (error) { | 807 | if (error) { |
| @@ -790,8 +810,12 @@ net_rx_queue_update_kobjects(struct net_device *net, int old_num, int new_num) | |||
| 790 | } | 810 | } |
| 791 | } | 811 | } |
| 792 | 812 | ||
| 793 | while (--i >= new_num) | 813 | while (--i >= new_num) { |
| 814 | if (net->sysfs_rx_queue_group) | ||
| 815 | sysfs_remove_group(&net->_rx[i].kobj, | ||
| 816 | net->sysfs_rx_queue_group); | ||
| 794 | kobject_put(&net->_rx[i].kobj); | 817 | kobject_put(&net->_rx[i].kobj); |
| 818 | } | ||
| 795 | 819 | ||
| 796 | return error; | 820 | return error; |
| 797 | #else | 821 | #else |
| @@ -1082,10 +1106,23 @@ static void netdev_queue_release(struct kobject *kobj) | |||
| 1082 | dev_put(queue->dev); | 1106 | dev_put(queue->dev); |
| 1083 | } | 1107 | } |
| 1084 | 1108 | ||
| 1109 | static const void *netdev_queue_namespace(struct kobject *kobj) | ||
| 1110 | { | ||
| 1111 | struct netdev_queue *queue = to_netdev_queue(kobj); | ||
| 1112 | struct device *dev = &queue->dev->dev; | ||
| 1113 | const void *ns = NULL; | ||
| 1114 | |||
| 1115 | if (dev->class && dev->class->ns_type) | ||
| 1116 | ns = dev->class->namespace(dev); | ||
| 1117 | |||
| 1118 | return ns; | ||
| 1119 | } | ||
| 1120 | |||
| 1085 | static struct kobj_type netdev_queue_ktype = { | 1121 | static struct kobj_type netdev_queue_ktype = { |
| 1086 | .sysfs_ops = &netdev_queue_sysfs_ops, | 1122 | .sysfs_ops = &netdev_queue_sysfs_ops, |
| 1087 | .release = netdev_queue_release, | 1123 | .release = netdev_queue_release, |
| 1088 | .default_attrs = netdev_queue_default_attrs, | 1124 | .default_attrs = netdev_queue_default_attrs, |
| 1125 | .namespace = netdev_queue_namespace, | ||
| 1089 | }; | 1126 | }; |
| 1090 | 1127 | ||
| 1091 | static int netdev_queue_add_kobject(struct net_device *net, int index) | 1128 | static int netdev_queue_add_kobject(struct net_device *net, int index) |
| @@ -1155,9 +1192,6 @@ static int register_queue_kobjects(struct net_device *net) | |||
| 1155 | NULL, &net->dev.kobj); | 1192 | NULL, &net->dev.kobj); |
| 1156 | if (!net->queues_kset) | 1193 | if (!net->queues_kset) |
| 1157 | return -ENOMEM; | 1194 | return -ENOMEM; |
| 1158 | #endif | ||
| 1159 | |||
| 1160 | #ifdef CONFIG_RPS | ||
| 1161 | real_rx = net->real_num_rx_queues; | 1195 | real_rx = net->real_num_rx_queues; |
| 1162 | #endif | 1196 | #endif |
| 1163 | real_tx = net->real_num_tx_queues; | 1197 | real_tx = net->real_num_tx_queues; |
| @@ -1184,7 +1218,7 @@ static void remove_queue_kobjects(struct net_device *net) | |||
| 1184 | { | 1218 | { |
| 1185 | int real_rx = 0, real_tx = 0; | 1219 | int real_rx = 0, real_tx = 0; |
| 1186 | 1220 | ||
| 1187 | #ifdef CONFIG_RPS | 1221 | #ifdef CONFIG_SYSFS |
| 1188 | real_rx = net->real_num_rx_queues; | 1222 | real_rx = net->real_num_rx_queues; |
| 1189 | #endif | 1223 | #endif |
| 1190 | real_tx = net->real_num_tx_queues; | 1224 | real_tx = net->real_num_tx_queues; |
| @@ -1358,7 +1392,7 @@ void netdev_class_remove_file_ns(struct class_attribute *class_attr, | |||
| 1358 | } | 1392 | } |
| 1359 | EXPORT_SYMBOL(netdev_class_remove_file_ns); | 1393 | EXPORT_SYMBOL(netdev_class_remove_file_ns); |
| 1360 | 1394 | ||
| 1361 | int netdev_kobject_init(void) | 1395 | int __init netdev_kobject_init(void) |
| 1362 | { | 1396 | { |
| 1363 | kobj_ns_type_register(&net_ns_type_operations); | 1397 | kobj_ns_type_register(&net_ns_type_operations); |
| 1364 | return class_register(&net_class); | 1398 | return class_register(&net_class); |
diff --git a/net/core/net-sysfs.h b/net/core/net-sysfs.h index bd7751ec1c4d..2745a1b51e03 100644 --- a/net/core/net-sysfs.h +++ b/net/core/net-sysfs.h | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | #ifndef __NET_SYSFS_H__ | 1 | #ifndef __NET_SYSFS_H__ |
| 2 | #define __NET_SYSFS_H__ | 2 | #define __NET_SYSFS_H__ |
| 3 | 3 | ||
| 4 | int netdev_kobject_init(void); | 4 | int __init netdev_kobject_init(void); |
| 5 | int netdev_register_kobject(struct net_device *); | 5 | int netdev_register_kobject(struct net_device *); |
| 6 | void netdev_unregister_kobject(struct net_device *); | 6 | void netdev_unregister_kobject(struct net_device *); |
| 7 | int net_rx_queue_update_kobjects(struct net_device *, int old_num, int new_num); | 7 | int net_rx_queue_update_kobjects(struct net_device *, int old_num, int new_num); |
diff --git a/net/core/netclassid_cgroup.c b/net/core/netclassid_cgroup.c new file mode 100644 index 000000000000..719efd541668 --- /dev/null +++ b/net/core/netclassid_cgroup.c | |||
| @@ -0,0 +1,120 @@ | |||
| 1 | /* | ||
| 2 | * net/core/netclassid_cgroup.c Classid Cgroupfs Handling | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or | ||
| 5 | * modify it under the terms of the GNU General Public License | ||
| 6 | * as published by the Free Software Foundation; either version | ||
| 7 | * 2 of the License, or (at your option) any later version. | ||
| 8 | * | ||
| 9 | * Authors: Thomas Graf <tgraf@suug.ch> | ||
| 10 | */ | ||
| 11 | |||
| 12 | #include <linux/module.h> | ||
| 13 | #include <linux/slab.h> | ||
| 14 | #include <linux/cgroup.h> | ||
| 15 | #include <linux/fdtable.h> | ||
| 16 | #include <net/cls_cgroup.h> | ||
| 17 | #include <net/sock.h> | ||
| 18 | |||
| 19 | static inline struct cgroup_cls_state *css_cls_state(struct cgroup_subsys_state *css) | ||
| 20 | { | ||
| 21 | return css ? container_of(css, struct cgroup_cls_state, css) : NULL; | ||
| 22 | } | ||
| 23 | |||
| 24 | struct cgroup_cls_state *task_cls_state(struct task_struct *p) | ||
| 25 | { | ||
| 26 | return css_cls_state(task_css(p, net_cls_subsys_id)); | ||
| 27 | } | ||
| 28 | EXPORT_SYMBOL_GPL(task_cls_state); | ||
| 29 | |||
| 30 | static struct cgroup_subsys_state * | ||
| 31 | cgrp_css_alloc(struct cgroup_subsys_state *parent_css) | ||
| 32 | { | ||
| 33 | struct cgroup_cls_state *cs; | ||
| 34 | |||
| 35 | cs = kzalloc(sizeof(*cs), GFP_KERNEL); | ||
| 36 | if (!cs) | ||
| 37 | return ERR_PTR(-ENOMEM); | ||
| 38 | |||
| 39 | return &cs->css; | ||
| 40 | } | ||
| 41 | |||
| 42 | static int cgrp_css_online(struct cgroup_subsys_state *css) | ||
| 43 | { | ||
| 44 | struct cgroup_cls_state *cs = css_cls_state(css); | ||
| 45 | struct cgroup_cls_state *parent = css_cls_state(css_parent(css)); | ||
| 46 | |||
| 47 | if (parent) | ||
| 48 | cs->classid = parent->classid; | ||
| 49 | |||
| 50 | return 0; | ||
| 51 | } | ||
| 52 | |||
| 53 | static void cgrp_css_free(struct cgroup_subsys_state *css) | ||
| 54 | { | ||
| 55 | kfree(css_cls_state(css)); | ||
| 56 | } | ||
| 57 | |||
| 58 | static int update_classid(const void *v, struct file *file, unsigned n) | ||
| 59 | { | ||
| 60 | int err; | ||
| 61 | struct socket *sock = sock_from_file(file, &err); | ||
| 62 | |||
| 63 | if (sock) | ||
| 64 | sock->sk->sk_classid = (u32)(unsigned long)v; | ||
| 65 | |||
| 66 | return 0; | ||
| 67 | } | ||
| 68 | |||
| 69 | static void cgrp_attach(struct cgroup_subsys_state *css, | ||
| 70 | struct cgroup_taskset *tset) | ||
| 71 | { | ||
| 72 | struct cgroup_cls_state *cs = css_cls_state(css); | ||
| 73 | void *v = (void *)(unsigned long)cs->classid; | ||
| 74 | struct task_struct *p; | ||
| 75 | |||
| 76 | cgroup_taskset_for_each(p, css, tset) { | ||
| 77 | task_lock(p); | ||
| 78 | iterate_fd(p->files, 0, update_classid, v); | ||
| 79 | task_unlock(p); | ||
| 80 | } | ||
| 81 | } | ||
| 82 | |||
| 83 | static u64 read_classid(struct cgroup_subsys_state *css, struct cftype *cft) | ||
| 84 | { | ||
| 85 | return css_cls_state(css)->classid; | ||
| 86 | } | ||
| 87 | |||
| 88 | static int write_classid(struct cgroup_subsys_state *css, struct cftype *cft, | ||
| 89 | u64 value) | ||
| 90 | { | ||
| 91 | css_cls_state(css)->classid = (u32) value; | ||
| 92 | |||
| 93 | return 0; | ||
| 94 | } | ||
| 95 | |||
| 96 | static struct cftype ss_files[] = { | ||
| 97 | { | ||
| 98 | .name = "classid", | ||
| 99 | .read_u64 = read_classid, | ||
| 100 | .write_u64 = write_classid, | ||
| 101 | }, | ||
| 102 | { } /* terminate */ | ||
| 103 | }; | ||
| 104 | |||
| 105 | struct cgroup_subsys net_cls_subsys = { | ||
| 106 | .name = "net_cls", | ||
| 107 | .css_alloc = cgrp_css_alloc, | ||
| 108 | .css_online = cgrp_css_online, | ||
| 109 | .css_free = cgrp_css_free, | ||
| 110 | .attach = cgrp_attach, | ||
| 111 | .subsys_id = net_cls_subsys_id, | ||
| 112 | .base_cftypes = ss_files, | ||
| 113 | .module = THIS_MODULE, | ||
| 114 | }; | ||
| 115 | |||
| 116 | static int __init init_netclassid_cgroup(void) | ||
| 117 | { | ||
| 118 | return cgroup_load_subsys(&net_cls_subsys); | ||
| 119 | } | ||
| 120 | __initcall(init_netclassid_cgroup); | ||
diff --git a/net/core/netpoll.c b/net/core/netpoll.c index 19fe9c717ced..c03f3dec4763 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c | |||
| @@ -520,8 +520,8 @@ void netpoll_send_udp(struct netpoll *np, const char *msg, int len) | |||
| 520 | skb->protocol = eth->h_proto = htons(ETH_P_IP); | 520 | skb->protocol = eth->h_proto = htons(ETH_P_IP); |
| 521 | } | 521 | } |
| 522 | 522 | ||
| 523 | memcpy(eth->h_source, np->dev->dev_addr, ETH_ALEN); | 523 | ether_addr_copy(eth->h_source, np->dev->dev_addr); |
| 524 | memcpy(eth->h_dest, np->remote_mac, ETH_ALEN); | 524 | ether_addr_copy(eth->h_dest, np->remote_mac); |
| 525 | 525 | ||
| 526 | skb->dev = np->dev; | 526 | skb->dev = np->dev; |
| 527 | 527 | ||
diff --git a/net/core/netprio_cgroup.c b/net/core/netprio_cgroup.c index 9b7cf6c85f82..9043caedcd08 100644 --- a/net/core/netprio_cgroup.c +++ b/net/core/netprio_cgroup.c | |||
| @@ -30,7 +30,7 @@ | |||
| 30 | #define PRIOMAP_MIN_SZ 128 | 30 | #define PRIOMAP_MIN_SZ 128 |
| 31 | 31 | ||
| 32 | /* | 32 | /* |
| 33 | * Extend @dev->priomap so that it's large enough to accomodate | 33 | * Extend @dev->priomap so that it's large enough to accommodate |
| 34 | * @target_idx. @dev->priomap.priomap_len > @target_idx after successful | 34 | * @target_idx. @dev->priomap.priomap_len > @target_idx after successful |
| 35 | * return. Must be called under rtnl lock. | 35 | * return. Must be called under rtnl lock. |
| 36 | */ | 36 | */ |
| @@ -173,14 +173,14 @@ static u64 read_prioidx(struct cgroup_subsys_state *css, struct cftype *cft) | |||
| 173 | return css->cgroup->id; | 173 | return css->cgroup->id; |
| 174 | } | 174 | } |
| 175 | 175 | ||
| 176 | static int read_priomap(struct cgroup_subsys_state *css, struct cftype *cft, | 176 | static int read_priomap(struct seq_file *sf, void *v) |
| 177 | struct cgroup_map_cb *cb) | ||
| 178 | { | 177 | { |
| 179 | struct net_device *dev; | 178 | struct net_device *dev; |
| 180 | 179 | ||
| 181 | rcu_read_lock(); | 180 | rcu_read_lock(); |
| 182 | for_each_netdev_rcu(&init_net, dev) | 181 | for_each_netdev_rcu(&init_net, dev) |
| 183 | cb->fill(cb, dev->name, netprio_prio(css, dev)); | 182 | seq_printf(sf, "%s %u\n", dev->name, |
| 183 | netprio_prio(seq_css(sf), dev)); | ||
| 184 | rcu_read_unlock(); | 184 | rcu_read_unlock(); |
| 185 | return 0; | 185 | return 0; |
| 186 | } | 186 | } |
| @@ -238,7 +238,7 @@ static struct cftype ss_files[] = { | |||
| 238 | }, | 238 | }, |
| 239 | { | 239 | { |
| 240 | .name = "ifpriomap", | 240 | .name = "ifpriomap", |
| 241 | .read_map = read_priomap, | 241 | .seq_show = read_priomap, |
| 242 | .write_string = write_priomap, | 242 | .write_string = write_priomap, |
| 243 | }, | 243 | }, |
| 244 | { } /* terminate */ | 244 | { } /* terminate */ |
diff --git a/net/core/pktgen.c b/net/core/pktgen.c index a797fff7f222..fdac61cac1bd 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c | |||
| @@ -389,6 +389,9 @@ struct pktgen_dev { | |||
| 389 | #ifdef CONFIG_XFRM | 389 | #ifdef CONFIG_XFRM |
| 390 | __u8 ipsmode; /* IPSEC mode (config) */ | 390 | __u8 ipsmode; /* IPSEC mode (config) */ |
| 391 | __u8 ipsproto; /* IPSEC type (config) */ | 391 | __u8 ipsproto; /* IPSEC type (config) */ |
| 392 | __u32 spi; | ||
| 393 | struct dst_entry dst; | ||
| 394 | struct dst_ops dstops; | ||
| 392 | #endif | 395 | #endif |
| 393 | char result[512]; | 396 | char result[512]; |
| 394 | }; | 397 | }; |
| @@ -654,8 +657,11 @@ static int pktgen_if_show(struct seq_file *seq, void *v) | |||
| 654 | } | 657 | } |
| 655 | 658 | ||
| 656 | #ifdef CONFIG_XFRM | 659 | #ifdef CONFIG_XFRM |
| 657 | if (pkt_dev->flags & F_IPSEC_ON) | 660 | if (pkt_dev->flags & F_IPSEC_ON) { |
| 658 | seq_printf(seq, "IPSEC "); | 661 | seq_printf(seq, "IPSEC "); |
| 662 | if (pkt_dev->spi) | ||
| 663 | seq_printf(seq, "spi:%u", pkt_dev->spi); | ||
| 664 | } | ||
| 659 | #endif | 665 | #endif |
| 660 | 666 | ||
| 661 | if (pkt_dev->flags & F_MACSRC_RND) | 667 | if (pkt_dev->flags & F_MACSRC_RND) |
| @@ -1434,7 +1440,7 @@ static ssize_t pktgen_if_write(struct file *file, | |||
| 1434 | if (!mac_pton(valstr, pkt_dev->dst_mac)) | 1440 | if (!mac_pton(valstr, pkt_dev->dst_mac)) |
| 1435 | return -EINVAL; | 1441 | return -EINVAL; |
| 1436 | /* Set up Dest MAC */ | 1442 | /* Set up Dest MAC */ |
| 1437 | memcpy(&pkt_dev->hh[0], pkt_dev->dst_mac, ETH_ALEN); | 1443 | ether_addr_copy(&pkt_dev->hh[0], pkt_dev->dst_mac); |
| 1438 | 1444 | ||
| 1439 | sprintf(pg_result, "OK: dstmac %pM", pkt_dev->dst_mac); | 1445 | sprintf(pg_result, "OK: dstmac %pM", pkt_dev->dst_mac); |
| 1440 | return count; | 1446 | return count; |
| @@ -1451,7 +1457,7 @@ static ssize_t pktgen_if_write(struct file *file, | |||
| 1451 | if (!mac_pton(valstr, pkt_dev->src_mac)) | 1457 | if (!mac_pton(valstr, pkt_dev->src_mac)) |
| 1452 | return -EINVAL; | 1458 | return -EINVAL; |
| 1453 | /* Set up Src MAC */ | 1459 | /* Set up Src MAC */ |
| 1454 | memcpy(&pkt_dev->hh[6], pkt_dev->src_mac, ETH_ALEN); | 1460 | ether_addr_copy(&pkt_dev->hh[6], pkt_dev->src_mac); |
| 1455 | 1461 | ||
| 1456 | sprintf(pg_result, "OK: srcmac %pM", pkt_dev->src_mac); | 1462 | sprintf(pg_result, "OK: srcmac %pM", pkt_dev->src_mac); |
| 1457 | return count; | 1463 | return count; |
| @@ -1476,7 +1482,18 @@ static ssize_t pktgen_if_write(struct file *file, | |||
| 1476 | sprintf(pg_result, "OK: flows=%u", pkt_dev->cflows); | 1482 | sprintf(pg_result, "OK: flows=%u", pkt_dev->cflows); |
| 1477 | return count; | 1483 | return count; |
| 1478 | } | 1484 | } |
| 1485 | #ifdef CONFIG_XFRM | ||
| 1486 | if (!strcmp(name, "spi")) { | ||
| 1487 | len = num_arg(&user_buffer[i], 10, &value); | ||
| 1488 | if (len < 0) | ||
| 1489 | return len; | ||
| 1479 | 1490 | ||
| 1491 | i += len; | ||
| 1492 | pkt_dev->spi = value; | ||
| 1493 | sprintf(pg_result, "OK: spi=%u", pkt_dev->spi); | ||
| 1494 | return count; | ||
| 1495 | } | ||
| 1496 | #endif | ||
| 1480 | if (!strcmp(name, "flowlen")) { | 1497 | if (!strcmp(name, "flowlen")) { |
| 1481 | len = num_arg(&user_buffer[i], 10, &value); | 1498 | len = num_arg(&user_buffer[i], 10, &value); |
| 1482 | if (len < 0) | 1499 | if (len < 0) |
| @@ -2043,10 +2060,10 @@ static void pktgen_setup_inject(struct pktgen_dev *pkt_dev) | |||
| 2043 | /* Default to the interface's mac if not explicitly set. */ | 2060 | /* Default to the interface's mac if not explicitly set. */ |
| 2044 | 2061 | ||
| 2045 | if (is_zero_ether_addr(pkt_dev->src_mac)) | 2062 | if (is_zero_ether_addr(pkt_dev->src_mac)) |
| 2046 | memcpy(&(pkt_dev->hh[6]), pkt_dev->odev->dev_addr, ETH_ALEN); | 2063 | ether_addr_copy(&(pkt_dev->hh[6]), pkt_dev->odev->dev_addr); |
| 2047 | 2064 | ||
| 2048 | /* Set up Dest MAC */ | 2065 | /* Set up Dest MAC */ |
| 2049 | memcpy(&(pkt_dev->hh[0]), pkt_dev->dst_mac, ETH_ALEN); | 2066 | ether_addr_copy(&(pkt_dev->hh[0]), pkt_dev->dst_mac); |
| 2050 | 2067 | ||
| 2051 | if (pkt_dev->flags & F_IPV6) { | 2068 | if (pkt_dev->flags & F_IPV6) { |
| 2052 | int i, set = 0, err = 1; | 2069 | int i, set = 0, err = 1; |
| @@ -2233,13 +2250,21 @@ static void get_ipsec_sa(struct pktgen_dev *pkt_dev, int flow) | |||
| 2233 | struct xfrm_state *x = pkt_dev->flows[flow].x; | 2250 | struct xfrm_state *x = pkt_dev->flows[flow].x; |
| 2234 | struct pktgen_net *pn = net_generic(dev_net(pkt_dev->odev), pg_net_id); | 2251 | struct pktgen_net *pn = net_generic(dev_net(pkt_dev->odev), pg_net_id); |
| 2235 | if (!x) { | 2252 | if (!x) { |
| 2236 | /*slow path: we dont already have xfrm_state*/ | 2253 | |
| 2237 | x = xfrm_stateonly_find(pn->net, DUMMY_MARK, | 2254 | if (pkt_dev->spi) { |
| 2238 | (xfrm_address_t *)&pkt_dev->cur_daddr, | 2255 | /* We need as quick as possible to find the right SA |
| 2239 | (xfrm_address_t *)&pkt_dev->cur_saddr, | 2256 | * Searching with minimum criteria to archieve this. |
| 2240 | AF_INET, | 2257 | */ |
| 2241 | pkt_dev->ipsmode, | 2258 | x = xfrm_state_lookup_byspi(pn->net, htonl(pkt_dev->spi), AF_INET); |
| 2242 | pkt_dev->ipsproto, 0); | 2259 | } else { |
| 2260 | /* slow path: we dont already have xfrm_state */ | ||
| 2261 | x = xfrm_stateonly_find(pn->net, DUMMY_MARK, | ||
| 2262 | (xfrm_address_t *)&pkt_dev->cur_daddr, | ||
| 2263 | (xfrm_address_t *)&pkt_dev->cur_saddr, | ||
| 2264 | AF_INET, | ||
| 2265 | pkt_dev->ipsmode, | ||
| 2266 | pkt_dev->ipsproto, 0); | ||
| 2267 | } | ||
| 2243 | if (x) { | 2268 | if (x) { |
| 2244 | pkt_dev->flows[flow].x = x; | 2269 | pkt_dev->flows[flow].x = x; |
| 2245 | set_pkt_overhead(pkt_dev); | 2270 | set_pkt_overhead(pkt_dev); |
| @@ -2475,31 +2500,47 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev) | |||
| 2475 | 2500 | ||
| 2476 | 2501 | ||
| 2477 | #ifdef CONFIG_XFRM | 2502 | #ifdef CONFIG_XFRM |
| 2503 | static u32 pktgen_dst_metrics[RTAX_MAX + 1] = { | ||
| 2504 | |||
| 2505 | [RTAX_HOPLIMIT] = 0x5, /* Set a static hoplimit */ | ||
| 2506 | }; | ||
| 2507 | |||
| 2478 | static int pktgen_output_ipsec(struct sk_buff *skb, struct pktgen_dev *pkt_dev) | 2508 | static int pktgen_output_ipsec(struct sk_buff *skb, struct pktgen_dev *pkt_dev) |
| 2479 | { | 2509 | { |
| 2480 | struct xfrm_state *x = pkt_dev->flows[pkt_dev->curfl].x; | 2510 | struct xfrm_state *x = pkt_dev->flows[pkt_dev->curfl].x; |
| 2481 | int err = 0; | 2511 | int err = 0; |
| 2512 | struct net *net = dev_net(pkt_dev->odev); | ||
| 2482 | 2513 | ||
| 2483 | if (!x) | 2514 | if (!x) |
| 2484 | return 0; | 2515 | return 0; |
| 2485 | /* XXX: we dont support tunnel mode for now until | 2516 | /* XXX: we dont support tunnel mode for now until |
| 2486 | * we resolve the dst issue */ | 2517 | * we resolve the dst issue */ |
| 2487 | if (x->props.mode != XFRM_MODE_TRANSPORT) | 2518 | if ((x->props.mode != XFRM_MODE_TRANSPORT) && (pkt_dev->spi == 0)) |
| 2488 | return 0; | 2519 | return 0; |
| 2489 | 2520 | ||
| 2490 | spin_lock(&x->lock); | 2521 | /* But when user specify an valid SPI, transformation |
| 2522 | * supports both transport/tunnel mode + ESP/AH type. | ||
| 2523 | */ | ||
| 2524 | if ((x->props.mode == XFRM_MODE_TUNNEL) && (pkt_dev->spi != 0)) | ||
| 2525 | skb->_skb_refdst = (unsigned long)&pkt_dev->dst | SKB_DST_NOREF; | ||
| 2491 | 2526 | ||
| 2527 | rcu_read_lock_bh(); | ||
| 2492 | err = x->outer_mode->output(x, skb); | 2528 | err = x->outer_mode->output(x, skb); |
| 2493 | if (err) | 2529 | rcu_read_unlock_bh(); |
| 2530 | if (err) { | ||
| 2531 | XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTSTATEMODEERROR); | ||
| 2494 | goto error; | 2532 | goto error; |
| 2533 | } | ||
| 2495 | err = x->type->output(x, skb); | 2534 | err = x->type->output(x, skb); |
| 2496 | if (err) | 2535 | if (err) { |
| 2536 | XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTSTATEPROTOERROR); | ||
| 2497 | goto error; | 2537 | goto error; |
| 2498 | 2538 | } | |
| 2539 | spin_lock_bh(&x->lock); | ||
| 2499 | x->curlft.bytes += skb->len; | 2540 | x->curlft.bytes += skb->len; |
| 2500 | x->curlft.packets++; | 2541 | x->curlft.packets++; |
| 2542 | spin_unlock_bh(&x->lock); | ||
| 2501 | error: | 2543 | error: |
| 2502 | spin_unlock(&x->lock); | ||
| 2503 | return err; | 2544 | return err; |
| 2504 | } | 2545 | } |
| 2505 | 2546 | ||
| @@ -3542,6 +3583,17 @@ static int pktgen_add_device(struct pktgen_thread *t, const char *ifname) | |||
| 3542 | #ifdef CONFIG_XFRM | 3583 | #ifdef CONFIG_XFRM |
| 3543 | pkt_dev->ipsmode = XFRM_MODE_TRANSPORT; | 3584 | pkt_dev->ipsmode = XFRM_MODE_TRANSPORT; |
| 3544 | pkt_dev->ipsproto = IPPROTO_ESP; | 3585 | pkt_dev->ipsproto = IPPROTO_ESP; |
| 3586 | |||
| 3587 | /* xfrm tunnel mode needs additional dst to extract outter | ||
| 3588 | * ip header protocol/ttl/id field, here creat a phony one. | ||
| 3589 | * instead of looking for a valid rt, which definitely hurting | ||
| 3590 | * performance under such circumstance. | ||
| 3591 | */ | ||
| 3592 | pkt_dev->dstops.family = AF_INET; | ||
| 3593 | pkt_dev->dst.dev = pkt_dev->odev; | ||
| 3594 | dst_init_metrics(&pkt_dev->dst, pktgen_dst_metrics, false); | ||
| 3595 | pkt_dev->dst.child = &pkt_dev->dst; | ||
| 3596 | pkt_dev->dst.ops = &pkt_dev->dstops; | ||
| 3545 | #endif | 3597 | #endif |
| 3546 | 3598 | ||
| 3547 | return add_dev_to_thread(t, pkt_dev); | 3599 | return add_dev_to_thread(t, pkt_dev); |
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index cf67144d3e3c..393b1bc9a618 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c | |||
| @@ -365,6 +365,22 @@ void rtnl_link_unregister(struct rtnl_link_ops *ops) | |||
| 365 | } | 365 | } |
| 366 | EXPORT_SYMBOL_GPL(rtnl_link_unregister); | 366 | EXPORT_SYMBOL_GPL(rtnl_link_unregister); |
| 367 | 367 | ||
| 368 | static size_t rtnl_link_get_slave_info_data_size(const struct net_device *dev) | ||
| 369 | { | ||
| 370 | struct net_device *master_dev; | ||
| 371 | const struct rtnl_link_ops *ops; | ||
| 372 | |||
| 373 | master_dev = netdev_master_upper_dev_get((struct net_device *) dev); | ||
| 374 | if (!master_dev) | ||
| 375 | return 0; | ||
| 376 | ops = master_dev->rtnl_link_ops; | ||
| 377 | if (!ops->get_slave_size) | ||
| 378 | return 0; | ||
| 379 | /* IFLA_INFO_SLAVE_DATA + nested data */ | ||
| 380 | return nla_total_size(sizeof(struct nlattr)) + | ||
| 381 | ops->get_slave_size(master_dev, dev); | ||
| 382 | } | ||
| 383 | |||
| 368 | static size_t rtnl_link_get_size(const struct net_device *dev) | 384 | static size_t rtnl_link_get_size(const struct net_device *dev) |
| 369 | { | 385 | { |
| 370 | const struct rtnl_link_ops *ops = dev->rtnl_link_ops; | 386 | const struct rtnl_link_ops *ops = dev->rtnl_link_ops; |
| @@ -385,6 +401,8 @@ static size_t rtnl_link_get_size(const struct net_device *dev) | |||
| 385 | /* IFLA_INFO_XSTATS */ | 401 | /* IFLA_INFO_XSTATS */ |
| 386 | size += nla_total_size(ops->get_xstats_size(dev)); | 402 | size += nla_total_size(ops->get_xstats_size(dev)); |
| 387 | 403 | ||
| 404 | size += rtnl_link_get_slave_info_data_size(dev); | ||
| 405 | |||
| 388 | return size; | 406 | return size; |
| 389 | } | 407 | } |
| 390 | 408 | ||
| @@ -403,34 +421,16 @@ static const struct rtnl_af_ops *rtnl_af_lookup(const int family) | |||
| 403 | } | 421 | } |
| 404 | 422 | ||
| 405 | /** | 423 | /** |
| 406 | * __rtnl_af_register - Register rtnl_af_ops with rtnetlink. | ||
| 407 | * @ops: struct rtnl_af_ops * to register | ||
| 408 | * | ||
| 409 | * The caller must hold the rtnl_mutex. | ||
| 410 | * | ||
| 411 | * Returns 0 on success or a negative error code. | ||
| 412 | */ | ||
| 413 | int __rtnl_af_register(struct rtnl_af_ops *ops) | ||
| 414 | { | ||
| 415 | list_add_tail(&ops->list, &rtnl_af_ops); | ||
| 416 | return 0; | ||
| 417 | } | ||
| 418 | EXPORT_SYMBOL_GPL(__rtnl_af_register); | ||
| 419 | |||
| 420 | /** | ||
| 421 | * rtnl_af_register - Register rtnl_af_ops with rtnetlink. | 424 | * rtnl_af_register - Register rtnl_af_ops with rtnetlink. |
| 422 | * @ops: struct rtnl_af_ops * to register | 425 | * @ops: struct rtnl_af_ops * to register |
| 423 | * | 426 | * |
| 424 | * Returns 0 on success or a negative error code. | 427 | * Returns 0 on success or a negative error code. |
| 425 | */ | 428 | */ |
| 426 | int rtnl_af_register(struct rtnl_af_ops *ops) | 429 | void rtnl_af_register(struct rtnl_af_ops *ops) |
| 427 | { | 430 | { |
| 428 | int err; | ||
| 429 | |||
| 430 | rtnl_lock(); | 431 | rtnl_lock(); |
| 431 | err = __rtnl_af_register(ops); | 432 | list_add_tail(&ops->list, &rtnl_af_ops); |
| 432 | rtnl_unlock(); | 433 | rtnl_unlock(); |
| 433 | return err; | ||
| 434 | } | 434 | } |
| 435 | EXPORT_SYMBOL_GPL(rtnl_af_register); | 435 | EXPORT_SYMBOL_GPL(rtnl_af_register); |
| 436 | 436 | ||
| @@ -477,40 +477,100 @@ static size_t rtnl_link_get_af_size(const struct net_device *dev) | |||
| 477 | return size; | 477 | return size; |
| 478 | } | 478 | } |
| 479 | 479 | ||
| 480 | static int rtnl_link_fill(struct sk_buff *skb, const struct net_device *dev) | 480 | static bool rtnl_have_link_slave_info(const struct net_device *dev) |
| 481 | { | 481 | { |
| 482 | const struct rtnl_link_ops *ops = dev->rtnl_link_ops; | 482 | struct net_device *master_dev; |
| 483 | struct nlattr *linkinfo, *data; | ||
| 484 | int err = -EMSGSIZE; | ||
| 485 | 483 | ||
| 486 | linkinfo = nla_nest_start(skb, IFLA_LINKINFO); | 484 | master_dev = netdev_master_upper_dev_get((struct net_device *) dev); |
| 487 | if (linkinfo == NULL) | 485 | if (master_dev && master_dev->rtnl_link_ops) |
| 488 | goto out; | 486 | return true; |
| 487 | return false; | ||
| 488 | } | ||
| 489 | |||
| 490 | static int rtnl_link_slave_info_fill(struct sk_buff *skb, | ||
| 491 | const struct net_device *dev) | ||
| 492 | { | ||
| 493 | struct net_device *master_dev; | ||
| 494 | const struct rtnl_link_ops *ops; | ||
| 495 | struct nlattr *slave_data; | ||
| 496 | int err; | ||
| 497 | |||
| 498 | master_dev = netdev_master_upper_dev_get((struct net_device *) dev); | ||
| 499 | if (!master_dev) | ||
| 500 | return 0; | ||
| 501 | ops = master_dev->rtnl_link_ops; | ||
| 502 | if (!ops) | ||
| 503 | return 0; | ||
| 504 | if (nla_put_string(skb, IFLA_INFO_SLAVE_KIND, ops->kind) < 0) | ||
| 505 | return -EMSGSIZE; | ||
| 506 | if (ops->fill_slave_info) { | ||
| 507 | slave_data = nla_nest_start(skb, IFLA_INFO_SLAVE_DATA); | ||
| 508 | if (!slave_data) | ||
| 509 | return -EMSGSIZE; | ||
| 510 | err = ops->fill_slave_info(skb, master_dev, dev); | ||
| 511 | if (err < 0) | ||
| 512 | goto err_cancel_slave_data; | ||
| 513 | nla_nest_end(skb, slave_data); | ||
| 514 | } | ||
| 515 | return 0; | ||
| 516 | |||
| 517 | err_cancel_slave_data: | ||
| 518 | nla_nest_cancel(skb, slave_data); | ||
| 519 | return err; | ||
| 520 | } | ||
| 521 | |||
| 522 | static int rtnl_link_info_fill(struct sk_buff *skb, | ||
| 523 | const struct net_device *dev) | ||
| 524 | { | ||
| 525 | const struct rtnl_link_ops *ops = dev->rtnl_link_ops; | ||
| 526 | struct nlattr *data; | ||
| 527 | int err; | ||
| 489 | 528 | ||
| 529 | if (!ops) | ||
| 530 | return 0; | ||
| 490 | if (nla_put_string(skb, IFLA_INFO_KIND, ops->kind) < 0) | 531 | if (nla_put_string(skb, IFLA_INFO_KIND, ops->kind) < 0) |
| 491 | goto err_cancel_link; | 532 | return -EMSGSIZE; |
| 492 | if (ops->fill_xstats) { | 533 | if (ops->fill_xstats) { |
| 493 | err = ops->fill_xstats(skb, dev); | 534 | err = ops->fill_xstats(skb, dev); |
| 494 | if (err < 0) | 535 | if (err < 0) |
| 495 | goto err_cancel_link; | 536 | return err; |
| 496 | } | 537 | } |
| 497 | if (ops->fill_info) { | 538 | if (ops->fill_info) { |
| 498 | data = nla_nest_start(skb, IFLA_INFO_DATA); | 539 | data = nla_nest_start(skb, IFLA_INFO_DATA); |
| 499 | if (data == NULL) { | 540 | if (data == NULL) |
| 500 | err = -EMSGSIZE; | 541 | return -EMSGSIZE; |
| 501 | goto err_cancel_link; | ||
| 502 | } | ||
| 503 | err = ops->fill_info(skb, dev); | 542 | err = ops->fill_info(skb, dev); |
| 504 | if (err < 0) | 543 | if (err < 0) |
| 505 | goto err_cancel_data; | 544 | goto err_cancel_data; |
| 506 | nla_nest_end(skb, data); | 545 | nla_nest_end(skb, data); |
| 507 | } | 546 | } |
| 508 | |||
| 509 | nla_nest_end(skb, linkinfo); | ||
| 510 | return 0; | 547 | return 0; |
| 511 | 548 | ||
| 512 | err_cancel_data: | 549 | err_cancel_data: |
| 513 | nla_nest_cancel(skb, data); | 550 | nla_nest_cancel(skb, data); |
| 551 | return err; | ||
| 552 | } | ||
| 553 | |||
| 554 | static int rtnl_link_fill(struct sk_buff *skb, const struct net_device *dev) | ||
| 555 | { | ||
| 556 | struct nlattr *linkinfo; | ||
| 557 | int err = -EMSGSIZE; | ||
| 558 | |||
| 559 | linkinfo = nla_nest_start(skb, IFLA_LINKINFO); | ||
| 560 | if (linkinfo == NULL) | ||
| 561 | goto out; | ||
| 562 | |||
| 563 | err = rtnl_link_info_fill(skb, dev); | ||
| 564 | if (err < 0) | ||
| 565 | goto err_cancel_link; | ||
| 566 | |||
| 567 | err = rtnl_link_slave_info_fill(skb, dev); | ||
| 568 | if (err < 0) | ||
| 569 | goto err_cancel_link; | ||
| 570 | |||
| 571 | nla_nest_end(skb, linkinfo); | ||
| 572 | return 0; | ||
| 573 | |||
| 514 | err_cancel_link: | 574 | err_cancel_link: |
| 515 | nla_nest_cancel(skb, linkinfo); | 575 | nla_nest_cancel(skb, linkinfo); |
| 516 | out: | 576 | out: |
| @@ -1019,7 +1079,7 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev, | |||
| 1019 | if (rtnl_port_fill(skb, dev)) | 1079 | if (rtnl_port_fill(skb, dev)) |
| 1020 | goto nla_put_failure; | 1080 | goto nla_put_failure; |
| 1021 | 1081 | ||
| 1022 | if (dev->rtnl_link_ops) { | 1082 | if (dev->rtnl_link_ops || rtnl_have_link_slave_info(dev)) { |
| 1023 | if (rtnl_link_fill(skb, dev) < 0) | 1083 | if (rtnl_link_fill(skb, dev) < 0) |
| 1024 | goto nla_put_failure; | 1084 | goto nla_put_failure; |
| 1025 | } | 1085 | } |
| @@ -1142,6 +1202,8 @@ EXPORT_SYMBOL(ifla_policy); | |||
| 1142 | static const struct nla_policy ifla_info_policy[IFLA_INFO_MAX+1] = { | 1202 | static const struct nla_policy ifla_info_policy[IFLA_INFO_MAX+1] = { |
| 1143 | [IFLA_INFO_KIND] = { .type = NLA_STRING }, | 1203 | [IFLA_INFO_KIND] = { .type = NLA_STRING }, |
| 1144 | [IFLA_INFO_DATA] = { .type = NLA_NESTED }, | 1204 | [IFLA_INFO_DATA] = { .type = NLA_NESTED }, |
| 1205 | [IFLA_INFO_SLAVE_KIND] = { .type = NLA_STRING }, | ||
| 1206 | [IFLA_INFO_SLAVE_DATA] = { .type = NLA_NESTED }, | ||
| 1145 | }; | 1207 | }; |
| 1146 | 1208 | ||
| 1147 | static const struct nla_policy ifla_vfinfo_policy[IFLA_VF_INFO_MAX+1] = { | 1209 | static const struct nla_policy ifla_vfinfo_policy[IFLA_VF_INFO_MAX+1] = { |
| @@ -1729,7 +1791,9 @@ static int rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
| 1729 | { | 1791 | { |
| 1730 | struct net *net = sock_net(skb->sk); | 1792 | struct net *net = sock_net(skb->sk); |
| 1731 | const struct rtnl_link_ops *ops; | 1793 | const struct rtnl_link_ops *ops; |
| 1794 | const struct rtnl_link_ops *m_ops = NULL; | ||
| 1732 | struct net_device *dev; | 1795 | struct net_device *dev; |
| 1796 | struct net_device *master_dev = NULL; | ||
| 1733 | struct ifinfomsg *ifm; | 1797 | struct ifinfomsg *ifm; |
| 1734 | char kind[MODULE_NAME_LEN]; | 1798 | char kind[MODULE_NAME_LEN]; |
| 1735 | char ifname[IFNAMSIZ]; | 1799 | char ifname[IFNAMSIZ]; |
| @@ -1759,6 +1823,12 @@ replay: | |||
| 1759 | dev = NULL; | 1823 | dev = NULL; |
| 1760 | } | 1824 | } |
| 1761 | 1825 | ||
| 1826 | if (dev) { | ||
| 1827 | master_dev = netdev_master_upper_dev_get(dev); | ||
| 1828 | if (master_dev) | ||
| 1829 | m_ops = master_dev->rtnl_link_ops; | ||
| 1830 | } | ||
| 1831 | |||
| 1762 | err = validate_linkmsg(dev, tb); | 1832 | err = validate_linkmsg(dev, tb); |
| 1763 | if (err < 0) | 1833 | if (err < 0) |
| 1764 | return err; | 1834 | return err; |
| @@ -1780,7 +1850,10 @@ replay: | |||
| 1780 | } | 1850 | } |
| 1781 | 1851 | ||
| 1782 | if (1) { | 1852 | if (1) { |
| 1783 | struct nlattr *attr[ops ? ops->maxtype + 1 : 0], **data = NULL; | 1853 | struct nlattr *attr[ops ? ops->maxtype + 1 : 0]; |
| 1854 | struct nlattr *slave_attr[m_ops ? m_ops->slave_maxtype + 1 : 0]; | ||
| 1855 | struct nlattr **data = NULL; | ||
| 1856 | struct nlattr **slave_data = NULL; | ||
| 1784 | struct net *dest_net; | 1857 | struct net *dest_net; |
| 1785 | 1858 | ||
| 1786 | if (ops) { | 1859 | if (ops) { |
| @@ -1799,6 +1872,24 @@ replay: | |||
| 1799 | } | 1872 | } |
| 1800 | } | 1873 | } |
| 1801 | 1874 | ||
| 1875 | if (m_ops) { | ||
| 1876 | if (m_ops->slave_maxtype && | ||
| 1877 | linkinfo[IFLA_INFO_SLAVE_DATA]) { | ||
| 1878 | err = nla_parse_nested(slave_attr, | ||
| 1879 | m_ops->slave_maxtype, | ||
| 1880 | linkinfo[IFLA_INFO_SLAVE_DATA], | ||
| 1881 | m_ops->slave_policy); | ||
| 1882 | if (err < 0) | ||
| 1883 | return err; | ||
| 1884 | slave_data = slave_attr; | ||
| 1885 | } | ||
| 1886 | if (m_ops->slave_validate) { | ||
| 1887 | err = m_ops->slave_validate(tb, slave_data); | ||
| 1888 | if (err < 0) | ||
| 1889 | return err; | ||
| 1890 | } | ||
| 1891 | } | ||
| 1892 | |||
| 1802 | if (dev) { | 1893 | if (dev) { |
| 1803 | int modified = 0; | 1894 | int modified = 0; |
| 1804 | 1895 | ||
| @@ -1818,6 +1909,17 @@ replay: | |||
| 1818 | modified = 1; | 1909 | modified = 1; |
| 1819 | } | 1910 | } |
| 1820 | 1911 | ||
| 1912 | if (linkinfo[IFLA_INFO_SLAVE_DATA]) { | ||
| 1913 | if (!m_ops || !m_ops->slave_changelink) | ||
| 1914 | return -EOPNOTSUPP; | ||
| 1915 | |||
| 1916 | err = m_ops->slave_changelink(master_dev, dev, | ||
| 1917 | tb, slave_data); | ||
| 1918 | if (err < 0) | ||
| 1919 | return err; | ||
| 1920 | modified = 1; | ||
| 1921 | } | ||
| 1922 | |||
| 1821 | return do_setlink(dev, ifm, tb, ifname, modified); | 1923 | return do_setlink(dev, ifm, tb, ifname, modified); |
| 1822 | } | 1924 | } |
| 1823 | 1925 | ||
diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 06e72d3cdf60..5976ef0846bd 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c | |||
| @@ -47,6 +47,8 @@ | |||
| 47 | #include <linux/in.h> | 47 | #include <linux/in.h> |
| 48 | #include <linux/inet.h> | 48 | #include <linux/inet.h> |
| 49 | #include <linux/slab.h> | 49 | #include <linux/slab.h> |
| 50 | #include <linux/tcp.h> | ||
| 51 | #include <linux/udp.h> | ||
| 50 | #include <linux/netdevice.h> | 52 | #include <linux/netdevice.h> |
| 51 | #ifdef CONFIG_NET_CLS_ACT | 53 | #ifdef CONFIG_NET_CLS_ACT |
| 52 | #include <net/pkt_sched.h> | 54 | #include <net/pkt_sched.h> |
| @@ -65,6 +67,7 @@ | |||
| 65 | #include <net/dst.h> | 67 | #include <net/dst.h> |
| 66 | #include <net/sock.h> | 68 | #include <net/sock.h> |
| 67 | #include <net/checksum.h> | 69 | #include <net/checksum.h> |
| 70 | #include <net/ip6_checksum.h> | ||
| 68 | #include <net/xfrm.h> | 71 | #include <net/xfrm.h> |
| 69 | 72 | ||
| 70 | #include <asm/uaccess.h> | 73 | #include <asm/uaccess.h> |
| @@ -74,36 +77,6 @@ | |||
| 74 | struct kmem_cache *skbuff_head_cache __read_mostly; | 77 | struct kmem_cache *skbuff_head_cache __read_mostly; |
| 75 | static struct kmem_cache *skbuff_fclone_cache __read_mostly; | 78 | static struct kmem_cache *skbuff_fclone_cache __read_mostly; |
| 76 | 79 | ||
| 77 | static void sock_pipe_buf_release(struct pipe_inode_info *pipe, | ||
| 78 | struct pipe_buffer *buf) | ||
| 79 | { | ||
| 80 | put_page(buf->page); | ||
| 81 | } | ||
| 82 | |||
| 83 | static void sock_pipe_buf_get(struct pipe_inode_info *pipe, | ||
| 84 | struct pipe_buffer *buf) | ||
| 85 | { | ||
| 86 | get_page(buf->page); | ||
| 87 | } | ||
| 88 | |||
| 89 | static int sock_pipe_buf_steal(struct pipe_inode_info *pipe, | ||
| 90 | struct pipe_buffer *buf) | ||
| 91 | { | ||
| 92 | return 1; | ||
| 93 | } | ||
| 94 | |||
| 95 | |||
| 96 | /* Pipe buffer operations for a socket. */ | ||
| 97 | static const struct pipe_buf_operations sock_pipe_buf_ops = { | ||
| 98 | .can_merge = 0, | ||
| 99 | .map = generic_pipe_buf_map, | ||
| 100 | .unmap = generic_pipe_buf_unmap, | ||
| 101 | .confirm = generic_pipe_buf_confirm, | ||
| 102 | .release = sock_pipe_buf_release, | ||
| 103 | .steal = sock_pipe_buf_steal, | ||
| 104 | .get = sock_pipe_buf_get, | ||
| 105 | }; | ||
| 106 | |||
| 107 | /** | 80 | /** |
| 108 | * skb_panic - private function for out-of-line support | 81 | * skb_panic - private function for out-of-line support |
| 109 | * @skb: buffer | 82 | * @skb: buffer |
| @@ -712,9 +685,8 @@ static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old) | |||
| 712 | new->inner_network_header = old->inner_network_header; | 685 | new->inner_network_header = old->inner_network_header; |
| 713 | new->inner_mac_header = old->inner_mac_header; | 686 | new->inner_mac_header = old->inner_mac_header; |
| 714 | skb_dst_copy(new, old); | 687 | skb_dst_copy(new, old); |
| 715 | new->rxhash = old->rxhash; | 688 | skb_copy_hash(new, old); |
| 716 | new->ooo_okay = old->ooo_okay; | 689 | new->ooo_okay = old->ooo_okay; |
| 717 | new->l4_rxhash = old->l4_rxhash; | ||
| 718 | new->no_fcs = old->no_fcs; | 690 | new->no_fcs = old->no_fcs; |
| 719 | new->encapsulation = old->encapsulation; | 691 | new->encapsulation = old->encapsulation; |
| 720 | #ifdef CONFIG_XFRM | 692 | #ifdef CONFIG_XFRM |
| @@ -1830,7 +1802,7 @@ int skb_splice_bits(struct sk_buff *skb, unsigned int offset, | |||
| 1830 | .partial = partial, | 1802 | .partial = partial, |
| 1831 | .nr_pages_max = MAX_SKB_FRAGS, | 1803 | .nr_pages_max = MAX_SKB_FRAGS, |
| 1832 | .flags = flags, | 1804 | .flags = flags, |
| 1833 | .ops = &sock_pipe_buf_ops, | 1805 | .ops = &nosteal_pipe_buf_ops, |
| 1834 | .spd_release = sock_spd_release, | 1806 | .spd_release = sock_spd_release, |
| 1835 | }; | 1807 | }; |
| 1836 | struct sk_buff *frag_iter; | 1808 | struct sk_buff *frag_iter; |
| @@ -2122,6 +2094,91 @@ __wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset, | |||
| 2122 | } | 2094 | } |
| 2123 | EXPORT_SYMBOL(skb_copy_and_csum_bits); | 2095 | EXPORT_SYMBOL(skb_copy_and_csum_bits); |
| 2124 | 2096 | ||
| 2097 | /** | ||
| 2098 | * skb_zerocopy_headlen - Calculate headroom needed for skb_zerocopy() | ||
| 2099 | * @from: source buffer | ||
| 2100 | * | ||
| 2101 | * Calculates the amount of linear headroom needed in the 'to' skb passed | ||
| 2102 | * into skb_zerocopy(). | ||
| 2103 | */ | ||
| 2104 | unsigned int | ||
| 2105 | skb_zerocopy_headlen(const struct sk_buff *from) | ||
| 2106 | { | ||
| 2107 | unsigned int hlen = 0; | ||
| 2108 | |||
| 2109 | if (!from->head_frag || | ||
| 2110 | skb_headlen(from) < L1_CACHE_BYTES || | ||
| 2111 | skb_shinfo(from)->nr_frags >= MAX_SKB_FRAGS) | ||
| 2112 | hlen = skb_headlen(from); | ||
| 2113 | |||
| 2114 | if (skb_has_frag_list(from)) | ||
| 2115 | hlen = from->len; | ||
| 2116 | |||
| 2117 | return hlen; | ||
| 2118 | } | ||
| 2119 | EXPORT_SYMBOL_GPL(skb_zerocopy_headlen); | ||
| 2120 | |||
| 2121 | /** | ||
| 2122 | * skb_zerocopy - Zero copy skb to skb | ||
| 2123 | * @to: destination buffer | ||
| 2124 | * @from: source buffer | ||
| 2125 | * @len: number of bytes to copy from source buffer | ||
| 2126 | * @hlen: size of linear headroom in destination buffer | ||
| 2127 | * | ||
| 2128 | * Copies up to `len` bytes from `from` to `to` by creating references | ||
| 2129 | * to the frags in the source buffer. | ||
| 2130 | * | ||
| 2131 | * The `hlen` as calculated by skb_zerocopy_headlen() specifies the | ||
| 2132 | * headroom in the `to` buffer. | ||
| 2133 | */ | ||
| 2134 | void | ||
| 2135 | skb_zerocopy(struct sk_buff *to, const struct sk_buff *from, int len, int hlen) | ||
| 2136 | { | ||
| 2137 | int i, j = 0; | ||
| 2138 | int plen = 0; /* length of skb->head fragment */ | ||
| 2139 | struct page *page; | ||
| 2140 | unsigned int offset; | ||
| 2141 | |||
| 2142 | BUG_ON(!from->head_frag && !hlen); | ||
| 2143 | |||
| 2144 | /* dont bother with small payloads */ | ||
| 2145 | if (len <= skb_tailroom(to)) { | ||
| 2146 | skb_copy_bits(from, 0, skb_put(to, len), len); | ||
| 2147 | return; | ||
| 2148 | } | ||
| 2149 | |||
| 2150 | if (hlen) { | ||
| 2151 | skb_copy_bits(from, 0, skb_put(to, hlen), hlen); | ||
| 2152 | len -= hlen; | ||
| 2153 | } else { | ||
| 2154 | plen = min_t(int, skb_headlen(from), len); | ||
| 2155 | if (plen) { | ||
| 2156 | page = virt_to_head_page(from->head); | ||
| 2157 | offset = from->data - (unsigned char *)page_address(page); | ||
| 2158 | __skb_fill_page_desc(to, 0, page, offset, plen); | ||
| 2159 | get_page(page); | ||
| 2160 | j = 1; | ||
| 2161 | len -= plen; | ||
| 2162 | } | ||
| 2163 | } | ||
| 2164 | |||
| 2165 | to->truesize += len + plen; | ||
| 2166 | to->len += len + plen; | ||
| 2167 | to->data_len += len + plen; | ||
| 2168 | |||
| 2169 | for (i = 0; i < skb_shinfo(from)->nr_frags; i++) { | ||
| 2170 | if (!len) | ||
| 2171 | break; | ||
| 2172 | skb_shinfo(to)->frags[j] = skb_shinfo(from)->frags[i]; | ||
| 2173 | skb_shinfo(to)->frags[j].size = min_t(int, skb_shinfo(to)->frags[j].size, len); | ||
| 2174 | len -= skb_shinfo(to)->frags[j].size; | ||
| 2175 | skb_frag_ref(to, j); | ||
| 2176 | j++; | ||
| 2177 | } | ||
| 2178 | skb_shinfo(to)->nr_frags = j; | ||
| 2179 | } | ||
| 2180 | EXPORT_SYMBOL_GPL(skb_zerocopy); | ||
| 2181 | |||
| 2125 | void skb_copy_and_csum_dev(const struct sk_buff *skb, u8 *to) | 2182 | void skb_copy_and_csum_dev(const struct sk_buff *skb, u8 *to) |
| 2126 | { | 2183 | { |
| 2127 | __wsum csum; | 2184 | __wsum csum; |
| @@ -2982,10 +3039,7 @@ perform_csum_check: | |||
| 2982 | return segs; | 3039 | return segs; |
| 2983 | 3040 | ||
| 2984 | err: | 3041 | err: |
| 2985 | while ((skb = segs)) { | 3042 | kfree_skb_list(segs); |
| 2986 | segs = skb->next; | ||
| 2987 | kfree_skb(skb); | ||
| 2988 | } | ||
| 2989 | return ERR_PTR(err); | 3043 | return ERR_PTR(err); |
| 2990 | } | 3044 | } |
| 2991 | EXPORT_SYMBOL_GPL(skb_segment); | 3045 | EXPORT_SYMBOL_GPL(skb_segment); |
| @@ -3468,6 +3522,278 @@ bool skb_partial_csum_set(struct sk_buff *skb, u16 start, u16 off) | |||
| 3468 | } | 3522 | } |
| 3469 | EXPORT_SYMBOL_GPL(skb_partial_csum_set); | 3523 | EXPORT_SYMBOL_GPL(skb_partial_csum_set); |
| 3470 | 3524 | ||
| 3525 | static int skb_maybe_pull_tail(struct sk_buff *skb, unsigned int len, | ||
| 3526 | unsigned int max) | ||
| 3527 | { | ||
| 3528 | if (skb_headlen(skb) >= len) | ||
| 3529 | return 0; | ||
| 3530 | |||
| 3531 | /* If we need to pullup then pullup to the max, so we | ||
| 3532 | * won't need to do it again. | ||
| 3533 | */ | ||
| 3534 | if (max > skb->len) | ||
| 3535 | max = skb->len; | ||
| 3536 | |||
| 3537 | if (__pskb_pull_tail(skb, max - skb_headlen(skb)) == NULL) | ||
| 3538 | return -ENOMEM; | ||
| 3539 | |||
| 3540 | if (skb_headlen(skb) < len) | ||
| 3541 | return -EPROTO; | ||
| 3542 | |||
| 3543 | return 0; | ||
| 3544 | } | ||
| 3545 | |||
| 3546 | /* This value should be large enough to cover a tagged ethernet header plus | ||
| 3547 | * maximally sized IP and TCP or UDP headers. | ||
| 3548 | */ | ||
| 3549 | #define MAX_IP_HDR_LEN 128 | ||
| 3550 | |||
| 3551 | static int skb_checksum_setup_ip(struct sk_buff *skb, bool recalculate) | ||
| 3552 | { | ||
| 3553 | unsigned int off; | ||
| 3554 | bool fragment; | ||
| 3555 | int err; | ||
| 3556 | |||
| 3557 | fragment = false; | ||
| 3558 | |||
| 3559 | err = skb_maybe_pull_tail(skb, | ||
| 3560 | sizeof(struct iphdr), | ||
| 3561 | MAX_IP_HDR_LEN); | ||
| 3562 | if (err < 0) | ||
| 3563 | goto out; | ||
| 3564 | |||
| 3565 | if (ip_hdr(skb)->frag_off & htons(IP_OFFSET | IP_MF)) | ||
| 3566 | fragment = true; | ||
| 3567 | |||
| 3568 | off = ip_hdrlen(skb); | ||
| 3569 | |||
| 3570 | err = -EPROTO; | ||
| 3571 | |||
| 3572 | if (fragment) | ||
| 3573 | goto out; | ||
| 3574 | |||
| 3575 | switch (ip_hdr(skb)->protocol) { | ||
| 3576 | case IPPROTO_TCP: | ||
| 3577 | err = skb_maybe_pull_tail(skb, | ||
| 3578 | off + sizeof(struct tcphdr), | ||
| 3579 | MAX_IP_HDR_LEN); | ||
| 3580 | if (err < 0) | ||
| 3581 | goto out; | ||
| 3582 | |||
| 3583 | if (!skb_partial_csum_set(skb, off, | ||
| 3584 | offsetof(struct tcphdr, check))) { | ||
| 3585 | err = -EPROTO; | ||
| 3586 | goto out; | ||
| 3587 | } | ||
| 3588 | |||
| 3589 | if (recalculate) | ||
| 3590 | tcp_hdr(skb)->check = | ||
| 3591 | ~csum_tcpudp_magic(ip_hdr(skb)->saddr, | ||
| 3592 | ip_hdr(skb)->daddr, | ||
| 3593 | skb->len - off, | ||
| 3594 | IPPROTO_TCP, 0); | ||
| 3595 | break; | ||
| 3596 | case IPPROTO_UDP: | ||
| 3597 | err = skb_maybe_pull_tail(skb, | ||
| 3598 | off + sizeof(struct udphdr), | ||
| 3599 | MAX_IP_HDR_LEN); | ||
| 3600 | if (err < 0) | ||
| 3601 | goto out; | ||
| 3602 | |||
| 3603 | if (!skb_partial_csum_set(skb, off, | ||
| 3604 | offsetof(struct udphdr, check))) { | ||
| 3605 | err = -EPROTO; | ||
| 3606 | goto out; | ||
| 3607 | } | ||
| 3608 | |||
| 3609 | if (recalculate) | ||
| 3610 | udp_hdr(skb)->check = | ||
| 3611 | ~csum_tcpudp_magic(ip_hdr(skb)->saddr, | ||
| 3612 | ip_hdr(skb)->daddr, | ||
| 3613 | skb->len - off, | ||
| 3614 | IPPROTO_UDP, 0); | ||
| 3615 | break; | ||
| 3616 | default: | ||
| 3617 | goto out; | ||
| 3618 | } | ||
| 3619 | |||
| 3620 | err = 0; | ||
| 3621 | |||
| 3622 | out: | ||
| 3623 | return err; | ||
| 3624 | } | ||
| 3625 | |||
| 3626 | /* This value should be large enough to cover a tagged ethernet header plus | ||
| 3627 | * an IPv6 header, all options, and a maximal TCP or UDP header. | ||
| 3628 | */ | ||
| 3629 | #define MAX_IPV6_HDR_LEN 256 | ||
| 3630 | |||
| 3631 | #define OPT_HDR(type, skb, off) \ | ||
| 3632 | (type *)(skb_network_header(skb) + (off)) | ||
| 3633 | |||
| 3634 | static int skb_checksum_setup_ipv6(struct sk_buff *skb, bool recalculate) | ||
| 3635 | { | ||
| 3636 | int err; | ||
| 3637 | u8 nexthdr; | ||
| 3638 | unsigned int off; | ||
| 3639 | unsigned int len; | ||
| 3640 | bool fragment; | ||
| 3641 | bool done; | ||
| 3642 | |||
| 3643 | fragment = false; | ||
| 3644 | done = false; | ||
| 3645 | |||
| 3646 | off = sizeof(struct ipv6hdr); | ||
| 3647 | |||
| 3648 | err = skb_maybe_pull_tail(skb, off, MAX_IPV6_HDR_LEN); | ||
| 3649 | if (err < 0) | ||
| 3650 | goto out; | ||
| 3651 | |||
| 3652 | nexthdr = ipv6_hdr(skb)->nexthdr; | ||
| 3653 | |||
| 3654 | len = sizeof(struct ipv6hdr) + ntohs(ipv6_hdr(skb)->payload_len); | ||
| 3655 | while (off <= len && !done) { | ||
| 3656 | switch (nexthdr) { | ||
| 3657 | case IPPROTO_DSTOPTS: | ||
| 3658 | case IPPROTO_HOPOPTS: | ||
| 3659 | case IPPROTO_ROUTING: { | ||
| 3660 | struct ipv6_opt_hdr *hp; | ||
| 3661 | |||
| 3662 | err = skb_maybe_pull_tail(skb, | ||
| 3663 | off + | ||
| 3664 | sizeof(struct ipv6_opt_hdr), | ||
| 3665 | MAX_IPV6_HDR_LEN); | ||
| 3666 | if (err < 0) | ||
| 3667 | goto out; | ||
| 3668 | |||
| 3669 | hp = OPT_HDR(struct ipv6_opt_hdr, skb, off); | ||
| 3670 | nexthdr = hp->nexthdr; | ||
| 3671 | off += ipv6_optlen(hp); | ||
| 3672 | break; | ||
| 3673 | } | ||
| 3674 | case IPPROTO_AH: { | ||
| 3675 | struct ip_auth_hdr *hp; | ||
| 3676 | |||
| 3677 | err = skb_maybe_pull_tail(skb, | ||
| 3678 | off + | ||
| 3679 | sizeof(struct ip_auth_hdr), | ||
| 3680 | MAX_IPV6_HDR_LEN); | ||
| 3681 | if (err < 0) | ||
| 3682 | goto out; | ||
| 3683 | |||
| 3684 | hp = OPT_HDR(struct ip_auth_hdr, skb, off); | ||
| 3685 | nexthdr = hp->nexthdr; | ||
| 3686 | off += ipv6_authlen(hp); | ||
| 3687 | break; | ||
| 3688 | } | ||
| 3689 | case IPPROTO_FRAGMENT: { | ||
| 3690 | struct frag_hdr *hp; | ||
| 3691 | |||
| 3692 | err = skb_maybe_pull_tail(skb, | ||
| 3693 | off + | ||
| 3694 | sizeof(struct frag_hdr), | ||
| 3695 | MAX_IPV6_HDR_LEN); | ||
| 3696 | if (err < 0) | ||
| 3697 | goto out; | ||
| 3698 | |||
| 3699 | hp = OPT_HDR(struct frag_hdr, skb, off); | ||
| 3700 | |||
| 3701 | if (hp->frag_off & htons(IP6_OFFSET | IP6_MF)) | ||
| 3702 | fragment = true; | ||
| 3703 | |||
| 3704 | nexthdr = hp->nexthdr; | ||
| 3705 | off += sizeof(struct frag_hdr); | ||
| 3706 | break; | ||
| 3707 | } | ||
| 3708 | default: | ||
| 3709 | done = true; | ||
| 3710 | break; | ||
| 3711 | } | ||
| 3712 | } | ||
| 3713 | |||
| 3714 | err = -EPROTO; | ||
| 3715 | |||
| 3716 | if (!done || fragment) | ||
| 3717 | goto out; | ||
| 3718 | |||
| 3719 | switch (nexthdr) { | ||
| 3720 | case IPPROTO_TCP: | ||
| 3721 | err = skb_maybe_pull_tail(skb, | ||
| 3722 | off + sizeof(struct tcphdr), | ||
| 3723 | MAX_IPV6_HDR_LEN); | ||
| 3724 | if (err < 0) | ||
| 3725 | goto out; | ||
| 3726 | |||
| 3727 | if (!skb_partial_csum_set(skb, off, | ||
| 3728 | offsetof(struct tcphdr, check))) { | ||
| 3729 | err = -EPROTO; | ||
| 3730 | goto out; | ||
| 3731 | } | ||
| 3732 | |||
| 3733 | if (recalculate) | ||
| 3734 | tcp_hdr(skb)->check = | ||
| 3735 | ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr, | ||
| 3736 | &ipv6_hdr(skb)->daddr, | ||
| 3737 | skb->len - off, | ||
| 3738 | IPPROTO_TCP, 0); | ||
| 3739 | break; | ||
| 3740 | case IPPROTO_UDP: | ||
| 3741 | err = skb_maybe_pull_tail(skb, | ||
| 3742 | off + sizeof(struct udphdr), | ||
| 3743 | MAX_IPV6_HDR_LEN); | ||
| 3744 | if (err < 0) | ||
| 3745 | goto out; | ||
| 3746 | |||
| 3747 | if (!skb_partial_csum_set(skb, off, | ||
| 3748 | offsetof(struct udphdr, check))) { | ||
| 3749 | err = -EPROTO; | ||
| 3750 | goto out; | ||
| 3751 | } | ||
| 3752 | |||
| 3753 | if (recalculate) | ||
| 3754 | udp_hdr(skb)->check = | ||
| 3755 | ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr, | ||
| 3756 | &ipv6_hdr(skb)->daddr, | ||
| 3757 | skb->len - off, | ||
| 3758 | IPPROTO_UDP, 0); | ||
| 3759 | break; | ||
| 3760 | default: | ||
| 3761 | goto out; | ||
| 3762 | } | ||
| 3763 | |||
| 3764 | err = 0; | ||
| 3765 | |||
| 3766 | out: | ||
| 3767 | return err; | ||
| 3768 | } | ||
| 3769 | |||
| 3770 | /** | ||
| 3771 | * skb_checksum_setup - set up partial checksum offset | ||
| 3772 | * @skb: the skb to set up | ||
| 3773 | * @recalculate: if true the pseudo-header checksum will be recalculated | ||
| 3774 | */ | ||
| 3775 | int skb_checksum_setup(struct sk_buff *skb, bool recalculate) | ||
| 3776 | { | ||
| 3777 | int err; | ||
| 3778 | |||
| 3779 | switch (skb->protocol) { | ||
| 3780 | case htons(ETH_P_IP): | ||
| 3781 | err = skb_checksum_setup_ip(skb, recalculate); | ||
| 3782 | break; | ||
| 3783 | |||
| 3784 | case htons(ETH_P_IPV6): | ||
| 3785 | err = skb_checksum_setup_ipv6(skb, recalculate); | ||
| 3786 | break; | ||
| 3787 | |||
| 3788 | default: | ||
| 3789 | err = -EPROTO; | ||
| 3790 | break; | ||
| 3791 | } | ||
| 3792 | |||
| 3793 | return err; | ||
| 3794 | } | ||
| 3795 | EXPORT_SYMBOL(skb_checksum_setup); | ||
| 3796 | |||
| 3471 | void __skb_warn_lro_forwarding(const struct sk_buff *skb) | 3797 | void __skb_warn_lro_forwarding(const struct sk_buff *skb) |
| 3472 | { | 3798 | { |
| 3473 | net_warn_ratelimited("%s: received packets cannot be forwarded while LRO is enabled\n", | 3799 | net_warn_ratelimited("%s: received packets cannot be forwarded while LRO is enabled\n", |
| @@ -3592,3 +3918,26 @@ void skb_scrub_packet(struct sk_buff *skb, bool xnet) | |||
| 3592 | nf_reset_trace(skb); | 3918 | nf_reset_trace(skb); |
| 3593 | } | 3919 | } |
| 3594 | EXPORT_SYMBOL_GPL(skb_scrub_packet); | 3920 | EXPORT_SYMBOL_GPL(skb_scrub_packet); |
| 3921 | |||
| 3922 | /** | ||
| 3923 | * skb_gso_transport_seglen - Return length of individual segments of a gso packet | ||
| 3924 | * | ||
| 3925 | * @skb: GSO skb | ||
| 3926 | * | ||
| 3927 | * skb_gso_transport_seglen is used to determine the real size of the | ||
| 3928 | * individual segments, including Layer4 headers (TCP/UDP). | ||
| 3929 | * | ||
| 3930 | * The MAC/L2 or network (IP, IPv6) headers are not accounted for. | ||
| 3931 | */ | ||
| 3932 | unsigned int skb_gso_transport_seglen(const struct sk_buff *skb) | ||
| 3933 | { | ||
| 3934 | const struct skb_shared_info *shinfo = skb_shinfo(skb); | ||
| 3935 | unsigned int hdr_len; | ||
| 3936 | |||
| 3937 | if (likely(shinfo->gso_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6))) | ||
| 3938 | hdr_len = tcp_hdrlen(skb); | ||
| 3939 | else | ||
| 3940 | hdr_len = sizeof(struct udphdr); | ||
| 3941 | return hdr_len + shinfo->gso_size; | ||
| 3942 | } | ||
| 3943 | EXPORT_SYMBOL_GPL(skb_gso_transport_seglen); | ||
diff --git a/net/core/sock.c b/net/core/sock.c index 5393b4b719d7..0c127dcdf6a8 100644 --- a/net/core/sock.c +++ b/net/core/sock.c | |||
| @@ -925,8 +925,8 @@ set_rcvbuf: | |||
| 925 | EXPORT_SYMBOL(sock_setsockopt); | 925 | EXPORT_SYMBOL(sock_setsockopt); |
| 926 | 926 | ||
| 927 | 927 | ||
| 928 | void cred_to_ucred(struct pid *pid, const struct cred *cred, | 928 | static void cred_to_ucred(struct pid *pid, const struct cred *cred, |
| 929 | struct ucred *ucred) | 929 | struct ucred *ucred) |
| 930 | { | 930 | { |
| 931 | ucred->pid = pid_vnr(pid); | 931 | ucred->pid = pid_vnr(pid); |
| 932 | ucred->uid = ucred->gid = -1; | 932 | ucred->uid = ucred->gid = -1; |
| @@ -937,7 +937,6 @@ void cred_to_ucred(struct pid *pid, const struct cred *cred, | |||
| 937 | ucred->gid = from_kgid_munged(current_ns, cred->egid); | 937 | ucred->gid = from_kgid_munged(current_ns, cred->egid); |
| 938 | } | 938 | } |
| 939 | } | 939 | } |
| 940 | EXPORT_SYMBOL_GPL(cred_to_ucred); | ||
| 941 | 940 | ||
| 942 | int sock_getsockopt(struct socket *sock, int level, int optname, | 941 | int sock_getsockopt(struct socket *sock, int level, int optname, |
| 943 | char __user *optval, int __user *optlen) | 942 | char __user *optval, int __user *optlen) |
| @@ -1168,6 +1167,10 @@ int sock_getsockopt(struct socket *sock, int level, int optname, | |||
| 1168 | v.val = sock_flag(sk, SOCK_FILTER_LOCKED); | 1167 | v.val = sock_flag(sk, SOCK_FILTER_LOCKED); |
| 1169 | break; | 1168 | break; |
| 1170 | 1169 | ||
| 1170 | case SO_BPF_EXTENSIONS: | ||
| 1171 | v.val = bpf_tell_extensions(); | ||
| 1172 | break; | ||
| 1173 | |||
| 1171 | case SO_SELECT_ERR_QUEUE: | 1174 | case SO_SELECT_ERR_QUEUE: |
| 1172 | v.val = sock_flag(sk, SOCK_SELECT_ERR_QUEUE); | 1175 | v.val = sock_flag(sk, SOCK_SELECT_ERR_QUEUE); |
| 1173 | break; | 1176 | break; |
| @@ -1308,19 +1311,7 @@ static void sk_prot_free(struct proto *prot, struct sock *sk) | |||
| 1308 | module_put(owner); | 1311 | module_put(owner); |
| 1309 | } | 1312 | } |
| 1310 | 1313 | ||
| 1311 | #if IS_ENABLED(CONFIG_NET_CLS_CGROUP) | 1314 | #if IS_ENABLED(CONFIG_CGROUP_NET_PRIO) |
| 1312 | void sock_update_classid(struct sock *sk) | ||
| 1313 | { | ||
| 1314 | u32 classid; | ||
| 1315 | |||
| 1316 | classid = task_cls_classid(current); | ||
| 1317 | if (classid != sk->sk_classid) | ||
| 1318 | sk->sk_classid = classid; | ||
| 1319 | } | ||
| 1320 | EXPORT_SYMBOL(sock_update_classid); | ||
| 1321 | #endif | ||
| 1322 | |||
| 1323 | #if IS_ENABLED(CONFIG_NETPRIO_CGROUP) | ||
| 1324 | void sock_update_netprioidx(struct sock *sk) | 1315 | void sock_update_netprioidx(struct sock *sk) |
| 1325 | { | 1316 | { |
| 1326 | if (in_interrupt()) | 1317 | if (in_interrupt()) |
| @@ -1666,22 +1657,6 @@ struct sk_buff *sock_wmalloc(struct sock *sk, unsigned long size, int force, | |||
| 1666 | EXPORT_SYMBOL(sock_wmalloc); | 1657 | EXPORT_SYMBOL(sock_wmalloc); |
| 1667 | 1658 | ||
| 1668 | /* | 1659 | /* |
| 1669 | * Allocate a skb from the socket's receive buffer. | ||
| 1670 | */ | ||
| 1671 | struct sk_buff *sock_rmalloc(struct sock *sk, unsigned long size, int force, | ||
| 1672 | gfp_t priority) | ||
| 1673 | { | ||
| 1674 | if (force || atomic_read(&sk->sk_rmem_alloc) < sk->sk_rcvbuf) { | ||
| 1675 | struct sk_buff *skb = alloc_skb(size, priority); | ||
| 1676 | if (skb) { | ||
| 1677 | skb_set_owner_r(skb, sk); | ||
| 1678 | return skb; | ||
| 1679 | } | ||
| 1680 | } | ||
| 1681 | return NULL; | ||
| 1682 | } | ||
| 1683 | |||
| 1684 | /* | ||
| 1685 | * Allocate a memory block from the socket's option memory buffer. | 1660 | * Allocate a memory block from the socket's option memory buffer. |
| 1686 | */ | 1661 | */ |
| 1687 | void *sock_kmalloc(struct sock *sk, int size, gfp_t priority) | 1662 | void *sock_kmalloc(struct sock *sk, int size, gfp_t priority) |
| @@ -1865,9 +1840,7 @@ bool skb_page_frag_refill(unsigned int sz, struct page_frag *pfrag, gfp_t prio) | |||
| 1865 | put_page(pfrag->page); | 1840 | put_page(pfrag->page); |
| 1866 | } | 1841 | } |
| 1867 | 1842 | ||
| 1868 | /* We restrict high order allocations to users that can afford to wait */ | 1843 | order = SKB_FRAG_PAGE_ORDER; |
| 1869 | order = (prio & __GFP_WAIT) ? SKB_FRAG_PAGE_ORDER : 0; | ||
| 1870 | |||
| 1871 | do { | 1844 | do { |
| 1872 | gfp_t gfp = prio; | 1845 | gfp_t gfp = prio; |
| 1873 | 1846 | ||
diff --git a/net/core/stream.c b/net/core/stream.c index 512f0a24269b..301c05f26060 100644 --- a/net/core/stream.c +++ b/net/core/stream.c | |||
| @@ -122,7 +122,7 @@ int sk_stream_wait_memory(struct sock *sk, long *timeo_p) | |||
| 122 | DEFINE_WAIT(wait); | 122 | DEFINE_WAIT(wait); |
| 123 | 123 | ||
| 124 | if (sk_stream_memory_free(sk)) | 124 | if (sk_stream_memory_free(sk)) |
| 125 | current_timeo = vm_wait = (net_random() % (HZ / 5)) + 2; | 125 | current_timeo = vm_wait = (prandom_u32() % (HZ / 5)) + 2; |
| 126 | 126 | ||
| 127 | while (1) { | 127 | while (1) { |
| 128 | set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags); | 128 | set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags); |
diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c index cca444190907..cf9cd13509a7 100644 --- a/net/core/sysctl_net_core.c +++ b/net/core/sysctl_net_core.c | |||
| @@ -122,7 +122,8 @@ static int flow_limit_cpu_sysctl(struct ctl_table *table, int write, | |||
| 122 | synchronize_rcu(); | 122 | synchronize_rcu(); |
| 123 | kfree(cur); | 123 | kfree(cur); |
| 124 | } else if (!cur && cpumask_test_cpu(i, mask)) { | 124 | } else if (!cur && cpumask_test_cpu(i, mask)) { |
| 125 | cur = kzalloc(len, GFP_KERNEL); | 125 | cur = kzalloc_node(len, GFP_KERNEL, |
| 126 | cpu_to_node(i)); | ||
| 126 | if (!cur) { | 127 | if (!cur) { |
| 127 | /* not unwinding previous changes */ | 128 | /* not unwinding previous changes */ |
| 128 | ret = -ENOMEM; | 129 | ret = -ENOMEM; |
diff --git a/net/dcb/dcbevent.c b/net/dcb/dcbevent.c index 4f72fc40bf02..a520d8004d89 100644 --- a/net/dcb/dcbevent.c +++ b/net/dcb/dcbevent.c | |||
| @@ -11,8 +11,7 @@ | |||
| 11 | * more details. | 11 | * more details. |
| 12 | * | 12 | * |
| 13 | * You should have received a copy of the GNU General Public License along with | 13 | * You should have received a copy of the GNU General Public License along with |
| 14 | * this program; if not, write to the Free Software Foundation, Inc., 59 Temple | 14 | * this program; if not, see <http://www.gnu.org/licenses/>. |
| 15 | * Place - Suite 330, Boston, MA 02111-1307 USA. | ||
| 16 | * | 15 | * |
| 17 | * Author: John Fastabend <john.r.fastabend@intel.com> | 16 | * Author: John Fastabend <john.r.fastabend@intel.com> |
| 18 | */ | 17 | */ |
diff --git a/net/dcb/dcbnl.c b/net/dcb/dcbnl.c index 40d5829ed36a..553644402670 100644 --- a/net/dcb/dcbnl.c +++ b/net/dcb/dcbnl.c | |||
| @@ -11,8 +11,7 @@ | |||
| 11 | * more details. | 11 | * more details. |
| 12 | * | 12 | * |
| 13 | * You should have received a copy of the GNU General Public License along with | 13 | * You should have received a copy of the GNU General Public License along with |
| 14 | * this program; if not, write to the Free Software Foundation, Inc., 59 Temple | 14 | * this program; if not, see <http://www.gnu.org/licenses/>. |
| 15 | * Place - Suite 330, Boston, MA 02111-1307 USA. | ||
| 16 | * | 15 | * |
| 17 | * Author: Lucy Liu <lucy.liu@intel.com> | 16 | * Author: Lucy Liu <lucy.liu@intel.com> |
| 18 | */ | 17 | */ |
| @@ -1689,21 +1688,17 @@ static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
| 1689 | if (!tb[DCB_ATTR_IFNAME]) | 1688 | if (!tb[DCB_ATTR_IFNAME]) |
| 1690 | return -EINVAL; | 1689 | return -EINVAL; |
| 1691 | 1690 | ||
| 1692 | netdev = dev_get_by_name(net, nla_data(tb[DCB_ATTR_IFNAME])); | 1691 | netdev = __dev_get_by_name(net, nla_data(tb[DCB_ATTR_IFNAME])); |
| 1693 | if (!netdev) | 1692 | if (!netdev) |
| 1694 | return -ENODEV; | 1693 | return -ENODEV; |
| 1695 | 1694 | ||
| 1696 | if (!netdev->dcbnl_ops) { | 1695 | if (!netdev->dcbnl_ops) |
| 1697 | ret = -EOPNOTSUPP; | 1696 | return -EOPNOTSUPP; |
| 1698 | goto out; | ||
| 1699 | } | ||
| 1700 | 1697 | ||
| 1701 | reply_skb = dcbnl_newmsg(fn->type, dcb->cmd, portid, nlh->nlmsg_seq, | 1698 | reply_skb = dcbnl_newmsg(fn->type, dcb->cmd, portid, nlh->nlmsg_seq, |
| 1702 | nlh->nlmsg_flags, &reply_nlh); | 1699 | nlh->nlmsg_flags, &reply_nlh); |
| 1703 | if (!reply_skb) { | 1700 | if (!reply_skb) |
| 1704 | ret = -ENOBUFS; | 1701 | return -ENOBUFS; |
| 1705 | goto out; | ||
| 1706 | } | ||
| 1707 | 1702 | ||
| 1708 | ret = fn->cb(netdev, nlh, nlh->nlmsg_seq, tb, reply_skb); | 1703 | ret = fn->cb(netdev, nlh, nlh->nlmsg_seq, tb, reply_skb); |
| 1709 | if (ret < 0) { | 1704 | if (ret < 0) { |
| @@ -1715,7 +1710,6 @@ static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
| 1715 | 1710 | ||
| 1716 | ret = rtnl_unicast(reply_skb, net, portid); | 1711 | ret = rtnl_unicast(reply_skb, net, portid); |
| 1717 | out: | 1712 | out: |
| 1718 | dev_put(netdev); | ||
| 1719 | return ret; | 1713 | return ret; |
| 1720 | } | 1714 | } |
| 1721 | 1715 | ||
diff --git a/net/dccp/ccids/lib/tfrc.c b/net/dccp/ccids/lib/tfrc.c index 62b5828acde0..c073b81a1f3e 100644 --- a/net/dccp/ccids/lib/tfrc.c +++ b/net/dccp/ccids/lib/tfrc.c | |||
| @@ -8,7 +8,7 @@ | |||
| 8 | #include "tfrc.h" | 8 | #include "tfrc.h" |
| 9 | 9 | ||
| 10 | #ifdef CONFIG_IP_DCCP_TFRC_DEBUG | 10 | #ifdef CONFIG_IP_DCCP_TFRC_DEBUG |
| 11 | bool tfrc_debug; | 11 | static bool tfrc_debug; |
| 12 | module_param(tfrc_debug, bool, 0644); | 12 | module_param(tfrc_debug, bool, 0644); |
| 13 | MODULE_PARM_DESC(tfrc_debug, "Enable TFRC debug messages"); | 13 | MODULE_PARM_DESC(tfrc_debug, "Enable TFRC debug messages"); |
| 14 | #endif | 14 | #endif |
diff --git a/net/dccp/ccids/lib/tfrc.h b/net/dccp/ccids/lib/tfrc.h index 40ee7d62b652..a3d8f7c76ae0 100644 --- a/net/dccp/ccids/lib/tfrc.h +++ b/net/dccp/ccids/lib/tfrc.h | |||
| @@ -21,7 +21,6 @@ | |||
| 21 | #include "packet_history.h" | 21 | #include "packet_history.h" |
| 22 | 22 | ||
| 23 | #ifdef CONFIG_IP_DCCP_TFRC_DEBUG | 23 | #ifdef CONFIG_IP_DCCP_TFRC_DEBUG |
| 24 | extern bool tfrc_debug; | ||
| 25 | #define tfrc_pr_debug(format, a...) DCCP_PR_DEBUG(tfrc_debug, format, ##a) | 24 | #define tfrc_pr_debug(format, a...) DCCP_PR_DEBUG(tfrc_debug, format, ##a) |
| 26 | #else | 25 | #else |
| 27 | #define tfrc_pr_debug(format, a...) | 26 | #define tfrc_pr_debug(format, a...) |
diff --git a/net/dccp/dccp.h b/net/dccp/dccp.h index 30948784dd58..c67816647cce 100644 --- a/net/dccp/dccp.h +++ b/net/dccp/dccp.h | |||
| @@ -479,7 +479,6 @@ void dccp_feat_list_purge(struct list_head *fn_list); | |||
| 479 | 479 | ||
| 480 | int dccp_insert_options(struct sock *sk, struct sk_buff *skb); | 480 | int dccp_insert_options(struct sock *sk, struct sk_buff *skb); |
| 481 | int dccp_insert_options_rsk(struct dccp_request_sock *, struct sk_buff *); | 481 | int dccp_insert_options_rsk(struct dccp_request_sock *, struct sk_buff *); |
| 482 | int dccp_insert_option_elapsed_time(struct sk_buff *skb, u32 elapsed); | ||
| 483 | u32 dccp_timestamp(void); | 482 | u32 dccp_timestamp(void); |
| 484 | void dccp_timestamping_init(void); | 483 | void dccp_timestamping_init(void); |
| 485 | int dccp_insert_option(struct sk_buff *skb, unsigned char option, | 484 | int dccp_insert_option(struct sk_buff *skb, unsigned char option, |
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index d9f65fc66db5..22b5d818b200 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c | |||
| @@ -75,7 +75,7 @@ int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) | |||
| 75 | rt = ip_route_connect(fl4, nexthop, inet->inet_saddr, | 75 | rt = ip_route_connect(fl4, nexthop, inet->inet_saddr, |
| 76 | RT_CONN_FLAGS(sk), sk->sk_bound_dev_if, | 76 | RT_CONN_FLAGS(sk), sk->sk_bound_dev_if, |
| 77 | IPPROTO_DCCP, | 77 | IPPROTO_DCCP, |
| 78 | orig_sport, orig_dport, sk, true); | 78 | orig_sport, orig_dport, sk); |
| 79 | if (IS_ERR(rt)) | 79 | if (IS_ERR(rt)) |
| 80 | return PTR_ERR(rt); | 80 | return PTR_ERR(rt); |
| 81 | 81 | ||
| @@ -989,6 +989,7 @@ static const struct net_protocol dccp_v4_protocol = { | |||
| 989 | .err_handler = dccp_v4_err, | 989 | .err_handler = dccp_v4_err, |
| 990 | .no_policy = 1, | 990 | .no_policy = 1, |
| 991 | .netns_ok = 1, | 991 | .netns_ok = 1, |
| 992 | .icmp_strict_tag_validation = 1, | ||
| 992 | }; | 993 | }; |
| 993 | 994 | ||
| 994 | static const struct proto_ops inet_dccp_ops = { | 995 | static const struct proto_ops inet_dccp_ops = { |
diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index 2b90a786e475..4db3c2a1679c 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c | |||
| @@ -141,6 +141,9 @@ static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
| 141 | if (type == ICMPV6_PKT_TOOBIG) { | 141 | if (type == ICMPV6_PKT_TOOBIG) { |
| 142 | struct dst_entry *dst = NULL; | 142 | struct dst_entry *dst = NULL; |
| 143 | 143 | ||
| 144 | if (!ip6_sk_accept_pmtu(sk)) | ||
| 145 | goto out; | ||
| 146 | |||
| 144 | if (sock_owned_by_user(sk)) | 147 | if (sock_owned_by_user(sk)) |
| 145 | goto out; | 148 | goto out; |
| 146 | if ((1 << sk->sk_state) & (DCCPF_LISTEN | DCCPF_CLOSED)) | 149 | if ((1 << sk->sk_state) & (DCCPF_LISTEN | DCCPF_CLOSED)) |
| @@ -237,7 +240,7 @@ static int dccp_v6_send_response(struct sock *sk, struct request_sock *req) | |||
| 237 | 240 | ||
| 238 | final_p = fl6_update_dst(&fl6, np->opt, &final); | 241 | final_p = fl6_update_dst(&fl6, np->opt, &final); |
| 239 | 242 | ||
| 240 | dst = ip6_dst_lookup_flow(sk, &fl6, final_p, false); | 243 | dst = ip6_dst_lookup_flow(sk, &fl6, final_p); |
| 241 | if (IS_ERR(dst)) { | 244 | if (IS_ERR(dst)) { |
| 242 | err = PTR_ERR(dst); | 245 | err = PTR_ERR(dst); |
| 243 | dst = NULL; | 246 | dst = NULL; |
| @@ -301,7 +304,7 @@ static void dccp_v6_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb) | |||
| 301 | security_skb_classify_flow(rxskb, flowi6_to_flowi(&fl6)); | 304 | security_skb_classify_flow(rxskb, flowi6_to_flowi(&fl6)); |
| 302 | 305 | ||
| 303 | /* sk = NULL, but it is safe for now. RST socket required. */ | 306 | /* sk = NULL, but it is safe for now. RST socket required. */ |
| 304 | dst = ip6_dst_lookup_flow(ctl_sk, &fl6, NULL, false); | 307 | dst = ip6_dst_lookup_flow(ctl_sk, &fl6, NULL); |
| 305 | if (!IS_ERR(dst)) { | 308 | if (!IS_ERR(dst)) { |
| 306 | skb_dst_set(skb, dst); | 309 | skb_dst_set(skb, dst); |
| 307 | ip6_xmit(ctl_sk, skb, &fl6, NULL, 0); | 310 | ip6_xmit(ctl_sk, skb, &fl6, NULL, 0); |
| @@ -512,7 +515,7 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk, | |||
| 512 | fl6.fl6_sport = htons(ireq->ir_num); | 515 | fl6.fl6_sport = htons(ireq->ir_num); |
| 513 | security_sk_classify_flow(sk, flowi6_to_flowi(&fl6)); | 516 | security_sk_classify_flow(sk, flowi6_to_flowi(&fl6)); |
| 514 | 517 | ||
| 515 | dst = ip6_dst_lookup_flow(sk, &fl6, final_p, false); | 518 | dst = ip6_dst_lookup_flow(sk, &fl6, final_p); |
| 516 | if (IS_ERR(dst)) | 519 | if (IS_ERR(dst)) |
| 517 | goto out; | 520 | goto out; |
| 518 | } | 521 | } |
| @@ -931,7 +934,7 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr, | |||
| 931 | 934 | ||
| 932 | final_p = fl6_update_dst(&fl6, np->opt, &final); | 935 | final_p = fl6_update_dst(&fl6, np->opt, &final); |
| 933 | 936 | ||
| 934 | dst = ip6_dst_lookup_flow(sk, &fl6, final_p, true); | 937 | dst = ip6_dst_lookup_flow(sk, &fl6, final_p); |
| 935 | if (IS_ERR(dst)) { | 938 | if (IS_ERR(dst)) { |
| 936 | err = PTR_ERR(dst); | 939 | err = PTR_ERR(dst); |
| 937 | goto failure; | 940 | goto failure; |
diff --git a/net/dccp/options.c b/net/dccp/options.c index a58e0b634050..9bce31886bda 100644 --- a/net/dccp/options.c +++ b/net/dccp/options.c | |||
| @@ -343,38 +343,6 @@ static inline int dccp_elapsed_time_len(const u32 elapsed_time) | |||
| 343 | return elapsed_time == 0 ? 0 : elapsed_time <= 0xFFFF ? 2 : 4; | 343 | return elapsed_time == 0 ? 0 : elapsed_time <= 0xFFFF ? 2 : 4; |
| 344 | } | 344 | } |
| 345 | 345 | ||
| 346 | /* FIXME: This function is currently not used anywhere */ | ||
| 347 | int dccp_insert_option_elapsed_time(struct sk_buff *skb, u32 elapsed_time) | ||
| 348 | { | ||
| 349 | const int elapsed_time_len = dccp_elapsed_time_len(elapsed_time); | ||
| 350 | const int len = 2 + elapsed_time_len; | ||
| 351 | unsigned char *to; | ||
| 352 | |||
| 353 | if (elapsed_time_len == 0) | ||
| 354 | return 0; | ||
| 355 | |||
| 356 | if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN) | ||
| 357 | return -1; | ||
| 358 | |||
| 359 | DCCP_SKB_CB(skb)->dccpd_opt_len += len; | ||
| 360 | |||
| 361 | to = skb_push(skb, len); | ||
| 362 | *to++ = DCCPO_ELAPSED_TIME; | ||
| 363 | *to++ = len; | ||
| 364 | |||
| 365 | if (elapsed_time_len == 2) { | ||
| 366 | const __be16 var16 = htons((u16)elapsed_time); | ||
| 367 | memcpy(to, &var16, 2); | ||
| 368 | } else { | ||
| 369 | const __be32 var32 = htonl(elapsed_time); | ||
| 370 | memcpy(to, &var32, 4); | ||
| 371 | } | ||
| 372 | |||
| 373 | return 0; | ||
| 374 | } | ||
| 375 | |||
| 376 | EXPORT_SYMBOL_GPL(dccp_insert_option_elapsed_time); | ||
| 377 | |||
| 378 | static int dccp_insert_option_timestamp(struct sk_buff *skb) | 346 | static int dccp_insert_option_timestamp(struct sk_buff *skb) |
| 379 | { | 347 | { |
| 380 | __be32 now = htonl(dccp_timestamp()); | 348 | __be32 now = htonl(dccp_timestamp()); |
diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c index dd4d506ef923..2954dcbca832 100644 --- a/net/decnet/af_decnet.c +++ b/net/decnet/af_decnet.c | |||
| @@ -1808,6 +1808,7 @@ out: | |||
| 1808 | rv = (flags & MSG_PEEK) ? -sk->sk_err : sock_error(sk); | 1808 | rv = (flags & MSG_PEEK) ? -sk->sk_err : sock_error(sk); |
| 1809 | 1809 | ||
| 1810 | if ((rv >= 0) && msg->msg_name) { | 1810 | if ((rv >= 0) && msg->msg_name) { |
| 1811 | __sockaddr_check_size(sizeof(struct sockaddr_dn)); | ||
| 1811 | memcpy(msg->msg_name, &scp->peer, sizeof(struct sockaddr_dn)); | 1812 | memcpy(msg->msg_name, &scp->peer, sizeof(struct sockaddr_dn)); |
| 1812 | msg->msg_namelen = sizeof(struct sockaddr_dn); | 1813 | msg->msg_namelen = sizeof(struct sockaddr_dn); |
| 1813 | } | 1814 | } |
| @@ -1914,7 +1915,7 @@ static int dn_sendmsg(struct kiocb *iocb, struct socket *sock, | |||
| 1914 | int err = 0; | 1915 | int err = 0; |
| 1915 | size_t sent = 0; | 1916 | size_t sent = 0; |
| 1916 | int addr_len = msg->msg_namelen; | 1917 | int addr_len = msg->msg_namelen; |
| 1917 | struct sockaddr_dn *addr = (struct sockaddr_dn *)msg->msg_name; | 1918 | DECLARE_SOCKADDR(struct sockaddr_dn *, addr, msg->msg_name); |
| 1918 | struct sk_buff *skb = NULL; | 1919 | struct sk_buff *skb = NULL; |
| 1919 | struct dn_skb_cb *cb; | 1920 | struct dn_skb_cb *cb; |
| 1920 | size_t len; | 1921 | size_t len; |
diff --git a/net/decnet/dn_dev.c b/net/decnet/dn_dev.c index dd0dfb25f4b1..a603823a3e27 100644 --- a/net/decnet/dn_dev.c +++ b/net/decnet/dn_dev.c | |||
| @@ -561,6 +561,7 @@ static const struct nla_policy dn_ifa_policy[IFA_MAX+1] = { | |||
| 561 | [IFA_LOCAL] = { .type = NLA_U16 }, | 561 | [IFA_LOCAL] = { .type = NLA_U16 }, |
| 562 | [IFA_LABEL] = { .type = NLA_STRING, | 562 | [IFA_LABEL] = { .type = NLA_STRING, |
| 563 | .len = IFNAMSIZ - 1 }, | 563 | .len = IFNAMSIZ - 1 }, |
| 564 | [IFA_FLAGS] = { .type = NLA_U32 }, | ||
| 564 | }; | 565 | }; |
| 565 | 566 | ||
| 566 | static int dn_nl_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh) | 567 | static int dn_nl_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh) |
| @@ -648,7 +649,8 @@ static int dn_nl_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
| 648 | 649 | ||
| 649 | ifa->ifa_local = nla_get_le16(tb[IFA_LOCAL]); | 650 | ifa->ifa_local = nla_get_le16(tb[IFA_LOCAL]); |
| 650 | ifa->ifa_address = nla_get_le16(tb[IFA_ADDRESS]); | 651 | ifa->ifa_address = nla_get_le16(tb[IFA_ADDRESS]); |
| 651 | ifa->ifa_flags = ifm->ifa_flags; | 652 | ifa->ifa_flags = tb[IFA_FLAGS] ? nla_get_u32(tb[IFA_FLAGS]) : |
| 653 | ifm->ifa_flags; | ||
| 652 | ifa->ifa_scope = ifm->ifa_scope; | 654 | ifa->ifa_scope = ifm->ifa_scope; |
| 653 | ifa->ifa_dev = dn_db; | 655 | ifa->ifa_dev = dn_db; |
| 654 | 656 | ||
| @@ -669,7 +671,8 @@ static inline size_t dn_ifaddr_nlmsg_size(void) | |||
| 669 | return NLMSG_ALIGN(sizeof(struct ifaddrmsg)) | 671 | return NLMSG_ALIGN(sizeof(struct ifaddrmsg)) |
| 670 | + nla_total_size(IFNAMSIZ) /* IFA_LABEL */ | 672 | + nla_total_size(IFNAMSIZ) /* IFA_LABEL */ |
| 671 | + nla_total_size(2) /* IFA_ADDRESS */ | 673 | + nla_total_size(2) /* IFA_ADDRESS */ |
| 672 | + nla_total_size(2); /* IFA_LOCAL */ | 674 | + nla_total_size(2) /* IFA_LOCAL */ |
| 675 | + nla_total_size(4); /* IFA_FLAGS */ | ||
| 673 | } | 676 | } |
| 674 | 677 | ||
| 675 | static int dn_nl_fill_ifaddr(struct sk_buff *skb, struct dn_ifaddr *ifa, | 678 | static int dn_nl_fill_ifaddr(struct sk_buff *skb, struct dn_ifaddr *ifa, |
| @@ -677,6 +680,7 @@ static int dn_nl_fill_ifaddr(struct sk_buff *skb, struct dn_ifaddr *ifa, | |||
| 677 | { | 680 | { |
| 678 | struct ifaddrmsg *ifm; | 681 | struct ifaddrmsg *ifm; |
| 679 | struct nlmsghdr *nlh; | 682 | struct nlmsghdr *nlh; |
| 683 | u32 ifa_flags = ifa->ifa_flags | IFA_F_PERMANENT; | ||
| 680 | 684 | ||
| 681 | nlh = nlmsg_put(skb, portid, seq, event, sizeof(*ifm), flags); | 685 | nlh = nlmsg_put(skb, portid, seq, event, sizeof(*ifm), flags); |
| 682 | if (nlh == NULL) | 686 | if (nlh == NULL) |
| @@ -685,7 +689,7 @@ static int dn_nl_fill_ifaddr(struct sk_buff *skb, struct dn_ifaddr *ifa, | |||
| 685 | ifm = nlmsg_data(nlh); | 689 | ifm = nlmsg_data(nlh); |
| 686 | ifm->ifa_family = AF_DECnet; | 690 | ifm->ifa_family = AF_DECnet; |
| 687 | ifm->ifa_prefixlen = 16; | 691 | ifm->ifa_prefixlen = 16; |
| 688 | ifm->ifa_flags = ifa->ifa_flags | IFA_F_PERMANENT; | 692 | ifm->ifa_flags = ifa_flags; |
| 689 | ifm->ifa_scope = ifa->ifa_scope; | 693 | ifm->ifa_scope = ifa->ifa_scope; |
| 690 | ifm->ifa_index = ifa->ifa_dev->dev->ifindex; | 694 | ifm->ifa_index = ifa->ifa_dev->dev->ifindex; |
| 691 | 695 | ||
| @@ -694,7 +698,8 @@ static int dn_nl_fill_ifaddr(struct sk_buff *skb, struct dn_ifaddr *ifa, | |||
| 694 | (ifa->ifa_local && | 698 | (ifa->ifa_local && |
| 695 | nla_put_le16(skb, IFA_LOCAL, ifa->ifa_local)) || | 699 | nla_put_le16(skb, IFA_LOCAL, ifa->ifa_local)) || |
| 696 | (ifa->ifa_label[0] && | 700 | (ifa->ifa_label[0] && |
| 697 | nla_put_string(skb, IFA_LABEL, ifa->ifa_label))) | 701 | nla_put_string(skb, IFA_LABEL, ifa->ifa_label)) || |
| 702 | nla_put_u32(skb, IFA_FLAGS, ifa_flags)) | ||
| 698 | goto nla_put_failure; | 703 | goto nla_put_failure; |
| 699 | return nlmsg_end(skb, nlh); | 704 | return nlmsg_end(skb, nlh); |
| 700 | 705 | ||
diff --git a/net/decnet/dn_neigh.c b/net/decnet/dn_neigh.c index f8637f93d318..c8121ceddb9e 100644 --- a/net/decnet/dn_neigh.c +++ b/net/decnet/dn_neigh.c | |||
| @@ -102,19 +102,21 @@ struct neigh_table dn_neigh_table = { | |||
| 102 | .id = "dn_neigh_cache", | 102 | .id = "dn_neigh_cache", |
| 103 | .parms ={ | 103 | .parms ={ |
| 104 | .tbl = &dn_neigh_table, | 104 | .tbl = &dn_neigh_table, |
| 105 | .base_reachable_time = 30 * HZ, | 105 | .reachable_time = 30 * HZ, |
| 106 | .retrans_time = 1 * HZ, | 106 | .data = { |
| 107 | .gc_staletime = 60 * HZ, | 107 | [NEIGH_VAR_MCAST_PROBES] = 0, |
| 108 | .reachable_time = 30 * HZ, | 108 | [NEIGH_VAR_UCAST_PROBES] = 0, |
| 109 | .delay_probe_time = 5 * HZ, | 109 | [NEIGH_VAR_APP_PROBES] = 0, |
| 110 | .queue_len_bytes = 64*1024, | 110 | [NEIGH_VAR_RETRANS_TIME] = 1 * HZ, |
| 111 | .ucast_probes = 0, | 111 | [NEIGH_VAR_BASE_REACHABLE_TIME] = 30 * HZ, |
| 112 | .app_probes = 0, | 112 | [NEIGH_VAR_DELAY_PROBE_TIME] = 5 * HZ, |
| 113 | .mcast_probes = 0, | 113 | [NEIGH_VAR_GC_STALETIME] = 60 * HZ, |
| 114 | .anycast_delay = 0, | 114 | [NEIGH_VAR_QUEUE_LEN_BYTES] = 64*1024, |
| 115 | .proxy_delay = 0, | 115 | [NEIGH_VAR_PROXY_QLEN] = 0, |
| 116 | .proxy_qlen = 0, | 116 | [NEIGH_VAR_ANYCAST_DELAY] = 0, |
| 117 | .locktime = 1 * HZ, | 117 | [NEIGH_VAR_PROXY_DELAY] = 0, |
| 118 | [NEIGH_VAR_LOCKTIME] = 1 * HZ, | ||
| 119 | }, | ||
| 118 | }, | 120 | }, |
| 119 | .gc_interval = 30 * HZ, | 121 | .gc_interval = 30 * HZ, |
| 120 | .gc_thresh1 = 128, | 122 | .gc_thresh1 = 128, |
diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c index fe32388ea24f..ce0cbbfe0f43 100644 --- a/net/decnet/dn_route.c +++ b/net/decnet/dn_route.c | |||
| @@ -1288,8 +1288,6 @@ int dn_route_output_sock(struct dst_entry __rcu **pprt, struct flowidn *fl, stru | |||
| 1288 | 1288 | ||
| 1289 | err = __dn_route_output_key(pprt, fl, flags & MSG_TRYHARD); | 1289 | err = __dn_route_output_key(pprt, fl, flags & MSG_TRYHARD); |
| 1290 | if (err == 0 && fl->flowidn_proto) { | 1290 | if (err == 0 && fl->flowidn_proto) { |
| 1291 | if (!(flags & MSG_DONTWAIT)) | ||
| 1292 | fl->flowidn_flags |= FLOWI_FLAG_CAN_SLEEP; | ||
| 1293 | *pprt = xfrm_lookup(&init_net, *pprt, | 1291 | *pprt = xfrm_lookup(&init_net, *pprt, |
| 1294 | flowidn_to_flowi(fl), sk, 0); | 1292 | flowidn_to_flowi(fl), sk, 0); |
| 1295 | if (IS_ERR(*pprt)) { | 1293 | if (IS_ERR(*pprt)) { |
| @@ -1668,12 +1666,8 @@ static int dn_cache_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh) | |||
| 1668 | 1666 | ||
| 1669 | if (fld.flowidn_iif) { | 1667 | if (fld.flowidn_iif) { |
| 1670 | struct net_device *dev; | 1668 | struct net_device *dev; |
| 1671 | if ((dev = dev_get_by_index(&init_net, fld.flowidn_iif)) == NULL) { | 1669 | dev = __dev_get_by_index(&init_net, fld.flowidn_iif); |
| 1672 | kfree_skb(skb); | 1670 | if (!dev || !dev->dn_ptr) { |
| 1673 | return -ENODEV; | ||
| 1674 | } | ||
| 1675 | if (!dev->dn_ptr) { | ||
| 1676 | dev_put(dev); | ||
| 1677 | kfree_skb(skb); | 1671 | kfree_skb(skb); |
| 1678 | return -ENODEV; | 1672 | return -ENODEV; |
| 1679 | } | 1673 | } |
| @@ -1695,8 +1689,6 @@ static int dn_cache_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh) | |||
| 1695 | err = dn_route_output_key((struct dst_entry **)&rt, &fld, 0); | 1689 | err = dn_route_output_key((struct dst_entry **)&rt, &fld, 0); |
| 1696 | } | 1690 | } |
| 1697 | 1691 | ||
| 1698 | if (skb->dev) | ||
| 1699 | dev_put(skb->dev); | ||
| 1700 | skb->dev = NULL; | 1692 | skb->dev = NULL; |
| 1701 | if (err) | 1693 | if (err) |
| 1702 | goto out_free; | 1694 | goto out_free; |
diff --git a/net/dns_resolver/dns_key.c b/net/dns_resolver/dns_key.c index f347a2ca7d7e..bf8584339048 100644 --- a/net/dns_resolver/dns_key.c +++ b/net/dns_resolver/dns_key.c | |||
| @@ -19,8 +19,7 @@ | |||
| 19 | * the GNU Lesser General Public License for more details. | 19 | * the GNU Lesser General Public License for more details. |
| 20 | * | 20 | * |
| 21 | * You should have received a copy of the GNU Lesser General Public License | 21 | * You should have received a copy of the GNU Lesser General Public License |
| 22 | * along with this library; if not, write to the Free Software | 22 | * along with this library; if not, see <http://www.gnu.org/licenses/>. |
| 23 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 24 | */ | 23 | */ |
| 25 | #include <linux/module.h> | 24 | #include <linux/module.h> |
| 26 | #include <linux/moduleparam.h> | 25 | #include <linux/moduleparam.h> |
diff --git a/net/dns_resolver/dns_query.c b/net/dns_resolver/dns_query.c index c32be292c7e3..e7b6d53eef88 100644 --- a/net/dns_resolver/dns_query.c +++ b/net/dns_resolver/dns_query.c | |||
| @@ -32,8 +32,7 @@ | |||
| 32 | * the GNU Lesser General Public License for more details. | 32 | * the GNU Lesser General Public License for more details. |
| 33 | * | 33 | * |
| 34 | * You should have received a copy of the GNU Lesser General Public License | 34 | * You should have received a copy of the GNU Lesser General Public License |
| 35 | * along with this library; if not, write to the Free Software | 35 | * along with this library; if not, see <http://www.gnu.org/licenses/>. |
| 36 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 37 | */ | 36 | */ |
| 38 | 37 | ||
| 39 | #include <linux/module.h> | 38 | #include <linux/module.h> |
diff --git a/net/dns_resolver/internal.h b/net/dns_resolver/internal.h index 17c7886b5b3a..7af1ed39c009 100644 --- a/net/dns_resolver/internal.h +++ b/net/dns_resolver/internal.h | |||
| @@ -15,8 +15,7 @@ | |||
| 15 | * the GNU Lesser General Public License for more details. | 15 | * the GNU Lesser General Public License for more details. |
| 16 | * | 16 | * |
| 17 | * You should have received a copy of the GNU Lesser General Public License | 17 | * You should have received a copy of the GNU Lesser General Public License |
| 18 | * along with this library; if not, write to the Free Software | 18 | * along with this library; if not, see <http://www.gnu.org/licenses/>. |
| 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 20 | */ | 19 | */ |
| 21 | 20 | ||
| 22 | #include <linux/compiler.h> | 21 | #include <linux/compiler.h> |
diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 29d684ebca6a..02c0e1716f64 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c | |||
| @@ -156,7 +156,7 @@ static int dsa_slave_set_mac_address(struct net_device *dev, void *a) | |||
| 156 | dev_uc_del(master, dev->dev_addr); | 156 | dev_uc_del(master, dev->dev_addr); |
| 157 | 157 | ||
| 158 | out: | 158 | out: |
| 159 | memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN); | 159 | ether_addr_copy(dev->dev_addr, addr->sa_data); |
| 160 | 160 | ||
| 161 | return 0; | 161 | return 0; |
| 162 | } | 162 | } |
diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c index 8f032bae60ad..5dc638cad2e1 100644 --- a/net/ethernet/eth.c +++ b/net/ethernet/eth.c | |||
| @@ -156,7 +156,9 @@ EXPORT_SYMBOL(eth_rebuild_header); | |||
| 156 | */ | 156 | */ |
| 157 | __be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev) | 157 | __be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev) |
| 158 | { | 158 | { |
| 159 | struct ethhdr *eth; | 159 | unsigned short _service_access_point; |
| 160 | const unsigned short *sap; | ||
| 161 | const struct ethhdr *eth; | ||
| 160 | 162 | ||
| 161 | skb->dev = dev; | 163 | skb->dev = dev; |
| 162 | skb_reset_mac_header(skb); | 164 | skb_reset_mac_header(skb); |
| @@ -194,7 +196,8 @@ __be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev) | |||
| 194 | * layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This | 196 | * layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This |
| 195 | * won't work for fault tolerant netware but does for the rest. | 197 | * won't work for fault tolerant netware but does for the rest. |
| 196 | */ | 198 | */ |
| 197 | if (unlikely(skb->len >= 2 && *(unsigned short *)(skb->data) == 0xFFFF)) | 199 | sap = skb_header_pointer(skb, 0, sizeof(*sap), &_service_access_point); |
| 200 | if (sap && *sap == 0xFFFF) | ||
| 198 | return htons(ETH_P_802_3); | 201 | return htons(ETH_P_802_3); |
| 199 | 202 | ||
| 200 | /* | 203 | /* |
diff --git a/net/hsr/hsr_framereg.c b/net/hsr/hsr_framereg.c index 4bdab1521878..327060c6c874 100644 --- a/net/hsr/hsr_framereg.c +++ b/net/hsr/hsr_framereg.c | |||
| @@ -127,11 +127,6 @@ int hsr_create_self_node(struct list_head *self_node_db, | |||
| 127 | return 0; | 127 | return 0; |
| 128 | } | 128 | } |
| 129 | 129 | ||
| 130 | static void node_entry_reclaim(struct rcu_head *rh) | ||
| 131 | { | ||
| 132 | kfree(container_of(rh, struct node_entry, rcu_head)); | ||
| 133 | } | ||
| 134 | |||
| 135 | 130 | ||
| 136 | /* Add/merge node to the database of nodes. 'skb' must contain an HSR | 131 | /* Add/merge node to the database of nodes. 'skb' must contain an HSR |
| 137 | * supervision frame. | 132 | * supervision frame. |
| @@ -175,7 +170,7 @@ struct node_entry *hsr_merge_node(struct hsr_priv *hsr_priv, | |||
| 175 | if (node && !ether_addr_equal(node->MacAddressA, hsr_sp->MacAddressA)) { | 170 | if (node && !ether_addr_equal(node->MacAddressA, hsr_sp->MacAddressA)) { |
| 176 | /* Node has changed its AddrA, frame was received from SlaveB */ | 171 | /* Node has changed its AddrA, frame was received from SlaveB */ |
| 177 | list_del_rcu(&node->mac_list); | 172 | list_del_rcu(&node->mac_list); |
| 178 | call_rcu(&node->rcu_head, node_entry_reclaim); | 173 | kfree_rcu(node, rcu_head); |
| 179 | node = NULL; | 174 | node = NULL; |
| 180 | } | 175 | } |
| 181 | 176 | ||
| @@ -183,7 +178,7 @@ struct node_entry *hsr_merge_node(struct hsr_priv *hsr_priv, | |||
| 183 | !ether_addr_equal(node->MacAddressB, hsr_ethsup->ethhdr.h_source)) { | 178 | !ether_addr_equal(node->MacAddressB, hsr_ethsup->ethhdr.h_source)) { |
| 184 | /* Cables have been swapped */ | 179 | /* Cables have been swapped */ |
| 185 | list_del_rcu(&node->mac_list); | 180 | list_del_rcu(&node->mac_list); |
| 186 | call_rcu(&node->rcu_head, node_entry_reclaim); | 181 | kfree_rcu(node, rcu_head); |
| 187 | node = NULL; | 182 | node = NULL; |
| 188 | } | 183 | } |
| 189 | 184 | ||
| @@ -192,7 +187,7 @@ struct node_entry *hsr_merge_node(struct hsr_priv *hsr_priv, | |||
| 192 | !ether_addr_equal(node->MacAddressA, hsr_ethsup->ethhdr.h_source)) { | 187 | !ether_addr_equal(node->MacAddressA, hsr_ethsup->ethhdr.h_source)) { |
| 193 | /* Cables have been swapped */ | 188 | /* Cables have been swapped */ |
| 194 | list_del_rcu(&node->mac_list); | 189 | list_del_rcu(&node->mac_list); |
| 195 | call_rcu(&node->rcu_head, node_entry_reclaim); | 190 | kfree_rcu(node, rcu_head); |
| 196 | node = NULL; | 191 | node = NULL; |
| 197 | } | 192 | } |
| 198 | 193 | ||
| @@ -417,7 +412,7 @@ void hsr_prune_nodes(struct hsr_priv *hsr_priv) | |||
| 417 | hsr_nl_nodedown(hsr_priv, node->MacAddressA); | 412 | hsr_nl_nodedown(hsr_priv, node->MacAddressA); |
| 418 | list_del_rcu(&node->mac_list); | 413 | list_del_rcu(&node->mac_list); |
| 419 | /* Note that we need to free this entry later: */ | 414 | /* Note that we need to free this entry later: */ |
| 420 | call_rcu(&node->rcu_head, node_entry_reclaim); | 415 | kfree_rcu(node, rcu_head); |
| 421 | } | 416 | } |
| 422 | } | 417 | } |
| 423 | rcu_read_unlock(); | 418 | rcu_read_unlock(); |
diff --git a/net/ieee802154/6lowpan.c b/net/ieee802154/6lowpan.c index a2d2456a557a..48b25c0af4d0 100644 --- a/net/ieee802154/6lowpan.c +++ b/net/ieee802154/6lowpan.c | |||
| @@ -62,9 +62,6 @@ | |||
| 62 | 62 | ||
| 63 | #include "6lowpan.h" | 63 | #include "6lowpan.h" |
| 64 | 64 | ||
| 65 | /* TTL uncompression values */ | ||
| 66 | static const u8 lowpan_ttl_values[] = {0, 1, 64, 255}; | ||
| 67 | |||
| 68 | static LIST_HEAD(lowpan_devices); | 65 | static LIST_HEAD(lowpan_devices); |
| 69 | 66 | ||
| 70 | /* private device info */ | 67 | /* private device info */ |
| @@ -104,378 +101,14 @@ static inline void lowpan_address_flip(u8 *src, u8 *dest) | |||
| 104 | (dest)[IEEE802154_ADDR_LEN - i - 1] = (src)[i]; | 101 | (dest)[IEEE802154_ADDR_LEN - i - 1] = (src)[i]; |
| 105 | } | 102 | } |
| 106 | 103 | ||
| 107 | /* list of all 6lowpan devices, uses for package delivering */ | ||
| 108 | /* print data in line */ | ||
| 109 | static inline void lowpan_raw_dump_inline(const char *caller, char *msg, | ||
| 110 | unsigned char *buf, int len) | ||
| 111 | { | ||
| 112 | #ifdef DEBUG | ||
| 113 | if (msg) | ||
| 114 | pr_debug("(%s) %s: ", caller, msg); | ||
| 115 | print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_NONE, | ||
| 116 | 16, 1, buf, len, false); | ||
| 117 | #endif /* DEBUG */ | ||
| 118 | } | ||
| 119 | |||
| 120 | /* | ||
| 121 | * print data in a table format: | ||
| 122 | * | ||
| 123 | * addr: xx xx xx xx xx xx | ||
| 124 | * addr: xx xx xx xx xx xx | ||
| 125 | * ... | ||
| 126 | */ | ||
| 127 | static inline void lowpan_raw_dump_table(const char *caller, char *msg, | ||
| 128 | unsigned char *buf, int len) | ||
| 129 | { | ||
| 130 | #ifdef DEBUG | ||
| 131 | if (msg) | ||
| 132 | pr_debug("(%s) %s:\n", caller, msg); | ||
| 133 | print_hex_dump(KERN_DEBUG, "\t", DUMP_PREFIX_OFFSET, | ||
| 134 | 16, 1, buf, len, false); | ||
| 135 | #endif /* DEBUG */ | ||
| 136 | } | ||
| 137 | |||
| 138 | static u8 | ||
| 139 | lowpan_compress_addr_64(u8 **hc06_ptr, u8 shift, const struct in6_addr *ipaddr, | ||
| 140 | const unsigned char *lladdr) | ||
| 141 | { | ||
| 142 | u8 val = 0; | ||
| 143 | |||
| 144 | if (is_addr_mac_addr_based(ipaddr, lladdr)) | ||
| 145 | val = 3; /* 0-bits */ | ||
| 146 | else if (lowpan_is_iid_16_bit_compressable(ipaddr)) { | ||
| 147 | /* compress IID to 16 bits xxxx::XXXX */ | ||
| 148 | memcpy(*hc06_ptr, &ipaddr->s6_addr16[7], 2); | ||
| 149 | *hc06_ptr += 2; | ||
| 150 | val = 2; /* 16-bits */ | ||
| 151 | } else { | ||
| 152 | /* do not compress IID => xxxx::IID */ | ||
| 153 | memcpy(*hc06_ptr, &ipaddr->s6_addr16[4], 8); | ||
| 154 | *hc06_ptr += 8; | ||
| 155 | val = 1; /* 64-bits */ | ||
| 156 | } | ||
| 157 | |||
| 158 | return rol8(val, shift); | ||
| 159 | } | ||
| 160 | |||
| 161 | /* | ||
| 162 | * Uncompress address function for source and | ||
| 163 | * destination address(non-multicast). | ||
| 164 | * | ||
| 165 | * address_mode is sam value or dam value. | ||
| 166 | */ | ||
| 167 | static int | ||
| 168 | lowpan_uncompress_addr(struct sk_buff *skb, | ||
| 169 | struct in6_addr *ipaddr, | ||
| 170 | const u8 address_mode, | ||
| 171 | const struct ieee802154_addr *lladdr) | ||
| 172 | { | ||
| 173 | bool fail; | ||
| 174 | |||
| 175 | switch (address_mode) { | ||
| 176 | case LOWPAN_IPHC_ADDR_00: | ||
| 177 | /* for global link addresses */ | ||
| 178 | fail = lowpan_fetch_skb(skb, ipaddr->s6_addr, 16); | ||
| 179 | break; | ||
| 180 | case LOWPAN_IPHC_ADDR_01: | ||
| 181 | /* fe:80::XXXX:XXXX:XXXX:XXXX */ | ||
| 182 | ipaddr->s6_addr[0] = 0xFE; | ||
| 183 | ipaddr->s6_addr[1] = 0x80; | ||
| 184 | fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[8], 8); | ||
| 185 | break; | ||
| 186 | case LOWPAN_IPHC_ADDR_02: | ||
| 187 | /* fe:80::ff:fe00:XXXX */ | ||
| 188 | ipaddr->s6_addr[0] = 0xFE; | ||
| 189 | ipaddr->s6_addr[1] = 0x80; | ||
| 190 | ipaddr->s6_addr[11] = 0xFF; | ||
| 191 | ipaddr->s6_addr[12] = 0xFE; | ||
| 192 | fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[14], 2); | ||
| 193 | break; | ||
| 194 | case LOWPAN_IPHC_ADDR_03: | ||
| 195 | fail = false; | ||
| 196 | switch (lladdr->addr_type) { | ||
| 197 | case IEEE802154_ADDR_LONG: | ||
| 198 | /* fe:80::XXXX:XXXX:XXXX:XXXX | ||
| 199 | * \_________________/ | ||
| 200 | * hwaddr | ||
| 201 | */ | ||
| 202 | ipaddr->s6_addr[0] = 0xFE; | ||
| 203 | ipaddr->s6_addr[1] = 0x80; | ||
| 204 | memcpy(&ipaddr->s6_addr[8], lladdr->hwaddr, | ||
| 205 | IEEE802154_ADDR_LEN); | ||
| 206 | /* second bit-flip (Universe/Local) | ||
| 207 | * is done according RFC2464 | ||
| 208 | */ | ||
| 209 | ipaddr->s6_addr[8] ^= 0x02; | ||
| 210 | break; | ||
| 211 | case IEEE802154_ADDR_SHORT: | ||
| 212 | /* fe:80::ff:fe00:XXXX | ||
| 213 | * \__/ | ||
| 214 | * short_addr | ||
| 215 | * | ||
| 216 | * Universe/Local bit is zero. | ||
| 217 | */ | ||
| 218 | ipaddr->s6_addr[0] = 0xFE; | ||
| 219 | ipaddr->s6_addr[1] = 0x80; | ||
| 220 | ipaddr->s6_addr[11] = 0xFF; | ||
| 221 | ipaddr->s6_addr[12] = 0xFE; | ||
| 222 | ipaddr->s6_addr16[7] = htons(lladdr->short_addr); | ||
| 223 | break; | ||
| 224 | default: | ||
| 225 | pr_debug("Invalid addr_type set\n"); | ||
| 226 | return -EINVAL; | ||
| 227 | } | ||
| 228 | break; | ||
| 229 | default: | ||
| 230 | pr_debug("Invalid address mode value: 0x%x\n", address_mode); | ||
| 231 | return -EINVAL; | ||
| 232 | } | ||
| 233 | |||
| 234 | if (fail) { | ||
| 235 | pr_debug("Failed to fetch skb data\n"); | ||
| 236 | return -EIO; | ||
| 237 | } | ||
| 238 | |||
| 239 | lowpan_raw_dump_inline(NULL, "Reconstructed ipv6 addr is:\n", | ||
| 240 | ipaddr->s6_addr, 16); | ||
| 241 | |||
| 242 | return 0; | ||
| 243 | } | ||
| 244 | |||
| 245 | /* Uncompress address function for source context | ||
| 246 | * based address(non-multicast). | ||
| 247 | */ | ||
| 248 | static int | ||
| 249 | lowpan_uncompress_context_based_src_addr(struct sk_buff *skb, | ||
| 250 | struct in6_addr *ipaddr, | ||
| 251 | const u8 sam) | ||
| 252 | { | ||
| 253 | switch (sam) { | ||
| 254 | case LOWPAN_IPHC_ADDR_00: | ||
| 255 | /* unspec address :: | ||
| 256 | * Do nothing, address is already :: | ||
| 257 | */ | ||
| 258 | break; | ||
| 259 | case LOWPAN_IPHC_ADDR_01: | ||
| 260 | /* TODO */ | ||
| 261 | case LOWPAN_IPHC_ADDR_02: | ||
| 262 | /* TODO */ | ||
| 263 | case LOWPAN_IPHC_ADDR_03: | ||
| 264 | /* TODO */ | ||
| 265 | netdev_warn(skb->dev, "SAM value 0x%x not supported\n", sam); | ||
| 266 | return -EINVAL; | ||
| 267 | default: | ||
| 268 | pr_debug("Invalid sam value: 0x%x\n", sam); | ||
| 269 | return -EINVAL; | ||
| 270 | } | ||
| 271 | |||
| 272 | lowpan_raw_dump_inline(NULL, | ||
| 273 | "Reconstructed context based ipv6 src addr is:\n", | ||
| 274 | ipaddr->s6_addr, 16); | ||
| 275 | |||
| 276 | return 0; | ||
| 277 | } | ||
| 278 | |||
| 279 | /* Uncompress function for multicast destination address, | ||
| 280 | * when M bit is set. | ||
| 281 | */ | ||
| 282 | static int | ||
| 283 | lowpan_uncompress_multicast_daddr(struct sk_buff *skb, | ||
| 284 | struct in6_addr *ipaddr, | ||
| 285 | const u8 dam) | ||
| 286 | { | ||
| 287 | bool fail; | ||
| 288 | |||
| 289 | switch (dam) { | ||
| 290 | case LOWPAN_IPHC_DAM_00: | ||
| 291 | /* 00: 128 bits. The full address | ||
| 292 | * is carried in-line. | ||
| 293 | */ | ||
| 294 | fail = lowpan_fetch_skb(skb, ipaddr->s6_addr, 16); | ||
| 295 | break; | ||
| 296 | case LOWPAN_IPHC_DAM_01: | ||
| 297 | /* 01: 48 bits. The address takes | ||
| 298 | * the form ffXX::00XX:XXXX:XXXX. | ||
| 299 | */ | ||
| 300 | ipaddr->s6_addr[0] = 0xFF; | ||
| 301 | fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[1], 1); | ||
| 302 | fail |= lowpan_fetch_skb(skb, &ipaddr->s6_addr[11], 5); | ||
| 303 | break; | ||
| 304 | case LOWPAN_IPHC_DAM_10: | ||
| 305 | /* 10: 32 bits. The address takes | ||
| 306 | * the form ffXX::00XX:XXXX. | ||
| 307 | */ | ||
| 308 | ipaddr->s6_addr[0] = 0xFF; | ||
| 309 | fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[1], 1); | ||
| 310 | fail |= lowpan_fetch_skb(skb, &ipaddr->s6_addr[13], 3); | ||
| 311 | break; | ||
| 312 | case LOWPAN_IPHC_DAM_11: | ||
| 313 | /* 11: 8 bits. The address takes | ||
| 314 | * the form ff02::00XX. | ||
| 315 | */ | ||
| 316 | ipaddr->s6_addr[0] = 0xFF; | ||
| 317 | ipaddr->s6_addr[1] = 0x02; | ||
| 318 | fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[15], 1); | ||
| 319 | break; | ||
| 320 | default: | ||
| 321 | pr_debug("DAM value has a wrong value: 0x%x\n", dam); | ||
| 322 | return -EINVAL; | ||
| 323 | } | ||
| 324 | |||
| 325 | if (fail) { | ||
| 326 | pr_debug("Failed to fetch skb data\n"); | ||
| 327 | return -EIO; | ||
| 328 | } | ||
| 329 | |||
| 330 | lowpan_raw_dump_inline(NULL, "Reconstructed ipv6 multicast addr is:\n", | ||
| 331 | ipaddr->s6_addr, 16); | ||
| 332 | |||
| 333 | return 0; | ||
| 334 | } | ||
| 335 | |||
| 336 | static void | ||
| 337 | lowpan_compress_udp_header(u8 **hc06_ptr, struct sk_buff *skb) | ||
| 338 | { | ||
| 339 | struct udphdr *uh = udp_hdr(skb); | ||
| 340 | |||
| 341 | if (((uh->source & LOWPAN_NHC_UDP_4BIT_MASK) == | ||
| 342 | LOWPAN_NHC_UDP_4BIT_PORT) && | ||
| 343 | ((uh->dest & LOWPAN_NHC_UDP_4BIT_MASK) == | ||
| 344 | LOWPAN_NHC_UDP_4BIT_PORT)) { | ||
| 345 | pr_debug("UDP header: both ports compression to 4 bits\n"); | ||
| 346 | **hc06_ptr = LOWPAN_NHC_UDP_CS_P_11; | ||
| 347 | **(hc06_ptr + 1) = /* subtraction is faster */ | ||
| 348 | (u8)((uh->dest - LOWPAN_NHC_UDP_4BIT_PORT) + | ||
| 349 | ((uh->source & LOWPAN_NHC_UDP_4BIT_PORT) << 4)); | ||
| 350 | *hc06_ptr += 2; | ||
| 351 | } else if ((uh->dest & LOWPAN_NHC_UDP_8BIT_MASK) == | ||
| 352 | LOWPAN_NHC_UDP_8BIT_PORT) { | ||
| 353 | pr_debug("UDP header: remove 8 bits of dest\n"); | ||
| 354 | **hc06_ptr = LOWPAN_NHC_UDP_CS_P_01; | ||
| 355 | memcpy(*hc06_ptr + 1, &uh->source, 2); | ||
| 356 | **(hc06_ptr + 3) = (u8)(uh->dest - LOWPAN_NHC_UDP_8BIT_PORT); | ||
| 357 | *hc06_ptr += 4; | ||
| 358 | } else if ((uh->source & LOWPAN_NHC_UDP_8BIT_MASK) == | ||
| 359 | LOWPAN_NHC_UDP_8BIT_PORT) { | ||
| 360 | pr_debug("UDP header: remove 8 bits of source\n"); | ||
| 361 | **hc06_ptr = LOWPAN_NHC_UDP_CS_P_10; | ||
| 362 | memcpy(*hc06_ptr + 1, &uh->dest, 2); | ||
| 363 | **(hc06_ptr + 3) = (u8)(uh->source - LOWPAN_NHC_UDP_8BIT_PORT); | ||
| 364 | *hc06_ptr += 4; | ||
| 365 | } else { | ||
| 366 | pr_debug("UDP header: can't compress\n"); | ||
| 367 | **hc06_ptr = LOWPAN_NHC_UDP_CS_P_00; | ||
| 368 | memcpy(*hc06_ptr + 1, &uh->source, 2); | ||
| 369 | memcpy(*hc06_ptr + 3, &uh->dest, 2); | ||
| 370 | *hc06_ptr += 5; | ||
| 371 | } | ||
| 372 | |||
| 373 | /* checksum is always inline */ | ||
| 374 | memcpy(*hc06_ptr, &uh->check, 2); | ||
| 375 | *hc06_ptr += 2; | ||
| 376 | |||
| 377 | /* skip the UDP header */ | ||
| 378 | skb_pull(skb, sizeof(struct udphdr)); | ||
| 379 | } | ||
| 380 | |||
| 381 | static inline int lowpan_fetch_skb_u8(struct sk_buff *skb, u8 *val) | ||
| 382 | { | ||
| 383 | if (unlikely(!pskb_may_pull(skb, 1))) | ||
| 384 | return -EINVAL; | ||
| 385 | |||
| 386 | *val = skb->data[0]; | ||
| 387 | skb_pull(skb, 1); | ||
| 388 | |||
| 389 | return 0; | ||
| 390 | } | ||
| 391 | |||
| 392 | static inline int lowpan_fetch_skb_u16(struct sk_buff *skb, u16 *val) | ||
| 393 | { | ||
| 394 | if (unlikely(!pskb_may_pull(skb, 2))) | ||
| 395 | return -EINVAL; | ||
| 396 | |||
| 397 | *val = (skb->data[0] << 8) | skb->data[1]; | ||
| 398 | skb_pull(skb, 2); | ||
| 399 | |||
| 400 | return 0; | ||
| 401 | } | ||
| 402 | |||
| 403 | static int | ||
| 404 | lowpan_uncompress_udp_header(struct sk_buff *skb, struct udphdr *uh) | ||
| 405 | { | ||
| 406 | u8 tmp; | ||
| 407 | |||
| 408 | if (!uh) | ||
| 409 | goto err; | ||
| 410 | |||
| 411 | if (lowpan_fetch_skb_u8(skb, &tmp)) | ||
| 412 | goto err; | ||
| 413 | |||
| 414 | if ((tmp & LOWPAN_NHC_UDP_MASK) == LOWPAN_NHC_UDP_ID) { | ||
| 415 | pr_debug("UDP header uncompression\n"); | ||
| 416 | switch (tmp & LOWPAN_NHC_UDP_CS_P_11) { | ||
| 417 | case LOWPAN_NHC_UDP_CS_P_00: | ||
| 418 | memcpy(&uh->source, &skb->data[0], 2); | ||
| 419 | memcpy(&uh->dest, &skb->data[2], 2); | ||
| 420 | skb_pull(skb, 4); | ||
| 421 | break; | ||
| 422 | case LOWPAN_NHC_UDP_CS_P_01: | ||
| 423 | memcpy(&uh->source, &skb->data[0], 2); | ||
| 424 | uh->dest = | ||
| 425 | skb->data[2] + LOWPAN_NHC_UDP_8BIT_PORT; | ||
| 426 | skb_pull(skb, 3); | ||
| 427 | break; | ||
| 428 | case LOWPAN_NHC_UDP_CS_P_10: | ||
| 429 | uh->source = skb->data[0] + LOWPAN_NHC_UDP_8BIT_PORT; | ||
| 430 | memcpy(&uh->dest, &skb->data[1], 2); | ||
| 431 | skb_pull(skb, 3); | ||
| 432 | break; | ||
| 433 | case LOWPAN_NHC_UDP_CS_P_11: | ||
| 434 | uh->source = | ||
| 435 | LOWPAN_NHC_UDP_4BIT_PORT + (skb->data[0] >> 4); | ||
| 436 | uh->dest = | ||
| 437 | LOWPAN_NHC_UDP_4BIT_PORT + (skb->data[0] & 0x0f); | ||
| 438 | skb_pull(skb, 1); | ||
| 439 | break; | ||
| 440 | default: | ||
| 441 | pr_debug("ERROR: unknown UDP format\n"); | ||
| 442 | goto err; | ||
| 443 | } | ||
| 444 | |||
| 445 | pr_debug("uncompressed UDP ports: src = %d, dst = %d\n", | ||
| 446 | uh->source, uh->dest); | ||
| 447 | |||
| 448 | /* copy checksum */ | ||
| 449 | memcpy(&uh->check, &skb->data[0], 2); | ||
| 450 | skb_pull(skb, 2); | ||
| 451 | |||
| 452 | /* | ||
| 453 | * UDP lenght needs to be infered from the lower layers | ||
| 454 | * here, we obtain the hint from the remaining size of the | ||
| 455 | * frame | ||
| 456 | */ | ||
| 457 | uh->len = htons(skb->len + sizeof(struct udphdr)); | ||
| 458 | pr_debug("uncompressed UDP length: src = %d", uh->len); | ||
| 459 | } else { | ||
| 460 | pr_debug("ERROR: unsupported NH format\n"); | ||
| 461 | goto err; | ||
| 462 | } | ||
| 463 | |||
| 464 | return 0; | ||
| 465 | err: | ||
| 466 | return -EINVAL; | ||
| 467 | } | ||
| 468 | |||
| 469 | static int lowpan_header_create(struct sk_buff *skb, | 104 | static int lowpan_header_create(struct sk_buff *skb, |
| 470 | struct net_device *dev, | 105 | struct net_device *dev, |
| 471 | unsigned short type, const void *_daddr, | 106 | unsigned short type, const void *_daddr, |
| 472 | const void *_saddr, unsigned int len) | 107 | const void *_saddr, unsigned int len) |
| 473 | { | 108 | { |
| 474 | u8 tmp, iphc0, iphc1, *hc06_ptr; | ||
| 475 | struct ipv6hdr *hdr; | 109 | struct ipv6hdr *hdr; |
| 476 | const u8 *saddr = _saddr; | 110 | const u8 *saddr = _saddr; |
| 477 | const u8 *daddr = _daddr; | 111 | const u8 *daddr = _daddr; |
| 478 | u8 head[100]; | ||
| 479 | struct ieee802154_addr sa, da; | 112 | struct ieee802154_addr sa, da; |
| 480 | 113 | ||
| 481 | /* TODO: | 114 | /* TODO: |
| @@ -485,181 +118,14 @@ static int lowpan_header_create(struct sk_buff *skb, | |||
| 485 | return 0; | 118 | return 0; |
| 486 | 119 | ||
| 487 | hdr = ipv6_hdr(skb); | 120 | hdr = ipv6_hdr(skb); |
| 488 | hc06_ptr = head + 2; | ||
| 489 | |||
| 490 | pr_debug("IPv6 header dump:\n\tversion = %d\n\tlength = %d\n" | ||
| 491 | "\tnexthdr = 0x%02x\n\thop_lim = %d\n", hdr->version, | ||
| 492 | ntohs(hdr->payload_len), hdr->nexthdr, hdr->hop_limit); | ||
| 493 | |||
| 494 | lowpan_raw_dump_table(__func__, "raw skb network header dump", | ||
| 495 | skb_network_header(skb), sizeof(struct ipv6hdr)); | ||
| 496 | 121 | ||
| 497 | if (!saddr) | 122 | if (!saddr) |
| 498 | saddr = dev->dev_addr; | 123 | saddr = dev->dev_addr; |
| 499 | 124 | ||
| 500 | lowpan_raw_dump_inline(__func__, "saddr", (unsigned char *)saddr, 8); | 125 | raw_dump_inline(__func__, "saddr", (unsigned char *)saddr, 8); |
| 501 | 126 | raw_dump_inline(__func__, "daddr", (unsigned char *)daddr, 8); | |
| 502 | /* | ||
| 503 | * As we copy some bit-length fields, in the IPHC encoding bytes, | ||
| 504 | * we sometimes use |= | ||
| 505 | * If the field is 0, and the current bit value in memory is 1, | ||
| 506 | * this does not work. We therefore reset the IPHC encoding here | ||
| 507 | */ | ||
| 508 | iphc0 = LOWPAN_DISPATCH_IPHC; | ||
| 509 | iphc1 = 0; | ||
| 510 | |||
| 511 | /* TODO: context lookup */ | ||
| 512 | 127 | ||
| 513 | lowpan_raw_dump_inline(__func__, "daddr", (unsigned char *)daddr, 8); | 128 | lowpan_header_compress(skb, dev, type, daddr, saddr, len); |
| 514 | |||
| 515 | /* | ||
| 516 | * Traffic class, flow label | ||
| 517 | * If flow label is 0, compress it. If traffic class is 0, compress it | ||
| 518 | * We have to process both in the same time as the offset of traffic | ||
| 519 | * class depends on the presence of version and flow label | ||
| 520 | */ | ||
| 521 | |||
| 522 | /* hc06 format of TC is ECN | DSCP , original one is DSCP | ECN */ | ||
| 523 | tmp = (hdr->priority << 4) | (hdr->flow_lbl[0] >> 4); | ||
| 524 | tmp = ((tmp & 0x03) << 6) | (tmp >> 2); | ||
| 525 | |||
| 526 | if (((hdr->flow_lbl[0] & 0x0F) == 0) && | ||
| 527 | (hdr->flow_lbl[1] == 0) && (hdr->flow_lbl[2] == 0)) { | ||
| 528 | /* flow label can be compressed */ | ||
| 529 | iphc0 |= LOWPAN_IPHC_FL_C; | ||
| 530 | if ((hdr->priority == 0) && | ||
| 531 | ((hdr->flow_lbl[0] & 0xF0) == 0)) { | ||
| 532 | /* compress (elide) all */ | ||
| 533 | iphc0 |= LOWPAN_IPHC_TC_C; | ||
| 534 | } else { | ||
| 535 | /* compress only the flow label */ | ||
| 536 | *hc06_ptr = tmp; | ||
| 537 | hc06_ptr += 1; | ||
| 538 | } | ||
| 539 | } else { | ||
| 540 | /* Flow label cannot be compressed */ | ||
| 541 | if ((hdr->priority == 0) && | ||
| 542 | ((hdr->flow_lbl[0] & 0xF0) == 0)) { | ||
| 543 | /* compress only traffic class */ | ||
| 544 | iphc0 |= LOWPAN_IPHC_TC_C; | ||
| 545 | *hc06_ptr = (tmp & 0xc0) | (hdr->flow_lbl[0] & 0x0F); | ||
| 546 | memcpy(hc06_ptr + 1, &hdr->flow_lbl[1], 2); | ||
| 547 | hc06_ptr += 3; | ||
| 548 | } else { | ||
| 549 | /* compress nothing */ | ||
| 550 | memcpy(hc06_ptr, hdr, 4); | ||
| 551 | /* replace the top byte with new ECN | DSCP format */ | ||
| 552 | *hc06_ptr = tmp; | ||
| 553 | hc06_ptr += 4; | ||
| 554 | } | ||
| 555 | } | ||
| 556 | |||
| 557 | /* NOTE: payload length is always compressed */ | ||
| 558 | |||
| 559 | /* Next Header is compress if UDP */ | ||
| 560 | if (hdr->nexthdr == UIP_PROTO_UDP) | ||
| 561 | iphc0 |= LOWPAN_IPHC_NH_C; | ||
| 562 | |||
| 563 | if ((iphc0 & LOWPAN_IPHC_NH_C) == 0) { | ||
| 564 | *hc06_ptr = hdr->nexthdr; | ||
| 565 | hc06_ptr += 1; | ||
| 566 | } | ||
| 567 | |||
| 568 | /* | ||
| 569 | * Hop limit | ||
| 570 | * if 1: compress, encoding is 01 | ||
| 571 | * if 64: compress, encoding is 10 | ||
| 572 | * if 255: compress, encoding is 11 | ||
| 573 | * else do not compress | ||
| 574 | */ | ||
| 575 | switch (hdr->hop_limit) { | ||
| 576 | case 1: | ||
| 577 | iphc0 |= LOWPAN_IPHC_TTL_1; | ||
| 578 | break; | ||
| 579 | case 64: | ||
| 580 | iphc0 |= LOWPAN_IPHC_TTL_64; | ||
| 581 | break; | ||
| 582 | case 255: | ||
| 583 | iphc0 |= LOWPAN_IPHC_TTL_255; | ||
| 584 | break; | ||
| 585 | default: | ||
| 586 | *hc06_ptr = hdr->hop_limit; | ||
| 587 | hc06_ptr += 1; | ||
| 588 | break; | ||
| 589 | } | ||
| 590 | |||
| 591 | /* source address compression */ | ||
| 592 | if (is_addr_unspecified(&hdr->saddr)) { | ||
| 593 | pr_debug("source address is unspecified, setting SAC\n"); | ||
| 594 | iphc1 |= LOWPAN_IPHC_SAC; | ||
| 595 | /* TODO: context lookup */ | ||
| 596 | } else if (is_addr_link_local(&hdr->saddr)) { | ||
| 597 | pr_debug("source address is link-local\n"); | ||
| 598 | iphc1 |= lowpan_compress_addr_64(&hc06_ptr, | ||
| 599 | LOWPAN_IPHC_SAM_BIT, &hdr->saddr, saddr); | ||
| 600 | } else { | ||
| 601 | pr_debug("send the full source address\n"); | ||
| 602 | memcpy(hc06_ptr, &hdr->saddr.s6_addr16[0], 16); | ||
| 603 | hc06_ptr += 16; | ||
| 604 | } | ||
| 605 | |||
| 606 | /* destination address compression */ | ||
| 607 | if (is_addr_mcast(&hdr->daddr)) { | ||
| 608 | pr_debug("destination address is multicast: "); | ||
| 609 | iphc1 |= LOWPAN_IPHC_M; | ||
| 610 | if (lowpan_is_mcast_addr_compressable8(&hdr->daddr)) { | ||
| 611 | pr_debug("compressed to 1 octet\n"); | ||
| 612 | iphc1 |= LOWPAN_IPHC_DAM_11; | ||
| 613 | /* use last byte */ | ||
| 614 | *hc06_ptr = hdr->daddr.s6_addr[15]; | ||
| 615 | hc06_ptr += 1; | ||
| 616 | } else if (lowpan_is_mcast_addr_compressable32(&hdr->daddr)) { | ||
| 617 | pr_debug("compressed to 4 octets\n"); | ||
| 618 | iphc1 |= LOWPAN_IPHC_DAM_10; | ||
| 619 | /* second byte + the last three */ | ||
| 620 | *hc06_ptr = hdr->daddr.s6_addr[1]; | ||
| 621 | memcpy(hc06_ptr + 1, &hdr->daddr.s6_addr[13], 3); | ||
| 622 | hc06_ptr += 4; | ||
| 623 | } else if (lowpan_is_mcast_addr_compressable48(&hdr->daddr)) { | ||
| 624 | pr_debug("compressed to 6 octets\n"); | ||
| 625 | iphc1 |= LOWPAN_IPHC_DAM_01; | ||
| 626 | /* second byte + the last five */ | ||
| 627 | *hc06_ptr = hdr->daddr.s6_addr[1]; | ||
| 628 | memcpy(hc06_ptr + 1, &hdr->daddr.s6_addr[11], 5); | ||
| 629 | hc06_ptr += 6; | ||
| 630 | } else { | ||
| 631 | pr_debug("using full address\n"); | ||
| 632 | iphc1 |= LOWPAN_IPHC_DAM_00; | ||
| 633 | memcpy(hc06_ptr, &hdr->daddr.s6_addr[0], 16); | ||
| 634 | hc06_ptr += 16; | ||
| 635 | } | ||
| 636 | } else { | ||
| 637 | /* TODO: context lookup */ | ||
| 638 | if (is_addr_link_local(&hdr->daddr)) { | ||
| 639 | pr_debug("dest address is unicast and link-local\n"); | ||
| 640 | iphc1 |= lowpan_compress_addr_64(&hc06_ptr, | ||
| 641 | LOWPAN_IPHC_DAM_BIT, &hdr->daddr, daddr); | ||
| 642 | } else { | ||
| 643 | pr_debug("dest address is unicast: using full one\n"); | ||
| 644 | memcpy(hc06_ptr, &hdr->daddr.s6_addr16[0], 16); | ||
| 645 | hc06_ptr += 16; | ||
| 646 | } | ||
| 647 | } | ||
| 648 | |||
| 649 | /* UDP header compression */ | ||
| 650 | if (hdr->nexthdr == UIP_PROTO_UDP) | ||
| 651 | lowpan_compress_udp_header(&hc06_ptr, skb); | ||
| 652 | |||
| 653 | head[0] = iphc0; | ||
| 654 | head[1] = iphc1; | ||
| 655 | |||
| 656 | skb_pull(skb, sizeof(struct ipv6hdr)); | ||
| 657 | skb_reset_transport_header(skb); | ||
| 658 | memcpy(skb_push(skb, hc06_ptr - head), head, hc06_ptr - head); | ||
| 659 | skb_reset_network_header(skb); | ||
| 660 | |||
| 661 | lowpan_raw_dump_table(__func__, "raw skb data dump", skb->data, | ||
| 662 | skb->len); | ||
| 663 | 129 | ||
| 664 | /* | 130 | /* |
| 665 | * NOTE1: I'm still unsure about the fact that compression and WPAN | 131 | * NOTE1: I'm still unsure about the fact that compression and WPAN |
| @@ -671,39 +137,38 @@ static int lowpan_header_create(struct sk_buff *skb, | |||
| 671 | * from MAC subif of the 'dev' and 'real_dev' network devices, but | 137 | * from MAC subif of the 'dev' and 'real_dev' network devices, but |
| 672 | * this isn't implemented in mainline yet, so currently we assign 0xff | 138 | * this isn't implemented in mainline yet, so currently we assign 0xff |
| 673 | */ | 139 | */ |
| 674 | { | 140 | mac_cb(skb)->flags = IEEE802154_FC_TYPE_DATA; |
| 675 | mac_cb(skb)->flags = IEEE802154_FC_TYPE_DATA; | 141 | mac_cb(skb)->seq = ieee802154_mlme_ops(dev)->get_dsn(dev); |
| 676 | mac_cb(skb)->seq = ieee802154_mlme_ops(dev)->get_dsn(dev); | ||
| 677 | 142 | ||
| 678 | /* prepare wpan address data */ | 143 | /* prepare wpan address data */ |
| 679 | sa.addr_type = IEEE802154_ADDR_LONG; | 144 | sa.addr_type = IEEE802154_ADDR_LONG; |
| 680 | sa.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev); | 145 | sa.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev); |
| 681 | 146 | ||
| 682 | memcpy(&(sa.hwaddr), saddr, 8); | 147 | memcpy(&(sa.hwaddr), saddr, 8); |
| 683 | /* intra-PAN communications */ | 148 | /* intra-PAN communications */ |
| 684 | da.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev); | 149 | da.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev); |
| 685 | 150 | ||
| 686 | /* | 151 | /* |
| 687 | * if the destination address is the broadcast address, use the | 152 | * if the destination address is the broadcast address, use the |
| 688 | * corresponding short address | 153 | * corresponding short address |
| 689 | */ | 154 | */ |
| 690 | if (lowpan_is_addr_broadcast(daddr)) { | 155 | if (lowpan_is_addr_broadcast(daddr)) { |
| 691 | da.addr_type = IEEE802154_ADDR_SHORT; | 156 | da.addr_type = IEEE802154_ADDR_SHORT; |
| 692 | da.short_addr = IEEE802154_ADDR_BROADCAST; | 157 | da.short_addr = IEEE802154_ADDR_BROADCAST; |
| 693 | } else { | 158 | } else { |
| 694 | da.addr_type = IEEE802154_ADDR_LONG; | 159 | da.addr_type = IEEE802154_ADDR_LONG; |
| 695 | memcpy(&(da.hwaddr), daddr, IEEE802154_ADDR_LEN); | 160 | memcpy(&(da.hwaddr), daddr, IEEE802154_ADDR_LEN); |
| 696 | |||
| 697 | /* request acknowledgment */ | ||
| 698 | mac_cb(skb)->flags |= MAC_CB_FLAG_ACKREQ; | ||
| 699 | } | ||
| 700 | 161 | ||
| 701 | return dev_hard_header(skb, lowpan_dev_info(dev)->real_dev, | 162 | /* request acknowledgment */ |
| 702 | type, (void *)&da, (void *)&sa, skb->len); | 163 | mac_cb(skb)->flags |= MAC_CB_FLAG_ACKREQ; |
| 703 | } | 164 | } |
| 165 | |||
| 166 | return dev_hard_header(skb, lowpan_dev_info(dev)->real_dev, | ||
| 167 | type, (void *)&da, (void *)&sa, skb->len); | ||
| 704 | } | 168 | } |
| 705 | 169 | ||
| 706 | static int lowpan_give_skb_to_devices(struct sk_buff *skb) | 170 | static int lowpan_give_skb_to_devices(struct sk_buff *skb, |
| 171 | struct net_device *dev) | ||
| 707 | { | 172 | { |
| 708 | struct lowpan_dev_record *entry; | 173 | struct lowpan_dev_record *entry; |
| 709 | struct sk_buff *skb_cp; | 174 | struct sk_buff *skb_cp; |
| @@ -726,31 +191,6 @@ static int lowpan_give_skb_to_devices(struct sk_buff *skb) | |||
| 726 | return stat; | 191 | return stat; |
| 727 | } | 192 | } |
| 728 | 193 | ||
| 729 | static int lowpan_skb_deliver(struct sk_buff *skb, struct ipv6hdr *hdr) | ||
| 730 | { | ||
| 731 | struct sk_buff *new; | ||
| 732 | int stat = NET_RX_SUCCESS; | ||
| 733 | |||
| 734 | new = skb_copy_expand(skb, sizeof(struct ipv6hdr), skb_tailroom(skb), | ||
| 735 | GFP_ATOMIC); | ||
| 736 | kfree_skb(skb); | ||
| 737 | |||
| 738 | if (!new) | ||
| 739 | return -ENOMEM; | ||
| 740 | |||
| 741 | skb_push(new, sizeof(struct ipv6hdr)); | ||
| 742 | skb_copy_to_linear_data(new, hdr, sizeof(struct ipv6hdr)); | ||
| 743 | |||
| 744 | new->protocol = htons(ETH_P_IPV6); | ||
| 745 | new->pkt_type = PACKET_HOST; | ||
| 746 | |||
| 747 | stat = lowpan_give_skb_to_devices(new); | ||
| 748 | |||
| 749 | kfree_skb(new); | ||
| 750 | |||
| 751 | return stat; | ||
| 752 | } | ||
| 753 | |||
| 754 | static void lowpan_fragment_timer_expired(unsigned long entry_addr) | 194 | static void lowpan_fragment_timer_expired(unsigned long entry_addr) |
| 755 | { | 195 | { |
| 756 | struct lowpan_fragment *entry = (struct lowpan_fragment *)entry_addr; | 196 | struct lowpan_fragment *entry = (struct lowpan_fragment *)entry_addr; |
| @@ -814,16 +254,12 @@ frame_err: | |||
| 814 | return NULL; | 254 | return NULL; |
| 815 | } | 255 | } |
| 816 | 256 | ||
| 817 | static int | 257 | static int process_data(struct sk_buff *skb) |
| 818 | lowpan_process_data(struct sk_buff *skb) | ||
| 819 | { | 258 | { |
| 820 | struct ipv6hdr hdr = {}; | 259 | u8 iphc0, iphc1; |
| 821 | u8 tmp, iphc0, iphc1, num_context = 0; | ||
| 822 | const struct ieee802154_addr *_saddr, *_daddr; | 260 | const struct ieee802154_addr *_saddr, *_daddr; |
| 823 | int err; | ||
| 824 | 261 | ||
| 825 | lowpan_raw_dump_table(__func__, "raw skb data dump", skb->data, | 262 | raw_dump_table(__func__, "raw skb data dump", skb->data, skb->len); |
| 826 | skb->len); | ||
| 827 | /* at least two bytes will be used for the encoding */ | 263 | /* at least two bytes will be used for the encoding */ |
| 828 | if (skb->len < 2) | 264 | if (skb->len < 2) |
| 829 | goto drop; | 265 | goto drop; |
| @@ -925,162 +361,11 @@ lowpan_process_data(struct sk_buff *skb) | |||
| 925 | _saddr = &mac_cb(skb)->sa; | 361 | _saddr = &mac_cb(skb)->sa; |
| 926 | _daddr = &mac_cb(skb)->da; | 362 | _daddr = &mac_cb(skb)->da; |
| 927 | 363 | ||
| 928 | pr_debug("iphc0 = %02x, iphc1 = %02x\n", iphc0, iphc1); | 364 | return lowpan_process_data(skb, skb->dev, (u8 *)_saddr->hwaddr, |
| 929 | 365 | _saddr->addr_type, IEEE802154_ADDR_LEN, | |
| 930 | /* another if the CID flag is set */ | 366 | (u8 *)_daddr->hwaddr, _daddr->addr_type, |
| 931 | if (iphc1 & LOWPAN_IPHC_CID) { | 367 | IEEE802154_ADDR_LEN, iphc0, iphc1, |
| 932 | pr_debug("CID flag is set, increase header with one\n"); | 368 | lowpan_give_skb_to_devices); |
| 933 | if (lowpan_fetch_skb_u8(skb, &num_context)) | ||
| 934 | goto drop; | ||
| 935 | } | ||
| 936 | |||
| 937 | hdr.version = 6; | ||
| 938 | |||
| 939 | /* Traffic Class and Flow Label */ | ||
| 940 | switch ((iphc0 & LOWPAN_IPHC_TF) >> 3) { | ||
| 941 | /* | ||
| 942 | * Traffic Class and FLow Label carried in-line | ||
| 943 | * ECN + DSCP + 4-bit Pad + Flow Label (4 bytes) | ||
| 944 | */ | ||
| 945 | case 0: /* 00b */ | ||
| 946 | if (lowpan_fetch_skb_u8(skb, &tmp)) | ||
| 947 | goto drop; | ||
| 948 | |||
| 949 | memcpy(&hdr.flow_lbl, &skb->data[0], 3); | ||
| 950 | skb_pull(skb, 3); | ||
| 951 | hdr.priority = ((tmp >> 2) & 0x0f); | ||
| 952 | hdr.flow_lbl[0] = ((tmp >> 2) & 0x30) | (tmp << 6) | | ||
| 953 | (hdr.flow_lbl[0] & 0x0f); | ||
| 954 | break; | ||
| 955 | /* | ||
| 956 | * Traffic class carried in-line | ||
| 957 | * ECN + DSCP (1 byte), Flow Label is elided | ||
| 958 | */ | ||
| 959 | case 2: /* 10b */ | ||
| 960 | if (lowpan_fetch_skb_u8(skb, &tmp)) | ||
| 961 | goto drop; | ||
| 962 | |||
| 963 | hdr.priority = ((tmp >> 2) & 0x0f); | ||
| 964 | hdr.flow_lbl[0] = ((tmp << 6) & 0xC0) | ((tmp >> 2) & 0x30); | ||
| 965 | break; | ||
| 966 | /* | ||
| 967 | * Flow Label carried in-line | ||
| 968 | * ECN + 2-bit Pad + Flow Label (3 bytes), DSCP is elided | ||
| 969 | */ | ||
| 970 | case 1: /* 01b */ | ||
| 971 | if (lowpan_fetch_skb_u8(skb, &tmp)) | ||
| 972 | goto drop; | ||
| 973 | |||
| 974 | hdr.flow_lbl[0] = (skb->data[0] & 0x0F) | ((tmp >> 2) & 0x30); | ||
| 975 | memcpy(&hdr.flow_lbl[1], &skb->data[0], 2); | ||
| 976 | skb_pull(skb, 2); | ||
| 977 | break; | ||
| 978 | /* Traffic Class and Flow Label are elided */ | ||
| 979 | case 3: /* 11b */ | ||
| 980 | break; | ||
| 981 | default: | ||
| 982 | break; | ||
| 983 | } | ||
| 984 | |||
| 985 | /* Next Header */ | ||
| 986 | if ((iphc0 & LOWPAN_IPHC_NH_C) == 0) { | ||
| 987 | /* Next header is carried inline */ | ||
| 988 | if (lowpan_fetch_skb_u8(skb, &(hdr.nexthdr))) | ||
| 989 | goto drop; | ||
| 990 | |||
| 991 | pr_debug("NH flag is set, next header carried inline: %02x\n", | ||
| 992 | hdr.nexthdr); | ||
| 993 | } | ||
| 994 | |||
| 995 | /* Hop Limit */ | ||
| 996 | if ((iphc0 & 0x03) != LOWPAN_IPHC_TTL_I) | ||
| 997 | hdr.hop_limit = lowpan_ttl_values[iphc0 & 0x03]; | ||
| 998 | else { | ||
| 999 | if (lowpan_fetch_skb_u8(skb, &(hdr.hop_limit))) | ||
| 1000 | goto drop; | ||
| 1001 | } | ||
| 1002 | |||
| 1003 | /* Extract SAM to the tmp variable */ | ||
| 1004 | tmp = ((iphc1 & LOWPAN_IPHC_SAM) >> LOWPAN_IPHC_SAM_BIT) & 0x03; | ||
| 1005 | |||
| 1006 | if (iphc1 & LOWPAN_IPHC_SAC) { | ||
| 1007 | /* Source address context based uncompression */ | ||
| 1008 | pr_debug("SAC bit is set. Handle context based source address.\n"); | ||
| 1009 | err = lowpan_uncompress_context_based_src_addr( | ||
| 1010 | skb, &hdr.saddr, tmp); | ||
| 1011 | } else { | ||
| 1012 | /* Source address uncompression */ | ||
| 1013 | pr_debug("source address stateless compression\n"); | ||
| 1014 | err = lowpan_uncompress_addr(skb, &hdr.saddr, tmp, _saddr); | ||
| 1015 | } | ||
| 1016 | |||
| 1017 | /* Check on error of previous branch */ | ||
| 1018 | if (err) | ||
| 1019 | goto drop; | ||
| 1020 | |||
| 1021 | /* Extract DAM to the tmp variable */ | ||
| 1022 | tmp = ((iphc1 & LOWPAN_IPHC_DAM_11) >> LOWPAN_IPHC_DAM_BIT) & 0x03; | ||
| 1023 | |||
| 1024 | /* check for Multicast Compression */ | ||
| 1025 | if (iphc1 & LOWPAN_IPHC_M) { | ||
| 1026 | if (iphc1 & LOWPAN_IPHC_DAC) { | ||
| 1027 | pr_debug("dest: context-based mcast compression\n"); | ||
| 1028 | /* TODO: implement this */ | ||
| 1029 | } else { | ||
| 1030 | err = lowpan_uncompress_multicast_daddr( | ||
| 1031 | skb, &hdr.daddr, tmp); | ||
| 1032 | if (err) | ||
| 1033 | goto drop; | ||
| 1034 | } | ||
| 1035 | } else { | ||
| 1036 | pr_debug("dest: stateless compression\n"); | ||
| 1037 | err = lowpan_uncompress_addr(skb, &hdr.daddr, tmp, _daddr); | ||
| 1038 | if (err) | ||
| 1039 | goto drop; | ||
| 1040 | } | ||
| 1041 | |||
| 1042 | /* UDP data uncompression */ | ||
| 1043 | if (iphc0 & LOWPAN_IPHC_NH_C) { | ||
| 1044 | struct udphdr uh; | ||
| 1045 | struct sk_buff *new; | ||
| 1046 | if (lowpan_uncompress_udp_header(skb, &uh)) | ||
| 1047 | goto drop; | ||
| 1048 | |||
| 1049 | /* | ||
| 1050 | * replace the compressed UDP head by the uncompressed UDP | ||
| 1051 | * header | ||
| 1052 | */ | ||
| 1053 | new = skb_copy_expand(skb, sizeof(struct udphdr), | ||
| 1054 | skb_tailroom(skb), GFP_ATOMIC); | ||
| 1055 | kfree_skb(skb); | ||
| 1056 | |||
| 1057 | if (!new) | ||
| 1058 | return -ENOMEM; | ||
| 1059 | |||
| 1060 | skb = new; | ||
| 1061 | |||
| 1062 | skb_push(skb, sizeof(struct udphdr)); | ||
| 1063 | skb_copy_to_linear_data(skb, &uh, sizeof(struct udphdr)); | ||
| 1064 | |||
| 1065 | lowpan_raw_dump_table(__func__, "raw UDP header dump", | ||
| 1066 | (u8 *)&uh, sizeof(uh)); | ||
| 1067 | |||
| 1068 | hdr.nexthdr = UIP_PROTO_UDP; | ||
| 1069 | } | ||
| 1070 | |||
| 1071 | /* Not fragmented package */ | ||
| 1072 | hdr.payload_len = htons(skb->len); | ||
| 1073 | |||
| 1074 | pr_debug("skb headroom size = %d, data length = %d\n", | ||
| 1075 | skb_headroom(skb), skb->len); | ||
| 1076 | |||
| 1077 | pr_debug("IPv6 header dump:\n\tversion = %d\n\tlength = %d\n\t" | ||
| 1078 | "nexthdr = 0x%02x\n\thop_lim = %d\n", hdr.version, | ||
| 1079 | ntohs(hdr.payload_len), hdr.nexthdr, hdr.hop_limit); | ||
| 1080 | |||
| 1081 | lowpan_raw_dump_table(__func__, "raw header dump", (u8 *)&hdr, | ||
| 1082 | sizeof(hdr)); | ||
| 1083 | return lowpan_skb_deliver(skb, &hdr); | ||
| 1084 | 369 | ||
| 1085 | unlock_and_drop: | 370 | unlock_and_drop: |
| 1086 | spin_unlock_bh(&flist_lock); | 371 | spin_unlock_bh(&flist_lock); |
| @@ -1112,7 +397,7 @@ lowpan_fragment_xmit(struct sk_buff *skb, u8 *head, | |||
| 1112 | hlen = (type == LOWPAN_DISPATCH_FRAG1) ? | 397 | hlen = (type == LOWPAN_DISPATCH_FRAG1) ? |
| 1113 | LOWPAN_FRAG1_HEAD_SIZE : LOWPAN_FRAGN_HEAD_SIZE; | 398 | LOWPAN_FRAG1_HEAD_SIZE : LOWPAN_FRAGN_HEAD_SIZE; |
| 1114 | 399 | ||
| 1115 | lowpan_raw_dump_inline(__func__, "6lowpan fragment header", head, hlen); | 400 | raw_dump_inline(__func__, "6lowpan fragment header", head, hlen); |
| 1116 | 401 | ||
| 1117 | frag = netdev_alloc_skb(skb->dev, | 402 | frag = netdev_alloc_skb(skb->dev, |
| 1118 | hlen + mlen + plen + IEEE802154_MFR_SIZE); | 403 | hlen + mlen + plen + IEEE802154_MFR_SIZE); |
| @@ -1132,8 +417,7 @@ lowpan_fragment_xmit(struct sk_buff *skb, u8 *head, | |||
| 1132 | skb_copy_to_linear_data_offset(frag, mlen + hlen, | 417 | skb_copy_to_linear_data_offset(frag, mlen + hlen, |
| 1133 | skb_network_header(skb) + offset, plen); | 418 | skb_network_header(skb) + offset, plen); |
| 1134 | 419 | ||
| 1135 | lowpan_raw_dump_table(__func__, " raw fragment dump", frag->data, | 420 | raw_dump_table(__func__, " raw fragment dump", frag->data, frag->len); |
| 1136 | frag->len); | ||
| 1137 | 421 | ||
| 1138 | return dev_queue_xmit(frag); | 422 | return dev_queue_xmit(frag); |
| 1139 | } | 423 | } |
| @@ -1316,7 +600,7 @@ static int lowpan_rcv(struct sk_buff *skb, struct net_device *dev, | |||
| 1316 | /* Pull off the 1-byte of 6lowpan header. */ | 600 | /* Pull off the 1-byte of 6lowpan header. */ |
| 1317 | skb_pull(local_skb, 1); | 601 | skb_pull(local_skb, 1); |
| 1318 | 602 | ||
| 1319 | lowpan_give_skb_to_devices(local_skb); | 603 | lowpan_give_skb_to_devices(local_skb, NULL); |
| 1320 | 604 | ||
| 1321 | kfree_skb(local_skb); | 605 | kfree_skb(local_skb); |
| 1322 | kfree_skb(skb); | 606 | kfree_skb(skb); |
| @@ -1328,7 +612,7 @@ static int lowpan_rcv(struct sk_buff *skb, struct net_device *dev, | |||
| 1328 | local_skb = skb_clone(skb, GFP_ATOMIC); | 612 | local_skb = skb_clone(skb, GFP_ATOMIC); |
| 1329 | if (!local_skb) | 613 | if (!local_skb) |
| 1330 | goto drop; | 614 | goto drop; |
| 1331 | lowpan_process_data(local_skb); | 615 | process_data(local_skb); |
| 1332 | 616 | ||
| 1333 | kfree_skb(skb); | 617 | kfree_skb(skb); |
| 1334 | break; | 618 | break; |
diff --git a/net/ieee802154/6lowpan.h b/net/ieee802154/6lowpan.h index 2869c0526dad..2b835db3bda8 100644 --- a/net/ieee802154/6lowpan.h +++ b/net/ieee802154/6lowpan.h | |||
| @@ -231,6 +231,61 @@ | |||
| 231 | #define LOWPAN_NHC_UDP_CS_P_10 0xF2 /* source = 0xF0 + 8bit inline, | 231 | #define LOWPAN_NHC_UDP_CS_P_10 0xF2 /* source = 0xF0 + 8bit inline, |
| 232 | dest = 16 bit inline */ | 232 | dest = 16 bit inline */ |
| 233 | #define LOWPAN_NHC_UDP_CS_P_11 0xF3 /* source & dest = 0xF0B + 4bit inline */ | 233 | #define LOWPAN_NHC_UDP_CS_P_11 0xF3 /* source & dest = 0xF0B + 4bit inline */ |
| 234 | #define LOWPAN_NHC_UDP_CS_C 0x04 /* checksum elided */ | ||
| 235 | |||
| 236 | #ifdef DEBUG | ||
| 237 | /* print data in line */ | ||
| 238 | static inline void raw_dump_inline(const char *caller, char *msg, | ||
| 239 | unsigned char *buf, int len) | ||
| 240 | { | ||
| 241 | if (msg) | ||
| 242 | pr_debug("%s():%s: ", caller, msg); | ||
| 243 | |||
| 244 | print_hex_dump_debug("", DUMP_PREFIX_NONE, 16, 1, buf, len, false); | ||
| 245 | } | ||
| 246 | |||
| 247 | /* print data in a table format: | ||
| 248 | * | ||
| 249 | * addr: xx xx xx xx xx xx | ||
| 250 | * addr: xx xx xx xx xx xx | ||
| 251 | * ... | ||
| 252 | */ | ||
| 253 | static inline void raw_dump_table(const char *caller, char *msg, | ||
| 254 | unsigned char *buf, int len) | ||
| 255 | { | ||
| 256 | if (msg) | ||
| 257 | pr_debug("%s():%s:\n", caller, msg); | ||
| 258 | |||
| 259 | print_hex_dump_debug("\t", DUMP_PREFIX_OFFSET, 16, 1, buf, len, false); | ||
| 260 | } | ||
| 261 | #else | ||
| 262 | static inline void raw_dump_table(const char *caller, char *msg, | ||
| 263 | unsigned char *buf, int len) { } | ||
| 264 | static inline void raw_dump_inline(const char *caller, char *msg, | ||
| 265 | unsigned char *buf, int len) { } | ||
| 266 | #endif | ||
| 267 | |||
| 268 | static inline int lowpan_fetch_skb_u8(struct sk_buff *skb, u8 *val) | ||
| 269 | { | ||
| 270 | if (unlikely(!pskb_may_pull(skb, 1))) | ||
| 271 | return -EINVAL; | ||
| 272 | |||
| 273 | *val = skb->data[0]; | ||
| 274 | skb_pull(skb, 1); | ||
| 275 | |||
| 276 | return 0; | ||
| 277 | } | ||
| 278 | |||
| 279 | static inline int lowpan_fetch_skb_u16(struct sk_buff *skb, u16 *val) | ||
| 280 | { | ||
| 281 | if (unlikely(!pskb_may_pull(skb, 2))) | ||
| 282 | return -EINVAL; | ||
| 283 | |||
| 284 | *val = (skb->data[0] << 8) | skb->data[1]; | ||
| 285 | skb_pull(skb, 2); | ||
| 286 | |||
| 287 | return 0; | ||
| 288 | } | ||
| 234 | 289 | ||
| 235 | static inline bool lowpan_fetch_skb(struct sk_buff *skb, | 290 | static inline bool lowpan_fetch_skb(struct sk_buff *skb, |
| 236 | void *data, const unsigned int len) | 291 | void *data, const unsigned int len) |
| @@ -244,4 +299,21 @@ static inline bool lowpan_fetch_skb(struct sk_buff *skb, | |||
| 244 | return false; | 299 | return false; |
| 245 | } | 300 | } |
| 246 | 301 | ||
| 302 | static inline void lowpan_push_hc_data(u8 **hc_ptr, const void *data, | ||
| 303 | const size_t len) | ||
| 304 | { | ||
| 305 | memcpy(*hc_ptr, data, len); | ||
| 306 | *hc_ptr += len; | ||
| 307 | } | ||
| 308 | |||
| 309 | typedef int (*skb_delivery_cb)(struct sk_buff *skb, struct net_device *dev); | ||
| 310 | |||
| 311 | int lowpan_process_data(struct sk_buff *skb, struct net_device *dev, | ||
| 312 | const u8 *saddr, const u8 saddr_type, const u8 saddr_len, | ||
| 313 | const u8 *daddr, const u8 daddr_type, const u8 daddr_len, | ||
| 314 | u8 iphc0, u8 iphc1, skb_delivery_cb skb_deliver); | ||
| 315 | int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev, | ||
| 316 | unsigned short type, const void *_daddr, | ||
| 317 | const void *_saddr, unsigned int len); | ||
| 318 | |||
| 247 | #endif /* __6LOWPAN_H__ */ | 319 | #endif /* __6LOWPAN_H__ */ |
diff --git a/net/ieee802154/6lowpan_iphc.c b/net/ieee802154/6lowpan_iphc.c new file mode 100644 index 000000000000..860aa2d445ba --- /dev/null +++ b/net/ieee802154/6lowpan_iphc.c | |||
| @@ -0,0 +1,802 @@ | |||
| 1 | /* | ||
| 2 | * Copyright 2011, Siemens AG | ||
| 3 | * written by Alexander Smirnov <alex.bluesman.smirnov@gmail.com> | ||
| 4 | */ | ||
| 5 | |||
| 6 | /* | ||
| 7 | * Based on patches from Jon Smirl <jonsmirl@gmail.com> | ||
| 8 | * Copyright (c) 2011 Jon Smirl <jonsmirl@gmail.com> | ||
| 9 | * | ||
| 10 | * This program is free software; you can redistribute it and/or modify | ||
| 11 | * it under the terms of the GNU General Public License version 2 | ||
| 12 | * as published by the Free Software Foundation. | ||
| 13 | * | ||
| 14 | * This program is distributed in the hope that it will be useful, | ||
| 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 17 | * GNU General Public License for more details. | ||
| 18 | * | ||
| 19 | * You should have received a copy of the GNU General Public License along | ||
| 20 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
| 21 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
| 22 | */ | ||
| 23 | |||
| 24 | /* Jon's code is based on 6lowpan implementation for Contiki which is: | ||
| 25 | * Copyright (c) 2008, Swedish Institute of Computer Science. | ||
| 26 | * All rights reserved. | ||
| 27 | * | ||
| 28 | * Redistribution and use in source and binary forms, with or without | ||
| 29 | * modification, are permitted provided that the following conditions | ||
| 30 | * are met: | ||
| 31 | * 1. Redistributions of source code must retain the above copyright | ||
| 32 | * notice, this list of conditions and the following disclaimer. | ||
| 33 | * 2. Redistributions in binary form must reproduce the above copyright | ||
| 34 | * notice, this list of conditions and the following disclaimer in the | ||
| 35 | * documentation and/or other materials provided with the distribution. | ||
| 36 | * 3. Neither the name of the Institute nor the names of its contributors | ||
| 37 | * may be used to endorse or promote products derived from this software | ||
| 38 | * without specific prior written permission. | ||
| 39 | * | ||
| 40 | * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND | ||
| 41 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
| 42 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
| 43 | * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE | ||
| 44 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
| 45 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
| 46 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
| 47 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||
| 48 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | ||
| 49 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | ||
| 50 | * SUCH DAMAGE. | ||
| 51 | */ | ||
| 52 | |||
| 53 | #include <linux/bitops.h> | ||
| 54 | #include <linux/if_arp.h> | ||
| 55 | #include <linux/module.h> | ||
| 56 | #include <linux/netdevice.h> | ||
| 57 | #include <net/ipv6.h> | ||
| 58 | #include <net/af_ieee802154.h> | ||
| 59 | |||
| 60 | #include "6lowpan.h" | ||
| 61 | |||
| 62 | /* | ||
| 63 | * Uncompress address function for source and | ||
| 64 | * destination address(non-multicast). | ||
| 65 | * | ||
| 66 | * address_mode is sam value or dam value. | ||
| 67 | */ | ||
| 68 | static int uncompress_addr(struct sk_buff *skb, | ||
| 69 | struct in6_addr *ipaddr, const u8 address_mode, | ||
| 70 | const u8 *lladdr, const u8 addr_type, | ||
| 71 | const u8 addr_len) | ||
| 72 | { | ||
| 73 | bool fail; | ||
| 74 | |||
| 75 | switch (address_mode) { | ||
| 76 | case LOWPAN_IPHC_ADDR_00: | ||
| 77 | /* for global link addresses */ | ||
| 78 | fail = lowpan_fetch_skb(skb, ipaddr->s6_addr, 16); | ||
| 79 | break; | ||
| 80 | case LOWPAN_IPHC_ADDR_01: | ||
| 81 | /* fe:80::XXXX:XXXX:XXXX:XXXX */ | ||
| 82 | ipaddr->s6_addr[0] = 0xFE; | ||
| 83 | ipaddr->s6_addr[1] = 0x80; | ||
| 84 | fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[8], 8); | ||
| 85 | break; | ||
| 86 | case LOWPAN_IPHC_ADDR_02: | ||
| 87 | /* fe:80::ff:fe00:XXXX */ | ||
| 88 | ipaddr->s6_addr[0] = 0xFE; | ||
| 89 | ipaddr->s6_addr[1] = 0x80; | ||
| 90 | ipaddr->s6_addr[11] = 0xFF; | ||
| 91 | ipaddr->s6_addr[12] = 0xFE; | ||
| 92 | fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[14], 2); | ||
| 93 | break; | ||
| 94 | case LOWPAN_IPHC_ADDR_03: | ||
| 95 | fail = false; | ||
| 96 | switch (addr_type) { | ||
| 97 | case IEEE802154_ADDR_LONG: | ||
| 98 | /* fe:80::XXXX:XXXX:XXXX:XXXX | ||
| 99 | * \_________________/ | ||
| 100 | * hwaddr | ||
| 101 | */ | ||
| 102 | ipaddr->s6_addr[0] = 0xFE; | ||
| 103 | ipaddr->s6_addr[1] = 0x80; | ||
| 104 | memcpy(&ipaddr->s6_addr[8], lladdr, addr_len); | ||
| 105 | /* second bit-flip (Universe/Local) | ||
| 106 | * is done according RFC2464 | ||
| 107 | */ | ||
| 108 | ipaddr->s6_addr[8] ^= 0x02; | ||
| 109 | break; | ||
| 110 | case IEEE802154_ADDR_SHORT: | ||
| 111 | /* fe:80::ff:fe00:XXXX | ||
| 112 | * \__/ | ||
| 113 | * short_addr | ||
| 114 | * | ||
| 115 | * Universe/Local bit is zero. | ||
| 116 | */ | ||
| 117 | ipaddr->s6_addr[0] = 0xFE; | ||
| 118 | ipaddr->s6_addr[1] = 0x80; | ||
| 119 | ipaddr->s6_addr[11] = 0xFF; | ||
| 120 | ipaddr->s6_addr[12] = 0xFE; | ||
| 121 | ipaddr->s6_addr16[7] = htons(*((u16 *)lladdr)); | ||
| 122 | break; | ||
| 123 | default: | ||
| 124 | pr_debug("Invalid addr_type set\n"); | ||
| 125 | return -EINVAL; | ||
| 126 | } | ||
| 127 | break; | ||
| 128 | default: | ||
| 129 | pr_debug("Invalid address mode value: 0x%x\n", address_mode); | ||
| 130 | return -EINVAL; | ||
| 131 | } | ||
| 132 | |||
| 133 | if (fail) { | ||
| 134 | pr_debug("Failed to fetch skb data\n"); | ||
| 135 | return -EIO; | ||
| 136 | } | ||
| 137 | |||
| 138 | raw_dump_inline(NULL, "Reconstructed ipv6 addr is", | ||
| 139 | ipaddr->s6_addr, 16); | ||
| 140 | |||
| 141 | return 0; | ||
| 142 | } | ||
| 143 | |||
| 144 | /* | ||
| 145 | * Uncompress address function for source context | ||
| 146 | * based address(non-multicast). | ||
| 147 | */ | ||
| 148 | static int uncompress_context_based_src_addr(struct sk_buff *skb, | ||
| 149 | struct in6_addr *ipaddr, | ||
| 150 | const u8 sam) | ||
| 151 | { | ||
| 152 | switch (sam) { | ||
| 153 | case LOWPAN_IPHC_ADDR_00: | ||
| 154 | /* unspec address :: | ||
| 155 | * Do nothing, address is already :: | ||
| 156 | */ | ||
| 157 | break; | ||
| 158 | case LOWPAN_IPHC_ADDR_01: | ||
| 159 | /* TODO */ | ||
| 160 | case LOWPAN_IPHC_ADDR_02: | ||
| 161 | /* TODO */ | ||
| 162 | case LOWPAN_IPHC_ADDR_03: | ||
| 163 | /* TODO */ | ||
| 164 | netdev_warn(skb->dev, "SAM value 0x%x not supported\n", sam); | ||
| 165 | return -EINVAL; | ||
| 166 | default: | ||
| 167 | pr_debug("Invalid sam value: 0x%x\n", sam); | ||
| 168 | return -EINVAL; | ||
| 169 | } | ||
| 170 | |||
| 171 | raw_dump_inline(NULL, | ||
| 172 | "Reconstructed context based ipv6 src addr is", | ||
| 173 | ipaddr->s6_addr, 16); | ||
| 174 | |||
| 175 | return 0; | ||
| 176 | } | ||
| 177 | |||
| 178 | static int skb_deliver(struct sk_buff *skb, struct ipv6hdr *hdr, | ||
| 179 | struct net_device *dev, skb_delivery_cb deliver_skb) | ||
| 180 | { | ||
| 181 | struct sk_buff *new; | ||
| 182 | int stat; | ||
| 183 | |||
| 184 | new = skb_copy_expand(skb, sizeof(struct ipv6hdr), skb_tailroom(skb), | ||
| 185 | GFP_ATOMIC); | ||
| 186 | kfree_skb(skb); | ||
| 187 | |||
| 188 | if (!new) | ||
| 189 | return -ENOMEM; | ||
| 190 | |||
| 191 | skb_push(new, sizeof(struct ipv6hdr)); | ||
| 192 | skb_reset_network_header(new); | ||
| 193 | skb_copy_to_linear_data(new, hdr, sizeof(struct ipv6hdr)); | ||
| 194 | |||
| 195 | new->protocol = htons(ETH_P_IPV6); | ||
| 196 | new->pkt_type = PACKET_HOST; | ||
| 197 | new->dev = dev; | ||
| 198 | |||
| 199 | raw_dump_table(__func__, "raw skb data dump before receiving", | ||
| 200 | new->data, new->len); | ||
| 201 | |||
| 202 | stat = deliver_skb(new, dev); | ||
| 203 | |||
| 204 | kfree_skb(new); | ||
| 205 | |||
| 206 | return stat; | ||
| 207 | } | ||
| 208 | |||
| 209 | /* Uncompress function for multicast destination address, | ||
| 210 | * when M bit is set. | ||
| 211 | */ | ||
| 212 | static int | ||
| 213 | lowpan_uncompress_multicast_daddr(struct sk_buff *skb, | ||
| 214 | struct in6_addr *ipaddr, | ||
| 215 | const u8 dam) | ||
| 216 | { | ||
| 217 | bool fail; | ||
| 218 | |||
| 219 | switch (dam) { | ||
| 220 | case LOWPAN_IPHC_DAM_00: | ||
| 221 | /* 00: 128 bits. The full address | ||
| 222 | * is carried in-line. | ||
| 223 | */ | ||
| 224 | fail = lowpan_fetch_skb(skb, ipaddr->s6_addr, 16); | ||
| 225 | break; | ||
| 226 | case LOWPAN_IPHC_DAM_01: | ||
| 227 | /* 01: 48 bits. The address takes | ||
| 228 | * the form ffXX::00XX:XXXX:XXXX. | ||
| 229 | */ | ||
| 230 | ipaddr->s6_addr[0] = 0xFF; | ||
| 231 | fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[1], 1); | ||
| 232 | fail |= lowpan_fetch_skb(skb, &ipaddr->s6_addr[11], 5); | ||
| 233 | break; | ||
| 234 | case LOWPAN_IPHC_DAM_10: | ||
| 235 | /* 10: 32 bits. The address takes | ||
| 236 | * the form ffXX::00XX:XXXX. | ||
| 237 | */ | ||
| 238 | ipaddr->s6_addr[0] = 0xFF; | ||
| 239 | fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[1], 1); | ||
| 240 | fail |= lowpan_fetch_skb(skb, &ipaddr->s6_addr[13], 3); | ||
| 241 | break; | ||
| 242 | case LOWPAN_IPHC_DAM_11: | ||
| 243 | /* 11: 8 bits. The address takes | ||
| 244 | * the form ff02::00XX. | ||
| 245 | */ | ||
| 246 | ipaddr->s6_addr[0] = 0xFF; | ||
| 247 | ipaddr->s6_addr[1] = 0x02; | ||
| 248 | fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[15], 1); | ||
| 249 | break; | ||
| 250 | default: | ||
| 251 | pr_debug("DAM value has a wrong value: 0x%x\n", dam); | ||
| 252 | return -EINVAL; | ||
| 253 | } | ||
| 254 | |||
| 255 | if (fail) { | ||
| 256 | pr_debug("Failed to fetch skb data\n"); | ||
| 257 | return -EIO; | ||
| 258 | } | ||
| 259 | |||
| 260 | raw_dump_inline(NULL, "Reconstructed ipv6 multicast addr is", | ||
| 261 | ipaddr->s6_addr, 16); | ||
| 262 | |||
| 263 | return 0; | ||
| 264 | } | ||
| 265 | |||
| 266 | static int | ||
| 267 | uncompress_udp_header(struct sk_buff *skb, struct udphdr *uh) | ||
| 268 | { | ||
| 269 | bool fail; | ||
| 270 | u8 tmp = 0, val = 0; | ||
| 271 | |||
| 272 | if (!uh) | ||
| 273 | goto err; | ||
| 274 | |||
| 275 | fail = lowpan_fetch_skb(skb, &tmp, 1); | ||
| 276 | |||
| 277 | if ((tmp & LOWPAN_NHC_UDP_MASK) == LOWPAN_NHC_UDP_ID) { | ||
| 278 | pr_debug("UDP header uncompression\n"); | ||
| 279 | switch (tmp & LOWPAN_NHC_UDP_CS_P_11) { | ||
| 280 | case LOWPAN_NHC_UDP_CS_P_00: | ||
| 281 | fail |= lowpan_fetch_skb(skb, &uh->source, 2); | ||
| 282 | fail |= lowpan_fetch_skb(skb, &uh->dest, 2); | ||
| 283 | break; | ||
| 284 | case LOWPAN_NHC_UDP_CS_P_01: | ||
| 285 | fail |= lowpan_fetch_skb(skb, &uh->source, 2); | ||
| 286 | fail |= lowpan_fetch_skb(skb, &val, 1); | ||
| 287 | uh->dest = htons(val + LOWPAN_NHC_UDP_8BIT_PORT); | ||
| 288 | break; | ||
| 289 | case LOWPAN_NHC_UDP_CS_P_10: | ||
| 290 | fail |= lowpan_fetch_skb(skb, &val, 1); | ||
| 291 | uh->source = htons(val + LOWPAN_NHC_UDP_8BIT_PORT); | ||
| 292 | fail |= lowpan_fetch_skb(skb, &uh->dest, 2); | ||
| 293 | break; | ||
| 294 | case LOWPAN_NHC_UDP_CS_P_11: | ||
| 295 | fail |= lowpan_fetch_skb(skb, &val, 1); | ||
| 296 | uh->source = htons(LOWPAN_NHC_UDP_4BIT_PORT + | ||
| 297 | (val >> 4)); | ||
| 298 | uh->dest = htons(LOWPAN_NHC_UDP_4BIT_PORT + | ||
| 299 | (val & 0x0f)); | ||
| 300 | break; | ||
| 301 | default: | ||
| 302 | pr_debug("ERROR: unknown UDP format\n"); | ||
| 303 | goto err; | ||
| 304 | break; | ||
| 305 | } | ||
| 306 | |||
| 307 | pr_debug("uncompressed UDP ports: src = %d, dst = %d\n", | ||
| 308 | ntohs(uh->source), ntohs(uh->dest)); | ||
| 309 | |||
| 310 | /* checksum */ | ||
| 311 | if (tmp & LOWPAN_NHC_UDP_CS_C) { | ||
| 312 | pr_debug_ratelimited("checksum elided currently not supported\n"); | ||
| 313 | goto err; | ||
| 314 | } else { | ||
| 315 | fail |= lowpan_fetch_skb(skb, &uh->check, 2); | ||
| 316 | } | ||
| 317 | |||
| 318 | /* | ||
| 319 | * UDP lenght needs to be infered from the lower layers | ||
| 320 | * here, we obtain the hint from the remaining size of the | ||
| 321 | * frame | ||
| 322 | */ | ||
| 323 | uh->len = htons(skb->len + sizeof(struct udphdr)); | ||
| 324 | pr_debug("uncompressed UDP length: src = %d", ntohs(uh->len)); | ||
| 325 | } else { | ||
| 326 | pr_debug("ERROR: unsupported NH format\n"); | ||
| 327 | goto err; | ||
| 328 | } | ||
| 329 | |||
| 330 | if (fail) | ||
| 331 | goto err; | ||
| 332 | |||
| 333 | return 0; | ||
| 334 | err: | ||
| 335 | return -EINVAL; | ||
| 336 | } | ||
| 337 | |||
| 338 | /* TTL uncompression values */ | ||
| 339 | static const u8 lowpan_ttl_values[] = { 0, 1, 64, 255 }; | ||
| 340 | |||
| 341 | int lowpan_process_data(struct sk_buff *skb, struct net_device *dev, | ||
| 342 | const u8 *saddr, const u8 saddr_type, const u8 saddr_len, | ||
| 343 | const u8 *daddr, const u8 daddr_type, const u8 daddr_len, | ||
| 344 | u8 iphc0, u8 iphc1, skb_delivery_cb deliver_skb) | ||
| 345 | { | ||
| 346 | struct ipv6hdr hdr = {}; | ||
| 347 | u8 tmp, num_context = 0; | ||
| 348 | int err; | ||
| 349 | |||
| 350 | raw_dump_table(__func__, "raw skb data dump uncompressed", | ||
| 351 | skb->data, skb->len); | ||
| 352 | |||
| 353 | /* another if the CID flag is set */ | ||
| 354 | if (iphc1 & LOWPAN_IPHC_CID) { | ||
| 355 | pr_debug("CID flag is set, increase header with one\n"); | ||
| 356 | if (lowpan_fetch_skb_u8(skb, &num_context)) | ||
| 357 | goto drop; | ||
| 358 | } | ||
| 359 | |||
| 360 | hdr.version = 6; | ||
| 361 | |||
| 362 | /* Traffic Class and Flow Label */ | ||
| 363 | switch ((iphc0 & LOWPAN_IPHC_TF) >> 3) { | ||
| 364 | /* | ||
| 365 | * Traffic Class and FLow Label carried in-line | ||
| 366 | * ECN + DSCP + 4-bit Pad + Flow Label (4 bytes) | ||
| 367 | */ | ||
| 368 | case 0: /* 00b */ | ||
| 369 | if (lowpan_fetch_skb_u8(skb, &tmp)) | ||
| 370 | goto drop; | ||
| 371 | |||
| 372 | memcpy(&hdr.flow_lbl, &skb->data[0], 3); | ||
| 373 | skb_pull(skb, 3); | ||
| 374 | hdr.priority = ((tmp >> 2) & 0x0f); | ||
| 375 | hdr.flow_lbl[0] = ((tmp >> 2) & 0x30) | (tmp << 6) | | ||
| 376 | (hdr.flow_lbl[0] & 0x0f); | ||
| 377 | break; | ||
| 378 | /* | ||
| 379 | * Traffic class carried in-line | ||
| 380 | * ECN + DSCP (1 byte), Flow Label is elided | ||
| 381 | */ | ||
| 382 | case 2: /* 10b */ | ||
| 383 | if (lowpan_fetch_skb_u8(skb, &tmp)) | ||
| 384 | goto drop; | ||
| 385 | |||
| 386 | hdr.priority = ((tmp >> 2) & 0x0f); | ||
| 387 | hdr.flow_lbl[0] = ((tmp << 6) & 0xC0) | ((tmp >> 2) & 0x30); | ||
| 388 | break; | ||
| 389 | /* | ||
| 390 | * Flow Label carried in-line | ||
| 391 | * ECN + 2-bit Pad + Flow Label (3 bytes), DSCP is elided | ||
| 392 | */ | ||
| 393 | case 1: /* 01b */ | ||
| 394 | if (lowpan_fetch_skb_u8(skb, &tmp)) | ||
| 395 | goto drop; | ||
| 396 | |||
| 397 | hdr.flow_lbl[0] = (skb->data[0] & 0x0F) | ((tmp >> 2) & 0x30); | ||
| 398 | memcpy(&hdr.flow_lbl[1], &skb->data[0], 2); | ||
| 399 | skb_pull(skb, 2); | ||
| 400 | break; | ||
| 401 | /* Traffic Class and Flow Label are elided */ | ||
| 402 | case 3: /* 11b */ | ||
| 403 | break; | ||
| 404 | default: | ||
| 405 | break; | ||
| 406 | } | ||
| 407 | |||
| 408 | /* Next Header */ | ||
| 409 | if ((iphc0 & LOWPAN_IPHC_NH_C) == 0) { | ||
| 410 | /* Next header is carried inline */ | ||
| 411 | if (lowpan_fetch_skb_u8(skb, &(hdr.nexthdr))) | ||
| 412 | goto drop; | ||
| 413 | |||
| 414 | pr_debug("NH flag is set, next header carried inline: %02x\n", | ||
| 415 | hdr.nexthdr); | ||
| 416 | } | ||
| 417 | |||
| 418 | /* Hop Limit */ | ||
| 419 | if ((iphc0 & 0x03) != LOWPAN_IPHC_TTL_I) | ||
| 420 | hdr.hop_limit = lowpan_ttl_values[iphc0 & 0x03]; | ||
| 421 | else { | ||
| 422 | if (lowpan_fetch_skb_u8(skb, &(hdr.hop_limit))) | ||
| 423 | goto drop; | ||
| 424 | } | ||
| 425 | |||
| 426 | /* Extract SAM to the tmp variable */ | ||
| 427 | tmp = ((iphc1 & LOWPAN_IPHC_SAM) >> LOWPAN_IPHC_SAM_BIT) & 0x03; | ||
| 428 | |||
| 429 | if (iphc1 & LOWPAN_IPHC_SAC) { | ||
| 430 | /* Source address context based uncompression */ | ||
| 431 | pr_debug("SAC bit is set. Handle context based source address.\n"); | ||
| 432 | err = uncompress_context_based_src_addr( | ||
| 433 | skb, &hdr.saddr, tmp); | ||
| 434 | } else { | ||
| 435 | /* Source address uncompression */ | ||
| 436 | pr_debug("source address stateless compression\n"); | ||
| 437 | err = uncompress_addr(skb, &hdr.saddr, tmp, saddr, | ||
| 438 | saddr_type, saddr_len); | ||
| 439 | } | ||
| 440 | |||
| 441 | /* Check on error of previous branch */ | ||
| 442 | if (err) | ||
| 443 | goto drop; | ||
| 444 | |||
| 445 | /* Extract DAM to the tmp variable */ | ||
| 446 | tmp = ((iphc1 & LOWPAN_IPHC_DAM_11) >> LOWPAN_IPHC_DAM_BIT) & 0x03; | ||
| 447 | |||
| 448 | /* check for Multicast Compression */ | ||
| 449 | if (iphc1 & LOWPAN_IPHC_M) { | ||
| 450 | if (iphc1 & LOWPAN_IPHC_DAC) { | ||
| 451 | pr_debug("dest: context-based mcast compression\n"); | ||
| 452 | /* TODO: implement this */ | ||
| 453 | } else { | ||
| 454 | err = lowpan_uncompress_multicast_daddr( | ||
| 455 | skb, &hdr.daddr, tmp); | ||
| 456 | if (err) | ||
| 457 | goto drop; | ||
| 458 | } | ||
| 459 | } else { | ||
| 460 | err = uncompress_addr(skb, &hdr.daddr, tmp, daddr, | ||
| 461 | daddr_type, daddr_len); | ||
| 462 | pr_debug("dest: stateless compression mode %d dest %pI6c\n", | ||
| 463 | tmp, &hdr.daddr); | ||
| 464 | if (err) | ||
| 465 | goto drop; | ||
| 466 | } | ||
| 467 | |||
| 468 | /* UDP data uncompression */ | ||
| 469 | if (iphc0 & LOWPAN_IPHC_NH_C) { | ||
| 470 | struct udphdr uh; | ||
| 471 | struct sk_buff *new; | ||
| 472 | if (uncompress_udp_header(skb, &uh)) | ||
| 473 | goto drop; | ||
| 474 | |||
| 475 | /* | ||
| 476 | * replace the compressed UDP head by the uncompressed UDP | ||
| 477 | * header | ||
| 478 | */ | ||
| 479 | new = skb_copy_expand(skb, sizeof(struct udphdr), | ||
| 480 | skb_tailroom(skb), GFP_ATOMIC); | ||
| 481 | kfree_skb(skb); | ||
| 482 | |||
| 483 | if (!new) | ||
| 484 | return -ENOMEM; | ||
| 485 | |||
| 486 | skb = new; | ||
| 487 | |||
| 488 | skb_push(skb, sizeof(struct udphdr)); | ||
| 489 | skb_reset_transport_header(skb); | ||
| 490 | skb_copy_to_linear_data(skb, &uh, sizeof(struct udphdr)); | ||
| 491 | |||
| 492 | raw_dump_table(__func__, "raw UDP header dump", | ||
| 493 | (u8 *)&uh, sizeof(uh)); | ||
| 494 | |||
| 495 | hdr.nexthdr = UIP_PROTO_UDP; | ||
| 496 | } | ||
| 497 | |||
| 498 | hdr.payload_len = htons(skb->len); | ||
| 499 | |||
| 500 | pr_debug("skb headroom size = %d, data length = %d\n", | ||
| 501 | skb_headroom(skb), skb->len); | ||
| 502 | |||
| 503 | pr_debug("IPv6 header dump:\n\tversion = %d\n\tlength = %d\n\t" | ||
| 504 | "nexthdr = 0x%02x\n\thop_lim = %d\n\tdest = %pI6c\n", | ||
| 505 | hdr.version, ntohs(hdr.payload_len), hdr.nexthdr, | ||
| 506 | hdr.hop_limit, &hdr.daddr); | ||
| 507 | |||
| 508 | raw_dump_table(__func__, "raw header dump", (u8 *)&hdr, | ||
| 509 | sizeof(hdr)); | ||
| 510 | |||
| 511 | return skb_deliver(skb, &hdr, dev, deliver_skb); | ||
| 512 | |||
| 513 | drop: | ||
| 514 | kfree_skb(skb); | ||
| 515 | return -EINVAL; | ||
| 516 | } | ||
| 517 | EXPORT_SYMBOL_GPL(lowpan_process_data); | ||
| 518 | |||
| 519 | static u8 lowpan_compress_addr_64(u8 **hc06_ptr, u8 shift, | ||
| 520 | const struct in6_addr *ipaddr, | ||
| 521 | const unsigned char *lladdr) | ||
| 522 | { | ||
| 523 | u8 val = 0; | ||
| 524 | |||
| 525 | if (is_addr_mac_addr_based(ipaddr, lladdr)) { | ||
| 526 | val = 3; /* 0-bits */ | ||
| 527 | pr_debug("address compression 0 bits\n"); | ||
| 528 | } else if (lowpan_is_iid_16_bit_compressable(ipaddr)) { | ||
| 529 | /* compress IID to 16 bits xxxx::XXXX */ | ||
| 530 | memcpy(*hc06_ptr, &ipaddr->s6_addr16[7], 2); | ||
| 531 | *hc06_ptr += 2; | ||
| 532 | val = 2; /* 16-bits */ | ||
| 533 | raw_dump_inline(NULL, "Compressed ipv6 addr is (16 bits)", | ||
| 534 | *hc06_ptr - 2, 2); | ||
| 535 | } else { | ||
| 536 | /* do not compress IID => xxxx::IID */ | ||
| 537 | memcpy(*hc06_ptr, &ipaddr->s6_addr16[4], 8); | ||
| 538 | *hc06_ptr += 8; | ||
| 539 | val = 1; /* 64-bits */ | ||
| 540 | raw_dump_inline(NULL, "Compressed ipv6 addr is (64 bits)", | ||
| 541 | *hc06_ptr - 8, 8); | ||
| 542 | } | ||
| 543 | |||
| 544 | return rol8(val, shift); | ||
| 545 | } | ||
| 546 | |||
| 547 | static void compress_udp_header(u8 **hc06_ptr, struct sk_buff *skb) | ||
| 548 | { | ||
| 549 | struct udphdr *uh = udp_hdr(skb); | ||
| 550 | u8 tmp; | ||
| 551 | |||
| 552 | if (((ntohs(uh->source) & LOWPAN_NHC_UDP_4BIT_MASK) == | ||
| 553 | LOWPAN_NHC_UDP_4BIT_PORT) && | ||
| 554 | ((ntohs(uh->dest) & LOWPAN_NHC_UDP_4BIT_MASK) == | ||
| 555 | LOWPAN_NHC_UDP_4BIT_PORT)) { | ||
| 556 | pr_debug("UDP header: both ports compression to 4 bits\n"); | ||
| 557 | /* compression value */ | ||
| 558 | tmp = LOWPAN_NHC_UDP_CS_P_11; | ||
| 559 | lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp)); | ||
| 560 | /* source and destination port */ | ||
| 561 | tmp = ntohs(uh->dest) - LOWPAN_NHC_UDP_4BIT_PORT + | ||
| 562 | ((ntohs(uh->source) - LOWPAN_NHC_UDP_4BIT_PORT) << 4); | ||
| 563 | lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp)); | ||
| 564 | } else if ((ntohs(uh->dest) & LOWPAN_NHC_UDP_8BIT_MASK) == | ||
| 565 | LOWPAN_NHC_UDP_8BIT_PORT) { | ||
| 566 | pr_debug("UDP header: remove 8 bits of dest\n"); | ||
| 567 | /* compression value */ | ||
| 568 | tmp = LOWPAN_NHC_UDP_CS_P_01; | ||
| 569 | lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp)); | ||
| 570 | /* source port */ | ||
| 571 | lowpan_push_hc_data(hc06_ptr, &uh->source, sizeof(uh->source)); | ||
| 572 | /* destination port */ | ||
| 573 | tmp = ntohs(uh->dest) - LOWPAN_NHC_UDP_8BIT_PORT; | ||
| 574 | lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp)); | ||
| 575 | } else if ((ntohs(uh->source) & LOWPAN_NHC_UDP_8BIT_MASK) == | ||
| 576 | LOWPAN_NHC_UDP_8BIT_PORT) { | ||
| 577 | pr_debug("UDP header: remove 8 bits of source\n"); | ||
| 578 | /* compression value */ | ||
| 579 | tmp = LOWPAN_NHC_UDP_CS_P_10; | ||
| 580 | lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp)); | ||
| 581 | /* source port */ | ||
| 582 | tmp = ntohs(uh->source) - LOWPAN_NHC_UDP_8BIT_PORT; | ||
| 583 | lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp)); | ||
| 584 | /* destination port */ | ||
| 585 | lowpan_push_hc_data(hc06_ptr, &uh->dest, sizeof(uh->dest)); | ||
| 586 | } else { | ||
| 587 | pr_debug("UDP header: can't compress\n"); | ||
| 588 | /* compression value */ | ||
| 589 | tmp = LOWPAN_NHC_UDP_CS_P_00; | ||
| 590 | lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp)); | ||
| 591 | /* source port */ | ||
| 592 | lowpan_push_hc_data(hc06_ptr, &uh->source, sizeof(uh->source)); | ||
| 593 | /* destination port */ | ||
| 594 | lowpan_push_hc_data(hc06_ptr, &uh->dest, sizeof(uh->dest)); | ||
| 595 | } | ||
| 596 | |||
| 597 | /* checksum is always inline */ | ||
| 598 | lowpan_push_hc_data(hc06_ptr, &uh->check, sizeof(uh->check)); | ||
| 599 | |||
| 600 | /* skip the UDP header */ | ||
| 601 | skb_pull(skb, sizeof(struct udphdr)); | ||
| 602 | } | ||
| 603 | |||
| 604 | int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev, | ||
| 605 | unsigned short type, const void *_daddr, | ||
| 606 | const void *_saddr, unsigned int len) | ||
| 607 | { | ||
| 608 | u8 tmp, iphc0, iphc1, *hc06_ptr; | ||
| 609 | struct ipv6hdr *hdr; | ||
| 610 | u8 head[100] = {}; | ||
| 611 | |||
| 612 | if (type != ETH_P_IPV6) | ||
| 613 | return -EINVAL; | ||
| 614 | |||
| 615 | hdr = ipv6_hdr(skb); | ||
| 616 | hc06_ptr = head + 2; | ||
| 617 | |||
| 618 | pr_debug("IPv6 header dump:\n\tversion = %d\n\tlength = %d\n" | ||
| 619 | "\tnexthdr = 0x%02x\n\thop_lim = %d\n\tdest = %pI6c\n", | ||
| 620 | hdr->version, ntohs(hdr->payload_len), hdr->nexthdr, | ||
| 621 | hdr->hop_limit, &hdr->daddr); | ||
| 622 | |||
| 623 | raw_dump_table(__func__, "raw skb network header dump", | ||
| 624 | skb_network_header(skb), sizeof(struct ipv6hdr)); | ||
| 625 | |||
| 626 | /* | ||
| 627 | * As we copy some bit-length fields, in the IPHC encoding bytes, | ||
| 628 | * we sometimes use |= | ||
| 629 | * If the field is 0, and the current bit value in memory is 1, | ||
| 630 | * this does not work. We therefore reset the IPHC encoding here | ||
| 631 | */ | ||
| 632 | iphc0 = LOWPAN_DISPATCH_IPHC; | ||
| 633 | iphc1 = 0; | ||
| 634 | |||
| 635 | /* TODO: context lookup */ | ||
| 636 | |||
| 637 | raw_dump_inline(__func__, "saddr", | ||
| 638 | (unsigned char *)_saddr, IEEE802154_ADDR_LEN); | ||
| 639 | raw_dump_inline(__func__, "daddr", | ||
| 640 | (unsigned char *)_daddr, IEEE802154_ADDR_LEN); | ||
| 641 | |||
| 642 | raw_dump_table(__func__, | ||
| 643 | "sending raw skb network uncompressed packet", | ||
| 644 | skb->data, skb->len); | ||
| 645 | |||
| 646 | /* | ||
| 647 | * Traffic class, flow label | ||
| 648 | * If flow label is 0, compress it. If traffic class is 0, compress it | ||
| 649 | * We have to process both in the same time as the offset of traffic | ||
| 650 | * class depends on the presence of version and flow label | ||
| 651 | */ | ||
| 652 | |||
| 653 | /* hc06 format of TC is ECN | DSCP , original one is DSCP | ECN */ | ||
| 654 | tmp = (hdr->priority << 4) | (hdr->flow_lbl[0] >> 4); | ||
| 655 | tmp = ((tmp & 0x03) << 6) | (tmp >> 2); | ||
| 656 | |||
| 657 | if (((hdr->flow_lbl[0] & 0x0F) == 0) && | ||
| 658 | (hdr->flow_lbl[1] == 0) && (hdr->flow_lbl[2] == 0)) { | ||
| 659 | /* flow label can be compressed */ | ||
| 660 | iphc0 |= LOWPAN_IPHC_FL_C; | ||
| 661 | if ((hdr->priority == 0) && | ||
| 662 | ((hdr->flow_lbl[0] & 0xF0) == 0)) { | ||
| 663 | /* compress (elide) all */ | ||
| 664 | iphc0 |= LOWPAN_IPHC_TC_C; | ||
| 665 | } else { | ||
| 666 | /* compress only the flow label */ | ||
| 667 | *hc06_ptr = tmp; | ||
| 668 | hc06_ptr += 1; | ||
| 669 | } | ||
| 670 | } else { | ||
| 671 | /* Flow label cannot be compressed */ | ||
| 672 | if ((hdr->priority == 0) && | ||
| 673 | ((hdr->flow_lbl[0] & 0xF0) == 0)) { | ||
| 674 | /* compress only traffic class */ | ||
| 675 | iphc0 |= LOWPAN_IPHC_TC_C; | ||
| 676 | *hc06_ptr = (tmp & 0xc0) | (hdr->flow_lbl[0] & 0x0F); | ||
| 677 | memcpy(hc06_ptr + 1, &hdr->flow_lbl[1], 2); | ||
| 678 | hc06_ptr += 3; | ||
| 679 | } else { | ||
| 680 | /* compress nothing */ | ||
| 681 | memcpy(hc06_ptr, hdr, 4); | ||
| 682 | /* replace the top byte with new ECN | DSCP format */ | ||
| 683 | *hc06_ptr = tmp; | ||
| 684 | hc06_ptr += 4; | ||
| 685 | } | ||
| 686 | } | ||
| 687 | |||
| 688 | /* NOTE: payload length is always compressed */ | ||
| 689 | |||
| 690 | /* Next Header is compress if UDP */ | ||
| 691 | if (hdr->nexthdr == UIP_PROTO_UDP) | ||
| 692 | iphc0 |= LOWPAN_IPHC_NH_C; | ||
| 693 | |||
| 694 | if ((iphc0 & LOWPAN_IPHC_NH_C) == 0) { | ||
| 695 | *hc06_ptr = hdr->nexthdr; | ||
| 696 | hc06_ptr += 1; | ||
| 697 | } | ||
| 698 | |||
| 699 | /* | ||
| 700 | * Hop limit | ||
| 701 | * if 1: compress, encoding is 01 | ||
| 702 | * if 64: compress, encoding is 10 | ||
| 703 | * if 255: compress, encoding is 11 | ||
| 704 | * else do not compress | ||
| 705 | */ | ||
| 706 | switch (hdr->hop_limit) { | ||
| 707 | case 1: | ||
| 708 | iphc0 |= LOWPAN_IPHC_TTL_1; | ||
| 709 | break; | ||
| 710 | case 64: | ||
| 711 | iphc0 |= LOWPAN_IPHC_TTL_64; | ||
| 712 | break; | ||
| 713 | case 255: | ||
| 714 | iphc0 |= LOWPAN_IPHC_TTL_255; | ||
| 715 | break; | ||
| 716 | default: | ||
| 717 | *hc06_ptr = hdr->hop_limit; | ||
| 718 | hc06_ptr += 1; | ||
| 719 | break; | ||
| 720 | } | ||
| 721 | |||
| 722 | /* source address compression */ | ||
| 723 | if (is_addr_unspecified(&hdr->saddr)) { | ||
| 724 | pr_debug("source address is unspecified, setting SAC\n"); | ||
| 725 | iphc1 |= LOWPAN_IPHC_SAC; | ||
| 726 | /* TODO: context lookup */ | ||
| 727 | } else if (is_addr_link_local(&hdr->saddr)) { | ||
| 728 | iphc1 |= lowpan_compress_addr_64(&hc06_ptr, | ||
| 729 | LOWPAN_IPHC_SAM_BIT, &hdr->saddr, _saddr); | ||
| 730 | pr_debug("source address unicast link-local %pI6c " | ||
| 731 | "iphc1 0x%02x\n", &hdr->saddr, iphc1); | ||
| 732 | } else { | ||
| 733 | pr_debug("send the full source address\n"); | ||
| 734 | memcpy(hc06_ptr, &hdr->saddr.s6_addr16[0], 16); | ||
| 735 | hc06_ptr += 16; | ||
| 736 | } | ||
| 737 | |||
| 738 | /* destination address compression */ | ||
| 739 | if (is_addr_mcast(&hdr->daddr)) { | ||
| 740 | pr_debug("destination address is multicast: "); | ||
| 741 | iphc1 |= LOWPAN_IPHC_M; | ||
| 742 | if (lowpan_is_mcast_addr_compressable8(&hdr->daddr)) { | ||
| 743 | pr_debug("compressed to 1 octet\n"); | ||
| 744 | iphc1 |= LOWPAN_IPHC_DAM_11; | ||
| 745 | /* use last byte */ | ||
| 746 | *hc06_ptr = hdr->daddr.s6_addr[15]; | ||
| 747 | hc06_ptr += 1; | ||
| 748 | } else if (lowpan_is_mcast_addr_compressable32(&hdr->daddr)) { | ||
| 749 | pr_debug("compressed to 4 octets\n"); | ||
| 750 | iphc1 |= LOWPAN_IPHC_DAM_10; | ||
| 751 | /* second byte + the last three */ | ||
| 752 | *hc06_ptr = hdr->daddr.s6_addr[1]; | ||
| 753 | memcpy(hc06_ptr + 1, &hdr->daddr.s6_addr[13], 3); | ||
| 754 | hc06_ptr += 4; | ||
| 755 | } else if (lowpan_is_mcast_addr_compressable48(&hdr->daddr)) { | ||
| 756 | pr_debug("compressed to 6 octets\n"); | ||
| 757 | iphc1 |= LOWPAN_IPHC_DAM_01; | ||
| 758 | /* second byte + the last five */ | ||
| 759 | *hc06_ptr = hdr->daddr.s6_addr[1]; | ||
| 760 | memcpy(hc06_ptr + 1, &hdr->daddr.s6_addr[11], 5); | ||
| 761 | hc06_ptr += 6; | ||
| 762 | } else { | ||
| 763 | pr_debug("using full address\n"); | ||
| 764 | iphc1 |= LOWPAN_IPHC_DAM_00; | ||
| 765 | memcpy(hc06_ptr, &hdr->daddr.s6_addr[0], 16); | ||
| 766 | hc06_ptr += 16; | ||
| 767 | } | ||
| 768 | } else { | ||
| 769 | /* TODO: context lookup */ | ||
| 770 | if (is_addr_link_local(&hdr->daddr)) { | ||
| 771 | iphc1 |= lowpan_compress_addr_64(&hc06_ptr, | ||
| 772 | LOWPAN_IPHC_DAM_BIT, &hdr->daddr, _daddr); | ||
| 773 | pr_debug("dest address unicast link-local %pI6c " | ||
| 774 | "iphc1 0x%02x\n", &hdr->daddr, iphc1); | ||
| 775 | } else { | ||
| 776 | pr_debug("dest address unicast %pI6c\n", &hdr->daddr); | ||
| 777 | memcpy(hc06_ptr, &hdr->daddr.s6_addr16[0], 16); | ||
| 778 | hc06_ptr += 16; | ||
| 779 | } | ||
| 780 | } | ||
| 781 | |||
| 782 | /* UDP header compression */ | ||
| 783 | if (hdr->nexthdr == UIP_PROTO_UDP) | ||
| 784 | compress_udp_header(&hc06_ptr, skb); | ||
| 785 | |||
| 786 | head[0] = iphc0; | ||
| 787 | head[1] = iphc1; | ||
| 788 | |||
| 789 | skb_pull(skb, sizeof(struct ipv6hdr)); | ||
| 790 | skb_reset_transport_header(skb); | ||
| 791 | memcpy(skb_push(skb, hc06_ptr - head), head, hc06_ptr - head); | ||
| 792 | skb_reset_network_header(skb); | ||
| 793 | |||
| 794 | pr_debug("header len %d skb %u\n", (int)(hc06_ptr - head), skb->len); | ||
| 795 | |||
| 796 | raw_dump_table(__func__, "raw skb data dump compressed", | ||
| 797 | skb->data, skb->len); | ||
| 798 | return 0; | ||
| 799 | } | ||
| 800 | EXPORT_SYMBOL_GPL(lowpan_header_compress); | ||
| 801 | |||
| 802 | MODULE_LICENSE("GPL"); | ||
diff --git a/net/ieee802154/Kconfig b/net/ieee802154/Kconfig index b2e06df0076c..9c9879d5ea64 100644 --- a/net/ieee802154/Kconfig +++ b/net/ieee802154/Kconfig | |||
| @@ -13,5 +13,12 @@ config IEEE802154 | |||
| 13 | config IEEE802154_6LOWPAN | 13 | config IEEE802154_6LOWPAN |
| 14 | tristate "6lowpan support over IEEE 802.15.4" | 14 | tristate "6lowpan support over IEEE 802.15.4" |
| 15 | depends on IEEE802154 && IPV6 | 15 | depends on IEEE802154 && IPV6 |
| 16 | select 6LOWPAN_IPHC | ||
| 16 | ---help--- | 17 | ---help--- |
| 17 | IPv6 compression over IEEE 802.15.4. | 18 | IPv6 compression over IEEE 802.15.4. |
| 19 | |||
| 20 | config 6LOWPAN_IPHC | ||
| 21 | tristate | ||
| 22 | ---help--- | ||
| 23 | 6lowpan compression code which is shared between IEEE 802.15.4 and Bluetooth | ||
| 24 | stacks. | ||
diff --git a/net/ieee802154/Makefile b/net/ieee802154/Makefile index d7716d64c6bb..e8f05885ced6 100644 --- a/net/ieee802154/Makefile +++ b/net/ieee802154/Makefile | |||
| @@ -1,5 +1,6 @@ | |||
| 1 | obj-$(CONFIG_IEEE802154) += ieee802154.o af_802154.o | 1 | obj-$(CONFIG_IEEE802154) += ieee802154.o af_802154.o |
| 2 | obj-$(CONFIG_IEEE802154_6LOWPAN) += 6lowpan.o | 2 | obj-$(CONFIG_IEEE802154_6LOWPAN) += 6lowpan.o |
| 3 | obj-$(CONFIG_6LOWPAN_IPHC) += 6lowpan_iphc.o | ||
| 3 | 4 | ||
| 4 | ieee802154-y := netlink.o nl-mac.o nl-phy.o nl_policy.o wpan-class.o | 5 | ieee802154-y := netlink.o nl-mac.o nl-phy.o nl_policy.o wpan-class.o |
| 5 | af_802154-y := af_ieee802154.o raw.o dgram.o | 6 | af_802154-y := af_ieee802154.o raw.o dgram.o |
diff --git a/net/ieee802154/dgram.c b/net/ieee802154/dgram.c index 1865fdf5a5a5..1846c1fe0d06 100644 --- a/net/ieee802154/dgram.c +++ b/net/ieee802154/dgram.c | |||
| @@ -291,9 +291,7 @@ static int dgram_recvmsg(struct kiocb *iocb, struct sock *sk, | |||
| 291 | size_t copied = 0; | 291 | size_t copied = 0; |
| 292 | int err = -EOPNOTSUPP; | 292 | int err = -EOPNOTSUPP; |
| 293 | struct sk_buff *skb; | 293 | struct sk_buff *skb; |
| 294 | struct sockaddr_ieee802154 *saddr; | 294 | DECLARE_SOCKADDR(struct sockaddr_ieee802154 *, saddr, msg->msg_name); |
| 295 | |||
| 296 | saddr = (struct sockaddr_ieee802154 *)msg->msg_name; | ||
| 297 | 295 | ||
| 298 | skb = skb_recv_datagram(sk, flags, noblock, &err); | 296 | skb = skb_recv_datagram(sk, flags, noblock, &err); |
| 299 | if (!skb) | 297 | if (!skb) |
diff --git a/net/ieee802154/wpan-class.c b/net/ieee802154/wpan-class.c index ef56ab5b35fe..4dd37615a749 100644 --- a/net/ieee802154/wpan-class.c +++ b/net/ieee802154/wpan-class.c | |||
| @@ -46,7 +46,7 @@ MASTER_SHOW(current_channel, "%d"); | |||
| 46 | MASTER_SHOW(current_page, "%d"); | 46 | MASTER_SHOW(current_page, "%d"); |
| 47 | MASTER_SHOW_COMPLEX(transmit_power, "%d +- %d dB", | 47 | MASTER_SHOW_COMPLEX(transmit_power, "%d +- %d dB", |
| 48 | ((signed char) (phy->transmit_power << 2)) >> 2, | 48 | ((signed char) (phy->transmit_power << 2)) >> 2, |
| 49 | (phy->transmit_power >> 6) ? (phy->transmit_power >> 6) * 3 : 1 ); | 49 | (phy->transmit_power >> 6) ? (phy->transmit_power >> 6) * 3 : 1); |
| 50 | MASTER_SHOW(cca_mode, "%d"); | 50 | MASTER_SHOW(cca_mode, "%d"); |
| 51 | 51 | ||
| 52 | static ssize_t channels_supported_show(struct device *dev, | 52 | static ssize_t channels_supported_show(struct device *dev, |
diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile index 4b81e91c80fe..f8c49ce5b283 100644 --- a/net/ipv4/Makefile +++ b/net/ipv4/Makefile | |||
| @@ -11,7 +11,7 @@ obj-y := route.o inetpeer.o protocol.o \ | |||
| 11 | tcp_offload.o datagram.o raw.o udp.o udplite.o \ | 11 | tcp_offload.o datagram.o raw.o udp.o udplite.o \ |
| 12 | udp_offload.o arp.o icmp.o devinet.o af_inet.o igmp.o \ | 12 | udp_offload.o arp.o icmp.o devinet.o af_inet.o igmp.o \ |
| 13 | fib_frontend.o fib_semantics.o fib_trie.o \ | 13 | fib_frontend.o fib_semantics.o fib_trie.o \ |
| 14 | inet_fragment.o ping.o ip_tunnel_core.o | 14 | inet_fragment.o ping.o ip_tunnel_core.o gre_offload.o |
| 15 | 15 | ||
| 16 | obj-$(CONFIG_NET_IP_TUNNEL) += ip_tunnel.o | 16 | obj-$(CONFIG_NET_IP_TUNNEL) += ip_tunnel.o |
| 17 | obj-$(CONFIG_SYSCTL) += sysctl_net_ipv4.o | 17 | obj-$(CONFIG_SYSCTL) += sysctl_net_ipv4.o |
| @@ -19,7 +19,7 @@ obj-$(CONFIG_PROC_FS) += proc.o | |||
| 19 | obj-$(CONFIG_IP_MULTIPLE_TABLES) += fib_rules.o | 19 | obj-$(CONFIG_IP_MULTIPLE_TABLES) += fib_rules.o |
| 20 | obj-$(CONFIG_IP_MROUTE) += ipmr.o | 20 | obj-$(CONFIG_IP_MROUTE) += ipmr.o |
| 21 | obj-$(CONFIG_NET_IPIP) += ipip.o | 21 | obj-$(CONFIG_NET_IPIP) += ipip.o |
| 22 | gre-y := gre_demux.o gre_offload.o | 22 | gre-y := gre_demux.o |
| 23 | obj-$(CONFIG_NET_IPGRE_DEMUX) += gre.o | 23 | obj-$(CONFIG_NET_IPGRE_DEMUX) += gre.o |
| 24 | obj-$(CONFIG_NET_IPGRE) += ip_gre.o | 24 | obj-$(CONFIG_NET_IPGRE) += ip_gre.o |
| 25 | obj-$(CONFIG_NET_IPVTI) += ip_vti.o | 25 | obj-$(CONFIG_NET_IPVTI) += ip_vti.o |
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 70011e029ac1..ecd2c3f245ce 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c | |||
| @@ -126,9 +126,6 @@ | |||
| 126 | static struct list_head inetsw[SOCK_MAX]; | 126 | static struct list_head inetsw[SOCK_MAX]; |
| 127 | static DEFINE_SPINLOCK(inetsw_lock); | 127 | static DEFINE_SPINLOCK(inetsw_lock); |
| 128 | 128 | ||
| 129 | struct ipv4_config ipv4_config; | ||
| 130 | EXPORT_SYMBOL(ipv4_config); | ||
| 131 | |||
| 132 | /* New destruction routine */ | 129 | /* New destruction routine */ |
| 133 | 130 | ||
| 134 | void inet_sock_destruct(struct sock *sk) | 131 | void inet_sock_destruct(struct sock *sk) |
| @@ -342,7 +339,7 @@ lookup_protocol: | |||
| 342 | inet->hdrincl = 1; | 339 | inet->hdrincl = 1; |
| 343 | } | 340 | } |
| 344 | 341 | ||
| 345 | if (ipv4_config.no_pmtu_disc) | 342 | if (net->ipv4.sysctl_ip_no_pmtu_disc) |
| 346 | inet->pmtudisc = IP_PMTUDISC_DONT; | 343 | inet->pmtudisc = IP_PMTUDISC_DONT; |
| 347 | else | 344 | else |
| 348 | inet->pmtudisc = IP_PMTUDISC_WANT; | 345 | inet->pmtudisc = IP_PMTUDISC_WANT; |
| @@ -1133,7 +1130,7 @@ static int inet_sk_reselect_saddr(struct sock *sk) | |||
| 1133 | fl4 = &inet->cork.fl.u.ip4; | 1130 | fl4 = &inet->cork.fl.u.ip4; |
| 1134 | rt = ip_route_connect(fl4, daddr, 0, RT_CONN_FLAGS(sk), | 1131 | rt = ip_route_connect(fl4, daddr, 0, RT_CONN_FLAGS(sk), |
| 1135 | sk->sk_bound_dev_if, sk->sk_protocol, | 1132 | sk->sk_bound_dev_if, sk->sk_protocol, |
| 1136 | inet->inet_sport, inet->inet_dport, sk, false); | 1133 | inet->inet_sport, inet->inet_dport, sk); |
| 1137 | if (IS_ERR(rt)) | 1134 | if (IS_ERR(rt)) |
| 1138 | return PTR_ERR(rt); | 1135 | return PTR_ERR(rt); |
| 1139 | 1136 | ||
| @@ -1377,8 +1374,12 @@ static struct sk_buff **inet_gro_receive(struct sk_buff **head, | |||
| 1377 | if (!NAPI_GRO_CB(p)->same_flow) | 1374 | if (!NAPI_GRO_CB(p)->same_flow) |
| 1378 | continue; | 1375 | continue; |
| 1379 | 1376 | ||
| 1380 | iph2 = ip_hdr(p); | 1377 | iph2 = (struct iphdr *)(p->data + off); |
| 1381 | 1378 | /* The above works because, with the exception of the top | |
| 1379 | * (inner most) layer, we only aggregate pkts with the same | ||
| 1380 | * hdr length so all the hdrs we'll need to verify will start | ||
| 1381 | * at the same offset. | ||
| 1382 | */ | ||
| 1382 | if ((iph->protocol ^ iph2->protocol) | | 1383 | if ((iph->protocol ^ iph2->protocol) | |
| 1383 | ((__force u32)iph->saddr ^ (__force u32)iph2->saddr) | | 1384 | ((__force u32)iph->saddr ^ (__force u32)iph2->saddr) | |
| 1384 | ((__force u32)iph->daddr ^ (__force u32)iph2->daddr)) { | 1385 | ((__force u32)iph->daddr ^ (__force u32)iph2->daddr)) { |
| @@ -1390,13 +1391,24 @@ static struct sk_buff **inet_gro_receive(struct sk_buff **head, | |||
| 1390 | NAPI_GRO_CB(p)->flush |= | 1391 | NAPI_GRO_CB(p)->flush |= |
| 1391 | (iph->ttl ^ iph2->ttl) | | 1392 | (iph->ttl ^ iph2->ttl) | |
| 1392 | (iph->tos ^ iph2->tos) | | 1393 | (iph->tos ^ iph2->tos) | |
| 1393 | (__force int)((iph->frag_off ^ iph2->frag_off) & htons(IP_DF)) | | 1394 | ((iph->frag_off ^ iph2->frag_off) & htons(IP_DF)); |
| 1394 | ((u16)(ntohs(iph2->id) + NAPI_GRO_CB(p)->count) ^ id); | ||
| 1395 | 1395 | ||
| 1396 | /* Save the IP ID check to be included later when we get to | ||
| 1397 | * the transport layer so only the inner most IP ID is checked. | ||
| 1398 | * This is because some GSO/TSO implementations do not | ||
| 1399 | * correctly increment the IP ID for the outer hdrs. | ||
| 1400 | */ | ||
| 1401 | NAPI_GRO_CB(p)->flush_id = | ||
| 1402 | ((u16)(ntohs(iph2->id) + NAPI_GRO_CB(p)->count) ^ id); | ||
| 1396 | NAPI_GRO_CB(p)->flush |= flush; | 1403 | NAPI_GRO_CB(p)->flush |= flush; |
| 1397 | } | 1404 | } |
| 1398 | 1405 | ||
| 1399 | NAPI_GRO_CB(skb)->flush |= flush; | 1406 | NAPI_GRO_CB(skb)->flush |= flush; |
| 1407 | skb_set_network_header(skb, off); | ||
| 1408 | /* The above will be needed by the transport layer if there is one | ||
| 1409 | * immediately following this IP hdr. | ||
| 1410 | */ | ||
| 1411 | |||
| 1400 | skb_gro_pull(skb, sizeof(*iph)); | 1412 | skb_gro_pull(skb, sizeof(*iph)); |
| 1401 | skb_set_transport_header(skb, skb_gro_offset(skb)); | 1413 | skb_set_transport_header(skb, skb_gro_offset(skb)); |
| 1402 | 1414 | ||
| @@ -1411,10 +1423,10 @@ out: | |||
| 1411 | return pp; | 1423 | return pp; |
| 1412 | } | 1424 | } |
| 1413 | 1425 | ||
| 1414 | static int inet_gro_complete(struct sk_buff *skb) | 1426 | static int inet_gro_complete(struct sk_buff *skb, int nhoff) |
| 1415 | { | 1427 | { |
| 1416 | __be16 newlen = htons(skb->len - skb_network_offset(skb)); | 1428 | __be16 newlen = htons(skb->len - nhoff); |
| 1417 | struct iphdr *iph = ip_hdr(skb); | 1429 | struct iphdr *iph = (struct iphdr *)(skb->data + nhoff); |
| 1418 | const struct net_offload *ops; | 1430 | const struct net_offload *ops; |
| 1419 | int proto = iph->protocol; | 1431 | int proto = iph->protocol; |
| 1420 | int err = -ENOSYS; | 1432 | int err = -ENOSYS; |
| @@ -1427,7 +1439,11 @@ static int inet_gro_complete(struct sk_buff *skb) | |||
| 1427 | if (WARN_ON(!ops || !ops->callbacks.gro_complete)) | 1439 | if (WARN_ON(!ops || !ops->callbacks.gro_complete)) |
| 1428 | goto out_unlock; | 1440 | goto out_unlock; |
| 1429 | 1441 | ||
| 1430 | err = ops->callbacks.gro_complete(skb); | 1442 | /* Only need to add sizeof(*iph) to get to the next hdr below |
| 1443 | * because any hdr with option will have been flushed in | ||
| 1444 | * inet_gro_receive(). | ||
| 1445 | */ | ||
| 1446 | err = ops->callbacks.gro_complete(skb, nhoff + sizeof(*iph)); | ||
| 1431 | 1447 | ||
| 1432 | out_unlock: | 1448 | out_unlock: |
| 1433 | rcu_read_unlock(); | 1449 | rcu_read_unlock(); |
| @@ -1529,6 +1545,7 @@ static const struct net_protocol tcp_protocol = { | |||
| 1529 | .err_handler = tcp_v4_err, | 1545 | .err_handler = tcp_v4_err, |
| 1530 | .no_policy = 1, | 1546 | .no_policy = 1, |
| 1531 | .netns_ok = 1, | 1547 | .netns_ok = 1, |
| 1548 | .icmp_strict_tag_validation = 1, | ||
| 1532 | }; | 1549 | }; |
| 1533 | 1550 | ||
| 1534 | static const struct net_protocol udp_protocol = { | 1551 | static const struct net_protocol udp_protocol = { |
diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index 7808093cede6..1a9b99e04465 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c | |||
| @@ -166,18 +166,20 @@ struct neigh_table arp_tbl = { | |||
| 166 | .id = "arp_cache", | 166 | .id = "arp_cache", |
| 167 | .parms = { | 167 | .parms = { |
| 168 | .tbl = &arp_tbl, | 168 | .tbl = &arp_tbl, |
| 169 | .base_reachable_time = 30 * HZ, | ||
| 170 | .retrans_time = 1 * HZ, | ||
| 171 | .gc_staletime = 60 * HZ, | ||
| 172 | .reachable_time = 30 * HZ, | 169 | .reachable_time = 30 * HZ, |
| 173 | .delay_probe_time = 5 * HZ, | 170 | .data = { |
| 174 | .queue_len_bytes = 64*1024, | 171 | [NEIGH_VAR_MCAST_PROBES] = 3, |
| 175 | .ucast_probes = 3, | 172 | [NEIGH_VAR_UCAST_PROBES] = 3, |
| 176 | .mcast_probes = 3, | 173 | [NEIGH_VAR_RETRANS_TIME] = 1 * HZ, |
| 177 | .anycast_delay = 1 * HZ, | 174 | [NEIGH_VAR_BASE_REACHABLE_TIME] = 30 * HZ, |
| 178 | .proxy_delay = (8 * HZ) / 10, | 175 | [NEIGH_VAR_DELAY_PROBE_TIME] = 5 * HZ, |
| 179 | .proxy_qlen = 64, | 176 | [NEIGH_VAR_GC_STALETIME] = 60 * HZ, |
| 180 | .locktime = 1 * HZ, | 177 | [NEIGH_VAR_QUEUE_LEN_BYTES] = 64 * 1024, |
| 178 | [NEIGH_VAR_PROXY_QLEN] = 64, | ||
| 179 | [NEIGH_VAR_ANYCAST_DELAY] = 1 * HZ, | ||
| 180 | [NEIGH_VAR_PROXY_DELAY] = (8 * HZ) / 10, | ||
| 181 | [NEIGH_VAR_LOCKTIME] = 1 * HZ, | ||
| 182 | }, | ||
| 181 | }, | 183 | }, |
| 182 | .gc_interval = 30 * HZ, | 184 | .gc_interval = 30 * HZ, |
| 183 | .gc_thresh1 = 128, | 185 | .gc_thresh1 = 128, |
| @@ -359,14 +361,14 @@ static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb) | |||
| 359 | if (!saddr) | 361 | if (!saddr) |
| 360 | saddr = inet_select_addr(dev, target, RT_SCOPE_LINK); | 362 | saddr = inet_select_addr(dev, target, RT_SCOPE_LINK); |
| 361 | 363 | ||
| 362 | probes -= neigh->parms->ucast_probes; | 364 | probes -= NEIGH_VAR(neigh->parms, UCAST_PROBES); |
| 363 | if (probes < 0) { | 365 | if (probes < 0) { |
| 364 | if (!(neigh->nud_state & NUD_VALID)) | 366 | if (!(neigh->nud_state & NUD_VALID)) |
| 365 | pr_debug("trying to ucast probe in NUD_INVALID\n"); | 367 | pr_debug("trying to ucast probe in NUD_INVALID\n"); |
| 366 | neigh_ha_snapshot(dst_ha, neigh, dev); | 368 | neigh_ha_snapshot(dst_ha, neigh, dev); |
| 367 | dst_hw = dst_ha; | 369 | dst_hw = dst_ha; |
| 368 | } else { | 370 | } else { |
| 369 | probes -= neigh->parms->app_probes; | 371 | probes -= NEIGH_VAR(neigh->parms, APP_PROBES); |
| 370 | if (probes < 0) { | 372 | if (probes < 0) { |
| 371 | neigh_app_ns(neigh); | 373 | neigh_app_ns(neigh); |
| 372 | return; | 374 | return; |
| @@ -379,6 +381,7 @@ static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb) | |||
| 379 | 381 | ||
| 380 | static int arp_ignore(struct in_device *in_dev, __be32 sip, __be32 tip) | 382 | static int arp_ignore(struct in_device *in_dev, __be32 sip, __be32 tip) |
| 381 | { | 383 | { |
| 384 | struct net *net = dev_net(in_dev->dev); | ||
| 382 | int scope; | 385 | int scope; |
| 383 | 386 | ||
| 384 | switch (IN_DEV_ARP_IGNORE(in_dev)) { | 387 | switch (IN_DEV_ARP_IGNORE(in_dev)) { |
| @@ -397,6 +400,7 @@ static int arp_ignore(struct in_device *in_dev, __be32 sip, __be32 tip) | |||
| 397 | case 3: /* Do not reply for scope host addresses */ | 400 | case 3: /* Do not reply for scope host addresses */ |
| 398 | sip = 0; | 401 | sip = 0; |
| 399 | scope = RT_SCOPE_LINK; | 402 | scope = RT_SCOPE_LINK; |
| 403 | in_dev = NULL; | ||
| 400 | break; | 404 | break; |
| 401 | case 4: /* Reserved */ | 405 | case 4: /* Reserved */ |
| 402 | case 5: | 406 | case 5: |
| @@ -408,7 +412,7 @@ static int arp_ignore(struct in_device *in_dev, __be32 sip, __be32 tip) | |||
| 408 | default: | 412 | default: |
| 409 | return 0; | 413 | return 0; |
| 410 | } | 414 | } |
| 411 | return !inet_confirm_addr(in_dev, sip, tip, scope); | 415 | return !inet_confirm_addr(net, in_dev, sip, tip, scope); |
| 412 | } | 416 | } |
| 413 | 417 | ||
| 414 | static int arp_filter(__be32 sip, __be32 tip, struct net_device *dev) | 418 | static int arp_filter(__be32 sip, __be32 tip, struct net_device *dev) |
| @@ -728,6 +732,7 @@ static int arp_process(struct sk_buff *skb) | |||
| 728 | int addr_type; | 732 | int addr_type; |
| 729 | struct neighbour *n; | 733 | struct neighbour *n; |
| 730 | struct net *net = dev_net(dev); | 734 | struct net *net = dev_net(dev); |
| 735 | bool is_garp = false; | ||
| 731 | 736 | ||
| 732 | /* arp_rcv below verifies the ARP header and verifies the device | 737 | /* arp_rcv below verifies the ARP header and verifies the device |
| 733 | * is ARP'able. | 738 | * is ARP'able. |
| @@ -871,7 +876,7 @@ static int arp_process(struct sk_buff *skb) | |||
| 871 | 876 | ||
| 872 | if (NEIGH_CB(skb)->flags & LOCALLY_ENQUEUED || | 877 | if (NEIGH_CB(skb)->flags & LOCALLY_ENQUEUED || |
| 873 | skb->pkt_type == PACKET_HOST || | 878 | skb->pkt_type == PACKET_HOST || |
| 874 | in_dev->arp_parms->proxy_delay == 0) { | 879 | NEIGH_VAR(in_dev->arp_parms, PROXY_DELAY) == 0) { |
| 875 | arp_send(ARPOP_REPLY, ETH_P_ARP, sip, | 880 | arp_send(ARPOP_REPLY, ETH_P_ARP, sip, |
| 876 | dev, tip, sha, dev->dev_addr, | 881 | dev, tip, sha, dev->dev_addr, |
| 877 | sha); | 882 | sha); |
| @@ -894,10 +899,12 @@ static int arp_process(struct sk_buff *skb) | |||
| 894 | It is possible, that this option should be enabled for some | 899 | It is possible, that this option should be enabled for some |
| 895 | devices (strip is candidate) | 900 | devices (strip is candidate) |
| 896 | */ | 901 | */ |
| 902 | is_garp = arp->ar_op == htons(ARPOP_REQUEST) && tip == sip && | ||
| 903 | inet_addr_type(net, sip) == RTN_UNICAST; | ||
| 904 | |||
| 897 | if (n == NULL && | 905 | if (n == NULL && |
| 898 | (arp->ar_op == htons(ARPOP_REPLY) || | 906 | ((arp->ar_op == htons(ARPOP_REPLY) && |
| 899 | (arp->ar_op == htons(ARPOP_REQUEST) && tip == sip)) && | 907 | inet_addr_type(net, sip) == RTN_UNICAST) || is_garp)) |
| 900 | inet_addr_type(net, sip) == RTN_UNICAST) | ||
| 901 | n = __neigh_lookup(&arp_tbl, &sip, dev, 1); | 908 | n = __neigh_lookup(&arp_tbl, &sip, dev, 1); |
| 902 | } | 909 | } |
| 903 | 910 | ||
| @@ -910,7 +917,10 @@ static int arp_process(struct sk_buff *skb) | |||
| 910 | agents are active. Taking the first reply prevents | 917 | agents are active. Taking the first reply prevents |
| 911 | arp trashing and chooses the fastest router. | 918 | arp trashing and chooses the fastest router. |
| 912 | */ | 919 | */ |
| 913 | override = time_after(jiffies, n->updated + n->parms->locktime); | 920 | override = time_after(jiffies, |
| 921 | n->updated + | ||
| 922 | NEIGH_VAR(n->parms, LOCKTIME)) || | ||
| 923 | is_garp; | ||
| 914 | 924 | ||
| 915 | /* Broadcast replies and request packets | 925 | /* Broadcast replies and request packets |
| 916 | do not assert neighbour reachability. | 926 | do not assert neighbour reachability. |
| @@ -1107,7 +1117,7 @@ static int arp_req_get(struct arpreq *r, struct net_device *dev) | |||
| 1107 | return err; | 1117 | return err; |
| 1108 | } | 1118 | } |
| 1109 | 1119 | ||
| 1110 | int arp_invalidate(struct net_device *dev, __be32 ip) | 1120 | static int arp_invalidate(struct net_device *dev, __be32 ip) |
| 1111 | { | 1121 | { |
| 1112 | struct neighbour *neigh = neigh_lookup(&arp_tbl, &ip, dev); | 1122 | struct neighbour *neigh = neigh_lookup(&arp_tbl, &ip, dev); |
| 1113 | int err = -ENXIO; | 1123 | int err = -ENXIO; |
| @@ -1122,7 +1132,6 @@ int arp_invalidate(struct net_device *dev, __be32 ip) | |||
| 1122 | 1132 | ||
| 1123 | return err; | 1133 | return err; |
| 1124 | } | 1134 | } |
| 1125 | EXPORT_SYMBOL(arp_invalidate); | ||
| 1126 | 1135 | ||
| 1127 | static int arp_req_delete_public(struct net *net, struct arpreq *r, | 1136 | static int arp_req_delete_public(struct net *net, struct arpreq *r, |
| 1128 | struct net_device *dev) | 1137 | struct net_device *dev) |
| @@ -1284,7 +1293,7 @@ void __init arp_init(void) | |||
| 1284 | dev_add_pack(&arp_packet_type); | 1293 | dev_add_pack(&arp_packet_type); |
| 1285 | arp_proc_init(); | 1294 | arp_proc_init(); |
| 1286 | #ifdef CONFIG_SYSCTL | 1295 | #ifdef CONFIG_SYSCTL |
| 1287 | neigh_sysctl_register(NULL, &arp_tbl.parms, "ipv4", NULL); | 1296 | neigh_sysctl_register(NULL, &arp_tbl.parms, NULL); |
| 1288 | #endif | 1297 | #endif |
| 1289 | register_netdevice_notifier(&arp_netdev_notifier); | 1298 | register_netdevice_notifier(&arp_netdev_notifier); |
| 1290 | } | 1299 | } |
diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c index 667c1d4ca984..69e77c8ff285 100644 --- a/net/ipv4/cipso_ipv4.c +++ b/net/ipv4/cipso_ipv4.c | |||
| @@ -31,8 +31,7 @@ | |||
| 31 | * the GNU General Public License for more details. | 31 | * the GNU General Public License for more details. |
| 32 | * | 32 | * |
| 33 | * You should have received a copy of the GNU General Public License | 33 | * You should have received a copy of the GNU General Public License |
| 34 | * along with this program; if not, write to the Free Software | 34 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 35 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 36 | * | 35 | * |
| 37 | */ | 36 | */ |
| 38 | 37 | ||
| @@ -1336,8 +1335,7 @@ static int cipso_v4_parsetag_rbm(const struct cipso_v4_doi *doi_def, | |||
| 1336 | secattr->flags |= NETLBL_SECATTR_MLS_LVL; | 1335 | secattr->flags |= NETLBL_SECATTR_MLS_LVL; |
| 1337 | 1336 | ||
| 1338 | if (tag_len > 4) { | 1337 | if (tag_len > 4) { |
| 1339 | secattr->attr.mls.cat = | 1338 | secattr->attr.mls.cat = netlbl_secattr_catmap_alloc(GFP_ATOMIC); |
| 1340 | netlbl_secattr_catmap_alloc(GFP_ATOMIC); | ||
| 1341 | if (secattr->attr.mls.cat == NULL) | 1339 | if (secattr->attr.mls.cat == NULL) |
| 1342 | return -ENOMEM; | 1340 | return -ENOMEM; |
| 1343 | 1341 | ||
| @@ -1432,8 +1430,7 @@ static int cipso_v4_parsetag_enum(const struct cipso_v4_doi *doi_def, | |||
| 1432 | secattr->flags |= NETLBL_SECATTR_MLS_LVL; | 1430 | secattr->flags |= NETLBL_SECATTR_MLS_LVL; |
| 1433 | 1431 | ||
| 1434 | if (tag_len > 4) { | 1432 | if (tag_len > 4) { |
| 1435 | secattr->attr.mls.cat = | 1433 | secattr->attr.mls.cat = netlbl_secattr_catmap_alloc(GFP_ATOMIC); |
| 1436 | netlbl_secattr_catmap_alloc(GFP_ATOMIC); | ||
| 1437 | if (secattr->attr.mls.cat == NULL) | 1434 | if (secattr->attr.mls.cat == NULL) |
| 1438 | return -ENOMEM; | 1435 | return -ENOMEM; |
| 1439 | 1436 | ||
| @@ -1527,8 +1524,7 @@ static int cipso_v4_parsetag_rng(const struct cipso_v4_doi *doi_def, | |||
| 1527 | secattr->flags |= NETLBL_SECATTR_MLS_LVL; | 1524 | secattr->flags |= NETLBL_SECATTR_MLS_LVL; |
| 1528 | 1525 | ||
| 1529 | if (tag_len > 4) { | 1526 | if (tag_len > 4) { |
| 1530 | secattr->attr.mls.cat = | 1527 | secattr->attr.mls.cat = netlbl_secattr_catmap_alloc(GFP_ATOMIC); |
| 1531 | netlbl_secattr_catmap_alloc(GFP_ATOMIC); | ||
| 1532 | if (secattr->attr.mls.cat == NULL) | 1528 | if (secattr->attr.mls.cat == NULL) |
| 1533 | return -ENOMEM; | 1529 | return -ENOMEM; |
| 1534 | 1530 | ||
diff --git a/net/ipv4/datagram.c b/net/ipv4/datagram.c index 19e36376d2a0..8b5134c582f1 100644 --- a/net/ipv4/datagram.c +++ b/net/ipv4/datagram.c | |||
| @@ -53,7 +53,7 @@ int ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) | |||
| 53 | rt = ip_route_connect(fl4, usin->sin_addr.s_addr, saddr, | 53 | rt = ip_route_connect(fl4, usin->sin_addr.s_addr, saddr, |
| 54 | RT_CONN_FLAGS(sk), oif, | 54 | RT_CONN_FLAGS(sk), oif, |
| 55 | sk->sk_protocol, | 55 | sk->sk_protocol, |
| 56 | inet->inet_sport, usin->sin_port, sk, true); | 56 | inet->inet_sport, usin->sin_port, sk); |
| 57 | if (IS_ERR(rt)) { | 57 | if (IS_ERR(rt)) { |
| 58 | err = PTR_ERR(rt); | 58 | err = PTR_ERR(rt); |
| 59 | if (err == -ENETUNREACH) | 59 | if (err == -ENETUNREACH) |
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index a1b5bcbd04ae..ac2dff3c2c1c 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c | |||
| @@ -99,6 +99,7 @@ static const struct nla_policy ifa_ipv4_policy[IFA_MAX+1] = { | |||
| 99 | [IFA_BROADCAST] = { .type = NLA_U32 }, | 99 | [IFA_BROADCAST] = { .type = NLA_U32 }, |
| 100 | [IFA_LABEL] = { .type = NLA_STRING, .len = IFNAMSIZ - 1 }, | 100 | [IFA_LABEL] = { .type = NLA_STRING, .len = IFNAMSIZ - 1 }, |
| 101 | [IFA_CACHEINFO] = { .len = sizeof(struct ifa_cacheinfo) }, | 101 | [IFA_CACHEINFO] = { .len = sizeof(struct ifa_cacheinfo) }, |
| 102 | [IFA_FLAGS] = { .type = NLA_U32 }, | ||
| 102 | }; | 103 | }; |
| 103 | 104 | ||
| 104 | #define IN4_ADDR_HSIZE_SHIFT 8 | 105 | #define IN4_ADDR_HSIZE_SHIFT 8 |
| @@ -463,7 +464,7 @@ static int __inet_insert_ifa(struct in_ifaddr *ifa, struct nlmsghdr *nlh, | |||
| 463 | } | 464 | } |
| 464 | 465 | ||
| 465 | if (!(ifa->ifa_flags & IFA_F_SECONDARY)) { | 466 | if (!(ifa->ifa_flags & IFA_F_SECONDARY)) { |
| 466 | net_srandom(ifa->ifa_local); | 467 | prandom_seed((__force u32) ifa->ifa_local); |
| 467 | ifap = last_primary; | 468 | ifap = last_primary; |
| 468 | } | 469 | } |
| 469 | 470 | ||
| @@ -473,7 +474,7 @@ static int __inet_insert_ifa(struct in_ifaddr *ifa, struct nlmsghdr *nlh, | |||
| 473 | inet_hash_insert(dev_net(in_dev->dev), ifa); | 474 | inet_hash_insert(dev_net(in_dev->dev), ifa); |
| 474 | 475 | ||
| 475 | cancel_delayed_work(&check_lifetime_work); | 476 | cancel_delayed_work(&check_lifetime_work); |
| 476 | schedule_delayed_work(&check_lifetime_work, 0); | 477 | queue_delayed_work(system_power_efficient_wq, &check_lifetime_work, 0); |
| 477 | 478 | ||
| 478 | /* Send message first, then call notifier. | 479 | /* Send message first, then call notifier. |
| 479 | Notifier will trigger FIB update, so that | 480 | Notifier will trigger FIB update, so that |
| @@ -500,6 +501,7 @@ static int inet_set_ifa(struct net_device *dev, struct in_ifaddr *ifa) | |||
| 500 | return -ENOBUFS; | 501 | return -ENOBUFS; |
| 501 | } | 502 | } |
| 502 | ipv4_devconf_setall(in_dev); | 503 | ipv4_devconf_setall(in_dev); |
| 504 | neigh_parms_data_state_setall(in_dev->arp_parms); | ||
| 503 | if (ifa->ifa_dev != in_dev) { | 505 | if (ifa->ifa_dev != in_dev) { |
| 504 | WARN_ON(ifa->ifa_dev); | 506 | WARN_ON(ifa->ifa_dev); |
| 505 | in_dev_hold(in_dev); | 507 | in_dev_hold(in_dev); |
| @@ -682,7 +684,8 @@ static void check_lifetime(struct work_struct *work) | |||
| 682 | if (time_before(next_sched, now + ADDRCONF_TIMER_FUZZ_MAX)) | 684 | if (time_before(next_sched, now + ADDRCONF_TIMER_FUZZ_MAX)) |
| 683 | next_sched = now + ADDRCONF_TIMER_FUZZ_MAX; | 685 | next_sched = now + ADDRCONF_TIMER_FUZZ_MAX; |
| 684 | 686 | ||
| 685 | schedule_delayed_work(&check_lifetime_work, next_sched - now); | 687 | queue_delayed_work(system_power_efficient_wq, &check_lifetime_work, |
| 688 | next_sched - now); | ||
| 686 | } | 689 | } |
| 687 | 690 | ||
| 688 | static void set_ifa_lifetime(struct in_ifaddr *ifa, __u32 valid_lft, | 691 | static void set_ifa_lifetime(struct in_ifaddr *ifa, __u32 valid_lft, |
| @@ -747,6 +750,7 @@ static struct in_ifaddr *rtm_to_ifaddr(struct net *net, struct nlmsghdr *nlh, | |||
| 747 | goto errout; | 750 | goto errout; |
| 748 | 751 | ||
| 749 | ipv4_devconf_setall(in_dev); | 752 | ipv4_devconf_setall(in_dev); |
| 753 | neigh_parms_data_state_setall(in_dev->arp_parms); | ||
| 750 | in_dev_hold(in_dev); | 754 | in_dev_hold(in_dev); |
| 751 | 755 | ||
| 752 | if (tb[IFA_ADDRESS] == NULL) | 756 | if (tb[IFA_ADDRESS] == NULL) |
| @@ -755,7 +759,8 @@ static struct in_ifaddr *rtm_to_ifaddr(struct net *net, struct nlmsghdr *nlh, | |||
| 755 | INIT_HLIST_NODE(&ifa->hash); | 759 | INIT_HLIST_NODE(&ifa->hash); |
| 756 | ifa->ifa_prefixlen = ifm->ifa_prefixlen; | 760 | ifa->ifa_prefixlen = ifm->ifa_prefixlen; |
| 757 | ifa->ifa_mask = inet_make_mask(ifm->ifa_prefixlen); | 761 | ifa->ifa_mask = inet_make_mask(ifm->ifa_prefixlen); |
| 758 | ifa->ifa_flags = ifm->ifa_flags; | 762 | ifa->ifa_flags = tb[IFA_FLAGS] ? nla_get_u32(tb[IFA_FLAGS]) : |
| 763 | ifm->ifa_flags; | ||
| 759 | ifa->ifa_scope = ifm->ifa_scope; | 764 | ifa->ifa_scope = ifm->ifa_scope; |
| 760 | ifa->ifa_dev = in_dev; | 765 | ifa->ifa_dev = in_dev; |
| 761 | 766 | ||
| @@ -838,7 +843,8 @@ static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
| 838 | ifa = ifa_existing; | 843 | ifa = ifa_existing; |
| 839 | set_ifa_lifetime(ifa, valid_lft, prefered_lft); | 844 | set_ifa_lifetime(ifa, valid_lft, prefered_lft); |
| 840 | cancel_delayed_work(&check_lifetime_work); | 845 | cancel_delayed_work(&check_lifetime_work); |
| 841 | schedule_delayed_work(&check_lifetime_work, 0); | 846 | queue_delayed_work(system_power_efficient_wq, |
| 847 | &check_lifetime_work, 0); | ||
| 842 | rtmsg_ifa(RTM_NEWADDR, ifa, nlh, NETLINK_CB(skb).portid); | 848 | rtmsg_ifa(RTM_NEWADDR, ifa, nlh, NETLINK_CB(skb).portid); |
| 843 | blocking_notifier_call_chain(&inetaddr_chain, NETDEV_UP, ifa); | 849 | blocking_notifier_call_chain(&inetaddr_chain, NETDEV_UP, ifa); |
| 844 | } | 850 | } |
| @@ -1236,22 +1242,21 @@ static __be32 confirm_addr_indev(struct in_device *in_dev, __be32 dst, | |||
| 1236 | 1242 | ||
| 1237 | /* | 1243 | /* |
| 1238 | * Confirm that local IP address exists using wildcards: | 1244 | * Confirm that local IP address exists using wildcards: |
| 1239 | * - in_dev: only on this interface, 0=any interface | 1245 | * - net: netns to check, cannot be NULL |
| 1246 | * - in_dev: only on this interface, NULL=any interface | ||
| 1240 | * - dst: only in the same subnet as dst, 0=any dst | 1247 | * - dst: only in the same subnet as dst, 0=any dst |
| 1241 | * - local: address, 0=autoselect the local address | 1248 | * - local: address, 0=autoselect the local address |
| 1242 | * - scope: maximum allowed scope value for the local address | 1249 | * - scope: maximum allowed scope value for the local address |
| 1243 | */ | 1250 | */ |
| 1244 | __be32 inet_confirm_addr(struct in_device *in_dev, | 1251 | __be32 inet_confirm_addr(struct net *net, struct in_device *in_dev, |
| 1245 | __be32 dst, __be32 local, int scope) | 1252 | __be32 dst, __be32 local, int scope) |
| 1246 | { | 1253 | { |
| 1247 | __be32 addr = 0; | 1254 | __be32 addr = 0; |
| 1248 | struct net_device *dev; | 1255 | struct net_device *dev; |
| 1249 | struct net *net; | ||
| 1250 | 1256 | ||
| 1251 | if (scope != RT_SCOPE_LINK) | 1257 | if (in_dev != NULL) |
| 1252 | return confirm_addr_indev(in_dev, dst, local, scope); | 1258 | return confirm_addr_indev(in_dev, dst, local, scope); |
| 1253 | 1259 | ||
| 1254 | net = dev_net(in_dev->dev); | ||
| 1255 | rcu_read_lock(); | 1260 | rcu_read_lock(); |
| 1256 | for_each_netdev_rcu(net, dev) { | 1261 | for_each_netdev_rcu(net, dev) { |
| 1257 | in_dev = __in_dev_get_rcu(dev); | 1262 | in_dev = __in_dev_get_rcu(dev); |
| @@ -1382,6 +1387,8 @@ static int inetdev_event(struct notifier_block *this, unsigned long event, | |||
| 1382 | memcpy(ifa->ifa_label, dev->name, IFNAMSIZ); | 1387 | memcpy(ifa->ifa_label, dev->name, IFNAMSIZ); |
| 1383 | set_ifa_lifetime(ifa, INFINITY_LIFE_TIME, | 1388 | set_ifa_lifetime(ifa, INFINITY_LIFE_TIME, |
| 1384 | INFINITY_LIFE_TIME); | 1389 | INFINITY_LIFE_TIME); |
| 1390 | ipv4_devconf_setall(in_dev); | ||
| 1391 | neigh_parms_data_state_setall(in_dev->arp_parms); | ||
| 1385 | inet_insert_ifa(ifa); | 1392 | inet_insert_ifa(ifa); |
| 1386 | } | 1393 | } |
| 1387 | } | 1394 | } |
| @@ -1435,7 +1442,8 @@ static size_t inet_nlmsg_size(void) | |||
| 1435 | + nla_total_size(4) /* IFA_ADDRESS */ | 1442 | + nla_total_size(4) /* IFA_ADDRESS */ |
| 1436 | + nla_total_size(4) /* IFA_LOCAL */ | 1443 | + nla_total_size(4) /* IFA_LOCAL */ |
| 1437 | + nla_total_size(4) /* IFA_BROADCAST */ | 1444 | + nla_total_size(4) /* IFA_BROADCAST */ |
| 1438 | + nla_total_size(IFNAMSIZ); /* IFA_LABEL */ | 1445 | + nla_total_size(IFNAMSIZ) /* IFA_LABEL */ |
| 1446 | + nla_total_size(4); /* IFA_FLAGS */ | ||
| 1439 | } | 1447 | } |
| 1440 | 1448 | ||
| 1441 | static inline u32 cstamp_delta(unsigned long cstamp) | 1449 | static inline u32 cstamp_delta(unsigned long cstamp) |
| @@ -1503,6 +1511,7 @@ static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa, | |||
| 1503 | nla_put_be32(skb, IFA_BROADCAST, ifa->ifa_broadcast)) || | 1511 | nla_put_be32(skb, IFA_BROADCAST, ifa->ifa_broadcast)) || |
| 1504 | (ifa->ifa_label[0] && | 1512 | (ifa->ifa_label[0] && |
| 1505 | nla_put_string(skb, IFA_LABEL, ifa->ifa_label)) || | 1513 | nla_put_string(skb, IFA_LABEL, ifa->ifa_label)) || |
| 1514 | nla_put_u32(skb, IFA_FLAGS, ifa->ifa_flags) || | ||
| 1506 | put_cacheinfo(skb, ifa->ifa_cstamp, ifa->ifa_tstamp, | 1515 | put_cacheinfo(skb, ifa->ifa_cstamp, ifa->ifa_tstamp, |
| 1507 | preferred, valid)) | 1516 | preferred, valid)) |
| 1508 | goto nla_put_failure; | 1517 | goto nla_put_failure; |
| @@ -1691,6 +1700,8 @@ static int inet_netconf_msgsize_devconf(int type) | |||
| 1691 | size += nla_total_size(4); | 1700 | size += nla_total_size(4); |
| 1692 | if (type == -1 || type == NETCONFA_MC_FORWARDING) | 1701 | if (type == -1 || type == NETCONFA_MC_FORWARDING) |
| 1693 | size += nla_total_size(4); | 1702 | size += nla_total_size(4); |
| 1703 | if (type == -1 || type == NETCONFA_PROXY_NEIGH) | ||
| 1704 | size += nla_total_size(4); | ||
| 1694 | 1705 | ||
| 1695 | return size; | 1706 | return size; |
| 1696 | } | 1707 | } |
| @@ -1727,6 +1738,10 @@ static int inet_netconf_fill_devconf(struct sk_buff *skb, int ifindex, | |||
| 1727 | nla_put_s32(skb, NETCONFA_MC_FORWARDING, | 1738 | nla_put_s32(skb, NETCONFA_MC_FORWARDING, |
| 1728 | IPV4_DEVCONF(*devconf, MC_FORWARDING)) < 0) | 1739 | IPV4_DEVCONF(*devconf, MC_FORWARDING)) < 0) |
| 1729 | goto nla_put_failure; | 1740 | goto nla_put_failure; |
| 1741 | if ((type == -1 || type == NETCONFA_PROXY_NEIGH) && | ||
| 1742 | nla_put_s32(skb, NETCONFA_PROXY_NEIGH, | ||
| 1743 | IPV4_DEVCONF(*devconf, PROXY_ARP)) < 0) | ||
| 1744 | goto nla_put_failure; | ||
| 1730 | 1745 | ||
| 1731 | return nlmsg_end(skb, nlh); | 1746 | return nlmsg_end(skb, nlh); |
| 1732 | 1747 | ||
| @@ -1764,6 +1779,7 @@ static const struct nla_policy devconf_ipv4_policy[NETCONFA_MAX+1] = { | |||
| 1764 | [NETCONFA_IFINDEX] = { .len = sizeof(int) }, | 1779 | [NETCONFA_IFINDEX] = { .len = sizeof(int) }, |
| 1765 | [NETCONFA_FORWARDING] = { .len = sizeof(int) }, | 1780 | [NETCONFA_FORWARDING] = { .len = sizeof(int) }, |
| 1766 | [NETCONFA_RP_FILTER] = { .len = sizeof(int) }, | 1781 | [NETCONFA_RP_FILTER] = { .len = sizeof(int) }, |
| 1782 | [NETCONFA_PROXY_NEIGH] = { .len = sizeof(int) }, | ||
| 1767 | }; | 1783 | }; |
| 1768 | 1784 | ||
| 1769 | static int inet_netconf_get_devconf(struct sk_buff *in_skb, | 1785 | static int inet_netconf_get_devconf(struct sk_buff *in_skb, |
| @@ -1945,6 +1961,19 @@ static void inet_forward_change(struct net *net) | |||
| 1945 | } | 1961 | } |
| 1946 | } | 1962 | } |
| 1947 | 1963 | ||
| 1964 | static int devinet_conf_ifindex(struct net *net, struct ipv4_devconf *cnf) | ||
| 1965 | { | ||
| 1966 | if (cnf == net->ipv4.devconf_dflt) | ||
| 1967 | return NETCONFA_IFINDEX_DEFAULT; | ||
| 1968 | else if (cnf == net->ipv4.devconf_all) | ||
| 1969 | return NETCONFA_IFINDEX_ALL; | ||
| 1970 | else { | ||
| 1971 | struct in_device *idev | ||
| 1972 | = container_of(cnf, struct in_device, cnf); | ||
| 1973 | return idev->dev->ifindex; | ||
| 1974 | } | ||
| 1975 | } | ||
| 1976 | |||
| 1948 | static int devinet_conf_proc(struct ctl_table *ctl, int write, | 1977 | static int devinet_conf_proc(struct ctl_table *ctl, int write, |
| 1949 | void __user *buffer, | 1978 | void __user *buffer, |
| 1950 | size_t *lenp, loff_t *ppos) | 1979 | size_t *lenp, loff_t *ppos) |
| @@ -1957,6 +1986,7 @@ static int devinet_conf_proc(struct ctl_table *ctl, int write, | |||
| 1957 | struct ipv4_devconf *cnf = ctl->extra1; | 1986 | struct ipv4_devconf *cnf = ctl->extra1; |
| 1958 | struct net *net = ctl->extra2; | 1987 | struct net *net = ctl->extra2; |
| 1959 | int i = (int *)ctl->data - cnf->data; | 1988 | int i = (int *)ctl->data - cnf->data; |
| 1989 | int ifindex; | ||
| 1960 | 1990 | ||
| 1961 | set_bit(i, cnf->state); | 1991 | set_bit(i, cnf->state); |
| 1962 | 1992 | ||
| @@ -1966,23 +1996,19 @@ static int devinet_conf_proc(struct ctl_table *ctl, int write, | |||
| 1966 | i == IPV4_DEVCONF_ROUTE_LOCALNET - 1) | 1996 | i == IPV4_DEVCONF_ROUTE_LOCALNET - 1) |
| 1967 | if ((new_value == 0) && (old_value != 0)) | 1997 | if ((new_value == 0) && (old_value != 0)) |
| 1968 | rt_cache_flush(net); | 1998 | rt_cache_flush(net); |
| 1999 | |||
| 1969 | if (i == IPV4_DEVCONF_RP_FILTER - 1 && | 2000 | if (i == IPV4_DEVCONF_RP_FILTER - 1 && |
| 1970 | new_value != old_value) { | 2001 | new_value != old_value) { |
| 1971 | int ifindex; | 2002 | ifindex = devinet_conf_ifindex(net, cnf); |
| 1972 | |||
| 1973 | if (cnf == net->ipv4.devconf_dflt) | ||
| 1974 | ifindex = NETCONFA_IFINDEX_DEFAULT; | ||
| 1975 | else if (cnf == net->ipv4.devconf_all) | ||
| 1976 | ifindex = NETCONFA_IFINDEX_ALL; | ||
| 1977 | else { | ||
| 1978 | struct in_device *idev = | ||
| 1979 | container_of(cnf, struct in_device, | ||
| 1980 | cnf); | ||
| 1981 | ifindex = idev->dev->ifindex; | ||
| 1982 | } | ||
| 1983 | inet_netconf_notify_devconf(net, NETCONFA_RP_FILTER, | 2003 | inet_netconf_notify_devconf(net, NETCONFA_RP_FILTER, |
| 1984 | ifindex, cnf); | 2004 | ifindex, cnf); |
| 1985 | } | 2005 | } |
| 2006 | if (i == IPV4_DEVCONF_PROXY_ARP - 1 && | ||
| 2007 | new_value != old_value) { | ||
| 2008 | ifindex = devinet_conf_ifindex(net, cnf); | ||
| 2009 | inet_netconf_notify_devconf(net, NETCONFA_PROXY_NEIGH, | ||
| 2010 | ifindex, cnf); | ||
| 2011 | } | ||
| 1986 | } | 2012 | } |
| 1987 | 2013 | ||
| 1988 | return ret; | 2014 | return ret; |
| @@ -2160,7 +2186,7 @@ static void __devinet_sysctl_unregister(struct ipv4_devconf *cnf) | |||
| 2160 | 2186 | ||
| 2161 | static void devinet_sysctl_register(struct in_device *idev) | 2187 | static void devinet_sysctl_register(struct in_device *idev) |
| 2162 | { | 2188 | { |
| 2163 | neigh_sysctl_register(idev->dev, idev->arp_parms, "ipv4", NULL); | 2189 | neigh_sysctl_register(idev->dev, idev->arp_parms, NULL); |
| 2164 | __devinet_sysctl_register(dev_net(idev->dev), idev->dev->name, | 2190 | __devinet_sysctl_register(dev_net(idev->dev), idev->dev->name, |
| 2165 | &idev->cnf); | 2191 | &idev->cnf); |
| 2166 | } | 2192 | } |
| @@ -2298,7 +2324,7 @@ void __init devinet_init(void) | |||
| 2298 | register_gifconf(PF_INET, inet_gifconf); | 2324 | register_gifconf(PF_INET, inet_gifconf); |
| 2299 | register_netdevice_notifier(&ip_netdev_notifier); | 2325 | register_netdevice_notifier(&ip_netdev_notifier); |
| 2300 | 2326 | ||
| 2301 | schedule_delayed_work(&check_lifetime_work, 0); | 2327 | queue_delayed_work(system_power_efficient_wq, &check_lifetime_work, 0); |
| 2302 | 2328 | ||
| 2303 | rtnl_af_register(&inet_af_ops); | 2329 | rtnl_af_register(&inet_af_ops); |
| 2304 | 2330 | ||
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index d846304b7b89..c7539e22868b 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c | |||
| @@ -1047,6 +1047,8 @@ static int fib_netdev_event(struct notifier_block *this, unsigned long event, vo | |||
| 1047 | } | 1047 | } |
| 1048 | 1048 | ||
| 1049 | in_dev = __in_dev_get_rtnl(dev); | 1049 | in_dev = __in_dev_get_rtnl(dev); |
| 1050 | if (!in_dev) | ||
| 1051 | return NOTIFY_DONE; | ||
| 1050 | 1052 | ||
| 1051 | switch (event) { | 1053 | switch (event) { |
| 1052 | case NETDEV_UP: | 1054 | case NETDEV_UP: |
diff --git a/net/ipv4/fib_lookup.h b/net/ipv4/fib_lookup.h index 388d113fd289..1e4f6600b31d 100644 --- a/net/ipv4/fib_lookup.h +++ b/net/ipv4/fib_lookup.h | |||
| @@ -33,8 +33,6 @@ int fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event, u32 tb_id, | |||
| 33 | void rtmsg_fib(int event, __be32 key, struct fib_alias *fa, int dst_len, | 33 | void rtmsg_fib(int event, __be32 key, struct fib_alias *fa, int dst_len, |
| 34 | u32 tb_id, const struct nl_info *info, unsigned int nlm_flags); | 34 | u32 tb_id, const struct nl_info *info, unsigned int nlm_flags); |
| 35 | struct fib_alias *fib_find_alias(struct list_head *fah, u8 tos, u32 prio); | 35 | struct fib_alias *fib_find_alias(struct list_head *fah, u8 tos, u32 prio); |
| 36 | int fib_detect_death(struct fib_info *fi, int order, | ||
| 37 | struct fib_info **last_resort, int *last_idx, int dflt); | ||
| 38 | 36 | ||
| 39 | static inline void fib_result_assign(struct fib_result *res, | 37 | static inline void fib_result_assign(struct fib_result *res, |
| 40 | struct fib_info *fi) | 38 | struct fib_info *fi) |
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c index e63f47a4e651..b53f0bf84dca 100644 --- a/net/ipv4/fib_semantics.c +++ b/net/ipv4/fib_semantics.c | |||
| @@ -426,8 +426,9 @@ struct fib_alias *fib_find_alias(struct list_head *fah, u8 tos, u32 prio) | |||
| 426 | return NULL; | 426 | return NULL; |
| 427 | } | 427 | } |
| 428 | 428 | ||
| 429 | int fib_detect_death(struct fib_info *fi, int order, | 429 | static int fib_detect_death(struct fib_info *fi, int order, |
| 430 | struct fib_info **last_resort, int *last_idx, int dflt) | 430 | struct fib_info **last_resort, int *last_idx, |
| 431 | int dflt) | ||
| 431 | { | 432 | { |
| 432 | struct neighbour *n; | 433 | struct neighbour *n; |
| 433 | int state = NUD_NONE; | 434 | int state = NUD_NONE; |
diff --git a/net/ipv4/gre_demux.c b/net/ipv4/gre_demux.c index 5893e99e8299..1863422fb7d5 100644 --- a/net/ipv4/gre_demux.c +++ b/net/ipv4/gre_demux.c | |||
| @@ -355,14 +355,7 @@ static int __init gre_init(void) | |||
| 355 | goto err_gre; | 355 | goto err_gre; |
| 356 | } | 356 | } |
| 357 | 357 | ||
| 358 | if (gre_offload_init()) { | ||
| 359 | pr_err("can't add protocol offload\n"); | ||
| 360 | goto err_gso; | ||
| 361 | } | ||
| 362 | |||
| 363 | return 0; | 358 | return 0; |
| 364 | err_gso: | ||
| 365 | gre_del_protocol(&ipgre_protocol, GREPROTO_CISCO); | ||
| 366 | err_gre: | 359 | err_gre: |
| 367 | inet_del_protocol(&net_gre_protocol, IPPROTO_GRE); | 360 | inet_del_protocol(&net_gre_protocol, IPPROTO_GRE); |
| 368 | err: | 361 | err: |
| @@ -371,8 +364,6 @@ err: | |||
| 371 | 364 | ||
| 372 | static void __exit gre_exit(void) | 365 | static void __exit gre_exit(void) |
| 373 | { | 366 | { |
| 374 | gre_offload_exit(); | ||
| 375 | |||
| 376 | gre_del_protocol(&ipgre_protocol, GREPROTO_CISCO); | 367 | gre_del_protocol(&ipgre_protocol, GREPROTO_CISCO); |
| 377 | inet_del_protocol(&net_gre_protocol, IPPROTO_GRE); | 368 | inet_del_protocol(&net_gre_protocol, IPPROTO_GRE); |
| 378 | } | 369 | } |
diff --git a/net/ipv4/gre_offload.c b/net/ipv4/gre_offload.c index 2cd02f32f99f..f1d32280cb54 100644 --- a/net/ipv4/gre_offload.c +++ b/net/ipv4/gre_offload.c | |||
| @@ -11,6 +11,7 @@ | |||
| 11 | */ | 11 | */ |
| 12 | 12 | ||
| 13 | #include <linux/skbuff.h> | 13 | #include <linux/skbuff.h> |
| 14 | #include <linux/init.h> | ||
| 14 | #include <net/protocol.h> | 15 | #include <net/protocol.h> |
| 15 | #include <net/gre.h> | 16 | #include <net/gre.h> |
| 16 | 17 | ||
| @@ -26,7 +27,7 @@ static struct sk_buff *gre_gso_segment(struct sk_buff *skb, | |||
| 26 | { | 27 | { |
| 27 | struct sk_buff *segs = ERR_PTR(-EINVAL); | 28 | struct sk_buff *segs = ERR_PTR(-EINVAL); |
| 28 | netdev_features_t enc_features; | 29 | netdev_features_t enc_features; |
| 29 | int ghl = GRE_HEADER_SECTION; | 30 | int ghl; |
| 30 | struct gre_base_hdr *greh; | 31 | struct gre_base_hdr *greh; |
| 31 | u16 mac_offset = skb->mac_header; | 32 | u16 mac_offset = skb->mac_header; |
| 32 | int mac_len = skb->mac_len; | 33 | int mac_len = skb->mac_len; |
| @@ -49,15 +50,11 @@ static struct sk_buff *gre_gso_segment(struct sk_buff *skb, | |||
| 49 | 50 | ||
| 50 | greh = (struct gre_base_hdr *)skb_transport_header(skb); | 51 | greh = (struct gre_base_hdr *)skb_transport_header(skb); |
| 51 | 52 | ||
| 52 | if (greh->flags & GRE_KEY) | 53 | ghl = skb_inner_network_header(skb) - skb_transport_header(skb); |
| 53 | ghl += GRE_HEADER_SECTION; | 54 | if (unlikely(ghl < sizeof(*greh))) |
| 54 | if (greh->flags & GRE_SEQ) | 55 | goto out; |
| 55 | ghl += GRE_HEADER_SECTION; | 56 | |
| 56 | if (greh->flags & GRE_CSUM) { | 57 | csum = !!(greh->flags & GRE_CSUM); |
| 57 | ghl += GRE_HEADER_SECTION; | ||
| 58 | csum = true; | ||
| 59 | } else | ||
| 60 | csum = false; | ||
| 61 | 58 | ||
| 62 | if (unlikely(!pskb_may_pull(skb, ghl))) | 59 | if (unlikely(!pskb_may_pull(skb, ghl))) |
| 63 | goto out; | 60 | goto out; |
| @@ -116,19 +113,175 @@ out: | |||
| 116 | return segs; | 113 | return segs; |
| 117 | } | 114 | } |
| 118 | 115 | ||
| 116 | /* Compute the whole skb csum in s/w and store it, then verify GRO csum | ||
| 117 | * starting from gro_offset. | ||
| 118 | */ | ||
| 119 | static __sum16 gro_skb_checksum(struct sk_buff *skb) | ||
| 120 | { | ||
| 121 | __sum16 sum; | ||
| 122 | |||
| 123 | skb->csum = skb_checksum(skb, 0, skb->len, 0); | ||
| 124 | NAPI_GRO_CB(skb)->csum = csum_sub(skb->csum, | ||
| 125 | csum_partial(skb->data, skb_gro_offset(skb), 0)); | ||
| 126 | sum = csum_fold(NAPI_GRO_CB(skb)->csum); | ||
| 127 | if (unlikely(skb->ip_summed == CHECKSUM_COMPLETE)) { | ||
| 128 | if (unlikely(!sum)) | ||
| 129 | netdev_rx_csum_fault(skb->dev); | ||
| 130 | } else | ||
| 131 | skb->ip_summed = CHECKSUM_COMPLETE; | ||
| 132 | |||
| 133 | return sum; | ||
| 134 | } | ||
| 135 | |||
| 136 | static struct sk_buff **gre_gro_receive(struct sk_buff **head, | ||
| 137 | struct sk_buff *skb) | ||
| 138 | { | ||
| 139 | struct sk_buff **pp = NULL; | ||
| 140 | struct sk_buff *p; | ||
| 141 | const struct gre_base_hdr *greh; | ||
| 142 | unsigned int hlen, grehlen; | ||
| 143 | unsigned int off; | ||
| 144 | int flush = 1; | ||
| 145 | struct packet_offload *ptype; | ||
| 146 | __be16 type; | ||
| 147 | |||
| 148 | off = skb_gro_offset(skb); | ||
| 149 | hlen = off + sizeof(*greh); | ||
| 150 | greh = skb_gro_header_fast(skb, off); | ||
| 151 | if (skb_gro_header_hard(skb, hlen)) { | ||
| 152 | greh = skb_gro_header_slow(skb, hlen, off); | ||
| 153 | if (unlikely(!greh)) | ||
| 154 | goto out; | ||
| 155 | } | ||
| 156 | |||
| 157 | /* Only support version 0 and K (key), C (csum) flags. Note that | ||
| 158 | * although the support for the S (seq#) flag can be added easily | ||
| 159 | * for GRO, this is problematic for GSO hence can not be enabled | ||
| 160 | * here because a GRO pkt may end up in the forwarding path, thus | ||
| 161 | * requiring GSO support to break it up correctly. | ||
| 162 | */ | ||
| 163 | if ((greh->flags & ~(GRE_KEY|GRE_CSUM)) != 0) | ||
| 164 | goto out; | ||
| 165 | |||
| 166 | type = greh->protocol; | ||
| 167 | |||
| 168 | rcu_read_lock(); | ||
| 169 | ptype = gro_find_receive_by_type(type); | ||
| 170 | if (ptype == NULL) | ||
| 171 | goto out_unlock; | ||
| 172 | |||
| 173 | grehlen = GRE_HEADER_SECTION; | ||
| 174 | |||
| 175 | if (greh->flags & GRE_KEY) | ||
| 176 | grehlen += GRE_HEADER_SECTION; | ||
| 177 | |||
| 178 | if (greh->flags & GRE_CSUM) | ||
| 179 | grehlen += GRE_HEADER_SECTION; | ||
| 180 | |||
| 181 | hlen = off + grehlen; | ||
| 182 | if (skb_gro_header_hard(skb, hlen)) { | ||
| 183 | greh = skb_gro_header_slow(skb, hlen, off); | ||
| 184 | if (unlikely(!greh)) | ||
| 185 | goto out_unlock; | ||
| 186 | } | ||
| 187 | if (greh->flags & GRE_CSUM) { /* Need to verify GRE csum first */ | ||
| 188 | __sum16 csum = 0; | ||
| 189 | |||
| 190 | if (skb->ip_summed == CHECKSUM_COMPLETE) | ||
| 191 | csum = csum_fold(NAPI_GRO_CB(skb)->csum); | ||
| 192 | /* Don't trust csum error calculated/reported by h/w */ | ||
| 193 | if (skb->ip_summed == CHECKSUM_NONE || csum != 0) | ||
| 194 | csum = gro_skb_checksum(skb); | ||
| 195 | |||
| 196 | /* GRE CSUM is the 1's complement of the 1's complement sum | ||
| 197 | * of the GRE hdr plus payload so it should add up to 0xffff | ||
| 198 | * (and 0 after csum_fold()) just like the IPv4 hdr csum. | ||
| 199 | */ | ||
| 200 | if (csum) | ||
| 201 | goto out_unlock; | ||
| 202 | } | ||
| 203 | flush = 0; | ||
| 204 | |||
| 205 | for (p = *head; p; p = p->next) { | ||
| 206 | const struct gre_base_hdr *greh2; | ||
| 207 | |||
| 208 | if (!NAPI_GRO_CB(p)->same_flow) | ||
| 209 | continue; | ||
| 210 | |||
| 211 | /* The following checks are needed to ensure only pkts | ||
| 212 | * from the same tunnel are considered for aggregation. | ||
| 213 | * The criteria for "the same tunnel" includes: | ||
| 214 | * 1) same version (we only support version 0 here) | ||
| 215 | * 2) same protocol (we only support ETH_P_IP for now) | ||
| 216 | * 3) same set of flags | ||
| 217 | * 4) same key if the key field is present. | ||
| 218 | */ | ||
| 219 | greh2 = (struct gre_base_hdr *)(p->data + off); | ||
| 220 | |||
| 221 | if (greh2->flags != greh->flags || | ||
| 222 | greh2->protocol != greh->protocol) { | ||
| 223 | NAPI_GRO_CB(p)->same_flow = 0; | ||
| 224 | continue; | ||
| 225 | } | ||
| 226 | if (greh->flags & GRE_KEY) { | ||
| 227 | /* compare keys */ | ||
| 228 | if (*(__be32 *)(greh2+1) != *(__be32 *)(greh+1)) { | ||
| 229 | NAPI_GRO_CB(p)->same_flow = 0; | ||
| 230 | continue; | ||
| 231 | } | ||
| 232 | } | ||
| 233 | } | ||
| 234 | |||
| 235 | skb_gro_pull(skb, grehlen); | ||
| 236 | |||
| 237 | /* Adjusted NAPI_GRO_CB(skb)->csum after skb_gro_pull()*/ | ||
| 238 | skb_gro_postpull_rcsum(skb, greh, grehlen); | ||
| 239 | |||
| 240 | pp = ptype->callbacks.gro_receive(head, skb); | ||
| 241 | |||
| 242 | out_unlock: | ||
| 243 | rcu_read_unlock(); | ||
| 244 | out: | ||
| 245 | NAPI_GRO_CB(skb)->flush |= flush; | ||
| 246 | |||
| 247 | return pp; | ||
| 248 | } | ||
| 249 | |||
| 250 | static int gre_gro_complete(struct sk_buff *skb, int nhoff) | ||
| 251 | { | ||
| 252 | struct gre_base_hdr *greh = (struct gre_base_hdr *)(skb->data + nhoff); | ||
| 253 | struct packet_offload *ptype; | ||
| 254 | unsigned int grehlen = sizeof(*greh); | ||
| 255 | int err = -ENOENT; | ||
| 256 | __be16 type; | ||
| 257 | |||
| 258 | type = greh->protocol; | ||
| 259 | if (greh->flags & GRE_KEY) | ||
| 260 | grehlen += GRE_HEADER_SECTION; | ||
| 261 | |||
| 262 | if (greh->flags & GRE_CSUM) | ||
| 263 | grehlen += GRE_HEADER_SECTION; | ||
| 264 | |||
| 265 | rcu_read_lock(); | ||
| 266 | ptype = gro_find_complete_by_type(type); | ||
| 267 | if (ptype != NULL) | ||
| 268 | err = ptype->callbacks.gro_complete(skb, nhoff + grehlen); | ||
| 269 | |||
| 270 | rcu_read_unlock(); | ||
| 271 | return err; | ||
| 272 | } | ||
| 273 | |||
| 119 | static const struct net_offload gre_offload = { | 274 | static const struct net_offload gre_offload = { |
| 120 | .callbacks = { | 275 | .callbacks = { |
| 121 | .gso_send_check = gre_gso_send_check, | 276 | .gso_send_check = gre_gso_send_check, |
| 122 | .gso_segment = gre_gso_segment, | 277 | .gso_segment = gre_gso_segment, |
| 278 | .gro_receive = gre_gro_receive, | ||
| 279 | .gro_complete = gre_gro_complete, | ||
| 123 | }, | 280 | }, |
| 124 | }; | 281 | }; |
| 125 | 282 | ||
| 126 | int __init gre_offload_init(void) | 283 | static int __init gre_offload_init(void) |
| 127 | { | 284 | { |
| 128 | return inet_add_offload(&gre_offload, IPPROTO_GRE); | 285 | return inet_add_offload(&gre_offload, IPPROTO_GRE); |
| 129 | } | 286 | } |
| 130 | 287 | device_initcall(gre_offload_init); | |
| 131 | void __exit gre_offload_exit(void) | ||
| 132 | { | ||
| 133 | inet_del_offload(&gre_offload, IPPROTO_GRE); | ||
| 134 | } | ||
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index 5c0e8bc6e5ba..0134663fdbce 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c | |||
| @@ -668,6 +668,16 @@ static void icmp_socket_deliver(struct sk_buff *skb, u32 info) | |||
| 668 | rcu_read_unlock(); | 668 | rcu_read_unlock(); |
| 669 | } | 669 | } |
| 670 | 670 | ||
| 671 | static bool icmp_tag_validation(int proto) | ||
| 672 | { | ||
| 673 | bool ok; | ||
| 674 | |||
| 675 | rcu_read_lock(); | ||
| 676 | ok = rcu_dereference(inet_protos[proto])->icmp_strict_tag_validation; | ||
| 677 | rcu_read_unlock(); | ||
| 678 | return ok; | ||
| 679 | } | ||
| 680 | |||
| 671 | /* | 681 | /* |
| 672 | * Handle ICMP_DEST_UNREACH, ICMP_TIME_EXCEED, ICMP_QUENCH, and | 682 | * Handle ICMP_DEST_UNREACH, ICMP_TIME_EXCEED, ICMP_QUENCH, and |
| 673 | * ICMP_PARAMETERPROB. | 683 | * ICMP_PARAMETERPROB. |
| @@ -705,10 +715,22 @@ static void icmp_unreach(struct sk_buff *skb) | |||
| 705 | case ICMP_PORT_UNREACH: | 715 | case ICMP_PORT_UNREACH: |
| 706 | break; | 716 | break; |
| 707 | case ICMP_FRAG_NEEDED: | 717 | case ICMP_FRAG_NEEDED: |
| 708 | if (ipv4_config.no_pmtu_disc) { | 718 | /* for documentation of the ip_no_pmtu_disc |
| 719 | * values please see | ||
| 720 | * Documentation/networking/ip-sysctl.txt | ||
| 721 | */ | ||
| 722 | switch (net->ipv4.sysctl_ip_no_pmtu_disc) { | ||
| 723 | default: | ||
| 709 | LIMIT_NETDEBUG(KERN_INFO pr_fmt("%pI4: fragmentation needed and DF set\n"), | 724 | LIMIT_NETDEBUG(KERN_INFO pr_fmt("%pI4: fragmentation needed and DF set\n"), |
| 710 | &iph->daddr); | 725 | &iph->daddr); |
| 711 | } else { | 726 | break; |
| 727 | case 2: | ||
| 728 | goto out; | ||
| 729 | case 3: | ||
| 730 | if (!icmp_tag_validation(iph->protocol)) | ||
| 731 | goto out; | ||
| 732 | /* fall through */ | ||
| 733 | case 0: | ||
| 712 | info = ntohs(icmph->un.frag.mtu); | 734 | info = ntohs(icmph->un.frag.mtu); |
| 713 | if (!info) | 735 | if (!info) |
| 714 | goto out; | 736 | goto out; |
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index 7defdc9ba167..97e4d1655d26 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c | |||
| @@ -211,7 +211,7 @@ static void igmp_stop_timer(struct ip_mc_list *im) | |||
| 211 | /* It must be called with locked im->lock */ | 211 | /* It must be called with locked im->lock */ |
| 212 | static void igmp_start_timer(struct ip_mc_list *im, int max_delay) | 212 | static void igmp_start_timer(struct ip_mc_list *im, int max_delay) |
| 213 | { | 213 | { |
| 214 | int tv = net_random() % max_delay; | 214 | int tv = prandom_u32() % max_delay; |
| 215 | 215 | ||
| 216 | im->tm_running = 1; | 216 | im->tm_running = 1; |
| 217 | if (!mod_timer(&im->timer, jiffies+tv+2)) | 217 | if (!mod_timer(&im->timer, jiffies+tv+2)) |
| @@ -220,7 +220,7 @@ static void igmp_start_timer(struct ip_mc_list *im, int max_delay) | |||
| 220 | 220 | ||
| 221 | static void igmp_gq_start_timer(struct in_device *in_dev) | 221 | static void igmp_gq_start_timer(struct in_device *in_dev) |
| 222 | { | 222 | { |
| 223 | int tv = net_random() % in_dev->mr_maxdelay; | 223 | int tv = prandom_u32() % in_dev->mr_maxdelay; |
| 224 | 224 | ||
| 225 | in_dev->mr_gq_running = 1; | 225 | in_dev->mr_gq_running = 1; |
| 226 | if (!mod_timer(&in_dev->mr_gq_timer, jiffies+tv+2)) | 226 | if (!mod_timer(&in_dev->mr_gq_timer, jiffies+tv+2)) |
| @@ -229,7 +229,7 @@ static void igmp_gq_start_timer(struct in_device *in_dev) | |||
| 229 | 229 | ||
| 230 | static void igmp_ifc_start_timer(struct in_device *in_dev, int delay) | 230 | static void igmp_ifc_start_timer(struct in_device *in_dev, int delay) |
| 231 | { | 231 | { |
| 232 | int tv = net_random() % delay; | 232 | int tv = prandom_u32() % delay; |
| 233 | 233 | ||
| 234 | if (!mod_timer(&in_dev->mr_ifc_timer, jiffies+tv+2)) | 234 | if (!mod_timer(&in_dev->mr_ifc_timer, jiffies+tv+2)) |
| 235 | in_dev_hold(in_dev); | 235 | in_dev_hold(in_dev); |
| @@ -310,7 +310,7 @@ igmp_scount(struct ip_mc_list *pmc, int type, int gdeleted, int sdeleted) | |||
| 310 | struct ip_sf_list *psf; | 310 | struct ip_sf_list *psf; |
| 311 | int scount = 0; | 311 | int scount = 0; |
| 312 | 312 | ||
| 313 | for (psf=pmc->sources; psf; psf=psf->sf_next) { | 313 | for (psf = pmc->sources; psf; psf = psf->sf_next) { |
| 314 | if (!is_in(pmc, psf, type, gdeleted, sdeleted)) | 314 | if (!is_in(pmc, psf, type, gdeleted, sdeleted)) |
| 315 | continue; | 315 | continue; |
| 316 | scount++; | 316 | scount++; |
| @@ -463,7 +463,7 @@ static struct sk_buff *add_grec(struct sk_buff *skb, struct ip_mc_list *pmc, | |||
| 463 | } | 463 | } |
| 464 | first = 1; | 464 | first = 1; |
| 465 | psf_prev = NULL; | 465 | psf_prev = NULL; |
| 466 | for (psf=*psf_list; psf; psf=psf_next) { | 466 | for (psf = *psf_list; psf; psf = psf_next) { |
| 467 | __be32 *psrc; | 467 | __be32 *psrc; |
| 468 | 468 | ||
| 469 | psf_next = psf->sf_next; | 469 | psf_next = psf->sf_next; |
| @@ -520,7 +520,7 @@ empty_source: | |||
| 520 | return skb; | 520 | return skb; |
| 521 | if (pmc->crcount || isquery) { | 521 | if (pmc->crcount || isquery) { |
| 522 | /* make sure we have room for group header */ | 522 | /* make sure we have room for group header */ |
| 523 | if (skb && AVAILABLE(skb)<sizeof(struct igmpv3_grec)) { | 523 | if (skb && AVAILABLE(skb) < sizeof(struct igmpv3_grec)) { |
| 524 | igmpv3_sendpack(skb); | 524 | igmpv3_sendpack(skb); |
| 525 | skb = NULL; /* add_grhead will get a new one */ | 525 | skb = NULL; /* add_grhead will get a new one */ |
| 526 | } | 526 | } |
| @@ -576,7 +576,7 @@ static void igmpv3_clear_zeros(struct ip_sf_list **ppsf) | |||
| 576 | struct ip_sf_list *psf_prev, *psf_next, *psf; | 576 | struct ip_sf_list *psf_prev, *psf_next, *psf; |
| 577 | 577 | ||
| 578 | psf_prev = NULL; | 578 | psf_prev = NULL; |
| 579 | for (psf=*ppsf; psf; psf = psf_next) { | 579 | for (psf = *ppsf; psf; psf = psf_next) { |
| 580 | psf_next = psf->sf_next; | 580 | psf_next = psf->sf_next; |
| 581 | if (psf->sf_crcount == 0) { | 581 | if (psf->sf_crcount == 0) { |
| 582 | if (psf_prev) | 582 | if (psf_prev) |
| @@ -600,7 +600,7 @@ static void igmpv3_send_cr(struct in_device *in_dev) | |||
| 600 | 600 | ||
| 601 | /* deleted MCA's */ | 601 | /* deleted MCA's */ |
| 602 | pmc_prev = NULL; | 602 | pmc_prev = NULL; |
| 603 | for (pmc=in_dev->mc_tomb; pmc; pmc=pmc_next) { | 603 | for (pmc = in_dev->mc_tomb; pmc; pmc = pmc_next) { |
| 604 | pmc_next = pmc->next; | 604 | pmc_next = pmc->next; |
| 605 | if (pmc->sfmode == MCAST_INCLUDE) { | 605 | if (pmc->sfmode == MCAST_INCLUDE) { |
| 606 | type = IGMPV3_BLOCK_OLD_SOURCES; | 606 | type = IGMPV3_BLOCK_OLD_SOURCES; |
| @@ -764,7 +764,7 @@ static void igmp_ifc_event(struct in_device *in_dev) | |||
| 764 | 764 | ||
| 765 | static void igmp_timer_expire(unsigned long data) | 765 | static void igmp_timer_expire(unsigned long data) |
| 766 | { | 766 | { |
| 767 | struct ip_mc_list *im=(struct ip_mc_list *)data; | 767 | struct ip_mc_list *im = (struct ip_mc_list *)data; |
| 768 | struct in_device *in_dev = im->interface; | 768 | struct in_device *in_dev = im->interface; |
| 769 | 769 | ||
| 770 | spin_lock(&im->lock); | 770 | spin_lock(&im->lock); |
| @@ -794,10 +794,10 @@ static int igmp_xmarksources(struct ip_mc_list *pmc, int nsrcs, __be32 *srcs) | |||
| 794 | int i, scount; | 794 | int i, scount; |
| 795 | 795 | ||
| 796 | scount = 0; | 796 | scount = 0; |
| 797 | for (psf=pmc->sources; psf; psf=psf->sf_next) { | 797 | for (psf = pmc->sources; psf; psf = psf->sf_next) { |
| 798 | if (scount == nsrcs) | 798 | if (scount == nsrcs) |
| 799 | break; | 799 | break; |
| 800 | for (i=0; i<nsrcs; i++) { | 800 | for (i = 0; i < nsrcs; i++) { |
| 801 | /* skip inactive filters */ | 801 | /* skip inactive filters */ |
| 802 | if (psf->sf_count[MCAST_INCLUDE] || | 802 | if (psf->sf_count[MCAST_INCLUDE] || |
| 803 | pmc->sfcount[MCAST_EXCLUDE] != | 803 | pmc->sfcount[MCAST_EXCLUDE] != |
| @@ -825,10 +825,10 @@ static int igmp_marksources(struct ip_mc_list *pmc, int nsrcs, __be32 *srcs) | |||
| 825 | 825 | ||
| 826 | /* mark INCLUDE-mode sources */ | 826 | /* mark INCLUDE-mode sources */ |
| 827 | scount = 0; | 827 | scount = 0; |
| 828 | for (psf=pmc->sources; psf; psf=psf->sf_next) { | 828 | for (psf = pmc->sources; psf; psf = psf->sf_next) { |
| 829 | if (scount == nsrcs) | 829 | if (scount == nsrcs) |
| 830 | break; | 830 | break; |
| 831 | for (i=0; i<nsrcs; i++) | 831 | for (i = 0; i < nsrcs; i++) |
| 832 | if (srcs[i] == psf->sf_inaddr) { | 832 | if (srcs[i] == psf->sf_inaddr) { |
| 833 | psf->sf_gsresp = 1; | 833 | psf->sf_gsresp = 1; |
| 834 | scount++; | 834 | scount++; |
| @@ -1103,7 +1103,7 @@ static void igmpv3_add_delrec(struct in_device *in_dev, struct ip_mc_list *im) | |||
| 1103 | pmc->tomb = im->tomb; | 1103 | pmc->tomb = im->tomb; |
| 1104 | pmc->sources = im->sources; | 1104 | pmc->sources = im->sources; |
| 1105 | im->tomb = im->sources = NULL; | 1105 | im->tomb = im->sources = NULL; |
| 1106 | for (psf=pmc->sources; psf; psf=psf->sf_next) | 1106 | for (psf = pmc->sources; psf; psf = psf->sf_next) |
| 1107 | psf->sf_crcount = pmc->crcount; | 1107 | psf->sf_crcount = pmc->crcount; |
| 1108 | } | 1108 | } |
| 1109 | spin_unlock_bh(&im->lock); | 1109 | spin_unlock_bh(&im->lock); |
| @@ -1121,7 +1121,7 @@ static void igmpv3_del_delrec(struct in_device *in_dev, __be32 multiaddr) | |||
| 1121 | 1121 | ||
| 1122 | spin_lock_bh(&in_dev->mc_tomb_lock); | 1122 | spin_lock_bh(&in_dev->mc_tomb_lock); |
| 1123 | pmc_prev = NULL; | 1123 | pmc_prev = NULL; |
| 1124 | for (pmc=in_dev->mc_tomb; pmc; pmc=pmc->next) { | 1124 | for (pmc = in_dev->mc_tomb; pmc; pmc = pmc->next) { |
| 1125 | if (pmc->multiaddr == multiaddr) | 1125 | if (pmc->multiaddr == multiaddr) |
| 1126 | break; | 1126 | break; |
| 1127 | pmc_prev = pmc; | 1127 | pmc_prev = pmc; |
| @@ -1134,7 +1134,7 @@ static void igmpv3_del_delrec(struct in_device *in_dev, __be32 multiaddr) | |||
| 1134 | } | 1134 | } |
| 1135 | spin_unlock_bh(&in_dev->mc_tomb_lock); | 1135 | spin_unlock_bh(&in_dev->mc_tomb_lock); |
| 1136 | if (pmc) { | 1136 | if (pmc) { |
| 1137 | for (psf=pmc->tomb; psf; psf=psf_next) { | 1137 | for (psf = pmc->tomb; psf; psf = psf_next) { |
| 1138 | psf_next = psf->sf_next; | 1138 | psf_next = psf->sf_next; |
| 1139 | kfree(psf); | 1139 | kfree(psf); |
| 1140 | } | 1140 | } |
| @@ -1167,7 +1167,7 @@ static void igmpv3_clear_delrec(struct in_device *in_dev) | |||
| 1167 | psf = pmc->tomb; | 1167 | psf = pmc->tomb; |
| 1168 | pmc->tomb = NULL; | 1168 | pmc->tomb = NULL; |
| 1169 | spin_unlock_bh(&pmc->lock); | 1169 | spin_unlock_bh(&pmc->lock); |
| 1170 | for (; psf; psf=psf_next) { | 1170 | for (; psf; psf = psf_next) { |
| 1171 | psf_next = psf->sf_next; | 1171 | psf_next = psf->sf_next; |
| 1172 | kfree(psf); | 1172 | kfree(psf); |
| 1173 | } | 1173 | } |
| @@ -1557,7 +1557,7 @@ static int ip_mc_del1_src(struct ip_mc_list *pmc, int sfmode, | |||
| 1557 | int rv = 0; | 1557 | int rv = 0; |
| 1558 | 1558 | ||
| 1559 | psf_prev = NULL; | 1559 | psf_prev = NULL; |
| 1560 | for (psf=pmc->sources; psf; psf=psf->sf_next) { | 1560 | for (psf = pmc->sources; psf; psf = psf->sf_next) { |
| 1561 | if (psf->sf_inaddr == *psfsrc) | 1561 | if (psf->sf_inaddr == *psfsrc) |
| 1562 | break; | 1562 | break; |
| 1563 | psf_prev = psf; | 1563 | psf_prev = psf; |
| @@ -1630,7 +1630,7 @@ static int ip_mc_del_src(struct in_device *in_dev, __be32 *pmca, int sfmode, | |||
| 1630 | pmc->sfcount[sfmode]--; | 1630 | pmc->sfcount[sfmode]--; |
| 1631 | } | 1631 | } |
| 1632 | err = 0; | 1632 | err = 0; |
| 1633 | for (i=0; i<sfcount; i++) { | 1633 | for (i = 0; i < sfcount; i++) { |
| 1634 | int rv = ip_mc_del1_src(pmc, sfmode, &psfsrc[i]); | 1634 | int rv = ip_mc_del1_src(pmc, sfmode, &psfsrc[i]); |
| 1635 | 1635 | ||
| 1636 | changerec |= rv > 0; | 1636 | changerec |= rv > 0; |
| @@ -1650,7 +1650,7 @@ static int ip_mc_del_src(struct in_device *in_dev, __be32 *pmca, int sfmode, | |||
| 1650 | pmc->crcount = in_dev->mr_qrv ? in_dev->mr_qrv : | 1650 | pmc->crcount = in_dev->mr_qrv ? in_dev->mr_qrv : |
| 1651 | IGMP_Unsolicited_Report_Count; | 1651 | IGMP_Unsolicited_Report_Count; |
| 1652 | in_dev->mr_ifc_count = pmc->crcount; | 1652 | in_dev->mr_ifc_count = pmc->crcount; |
| 1653 | for (psf=pmc->sources; psf; psf = psf->sf_next) | 1653 | for (psf = pmc->sources; psf; psf = psf->sf_next) |
| 1654 | psf->sf_crcount = 0; | 1654 | psf->sf_crcount = 0; |
| 1655 | igmp_ifc_event(pmc->interface); | 1655 | igmp_ifc_event(pmc->interface); |
| 1656 | } else if (sf_setstate(pmc) || changerec) { | 1656 | } else if (sf_setstate(pmc) || changerec) { |
| @@ -1671,7 +1671,7 @@ static int ip_mc_add1_src(struct ip_mc_list *pmc, int sfmode, | |||
| 1671 | struct ip_sf_list *psf, *psf_prev; | 1671 | struct ip_sf_list *psf, *psf_prev; |
| 1672 | 1672 | ||
| 1673 | psf_prev = NULL; | 1673 | psf_prev = NULL; |
| 1674 | for (psf=pmc->sources; psf; psf=psf->sf_next) { | 1674 | for (psf = pmc->sources; psf; psf = psf->sf_next) { |
| 1675 | if (psf->sf_inaddr == *psfsrc) | 1675 | if (psf->sf_inaddr == *psfsrc) |
| 1676 | break; | 1676 | break; |
| 1677 | psf_prev = psf; | 1677 | psf_prev = psf; |
| @@ -1699,7 +1699,7 @@ static void sf_markstate(struct ip_mc_list *pmc) | |||
| 1699 | struct ip_sf_list *psf; | 1699 | struct ip_sf_list *psf; |
| 1700 | int mca_xcount = pmc->sfcount[MCAST_EXCLUDE]; | 1700 | int mca_xcount = pmc->sfcount[MCAST_EXCLUDE]; |
| 1701 | 1701 | ||
| 1702 | for (psf=pmc->sources; psf; psf=psf->sf_next) | 1702 | for (psf = pmc->sources; psf; psf = psf->sf_next) |
| 1703 | if (pmc->sfcount[MCAST_EXCLUDE]) { | 1703 | if (pmc->sfcount[MCAST_EXCLUDE]) { |
| 1704 | psf->sf_oldin = mca_xcount == | 1704 | psf->sf_oldin = mca_xcount == |
| 1705 | psf->sf_count[MCAST_EXCLUDE] && | 1705 | psf->sf_count[MCAST_EXCLUDE] && |
| @@ -1716,7 +1716,7 @@ static int sf_setstate(struct ip_mc_list *pmc) | |||
| 1716 | int new_in, rv; | 1716 | int new_in, rv; |
| 1717 | 1717 | ||
| 1718 | rv = 0; | 1718 | rv = 0; |
| 1719 | for (psf=pmc->sources; psf; psf=psf->sf_next) { | 1719 | for (psf = pmc->sources; psf; psf = psf->sf_next) { |
| 1720 | if (pmc->sfcount[MCAST_EXCLUDE]) { | 1720 | if (pmc->sfcount[MCAST_EXCLUDE]) { |
| 1721 | new_in = mca_xcount == psf->sf_count[MCAST_EXCLUDE] && | 1721 | new_in = mca_xcount == psf->sf_count[MCAST_EXCLUDE] && |
| 1722 | !psf->sf_count[MCAST_INCLUDE]; | 1722 | !psf->sf_count[MCAST_INCLUDE]; |
| @@ -1726,7 +1726,7 @@ static int sf_setstate(struct ip_mc_list *pmc) | |||
| 1726 | if (!psf->sf_oldin) { | 1726 | if (!psf->sf_oldin) { |
| 1727 | struct ip_sf_list *prev = NULL; | 1727 | struct ip_sf_list *prev = NULL; |
| 1728 | 1728 | ||
| 1729 | for (dpsf=pmc->tomb; dpsf; dpsf=dpsf->sf_next) { | 1729 | for (dpsf = pmc->tomb; dpsf; dpsf = dpsf->sf_next) { |
| 1730 | if (dpsf->sf_inaddr == psf->sf_inaddr) | 1730 | if (dpsf->sf_inaddr == psf->sf_inaddr) |
| 1731 | break; | 1731 | break; |
| 1732 | prev = dpsf; | 1732 | prev = dpsf; |
| @@ -1748,7 +1748,7 @@ static int sf_setstate(struct ip_mc_list *pmc) | |||
| 1748 | * add or update "delete" records if an active filter | 1748 | * add or update "delete" records if an active filter |
| 1749 | * is now inactive | 1749 | * is now inactive |
| 1750 | */ | 1750 | */ |
| 1751 | for (dpsf=pmc->tomb; dpsf; dpsf=dpsf->sf_next) | 1751 | for (dpsf = pmc->tomb; dpsf; dpsf = dpsf->sf_next) |
| 1752 | if (dpsf->sf_inaddr == psf->sf_inaddr) | 1752 | if (dpsf->sf_inaddr == psf->sf_inaddr) |
| 1753 | break; | 1753 | break; |
| 1754 | if (!dpsf) { | 1754 | if (!dpsf) { |
| @@ -1800,7 +1800,7 @@ static int ip_mc_add_src(struct in_device *in_dev, __be32 *pmca, int sfmode, | |||
| 1800 | if (!delta) | 1800 | if (!delta) |
| 1801 | pmc->sfcount[sfmode]++; | 1801 | pmc->sfcount[sfmode]++; |
| 1802 | err = 0; | 1802 | err = 0; |
| 1803 | for (i=0; i<sfcount; i++) { | 1803 | for (i = 0; i < sfcount; i++) { |
| 1804 | err = ip_mc_add1_src(pmc, sfmode, &psfsrc[i]); | 1804 | err = ip_mc_add1_src(pmc, sfmode, &psfsrc[i]); |
| 1805 | if (err) | 1805 | if (err) |
| 1806 | break; | 1806 | break; |
| @@ -1810,7 +1810,7 @@ static int ip_mc_add_src(struct in_device *in_dev, __be32 *pmca, int sfmode, | |||
| 1810 | 1810 | ||
| 1811 | if (!delta) | 1811 | if (!delta) |
| 1812 | pmc->sfcount[sfmode]--; | 1812 | pmc->sfcount[sfmode]--; |
| 1813 | for (j=0; j<i; j++) | 1813 | for (j = 0; j < i; j++) |
| 1814 | (void) ip_mc_del1_src(pmc, sfmode, &psfsrc[j]); | 1814 | (void) ip_mc_del1_src(pmc, sfmode, &psfsrc[j]); |
| 1815 | } else if (isexclude != (pmc->sfcount[MCAST_EXCLUDE] != 0)) { | 1815 | } else if (isexclude != (pmc->sfcount[MCAST_EXCLUDE] != 0)) { |
| 1816 | #ifdef CONFIG_IP_MULTICAST | 1816 | #ifdef CONFIG_IP_MULTICAST |
| @@ -1829,7 +1829,7 @@ static int ip_mc_add_src(struct in_device *in_dev, __be32 *pmca, int sfmode, | |||
| 1829 | pmc->crcount = in_dev->mr_qrv ? in_dev->mr_qrv : | 1829 | pmc->crcount = in_dev->mr_qrv ? in_dev->mr_qrv : |
| 1830 | IGMP_Unsolicited_Report_Count; | 1830 | IGMP_Unsolicited_Report_Count; |
| 1831 | in_dev->mr_ifc_count = pmc->crcount; | 1831 | in_dev->mr_ifc_count = pmc->crcount; |
| 1832 | for (psf=pmc->sources; psf; psf = psf->sf_next) | 1832 | for (psf = pmc->sources; psf; psf = psf->sf_next) |
| 1833 | psf->sf_crcount = 0; | 1833 | psf->sf_crcount = 0; |
| 1834 | igmp_ifc_event(in_dev); | 1834 | igmp_ifc_event(in_dev); |
| 1835 | } else if (sf_setstate(pmc)) { | 1835 | } else if (sf_setstate(pmc)) { |
| @@ -1844,12 +1844,12 @@ static void ip_mc_clear_src(struct ip_mc_list *pmc) | |||
| 1844 | { | 1844 | { |
| 1845 | struct ip_sf_list *psf, *nextpsf; | 1845 | struct ip_sf_list *psf, *nextpsf; |
| 1846 | 1846 | ||
| 1847 | for (psf=pmc->tomb; psf; psf=nextpsf) { | 1847 | for (psf = pmc->tomb; psf; psf = nextpsf) { |
| 1848 | nextpsf = psf->sf_next; | 1848 | nextpsf = psf->sf_next; |
| 1849 | kfree(psf); | 1849 | kfree(psf); |
| 1850 | } | 1850 | } |
| 1851 | pmc->tomb = NULL; | 1851 | pmc->tomb = NULL; |
| 1852 | for (psf=pmc->sources; psf; psf=nextpsf) { | 1852 | for (psf = pmc->sources; psf; psf = nextpsf) { |
| 1853 | nextpsf = psf->sf_next; | 1853 | nextpsf = psf->sf_next; |
| 1854 | kfree(psf); | 1854 | kfree(psf); |
| 1855 | } | 1855 | } |
| @@ -2043,7 +2043,7 @@ int ip_mc_source(int add, int omode, struct sock *sk, struct | |||
| 2043 | if (!psl) | 2043 | if (!psl) |
| 2044 | goto done; /* err = -EADDRNOTAVAIL */ | 2044 | goto done; /* err = -EADDRNOTAVAIL */ |
| 2045 | rv = !0; | 2045 | rv = !0; |
| 2046 | for (i=0; i<psl->sl_count; i++) { | 2046 | for (i = 0; i < psl->sl_count; i++) { |
| 2047 | rv = memcmp(&psl->sl_addr[i], &mreqs->imr_sourceaddr, | 2047 | rv = memcmp(&psl->sl_addr[i], &mreqs->imr_sourceaddr, |
| 2048 | sizeof(__be32)); | 2048 | sizeof(__be32)); |
| 2049 | if (rv == 0) | 2049 | if (rv == 0) |
| @@ -2062,7 +2062,7 @@ int ip_mc_source(int add, int omode, struct sock *sk, struct | |||
| 2062 | ip_mc_del_src(in_dev, &mreqs->imr_multiaddr, omode, 1, | 2062 | ip_mc_del_src(in_dev, &mreqs->imr_multiaddr, omode, 1, |
| 2063 | &mreqs->imr_sourceaddr, 1); | 2063 | &mreqs->imr_sourceaddr, 1); |
| 2064 | 2064 | ||
| 2065 | for (j=i+1; j<psl->sl_count; j++) | 2065 | for (j = i+1; j < psl->sl_count; j++) |
| 2066 | psl->sl_addr[j-1] = psl->sl_addr[j]; | 2066 | psl->sl_addr[j-1] = psl->sl_addr[j]; |
| 2067 | psl->sl_count--; | 2067 | psl->sl_count--; |
| 2068 | err = 0; | 2068 | err = 0; |
| @@ -2088,7 +2088,7 @@ int ip_mc_source(int add, int omode, struct sock *sk, struct | |||
| 2088 | newpsl->sl_max = count; | 2088 | newpsl->sl_max = count; |
| 2089 | newpsl->sl_count = count - IP_SFBLOCK; | 2089 | newpsl->sl_count = count - IP_SFBLOCK; |
| 2090 | if (psl) { | 2090 | if (psl) { |
| 2091 | for (i=0; i<psl->sl_count; i++) | 2091 | for (i = 0; i < psl->sl_count; i++) |
| 2092 | newpsl->sl_addr[i] = psl->sl_addr[i]; | 2092 | newpsl->sl_addr[i] = psl->sl_addr[i]; |
| 2093 | /* decrease mem now to avoid the memleak warning */ | 2093 | /* decrease mem now to avoid the memleak warning */ |
| 2094 | atomic_sub(IP_SFLSIZE(psl->sl_max), &sk->sk_omem_alloc); | 2094 | atomic_sub(IP_SFLSIZE(psl->sl_max), &sk->sk_omem_alloc); |
| @@ -2098,7 +2098,7 @@ int ip_mc_source(int add, int omode, struct sock *sk, struct | |||
| 2098 | psl = newpsl; | 2098 | psl = newpsl; |
| 2099 | } | 2099 | } |
| 2100 | rv = 1; /* > 0 for insert logic below if sl_count is 0 */ | 2100 | rv = 1; /* > 0 for insert logic below if sl_count is 0 */ |
| 2101 | for (i=0; i<psl->sl_count; i++) { | 2101 | for (i = 0; i < psl->sl_count; i++) { |
| 2102 | rv = memcmp(&psl->sl_addr[i], &mreqs->imr_sourceaddr, | 2102 | rv = memcmp(&psl->sl_addr[i], &mreqs->imr_sourceaddr, |
| 2103 | sizeof(__be32)); | 2103 | sizeof(__be32)); |
| 2104 | if (rv == 0) | 2104 | if (rv == 0) |
| @@ -2106,7 +2106,7 @@ int ip_mc_source(int add, int omode, struct sock *sk, struct | |||
| 2106 | } | 2106 | } |
| 2107 | if (rv == 0) /* address already there is an error */ | 2107 | if (rv == 0) /* address already there is an error */ |
| 2108 | goto done; | 2108 | goto done; |
| 2109 | for (j=psl->sl_count-1; j>=i; j--) | 2109 | for (j = psl->sl_count-1; j >= i; j--) |
| 2110 | psl->sl_addr[j+1] = psl->sl_addr[j]; | 2110 | psl->sl_addr[j+1] = psl->sl_addr[j]; |
| 2111 | psl->sl_addr[i] = mreqs->imr_sourceaddr; | 2111 | psl->sl_addr[i] = mreqs->imr_sourceaddr; |
| 2112 | psl->sl_count++; | 2112 | psl->sl_count++; |
| @@ -2305,7 +2305,7 @@ int ip_mc_gsfget(struct sock *sk, struct group_filter *gsf, | |||
| 2305 | copy_to_user(optval, gsf, GROUP_FILTER_SIZE(0))) { | 2305 | copy_to_user(optval, gsf, GROUP_FILTER_SIZE(0))) { |
| 2306 | return -EFAULT; | 2306 | return -EFAULT; |
| 2307 | } | 2307 | } |
| 2308 | for (i=0; i<copycount; i++) { | 2308 | for (i = 0; i < copycount; i++) { |
| 2309 | struct sockaddr_storage ss; | 2309 | struct sockaddr_storage ss; |
| 2310 | 2310 | ||
| 2311 | psin = (struct sockaddr_in *)&ss; | 2311 | psin = (struct sockaddr_in *)&ss; |
| @@ -2350,7 +2350,7 @@ int ip_mc_sf_allow(struct sock *sk, __be32 loc_addr, __be32 rmt_addr, int dif) | |||
| 2350 | if (!psl) | 2350 | if (!psl) |
| 2351 | goto unlock; | 2351 | goto unlock; |
| 2352 | 2352 | ||
| 2353 | for (i=0; i<psl->sl_count; i++) { | 2353 | for (i = 0; i < psl->sl_count; i++) { |
| 2354 | if (psl->sl_addr[i] == rmt_addr) | 2354 | if (psl->sl_addr[i] == rmt_addr) |
| 2355 | break; | 2355 | break; |
| 2356 | } | 2356 | } |
| @@ -2423,7 +2423,7 @@ int ip_check_mc_rcu(struct in_device *in_dev, __be32 mc_addr, __be32 src_addr, u | |||
| 2423 | rv = 1; | 2423 | rv = 1; |
| 2424 | } else if (im) { | 2424 | } else if (im) { |
| 2425 | if (src_addr) { | 2425 | if (src_addr) { |
| 2426 | for (psf=im->sources; psf; psf=psf->sf_next) { | 2426 | for (psf = im->sources; psf; psf = psf->sf_next) { |
| 2427 | if (psf->sf_inaddr == src_addr) | 2427 | if (psf->sf_inaddr == src_addr) |
| 2428 | break; | 2428 | break; |
| 2429 | } | 2429 | } |
| @@ -2762,6 +2762,7 @@ static struct pernet_operations igmp_net_ops = { | |||
| 2762 | .init = igmp_net_init, | 2762 | .init = igmp_net_init, |
| 2763 | .exit = igmp_net_exit, | 2763 | .exit = igmp_net_exit, |
| 2764 | }; | 2764 | }; |
| 2765 | #endif | ||
| 2765 | 2766 | ||
| 2766 | static int igmp_netdev_event(struct notifier_block *this, | 2767 | static int igmp_netdev_event(struct notifier_block *this, |
| 2767 | unsigned long event, void *ptr) | 2768 | unsigned long event, void *ptr) |
| @@ -2785,8 +2786,9 @@ static struct notifier_block igmp_notifier = { | |||
| 2785 | .notifier_call = igmp_netdev_event, | 2786 | .notifier_call = igmp_netdev_event, |
| 2786 | }; | 2787 | }; |
| 2787 | 2788 | ||
| 2788 | int __init igmp_mc_proc_init(void) | 2789 | int __init igmp_mc_init(void) |
| 2789 | { | 2790 | { |
| 2791 | #if defined(CONFIG_PROC_FS) | ||
| 2790 | int err; | 2792 | int err; |
| 2791 | 2793 | ||
| 2792 | err = register_pernet_subsys(&igmp_net_ops); | 2794 | err = register_pernet_subsys(&igmp_net_ops); |
| @@ -2800,5 +2802,7 @@ int __init igmp_mc_proc_init(void) | |||
| 2800 | reg_notif_fail: | 2802 | reg_notif_fail: |
| 2801 | unregister_pernet_subsys(&igmp_net_ops); | 2803 | unregister_pernet_subsys(&igmp_net_ops); |
| 2802 | return err; | 2804 | return err; |
| 2803 | } | 2805 | #else |
| 2806 | return register_netdevice_notifier(&igmp_notifier); | ||
| 2804 | #endif | 2807 | #endif |
| 2808 | } | ||
diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index fc0e649cc002..0d1e2cb877ec 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c | |||
| @@ -109,7 +109,7 @@ int inet_csk_get_port(struct sock *sk, unsigned short snum) | |||
| 109 | again: | 109 | again: |
| 110 | inet_get_local_port_range(net, &low, &high); | 110 | inet_get_local_port_range(net, &low, &high); |
| 111 | remaining = (high - low) + 1; | 111 | remaining = (high - low) + 1; |
| 112 | smallest_rover = rover = net_random() % remaining + low; | 112 | smallest_rover = rover = prandom_u32() % remaining + low; |
| 113 | 113 | ||
| 114 | smallest_size = -1; | 114 | smallest_size = -1; |
| 115 | do { | 115 | do { |
diff --git a/net/ipv4/inet_lro.c b/net/ipv4/inet_lro.c index 1975f52933c5..f17ea49b28fb 100644 --- a/net/ipv4/inet_lro.c +++ b/net/ipv4/inet_lro.c | |||
| @@ -230,29 +230,6 @@ static void lro_add_packet(struct net_lro_desc *lro_desc, struct sk_buff *skb, | |||
| 230 | lro_desc->last_skb = skb; | 230 | lro_desc->last_skb = skb; |
| 231 | } | 231 | } |
| 232 | 232 | ||
| 233 | static void lro_add_frags(struct net_lro_desc *lro_desc, | ||
| 234 | int len, int hlen, int truesize, | ||
| 235 | struct skb_frag_struct *skb_frags, | ||
| 236 | struct iphdr *iph, struct tcphdr *tcph) | ||
| 237 | { | ||
| 238 | struct sk_buff *skb = lro_desc->parent; | ||
| 239 | int tcp_data_len = TCP_PAYLOAD_LENGTH(iph, tcph); | ||
| 240 | |||
| 241 | lro_add_common(lro_desc, iph, tcph, tcp_data_len); | ||
| 242 | |||
| 243 | skb->truesize += truesize; | ||
| 244 | |||
| 245 | skb_frags[0].page_offset += hlen; | ||
| 246 | skb_frag_size_sub(&skb_frags[0], hlen); | ||
| 247 | |||
| 248 | while (tcp_data_len > 0) { | ||
| 249 | *(lro_desc->next_frag) = *skb_frags; | ||
| 250 | tcp_data_len -= skb_frag_size(skb_frags); | ||
| 251 | lro_desc->next_frag++; | ||
| 252 | skb_frags++; | ||
| 253 | skb_shinfo(skb)->nr_frags++; | ||
| 254 | } | ||
| 255 | } | ||
| 256 | 233 | ||
| 257 | static int lro_check_tcp_conn(struct net_lro_desc *lro_desc, | 234 | static int lro_check_tcp_conn(struct net_lro_desc *lro_desc, |
| 258 | struct iphdr *iph, | 235 | struct iphdr *iph, |
| @@ -371,128 +348,6 @@ out: | |||
| 371 | return 1; | 348 | return 1; |
| 372 | } | 349 | } |
| 373 | 350 | ||
| 374 | |||
| 375 | static struct sk_buff *lro_gen_skb(struct net_lro_mgr *lro_mgr, | ||
| 376 | struct skb_frag_struct *frags, | ||
| 377 | int len, int true_size, | ||
| 378 | void *mac_hdr, | ||
| 379 | int hlen, __wsum sum, | ||
| 380 | u32 ip_summed) | ||
| 381 | { | ||
| 382 | struct sk_buff *skb; | ||
| 383 | struct skb_frag_struct *skb_frags; | ||
| 384 | int data_len = len; | ||
| 385 | int hdr_len = min(len, hlen); | ||
| 386 | |||
| 387 | skb = netdev_alloc_skb(lro_mgr->dev, hlen + lro_mgr->frag_align_pad); | ||
| 388 | if (!skb) | ||
| 389 | return NULL; | ||
| 390 | |||
| 391 | skb_reserve(skb, lro_mgr->frag_align_pad); | ||
| 392 | skb->len = len; | ||
| 393 | skb->data_len = len - hdr_len; | ||
| 394 | skb->truesize += true_size; | ||
| 395 | skb->tail += hdr_len; | ||
| 396 | |||
| 397 | memcpy(skb->data, mac_hdr, hdr_len); | ||
| 398 | |||
| 399 | skb_frags = skb_shinfo(skb)->frags; | ||
| 400 | while (data_len > 0) { | ||
| 401 | *skb_frags = *frags; | ||
| 402 | data_len -= skb_frag_size(frags); | ||
| 403 | skb_frags++; | ||
| 404 | frags++; | ||
| 405 | skb_shinfo(skb)->nr_frags++; | ||
| 406 | } | ||
| 407 | |||
| 408 | skb_shinfo(skb)->frags[0].page_offset += hdr_len; | ||
| 409 | skb_frag_size_sub(&skb_shinfo(skb)->frags[0], hdr_len); | ||
| 410 | |||
| 411 | skb->ip_summed = ip_summed; | ||
| 412 | skb->csum = sum; | ||
| 413 | skb->protocol = eth_type_trans(skb, lro_mgr->dev); | ||
| 414 | return skb; | ||
| 415 | } | ||
| 416 | |||
| 417 | static struct sk_buff *__lro_proc_segment(struct net_lro_mgr *lro_mgr, | ||
| 418 | struct skb_frag_struct *frags, | ||
| 419 | int len, int true_size, | ||
| 420 | void *priv, __wsum sum) | ||
| 421 | { | ||
| 422 | struct net_lro_desc *lro_desc; | ||
| 423 | struct iphdr *iph; | ||
| 424 | struct tcphdr *tcph; | ||
| 425 | struct sk_buff *skb; | ||
| 426 | u64 flags; | ||
| 427 | void *mac_hdr; | ||
| 428 | int mac_hdr_len; | ||
| 429 | int hdr_len = LRO_MAX_PG_HLEN; | ||
| 430 | int vlan_hdr_len = 0; | ||
| 431 | |||
| 432 | if (!lro_mgr->get_frag_header || | ||
| 433 | lro_mgr->get_frag_header(frags, (void *)&mac_hdr, (void *)&iph, | ||
| 434 | (void *)&tcph, &flags, priv)) { | ||
| 435 | mac_hdr = skb_frag_address(frags); | ||
| 436 | goto out1; | ||
| 437 | } | ||
| 438 | |||
| 439 | if (!(flags & LRO_IPV4) || !(flags & LRO_TCP)) | ||
| 440 | goto out1; | ||
| 441 | |||
| 442 | hdr_len = (int)((void *)(tcph) + TCP_HDR_LEN(tcph) - mac_hdr); | ||
| 443 | mac_hdr_len = (int)((void *)(iph) - mac_hdr); | ||
| 444 | |||
| 445 | lro_desc = lro_get_desc(lro_mgr, lro_mgr->lro_arr, iph, tcph); | ||
| 446 | if (!lro_desc) | ||
| 447 | goto out1; | ||
| 448 | |||
| 449 | if (!lro_desc->active) { /* start new lro session */ | ||
| 450 | if (lro_tcp_ip_check(iph, tcph, len - mac_hdr_len, NULL)) | ||
| 451 | goto out1; | ||
| 452 | |||
| 453 | skb = lro_gen_skb(lro_mgr, frags, len, true_size, mac_hdr, | ||
| 454 | hdr_len, 0, lro_mgr->ip_summed_aggr); | ||
| 455 | if (!skb) | ||
| 456 | goto out; | ||
| 457 | |||
| 458 | if ((skb->protocol == htons(ETH_P_8021Q)) && | ||
| 459 | !(lro_mgr->features & LRO_F_EXTRACT_VLAN_ID)) | ||
| 460 | vlan_hdr_len = VLAN_HLEN; | ||
| 461 | |||
| 462 | iph = (void *)(skb->data + vlan_hdr_len); | ||
| 463 | tcph = (void *)((u8 *)skb->data + vlan_hdr_len | ||
| 464 | + IP_HDR_LEN(iph)); | ||
| 465 | |||
| 466 | lro_init_desc(lro_desc, skb, iph, tcph); | ||
| 467 | LRO_INC_STATS(lro_mgr, aggregated); | ||
| 468 | return NULL; | ||
| 469 | } | ||
| 470 | |||
| 471 | if (lro_desc->tcp_next_seq != ntohl(tcph->seq)) | ||
| 472 | goto out2; | ||
| 473 | |||
| 474 | if (lro_tcp_ip_check(iph, tcph, len - mac_hdr_len, lro_desc)) | ||
| 475 | goto out2; | ||
| 476 | |||
| 477 | lro_add_frags(lro_desc, len, hdr_len, true_size, frags, iph, tcph); | ||
| 478 | LRO_INC_STATS(lro_mgr, aggregated); | ||
| 479 | |||
| 480 | if ((skb_shinfo(lro_desc->parent)->nr_frags >= lro_mgr->max_aggr) || | ||
| 481 | lro_desc->parent->len > (0xFFFF - lro_mgr->dev->mtu)) | ||
| 482 | lro_flush(lro_mgr, lro_desc); | ||
| 483 | |||
| 484 | return NULL; | ||
| 485 | |||
| 486 | out2: /* send aggregated packets to the stack */ | ||
| 487 | lro_flush(lro_mgr, lro_desc); | ||
| 488 | |||
| 489 | out1: /* Original packet has to be posted to the stack */ | ||
| 490 | skb = lro_gen_skb(lro_mgr, frags, len, true_size, mac_hdr, | ||
| 491 | hdr_len, sum, lro_mgr->ip_summed); | ||
| 492 | out: | ||
| 493 | return skb; | ||
| 494 | } | ||
| 495 | |||
| 496 | void lro_receive_skb(struct net_lro_mgr *lro_mgr, | 351 | void lro_receive_skb(struct net_lro_mgr *lro_mgr, |
| 497 | struct sk_buff *skb, | 352 | struct sk_buff *skb, |
| 498 | void *priv) | 353 | void *priv) |
| @@ -506,23 +361,6 @@ void lro_receive_skb(struct net_lro_mgr *lro_mgr, | |||
| 506 | } | 361 | } |
| 507 | EXPORT_SYMBOL(lro_receive_skb); | 362 | EXPORT_SYMBOL(lro_receive_skb); |
| 508 | 363 | ||
| 509 | void lro_receive_frags(struct net_lro_mgr *lro_mgr, | ||
| 510 | struct skb_frag_struct *frags, | ||
| 511 | int len, int true_size, void *priv, __wsum sum) | ||
| 512 | { | ||
| 513 | struct sk_buff *skb; | ||
| 514 | |||
| 515 | skb = __lro_proc_segment(lro_mgr, frags, len, true_size, priv, sum); | ||
| 516 | if (!skb) | ||
| 517 | return; | ||
| 518 | |||
| 519 | if (lro_mgr->features & LRO_F_NAPI) | ||
| 520 | netif_receive_skb(skb); | ||
| 521 | else | ||
| 522 | netif_rx(skb); | ||
| 523 | } | ||
| 524 | EXPORT_SYMBOL(lro_receive_frags); | ||
| 525 | |||
| 526 | void lro_flush_all(struct net_lro_mgr *lro_mgr) | 364 | void lro_flush_all(struct net_lro_mgr *lro_mgr) |
| 527 | { | 365 | { |
| 528 | int i; | 366 | int i; |
| @@ -534,14 +372,3 @@ void lro_flush_all(struct net_lro_mgr *lro_mgr) | |||
| 534 | } | 372 | } |
| 535 | } | 373 | } |
| 536 | EXPORT_SYMBOL(lro_flush_all); | 374 | EXPORT_SYMBOL(lro_flush_all); |
| 537 | |||
| 538 | void lro_flush_pkt(struct net_lro_mgr *lro_mgr, | ||
| 539 | struct iphdr *iph, struct tcphdr *tcph) | ||
| 540 | { | ||
| 541 | struct net_lro_desc *lro_desc; | ||
| 542 | |||
| 543 | lro_desc = lro_get_desc(lro_mgr, lro_mgr->lro_arr, iph, tcph); | ||
| 544 | if (lro_desc->active) | ||
| 545 | lro_flush(lro_mgr, lro_desc); | ||
| 546 | } | ||
| 547 | EXPORT_SYMBOL(lro_flush_pkt); | ||
diff --git a/net/ipv4/inetpeer.c b/net/ipv4/inetpeer.c index 33d5537881ed..48f424465112 100644 --- a/net/ipv4/inetpeer.c +++ b/net/ipv4/inetpeer.c | |||
| @@ -109,13 +109,6 @@ static inline void flush_check(struct inet_peer_base *base, int family) | |||
| 109 | } | 109 | } |
| 110 | } | 110 | } |
| 111 | 111 | ||
| 112 | void inetpeer_invalidate_family(int family) | ||
| 113 | { | ||
| 114 | atomic_t *fp = inetpeer_seq_ptr(family); | ||
| 115 | |||
| 116 | atomic_inc(fp); | ||
| 117 | } | ||
| 118 | |||
| 119 | #define PEER_MAXDEPTH 40 /* sufficient for about 2^27 nodes */ | 112 | #define PEER_MAXDEPTH 40 /* sufficient for about 2^27 nodes */ |
| 120 | 113 | ||
| 121 | /* Exported for sysctl_net_ipv4. */ | 114 | /* Exported for sysctl_net_ipv4. */ |
| @@ -227,7 +220,7 @@ static int addr_compare(const struct inetpeer_addr *a, | |||
| 227 | stackptr = _stack; \ | 220 | stackptr = _stack; \ |
| 228 | *stackptr++ = &_base->root; \ | 221 | *stackptr++ = &_base->root; \ |
| 229 | for (u = rcu_deref_locked(_base->root, _base); \ | 222 | for (u = rcu_deref_locked(_base->root, _base); \ |
| 230 | u != peer_avl_empty; ) { \ | 223 | u != peer_avl_empty;) { \ |
| 231 | int cmp = addr_compare(_daddr, &u->daddr); \ | 224 | int cmp = addr_compare(_daddr, &u->daddr); \ |
| 232 | if (cmp == 0) \ | 225 | if (cmp == 0) \ |
| 233 | break; \ | 226 | break; \ |
| @@ -282,7 +275,7 @@ static struct inet_peer *lookup_rcu(const struct inetpeer_addr *daddr, | |||
| 282 | *stackptr++ = &start->avl_left; \ | 275 | *stackptr++ = &start->avl_left; \ |
| 283 | v = &start->avl_left; \ | 276 | v = &start->avl_left; \ |
| 284 | for (u = rcu_deref_locked(*v, base); \ | 277 | for (u = rcu_deref_locked(*v, base); \ |
| 285 | u->avl_right != peer_avl_empty_rcu; ) { \ | 278 | u->avl_right != peer_avl_empty_rcu;) { \ |
| 286 | v = &u->avl_right; \ | 279 | v = &u->avl_right; \ |
| 287 | *stackptr++ = v; \ | 280 | *stackptr++ = v; \ |
| 288 | u = rcu_deref_locked(*v, base); \ | 281 | u = rcu_deref_locked(*v, base); \ |
diff --git a/net/ipv4/ip_forward.c b/net/ipv4/ip_forward.c index 694de3b7aebf..e9f1217a8afd 100644 --- a/net/ipv4/ip_forward.c +++ b/net/ipv4/ip_forward.c | |||
| @@ -54,6 +54,7 @@ static int ip_forward_finish(struct sk_buff *skb) | |||
| 54 | 54 | ||
| 55 | int ip_forward(struct sk_buff *skb) | 55 | int ip_forward(struct sk_buff *skb) |
| 56 | { | 56 | { |
| 57 | u32 mtu; | ||
| 57 | struct iphdr *iph; /* Our header */ | 58 | struct iphdr *iph; /* Our header */ |
| 58 | struct rtable *rt; /* Route we use */ | 59 | struct rtable *rt; /* Route we use */ |
| 59 | struct ip_options *opt = &(IPCB(skb)->opt); | 60 | struct ip_options *opt = &(IPCB(skb)->opt); |
| @@ -88,11 +89,13 @@ int ip_forward(struct sk_buff *skb) | |||
| 88 | if (opt->is_strictroute && rt->rt_uses_gateway) | 89 | if (opt->is_strictroute && rt->rt_uses_gateway) |
| 89 | goto sr_failed; | 90 | goto sr_failed; |
| 90 | 91 | ||
| 91 | if (unlikely(skb->len > dst_mtu(&rt->dst) && !skb_is_gso(skb) && | 92 | IPCB(skb)->flags |= IPSKB_FORWARDED; |
| 93 | mtu = ip_dst_mtu_maybe_forward(&rt->dst, true); | ||
| 94 | if (unlikely(skb->len > mtu && !skb_is_gso(skb) && | ||
| 92 | (ip_hdr(skb)->frag_off & htons(IP_DF))) && !skb->local_df) { | 95 | (ip_hdr(skb)->frag_off & htons(IP_DF))) && !skb->local_df) { |
| 93 | IP_INC_STATS(dev_net(rt->dst.dev), IPSTATS_MIB_FRAGFAILS); | 96 | IP_INC_STATS(dev_net(rt->dst.dev), IPSTATS_MIB_FRAGFAILS); |
| 94 | icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, | 97 | icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, |
| 95 | htonl(dst_mtu(&rt->dst))); | 98 | htonl(mtu)); |
| 96 | goto drop; | 99 | goto drop; |
| 97 | } | 100 | } |
| 98 | 101 | ||
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index 2481993a4970..c10a3ce5cbff 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c | |||
| @@ -704,7 +704,7 @@ struct sk_buff *ip_check_defrag(struct sk_buff *skb, u32 user) | |||
| 704 | memset(IPCB(skb), 0, sizeof(struct inet_skb_parm)); | 704 | memset(IPCB(skb), 0, sizeof(struct inet_skb_parm)); |
| 705 | if (ip_defrag(skb, user)) | 705 | if (ip_defrag(skb, user)) |
| 706 | return NULL; | 706 | return NULL; |
| 707 | skb->rxhash = 0; | 707 | skb_clear_hash(skb); |
| 708 | } | 708 | } |
| 709 | } | 709 | } |
| 710 | return skb; | 710 | return skb; |
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index e560ef34cf4b..ec4f762efda5 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c | |||
| @@ -178,7 +178,7 @@ static int ipgre_err(struct sk_buff *skb, u32 info, | |||
| 178 | else | 178 | else |
| 179 | itn = net_generic(net, ipgre_net_id); | 179 | itn = net_generic(net, ipgre_net_id); |
| 180 | 180 | ||
| 181 | iph = (const struct iphdr *)skb->data; | 181 | iph = (const struct iphdr *)(icmp_hdr(skb) + 1); |
| 182 | t = ip_tunnel_lookup(itn, skb->dev->ifindex, tpi->flags, | 182 | t = ip_tunnel_lookup(itn, skb->dev->ifindex, tpi->flags, |
| 183 | iph->daddr, iph->saddr, tpi->key); | 183 | iph->daddr, iph->saddr, tpi->key); |
| 184 | 184 | ||
| @@ -278,7 +278,7 @@ static netdev_tx_t ipgre_xmit(struct sk_buff *skb, | |||
| 278 | return NETDEV_TX_OK; | 278 | return NETDEV_TX_OK; |
| 279 | 279 | ||
| 280 | free_skb: | 280 | free_skb: |
| 281 | dev_kfree_skb(skb); | 281 | kfree_skb(skb); |
| 282 | out: | 282 | out: |
| 283 | dev->stats.tx_dropped++; | 283 | dev->stats.tx_dropped++; |
| 284 | return NETDEV_TX_OK; | 284 | return NETDEV_TX_OK; |
| @@ -301,7 +301,7 @@ static netdev_tx_t gre_tap_xmit(struct sk_buff *skb, | |||
| 301 | return NETDEV_TX_OK; | 301 | return NETDEV_TX_OK; |
| 302 | 302 | ||
| 303 | free_skb: | 303 | free_skb: |
| 304 | dev_kfree_skb(skb); | 304 | kfree_skb(skb); |
| 305 | out: | 305 | out: |
| 306 | dev->stats.tx_dropped++; | 306 | dev->stats.tx_dropped++; |
| 307 | return NETDEV_TX_OK; | 307 | return NETDEV_TX_OK; |
diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c index 054a3e97d822..3d4da2c16b6a 100644 --- a/net/ipv4/ip_input.c +++ b/net/ipv4/ip_input.c | |||
| @@ -314,7 +314,7 @@ static int ip_rcv_finish(struct sk_buff *skb) | |||
| 314 | const struct iphdr *iph = ip_hdr(skb); | 314 | const struct iphdr *iph = ip_hdr(skb); |
| 315 | struct rtable *rt; | 315 | struct rtable *rt; |
| 316 | 316 | ||
| 317 | if (sysctl_ip_early_demux && !skb_dst(skb)) { | 317 | if (sysctl_ip_early_demux && !skb_dst(skb) && skb->sk == NULL) { |
| 318 | const struct net_protocol *ipprot; | 318 | const struct net_protocol *ipprot; |
| 319 | int protocol = iph->protocol; | 319 | int protocol = iph->protocol; |
| 320 | 320 | ||
diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c index ec7264514a82..f4ab72e19af9 100644 --- a/net/ipv4/ip_options.c +++ b/net/ipv4/ip_options.c | |||
| @@ -167,7 +167,7 @@ int ip_options_echo(struct ip_options *dopt, struct sk_buff *skb) | |||
| 167 | soffset -= 4; | 167 | soffset -= 4; |
| 168 | if (soffset > 3) { | 168 | if (soffset > 3) { |
| 169 | memcpy(&faddr, &start[soffset-1], 4); | 169 | memcpy(&faddr, &start[soffset-1], 4); |
| 170 | for (soffset-=4, doffset=4; soffset > 3; soffset-=4, doffset+=4) | 170 | for (soffset -= 4, doffset = 4; soffset > 3; soffset -= 4, doffset += 4) |
| 171 | memcpy(&dptr[doffset-1], &start[soffset-1], 4); | 171 | memcpy(&dptr[doffset-1], &start[soffset-1], 4); |
| 172 | /* | 172 | /* |
| 173 | * RFC1812 requires to fix illegal source routes. | 173 | * RFC1812 requires to fix illegal source routes. |
| @@ -227,7 +227,7 @@ void ip_options_fragment(struct sk_buff *skb) | |||
| 227 | continue; | 227 | continue; |
| 228 | } | 228 | } |
| 229 | optlen = optptr[1]; | 229 | optlen = optptr[1]; |
| 230 | if (optlen<2 || optlen>l) | 230 | if (optlen < 2 || optlen > l) |
| 231 | return; | 231 | return; |
| 232 | if (!IPOPT_COPIED(*optptr)) | 232 | if (!IPOPT_COPIED(*optptr)) |
| 233 | memset(optptr, IPOPT_NOOP, optlen); | 233 | memset(optptr, IPOPT_NOOP, optlen); |
| @@ -275,27 +275,27 @@ int ip_options_compile(struct net *net, | |||
| 275 | 275 | ||
| 276 | for (l = opt->optlen; l > 0; ) { | 276 | for (l = opt->optlen; l > 0; ) { |
| 277 | switch (*optptr) { | 277 | switch (*optptr) { |
| 278 | case IPOPT_END: | 278 | case IPOPT_END: |
| 279 | for (optptr++, l--; l>0; optptr++, l--) { | 279 | for (optptr++, l--; l > 0; optptr++, l--) { |
| 280 | if (*optptr != IPOPT_END) { | 280 | if (*optptr != IPOPT_END) { |
| 281 | *optptr = IPOPT_END; | 281 | *optptr = IPOPT_END; |
| 282 | opt->is_changed = 1; | 282 | opt->is_changed = 1; |
| 283 | } | 283 | } |
| 284 | } | 284 | } |
| 285 | goto eol; | 285 | goto eol; |
| 286 | case IPOPT_NOOP: | 286 | case IPOPT_NOOP: |
| 287 | l--; | 287 | l--; |
| 288 | optptr++; | 288 | optptr++; |
| 289 | continue; | 289 | continue; |
| 290 | } | 290 | } |
| 291 | optlen = optptr[1]; | 291 | optlen = optptr[1]; |
| 292 | if (optlen<2 || optlen>l) { | 292 | if (optlen < 2 || optlen > l) { |
| 293 | pp_ptr = optptr; | 293 | pp_ptr = optptr; |
| 294 | goto error; | 294 | goto error; |
| 295 | } | 295 | } |
| 296 | switch (*optptr) { | 296 | switch (*optptr) { |
| 297 | case IPOPT_SSRR: | 297 | case IPOPT_SSRR: |
| 298 | case IPOPT_LSRR: | 298 | case IPOPT_LSRR: |
| 299 | if (optlen < 3) { | 299 | if (optlen < 3) { |
| 300 | pp_ptr = optptr + 1; | 300 | pp_ptr = optptr + 1; |
| 301 | goto error; | 301 | goto error; |
| @@ -321,7 +321,7 @@ int ip_options_compile(struct net *net, | |||
| 321 | opt->is_strictroute = (optptr[0] == IPOPT_SSRR); | 321 | opt->is_strictroute = (optptr[0] == IPOPT_SSRR); |
| 322 | opt->srr = optptr - iph; | 322 | opt->srr = optptr - iph; |
| 323 | break; | 323 | break; |
| 324 | case IPOPT_RR: | 324 | case IPOPT_RR: |
| 325 | if (opt->rr) { | 325 | if (opt->rr) { |
| 326 | pp_ptr = optptr; | 326 | pp_ptr = optptr; |
| 327 | goto error; | 327 | goto error; |
| @@ -349,7 +349,7 @@ int ip_options_compile(struct net *net, | |||
| 349 | } | 349 | } |
| 350 | opt->rr = optptr - iph; | 350 | opt->rr = optptr - iph; |
| 351 | break; | 351 | break; |
| 352 | case IPOPT_TIMESTAMP: | 352 | case IPOPT_TIMESTAMP: |
| 353 | if (opt->ts) { | 353 | if (opt->ts) { |
| 354 | pp_ptr = optptr; | 354 | pp_ptr = optptr; |
| 355 | goto error; | 355 | goto error; |
| @@ -369,13 +369,13 @@ int ip_options_compile(struct net *net, | |||
| 369 | goto error; | 369 | goto error; |
| 370 | } | 370 | } |
| 371 | switch (optptr[3]&0xF) { | 371 | switch (optptr[3]&0xF) { |
| 372 | case IPOPT_TS_TSONLY: | 372 | case IPOPT_TS_TSONLY: |
| 373 | if (skb) | 373 | if (skb) |
| 374 | timeptr = &optptr[optptr[2]-1]; | 374 | timeptr = &optptr[optptr[2]-1]; |
| 375 | opt->ts_needtime = 1; | 375 | opt->ts_needtime = 1; |
| 376 | optptr[2] += 4; | 376 | optptr[2] += 4; |
| 377 | break; | 377 | break; |
| 378 | case IPOPT_TS_TSANDADDR: | 378 | case IPOPT_TS_TSANDADDR: |
| 379 | if (optptr[2]+7 > optptr[1]) { | 379 | if (optptr[2]+7 > optptr[1]) { |
| 380 | pp_ptr = optptr + 2; | 380 | pp_ptr = optptr + 2; |
| 381 | goto error; | 381 | goto error; |
| @@ -389,7 +389,7 @@ int ip_options_compile(struct net *net, | |||
| 389 | opt->ts_needtime = 1; | 389 | opt->ts_needtime = 1; |
| 390 | optptr[2] += 8; | 390 | optptr[2] += 8; |
| 391 | break; | 391 | break; |
| 392 | case IPOPT_TS_PRESPEC: | 392 | case IPOPT_TS_PRESPEC: |
| 393 | if (optptr[2]+7 > optptr[1]) { | 393 | if (optptr[2]+7 > optptr[1]) { |
| 394 | pp_ptr = optptr + 2; | 394 | pp_ptr = optptr + 2; |
| 395 | goto error; | 395 | goto error; |
| @@ -405,7 +405,7 @@ int ip_options_compile(struct net *net, | |||
| 405 | opt->ts_needtime = 1; | 405 | opt->ts_needtime = 1; |
| 406 | optptr[2] += 8; | 406 | optptr[2] += 8; |
| 407 | break; | 407 | break; |
| 408 | default: | 408 | default: |
| 409 | if (!skb && !ns_capable(net->user_ns, CAP_NET_RAW)) { | 409 | if (!skb && !ns_capable(net->user_ns, CAP_NET_RAW)) { |
| 410 | pp_ptr = optptr + 3; | 410 | pp_ptr = optptr + 3; |
| 411 | goto error; | 411 | goto error; |
| @@ -433,7 +433,7 @@ int ip_options_compile(struct net *net, | |||
| 433 | } | 433 | } |
| 434 | opt->ts = optptr - iph; | 434 | opt->ts = optptr - iph; |
| 435 | break; | 435 | break; |
| 436 | case IPOPT_RA: | 436 | case IPOPT_RA: |
| 437 | if (optlen < 4) { | 437 | if (optlen < 4) { |
| 438 | pp_ptr = optptr + 1; | 438 | pp_ptr = optptr + 1; |
| 439 | goto error; | 439 | goto error; |
| @@ -441,7 +441,7 @@ int ip_options_compile(struct net *net, | |||
| 441 | if (optptr[2] == 0 && optptr[3] == 0) | 441 | if (optptr[2] == 0 && optptr[3] == 0) |
| 442 | opt->router_alert = optptr - iph; | 442 | opt->router_alert = optptr - iph; |
| 443 | break; | 443 | break; |
| 444 | case IPOPT_CIPSO: | 444 | case IPOPT_CIPSO: |
| 445 | if ((!skb && !ns_capable(net->user_ns, CAP_NET_RAW)) || opt->cipso) { | 445 | if ((!skb && !ns_capable(net->user_ns, CAP_NET_RAW)) || opt->cipso) { |
| 446 | pp_ptr = optptr; | 446 | pp_ptr = optptr; |
| 447 | goto error; | 447 | goto error; |
| @@ -452,9 +452,9 @@ int ip_options_compile(struct net *net, | |||
| 452 | goto error; | 452 | goto error; |
| 453 | } | 453 | } |
| 454 | break; | 454 | break; |
| 455 | case IPOPT_SEC: | 455 | case IPOPT_SEC: |
| 456 | case IPOPT_SID: | 456 | case IPOPT_SID: |
| 457 | default: | 457 | default: |
| 458 | if (!skb && !ns_capable(net->user_ns, CAP_NET_RAW)) { | 458 | if (!skb && !ns_capable(net->user_ns, CAP_NET_RAW)) { |
| 459 | pp_ptr = optptr; | 459 | pp_ptr = optptr; |
| 460 | goto error; | 460 | goto error; |
| @@ -572,7 +572,7 @@ void ip_forward_options(struct sk_buff *skb) | |||
| 572 | 572 | ||
| 573 | optptr = raw + opt->srr; | 573 | optptr = raw + opt->srr; |
| 574 | 574 | ||
| 575 | for ( srrptr=optptr[2], srrspace = optptr[1]; | 575 | for ( srrptr = optptr[2], srrspace = optptr[1]; |
| 576 | srrptr <= srrspace; | 576 | srrptr <= srrspace; |
| 577 | srrptr += 4 | 577 | srrptr += 4 |
| 578 | ) { | 578 | ) { |
| @@ -628,7 +628,7 @@ int ip_options_rcv_srr(struct sk_buff *skb) | |||
| 628 | if (rt->rt_type != RTN_LOCAL) | 628 | if (rt->rt_type != RTN_LOCAL) |
| 629 | return -EINVAL; | 629 | return -EINVAL; |
| 630 | 630 | ||
| 631 | for (srrptr=optptr[2], srrspace = optptr[1]; srrptr <= srrspace; srrptr += 4) { | 631 | for (srrptr = optptr[2], srrspace = optptr[1]; srrptr <= srrspace; srrptr += 4) { |
| 632 | if (srrptr + 3 > srrspace) { | 632 | if (srrptr + 3 > srrspace) { |
| 633 | icmp_send(skb, ICMP_PARAMETERPROB, 0, htonl((opt->srr+2)<<24)); | 633 | icmp_send(skb, ICMP_PARAMETERPROB, 0, htonl((opt->srr+2)<<24)); |
| 634 | return -EINVAL; | 634 | return -EINVAL; |
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index df184616493f..8971780aec7c 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c | |||
| @@ -449,6 +449,7 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) | |||
| 449 | __be16 not_last_frag; | 449 | __be16 not_last_frag; |
| 450 | struct rtable *rt = skb_rtable(skb); | 450 | struct rtable *rt = skb_rtable(skb); |
| 451 | int err = 0; | 451 | int err = 0; |
| 452 | bool forwarding = IPCB(skb)->flags & IPSKB_FORWARDED; | ||
| 452 | 453 | ||
| 453 | dev = rt->dst.dev; | 454 | dev = rt->dst.dev; |
| 454 | 455 | ||
| @@ -458,12 +459,13 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) | |||
| 458 | 459 | ||
| 459 | iph = ip_hdr(skb); | 460 | iph = ip_hdr(skb); |
| 460 | 461 | ||
| 462 | mtu = ip_dst_mtu_maybe_forward(&rt->dst, forwarding); | ||
| 461 | if (unlikely(((iph->frag_off & htons(IP_DF)) && !skb->local_df) || | 463 | if (unlikely(((iph->frag_off & htons(IP_DF)) && !skb->local_df) || |
| 462 | (IPCB(skb)->frag_max_size && | 464 | (IPCB(skb)->frag_max_size && |
| 463 | IPCB(skb)->frag_max_size > dst_mtu(&rt->dst)))) { | 465 | IPCB(skb)->frag_max_size > mtu))) { |
| 464 | IP_INC_STATS(dev_net(dev), IPSTATS_MIB_FRAGFAILS); | 466 | IP_INC_STATS(dev_net(dev), IPSTATS_MIB_FRAGFAILS); |
| 465 | icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, | 467 | icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, |
| 466 | htonl(ip_skb_dst_mtu(skb))); | 468 | htonl(mtu)); |
| 467 | kfree_skb(skb); | 469 | kfree_skb(skb); |
| 468 | return -EMSGSIZE; | 470 | return -EMSGSIZE; |
| 469 | } | 471 | } |
| @@ -473,7 +475,7 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) | |||
| 473 | */ | 475 | */ |
| 474 | 476 | ||
| 475 | hlen = iph->ihl * 4; | 477 | hlen = iph->ihl * 4; |
| 476 | mtu = dst_mtu(&rt->dst) - hlen; /* Size of data space */ | 478 | mtu = mtu - hlen; /* Size of data space */ |
| 477 | #ifdef CONFIG_BRIDGE_NETFILTER | 479 | #ifdef CONFIG_BRIDGE_NETFILTER |
| 478 | if (skb->nf_bridge) | 480 | if (skb->nf_bridge) |
| 479 | mtu -= nf_bridge_mtu_reduction(skb); | 481 | mtu -= nf_bridge_mtu_reduction(skb); |
| @@ -1551,7 +1553,7 @@ void __init ip_init(void) | |||
| 1551 | ip_rt_init(); | 1553 | ip_rt_init(); |
| 1552 | inet_initpeers(); | 1554 | inet_initpeers(); |
| 1553 | 1555 | ||
| 1554 | #if defined(CONFIG_IP_MULTICAST) && defined(CONFIG_PROC_FS) | 1556 | #if defined(CONFIG_IP_MULTICAST) |
| 1555 | igmp_mc_proc_init(); | 1557 | igmp_mc_init(); |
| 1556 | #endif | 1558 | #endif |
| 1557 | } | 1559 | } |
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index ddf32a6bc415..580dd96666e0 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c | |||
| @@ -56,7 +56,6 @@ | |||
| 56 | /* | 56 | /* |
| 57 | * SOL_IP control messages. | 57 | * SOL_IP control messages. |
| 58 | */ | 58 | */ |
| 59 | #define PKTINFO_SKB_CB(__skb) ((struct in_pktinfo *)((__skb)->cb)) | ||
| 60 | 59 | ||
| 61 | static void ip_cmsg_recv_pktinfo(struct msghdr *msg, struct sk_buff *skb) | 60 | static void ip_cmsg_recv_pktinfo(struct msghdr *msg, struct sk_buff *skb) |
| 62 | { | 61 | { |
| @@ -390,7 +389,7 @@ int ip_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len) | |||
| 390 | { | 389 | { |
| 391 | struct sock_exterr_skb *serr; | 390 | struct sock_exterr_skb *serr; |
| 392 | struct sk_buff *skb, *skb2; | 391 | struct sk_buff *skb, *skb2; |
| 393 | struct sockaddr_in *sin; | 392 | DECLARE_SOCKADDR(struct sockaddr_in *, sin, msg->msg_name); |
| 394 | struct { | 393 | struct { |
| 395 | struct sock_extended_err ee; | 394 | struct sock_extended_err ee; |
| 396 | struct sockaddr_in offender; | 395 | struct sockaddr_in offender; |
| @@ -416,7 +415,6 @@ int ip_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len) | |||
| 416 | 415 | ||
| 417 | serr = SKB_EXT_ERR(skb); | 416 | serr = SKB_EXT_ERR(skb); |
| 418 | 417 | ||
| 419 | sin = (struct sockaddr_in *)msg->msg_name; | ||
| 420 | if (sin) { | 418 | if (sin) { |
| 421 | sin->sin_family = AF_INET; | 419 | sin->sin_family = AF_INET; |
| 422 | sin->sin_addr.s_addr = *(__be32 *)(skb_network_header(skb) + | 420 | sin->sin_addr.s_addr = *(__be32 *)(skb_network_header(skb) + |
| @@ -1051,14 +1049,15 @@ e_inval: | |||
| 1051 | * | 1049 | * |
| 1052 | * To support IP_CMSG_PKTINFO option, we store rt_iif and specific | 1050 | * To support IP_CMSG_PKTINFO option, we store rt_iif and specific |
| 1053 | * destination in skb->cb[] before dst drop. | 1051 | * destination in skb->cb[] before dst drop. |
| 1054 | * This way, receiver doesnt make cache line misses to read rtable. | 1052 | * This way, receiver doesn't make cache line misses to read rtable. |
| 1055 | */ | 1053 | */ |
| 1056 | void ipv4_pktinfo_prepare(const struct sock *sk, struct sk_buff *skb) | 1054 | void ipv4_pktinfo_prepare(const struct sock *sk, struct sk_buff *skb) |
| 1057 | { | 1055 | { |
| 1058 | struct in_pktinfo *pktinfo = PKTINFO_SKB_CB(skb); | 1056 | struct in_pktinfo *pktinfo = PKTINFO_SKB_CB(skb); |
| 1057 | bool prepare = (inet_sk(sk)->cmsg_flags & IP_CMSG_PKTINFO) || | ||
| 1058 | ipv6_sk_rxinfo(sk); | ||
| 1059 | 1059 | ||
| 1060 | if ((inet_sk(sk)->cmsg_flags & IP_CMSG_PKTINFO) && | 1060 | if (prepare && skb_rtable(skb)) { |
| 1061 | skb_rtable(skb)) { | ||
| 1062 | pktinfo->ipi_ifindex = inet_iif(skb); | 1061 | pktinfo->ipi_ifindex = inet_iif(skb); |
| 1063 | pktinfo->ipi_spec_dst.s_addr = fib_compute_spec_dst(skb); | 1062 | pktinfo->ipi_spec_dst.s_addr = fib_compute_spec_dst(skb); |
| 1064 | } else { | 1063 | } else { |
diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c index 90ff9570d7d4..bd28f386bd02 100644 --- a/net/ipv4/ip_tunnel.c +++ b/net/ipv4/ip_tunnel.c | |||
| @@ -40,6 +40,7 @@ | |||
| 40 | #include <linux/if_ether.h> | 40 | #include <linux/if_ether.h> |
| 41 | #include <linux/if_vlan.h> | 41 | #include <linux/if_vlan.h> |
| 42 | #include <linux/rculist.h> | 42 | #include <linux/rculist.h> |
| 43 | #include <linux/err.h> | ||
| 43 | 44 | ||
| 44 | #include <net/sock.h> | 45 | #include <net/sock.h> |
| 45 | #include <net/ip.h> | 46 | #include <net/ip.h> |
| @@ -61,13 +62,69 @@ | |||
| 61 | #include <net/ip6_route.h> | 62 | #include <net/ip6_route.h> |
| 62 | #endif | 63 | #endif |
| 63 | 64 | ||
| 64 | static unsigned int ip_tunnel_hash(struct ip_tunnel_net *itn, | 65 | static unsigned int ip_tunnel_hash(__be32 key, __be32 remote) |
| 65 | __be32 key, __be32 remote) | ||
| 66 | { | 66 | { |
| 67 | return hash_32((__force u32)key ^ (__force u32)remote, | 67 | return hash_32((__force u32)key ^ (__force u32)remote, |
| 68 | IP_TNL_HASH_BITS); | 68 | IP_TNL_HASH_BITS); |
| 69 | } | 69 | } |
| 70 | 70 | ||
| 71 | static void __tunnel_dst_set(struct ip_tunnel_dst *idst, | ||
| 72 | struct dst_entry *dst) | ||
| 73 | { | ||
| 74 | struct dst_entry *old_dst; | ||
| 75 | |||
| 76 | if (dst) { | ||
| 77 | if (dst->flags & DST_NOCACHE) | ||
| 78 | dst = NULL; | ||
| 79 | else | ||
| 80 | dst_clone(dst); | ||
| 81 | } | ||
| 82 | old_dst = xchg((__force struct dst_entry **)&idst->dst, dst); | ||
| 83 | dst_release(old_dst); | ||
| 84 | } | ||
| 85 | |||
| 86 | static void tunnel_dst_set(struct ip_tunnel *t, struct dst_entry *dst) | ||
| 87 | { | ||
| 88 | __tunnel_dst_set(this_cpu_ptr(t->dst_cache), dst); | ||
| 89 | } | ||
| 90 | |||
| 91 | static void tunnel_dst_reset(struct ip_tunnel *t) | ||
| 92 | { | ||
| 93 | tunnel_dst_set(t, NULL); | ||
| 94 | } | ||
| 95 | |||
| 96 | static void tunnel_dst_reset_all(struct ip_tunnel *t) | ||
| 97 | { | ||
| 98 | int i; | ||
| 99 | |||
| 100 | for_each_possible_cpu(i) | ||
| 101 | __tunnel_dst_set(per_cpu_ptr(t->dst_cache, i), NULL); | ||
| 102 | } | ||
| 103 | |||
| 104 | static struct dst_entry *tunnel_dst_get(struct ip_tunnel *t) | ||
| 105 | { | ||
| 106 | struct dst_entry *dst; | ||
| 107 | |||
| 108 | rcu_read_lock(); | ||
| 109 | dst = rcu_dereference(this_cpu_ptr(t->dst_cache)->dst); | ||
| 110 | if (dst) | ||
| 111 | dst_hold(dst); | ||
| 112 | rcu_read_unlock(); | ||
| 113 | return dst; | ||
| 114 | } | ||
| 115 | |||
| 116 | static struct dst_entry *tunnel_dst_check(struct ip_tunnel *t, u32 cookie) | ||
| 117 | { | ||
| 118 | struct dst_entry *dst = tunnel_dst_get(t); | ||
| 119 | |||
| 120 | if (dst && dst->obsolete && dst->ops->check(dst, cookie) == NULL) { | ||
| 121 | tunnel_dst_reset(t); | ||
| 122 | return NULL; | ||
| 123 | } | ||
| 124 | |||
| 125 | return dst; | ||
| 126 | } | ||
| 127 | |||
| 71 | /* Often modified stats are per cpu, other are shared (netdev->stats) */ | 128 | /* Often modified stats are per cpu, other are shared (netdev->stats) */ |
| 72 | struct rtnl_link_stats64 *ip_tunnel_get_stats64(struct net_device *dev, | 129 | struct rtnl_link_stats64 *ip_tunnel_get_stats64(struct net_device *dev, |
| 73 | struct rtnl_link_stats64 *tot) | 130 | struct rtnl_link_stats64 *tot) |
| @@ -75,7 +132,8 @@ struct rtnl_link_stats64 *ip_tunnel_get_stats64(struct net_device *dev, | |||
| 75 | int i; | 132 | int i; |
| 76 | 133 | ||
| 77 | for_each_possible_cpu(i) { | 134 | for_each_possible_cpu(i) { |
| 78 | const struct pcpu_tstats *tstats = per_cpu_ptr(dev->tstats, i); | 135 | const struct pcpu_sw_netstats *tstats = |
| 136 | per_cpu_ptr(dev->tstats, i); | ||
| 79 | u64 rx_packets, rx_bytes, tx_packets, tx_bytes; | 137 | u64 rx_packets, rx_bytes, tx_packets, tx_bytes; |
| 80 | unsigned int start; | 138 | unsigned int start; |
| 81 | 139 | ||
| @@ -146,7 +204,7 @@ struct ip_tunnel *ip_tunnel_lookup(struct ip_tunnel_net *itn, | |||
| 146 | struct ip_tunnel *t, *cand = NULL; | 204 | struct ip_tunnel *t, *cand = NULL; |
| 147 | struct hlist_head *head; | 205 | struct hlist_head *head; |
| 148 | 206 | ||
| 149 | hash = ip_tunnel_hash(itn, key, remote); | 207 | hash = ip_tunnel_hash(key, remote); |
| 150 | head = &itn->tunnels[hash]; | 208 | head = &itn->tunnels[hash]; |
| 151 | 209 | ||
| 152 | hlist_for_each_entry_rcu(t, head, hash_node) { | 210 | hlist_for_each_entry_rcu(t, head, hash_node) { |
| @@ -178,7 +236,7 @@ struct ip_tunnel *ip_tunnel_lookup(struct ip_tunnel_net *itn, | |||
| 178 | cand = t; | 236 | cand = t; |
| 179 | } | 237 | } |
| 180 | 238 | ||
| 181 | hash = ip_tunnel_hash(itn, key, 0); | 239 | hash = ip_tunnel_hash(key, 0); |
| 182 | head = &itn->tunnels[hash]; | 240 | head = &itn->tunnels[hash]; |
| 183 | 241 | ||
| 184 | hlist_for_each_entry_rcu(t, head, hash_node) { | 242 | hlist_for_each_entry_rcu(t, head, hash_node) { |
| @@ -234,7 +292,7 @@ static struct hlist_head *ip_bucket(struct ip_tunnel_net *itn, | |||
| 234 | else | 292 | else |
| 235 | remote = 0; | 293 | remote = 0; |
| 236 | 294 | ||
| 237 | h = ip_tunnel_hash(itn, parms->i_key, remote); | 295 | h = ip_tunnel_hash(parms->i_key, remote); |
| 238 | return &itn->tunnels[h]; | 296 | return &itn->tunnels[h]; |
| 239 | } | 297 | } |
| 240 | 298 | ||
| @@ -318,11 +376,10 @@ failed: | |||
| 318 | return ERR_PTR(err); | 376 | return ERR_PTR(err); |
| 319 | } | 377 | } |
| 320 | 378 | ||
| 321 | static inline struct rtable *ip_route_output_tunnel(struct net *net, | 379 | static inline void init_tunnel_flow(struct flowi4 *fl4, |
| 322 | struct flowi4 *fl4, | 380 | int proto, |
| 323 | int proto, | 381 | __be32 daddr, __be32 saddr, |
| 324 | __be32 daddr, __be32 saddr, | 382 | __be32 key, __u8 tos, int oif) |
| 325 | __be32 key, __u8 tos, int oif) | ||
| 326 | { | 383 | { |
| 327 | memset(fl4, 0, sizeof(*fl4)); | 384 | memset(fl4, 0, sizeof(*fl4)); |
| 328 | fl4->flowi4_oif = oif; | 385 | fl4->flowi4_oif = oif; |
| @@ -331,7 +388,6 @@ static inline struct rtable *ip_route_output_tunnel(struct net *net, | |||
| 331 | fl4->flowi4_tos = tos; | 388 | fl4->flowi4_tos = tos; |
| 332 | fl4->flowi4_proto = proto; | 389 | fl4->flowi4_proto = proto; |
| 333 | fl4->fl4_gre_key = key; | 390 | fl4->fl4_gre_key = key; |
| 334 | return ip_route_output_key(net, fl4); | ||
| 335 | } | 391 | } |
| 336 | 392 | ||
| 337 | static int ip_tunnel_bind_dev(struct net_device *dev) | 393 | static int ip_tunnel_bind_dev(struct net_device *dev) |
| @@ -350,14 +406,14 @@ static int ip_tunnel_bind_dev(struct net_device *dev) | |||
| 350 | struct flowi4 fl4; | 406 | struct flowi4 fl4; |
| 351 | struct rtable *rt; | 407 | struct rtable *rt; |
| 352 | 408 | ||
| 353 | rt = ip_route_output_tunnel(tunnel->net, &fl4, | 409 | init_tunnel_flow(&fl4, iph->protocol, iph->daddr, |
| 354 | tunnel->parms.iph.protocol, | 410 | iph->saddr, tunnel->parms.o_key, |
| 355 | iph->daddr, iph->saddr, | 411 | RT_TOS(iph->tos), tunnel->parms.link); |
| 356 | tunnel->parms.o_key, | 412 | rt = ip_route_output_key(tunnel->net, &fl4); |
| 357 | RT_TOS(iph->tos), | 413 | |
| 358 | tunnel->parms.link); | ||
| 359 | if (!IS_ERR(rt)) { | 414 | if (!IS_ERR(rt)) { |
| 360 | tdev = rt->dst.dev; | 415 | tdev = rt->dst.dev; |
| 416 | tunnel_dst_set(tunnel, &rt->dst); | ||
| 361 | ip_rt_put(rt); | 417 | ip_rt_put(rt); |
| 362 | } | 418 | } |
| 363 | if (dev->type != ARPHRD_ETHER) | 419 | if (dev->type != ARPHRD_ETHER) |
| @@ -405,7 +461,7 @@ static struct ip_tunnel *ip_tunnel_create(struct net *net, | |||
| 405 | int ip_tunnel_rcv(struct ip_tunnel *tunnel, struct sk_buff *skb, | 461 | int ip_tunnel_rcv(struct ip_tunnel *tunnel, struct sk_buff *skb, |
| 406 | const struct tnl_ptk_info *tpi, bool log_ecn_error) | 462 | const struct tnl_ptk_info *tpi, bool log_ecn_error) |
| 407 | { | 463 | { |
| 408 | struct pcpu_tstats *tstats; | 464 | struct pcpu_sw_netstats *tstats; |
| 409 | const struct iphdr *iph = ip_hdr(skb); | 465 | const struct iphdr *iph = ip_hdr(skb); |
| 410 | int err; | 466 | int err; |
| 411 | 467 | ||
| @@ -528,10 +584,11 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev, | |||
| 528 | struct flowi4 fl4; | 584 | struct flowi4 fl4; |
| 529 | u8 tos, ttl; | 585 | u8 tos, ttl; |
| 530 | __be16 df; | 586 | __be16 df; |
| 531 | struct rtable *rt; /* Route to the other host */ | 587 | struct rtable *rt = NULL; /* Route to the other host */ |
| 532 | unsigned int max_headroom; /* The extra header space needed */ | 588 | unsigned int max_headroom; /* The extra header space needed */ |
| 533 | __be32 dst; | 589 | __be32 dst; |
| 534 | int err; | 590 | int err; |
| 591 | bool connected = true; | ||
| 535 | 592 | ||
| 536 | inner_iph = (const struct iphdr *)skb_inner_network_header(skb); | 593 | inner_iph = (const struct iphdr *)skb_inner_network_header(skb); |
| 537 | 594 | ||
| @@ -581,27 +638,39 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev, | |||
| 581 | #endif | 638 | #endif |
| 582 | else | 639 | else |
| 583 | goto tx_error; | 640 | goto tx_error; |
| 641 | |||
| 642 | connected = false; | ||
| 584 | } | 643 | } |
| 585 | 644 | ||
| 586 | tos = tnl_params->tos; | 645 | tos = tnl_params->tos; |
| 587 | if (tos & 0x1) { | 646 | if (tos & 0x1) { |
| 588 | tos &= ~0x1; | 647 | tos &= ~0x1; |
| 589 | if (skb->protocol == htons(ETH_P_IP)) | 648 | if (skb->protocol == htons(ETH_P_IP)) { |
| 590 | tos = inner_iph->tos; | 649 | tos = inner_iph->tos; |
| 591 | else if (skb->protocol == htons(ETH_P_IPV6)) | 650 | connected = false; |
| 651 | } else if (skb->protocol == htons(ETH_P_IPV6)) { | ||
| 592 | tos = ipv6_get_dsfield((const struct ipv6hdr *)inner_iph); | 652 | tos = ipv6_get_dsfield((const struct ipv6hdr *)inner_iph); |
| 653 | connected = false; | ||
| 654 | } | ||
| 593 | } | 655 | } |
| 594 | 656 | ||
| 595 | rt = ip_route_output_tunnel(tunnel->net, &fl4, | 657 | init_tunnel_flow(&fl4, protocol, dst, tnl_params->saddr, |
| 596 | protocol, | 658 | tunnel->parms.o_key, RT_TOS(tos), tunnel->parms.link); |
| 597 | dst, tnl_params->saddr, | 659 | |
| 598 | tunnel->parms.o_key, | 660 | if (connected) |
| 599 | RT_TOS(tos), | 661 | rt = (struct rtable *)tunnel_dst_check(tunnel, 0); |
| 600 | tunnel->parms.link); | 662 | |
| 601 | if (IS_ERR(rt)) { | 663 | if (!rt) { |
| 602 | dev->stats.tx_carrier_errors++; | 664 | rt = ip_route_output_key(tunnel->net, &fl4); |
| 603 | goto tx_error; | 665 | |
| 666 | if (IS_ERR(rt)) { | ||
| 667 | dev->stats.tx_carrier_errors++; | ||
| 668 | goto tx_error; | ||
| 669 | } | ||
| 670 | if (connected) | ||
| 671 | tunnel_dst_set(tunnel, &rt->dst); | ||
| 604 | } | 672 | } |
| 673 | |||
| 605 | if (rt->dst.dev == dev) { | 674 | if (rt->dst.dev == dev) { |
| 606 | ip_rt_put(rt); | 675 | ip_rt_put(rt); |
| 607 | dev->stats.collisions++; | 676 | dev->stats.collisions++; |
| @@ -618,6 +687,7 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev, | |||
| 618 | tunnel->err_time + IPTUNNEL_ERR_TIMEO)) { | 687 | tunnel->err_time + IPTUNNEL_ERR_TIMEO)) { |
| 619 | tunnel->err_count--; | 688 | tunnel->err_count--; |
| 620 | 689 | ||
| 690 | memset(IPCB(skb), 0, sizeof(*IPCB(skb))); | ||
| 621 | dst_link_failure(skb); | 691 | dst_link_failure(skb); |
| 622 | } else | 692 | } else |
| 623 | tunnel->err_count = 0; | 693 | tunnel->err_count = 0; |
| @@ -647,7 +717,7 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev, | |||
| 647 | 717 | ||
| 648 | if (skb_cow_head(skb, dev->needed_headroom)) { | 718 | if (skb_cow_head(skb, dev->needed_headroom)) { |
| 649 | dev->stats.tx_dropped++; | 719 | dev->stats.tx_dropped++; |
| 650 | dev_kfree_skb(skb); | 720 | kfree_skb(skb); |
| 651 | return; | 721 | return; |
| 652 | } | 722 | } |
| 653 | 723 | ||
| @@ -663,7 +733,7 @@ tx_error_icmp: | |||
| 663 | #endif | 733 | #endif |
| 664 | tx_error: | 734 | tx_error: |
| 665 | dev->stats.tx_errors++; | 735 | dev->stats.tx_errors++; |
| 666 | dev_kfree_skb(skb); | 736 | kfree_skb(skb); |
| 667 | } | 737 | } |
| 668 | EXPORT_SYMBOL_GPL(ip_tunnel_xmit); | 738 | EXPORT_SYMBOL_GPL(ip_tunnel_xmit); |
| 669 | 739 | ||
| @@ -696,6 +766,7 @@ static void ip_tunnel_update(struct ip_tunnel_net *itn, | |||
| 696 | if (set_mtu) | 766 | if (set_mtu) |
| 697 | dev->mtu = mtu; | 767 | dev->mtu = mtu; |
| 698 | } | 768 | } |
| 769 | tunnel_dst_reset_all(t); | ||
| 699 | netdev_state_change(dev); | 770 | netdev_state_change(dev); |
| 700 | } | 771 | } |
| 701 | 772 | ||
| @@ -811,6 +882,7 @@ static void ip_tunnel_dev_free(struct net_device *dev) | |||
| 811 | struct ip_tunnel *tunnel = netdev_priv(dev); | 882 | struct ip_tunnel *tunnel = netdev_priv(dev); |
| 812 | 883 | ||
| 813 | gro_cells_destroy(&tunnel->gro_cells); | 884 | gro_cells_destroy(&tunnel->gro_cells); |
| 885 | free_percpu(tunnel->dst_cache); | ||
| 814 | free_percpu(dev->tstats); | 886 | free_percpu(dev->tstats); |
| 815 | free_netdev(dev); | 887 | free_netdev(dev); |
| 816 | } | 888 | } |
| @@ -859,7 +931,7 @@ int ip_tunnel_init_net(struct net *net, int ip_tnl_net_id, | |||
| 859 | } | 931 | } |
| 860 | rtnl_unlock(); | 932 | rtnl_unlock(); |
| 861 | 933 | ||
| 862 | return PTR_RET(itn->fb_tunnel_dev); | 934 | return PTR_ERR_OR_ZERO(itn->fb_tunnel_dev); |
| 863 | } | 935 | } |
| 864 | EXPORT_SYMBOL_GPL(ip_tunnel_init_net); | 936 | EXPORT_SYMBOL_GPL(ip_tunnel_init_net); |
| 865 | 937 | ||
| @@ -979,18 +1051,25 @@ int ip_tunnel_init(struct net_device *dev) | |||
| 979 | int i, err; | 1051 | int i, err; |
| 980 | 1052 | ||
| 981 | dev->destructor = ip_tunnel_dev_free; | 1053 | dev->destructor = ip_tunnel_dev_free; |
| 982 | dev->tstats = alloc_percpu(struct pcpu_tstats); | 1054 | dev->tstats = alloc_percpu(struct pcpu_sw_netstats); |
| 983 | if (!dev->tstats) | 1055 | if (!dev->tstats) |
| 984 | return -ENOMEM; | 1056 | return -ENOMEM; |
| 985 | 1057 | ||
| 986 | for_each_possible_cpu(i) { | 1058 | for_each_possible_cpu(i) { |
| 987 | struct pcpu_tstats *ipt_stats; | 1059 | struct pcpu_sw_netstats *ipt_stats; |
| 988 | ipt_stats = per_cpu_ptr(dev->tstats, i); | 1060 | ipt_stats = per_cpu_ptr(dev->tstats, i); |
| 989 | u64_stats_init(&ipt_stats->syncp); | 1061 | u64_stats_init(&ipt_stats->syncp); |
| 990 | } | 1062 | } |
| 991 | 1063 | ||
| 1064 | tunnel->dst_cache = alloc_percpu(struct ip_tunnel_dst); | ||
| 1065 | if (!tunnel->dst_cache) { | ||
| 1066 | free_percpu(dev->tstats); | ||
| 1067 | return -ENOMEM; | ||
| 1068 | } | ||
| 1069 | |||
| 992 | err = gro_cells_init(&tunnel->gro_cells, dev); | 1070 | err = gro_cells_init(&tunnel->gro_cells, dev); |
| 993 | if (err) { | 1071 | if (err) { |
| 1072 | free_percpu(tunnel->dst_cache); | ||
| 994 | free_percpu(dev->tstats); | 1073 | free_percpu(dev->tstats); |
| 995 | return err; | 1074 | return err; |
| 996 | } | 1075 | } |
| @@ -1015,6 +1094,8 @@ void ip_tunnel_uninit(struct net_device *dev) | |||
| 1015 | /* fb_tunnel_dev will be unregisted in net-exit call. */ | 1094 | /* fb_tunnel_dev will be unregisted in net-exit call. */ |
| 1016 | if (itn->fb_tunnel_dev != dev) | 1095 | if (itn->fb_tunnel_dev != dev) |
| 1017 | ip_tunnel_del(netdev_priv(dev)); | 1096 | ip_tunnel_del(netdev_priv(dev)); |
| 1097 | |||
| 1098 | tunnel_dst_reset_all(tunnel); | ||
| 1018 | } | 1099 | } |
| 1019 | EXPORT_SYMBOL_GPL(ip_tunnel_uninit); | 1100 | EXPORT_SYMBOL_GPL(ip_tunnel_uninit); |
| 1020 | 1101 | ||
diff --git a/net/ipv4/ip_tunnel_core.c b/net/ipv4/ip_tunnel_core.c index 42ffbc8d65c6..6156f4ef5e91 100644 --- a/net/ipv4/ip_tunnel_core.c +++ b/net/ipv4/ip_tunnel_core.c | |||
| @@ -56,7 +56,7 @@ int iptunnel_xmit(struct rtable *rt, struct sk_buff *skb, | |||
| 56 | 56 | ||
| 57 | skb_scrub_packet(skb, xnet); | 57 | skb_scrub_packet(skb, xnet); |
| 58 | 58 | ||
| 59 | skb->rxhash = 0; | 59 | skb_clear_hash(skb); |
| 60 | skb_dst_set(skb, &rt->dst); | 60 | skb_dst_set(skb, &rt->dst); |
| 61 | memset(IPCB(skb), 0, sizeof(*IPCB(skb))); | 61 | memset(IPCB(skb), 0, sizeof(*IPCB(skb))); |
| 62 | 62 | ||
| @@ -107,8 +107,7 @@ int iptunnel_pull_header(struct sk_buff *skb, int hdr_len, __be16 inner_proto) | |||
| 107 | 107 | ||
| 108 | nf_reset(skb); | 108 | nf_reset(skb); |
| 109 | secpath_reset(skb); | 109 | secpath_reset(skb); |
| 110 | if (!skb->l4_rxhash) | 110 | skb_clear_hash_if_not_l4(skb); |
| 111 | skb->rxhash = 0; | ||
| 112 | skb_dst_drop(skb); | 111 | skb_dst_drop(skb); |
| 113 | skb->vlan_tci = 0; | 112 | skb->vlan_tci = 0; |
| 114 | skb_set_queue_mapping(skb, 0); | 113 | skb_set_queue_mapping(skb, 0); |
diff --git a/net/ipv4/ip_vti.c b/net/ipv4/ip_vti.c index 52b802a0cd8c..48eafae51769 100644 --- a/net/ipv4/ip_vti.c +++ b/net/ipv4/ip_vti.c | |||
| @@ -60,7 +60,7 @@ static int vti_rcv(struct sk_buff *skb) | |||
| 60 | tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, TUNNEL_NO_KEY, | 60 | tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, TUNNEL_NO_KEY, |
| 61 | iph->saddr, iph->daddr, 0); | 61 | iph->saddr, iph->daddr, 0); |
| 62 | if (tunnel != NULL) { | 62 | if (tunnel != NULL) { |
| 63 | struct pcpu_tstats *tstats; | 63 | struct pcpu_sw_netstats *tstats; |
| 64 | u32 oldmark = skb->mark; | 64 | u32 oldmark = skb->mark; |
| 65 | int ret; | 65 | int ret; |
| 66 | 66 | ||
| @@ -162,7 +162,7 @@ tx_error_icmp: | |||
| 162 | dst_link_failure(skb); | 162 | dst_link_failure(skb); |
| 163 | tx_error: | 163 | tx_error: |
| 164 | dev->stats.tx_errors++; | 164 | dev->stats.tx_errors++; |
| 165 | dev_kfree_skb(skb); | 165 | kfree_skb(skb); |
| 166 | return NETDEV_TX_OK; | 166 | return NETDEV_TX_OK; |
| 167 | } | 167 | } |
| 168 | 168 | ||
diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index fe3e9f7f1f0b..812b18351462 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c | |||
| @@ -228,7 +228,7 @@ static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) | |||
| 228 | return NETDEV_TX_OK; | 228 | return NETDEV_TX_OK; |
| 229 | 229 | ||
| 230 | tx_error: | 230 | tx_error: |
| 231 | dev_kfree_skb(skb); | 231 | kfree_skb(skb); |
| 232 | out: | 232 | out: |
| 233 | dev->stats.tx_errors++; | 233 | dev->stats.tx_errors++; |
| 234 | return NETDEV_TX_OK; | 234 | return NETDEV_TX_OK; |
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index 1672409f5ba5..b9b3472975ba 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c | |||
| @@ -428,6 +428,7 @@ struct net_device *ipmr_new_tunnel(struct net *net, struct vifctl *v) | |||
| 428 | goto failure; | 428 | goto failure; |
| 429 | 429 | ||
| 430 | ipv4_devconf_setall(in_dev); | 430 | ipv4_devconf_setall(in_dev); |
| 431 | neigh_parms_data_state_setall(in_dev->arp_parms); | ||
| 431 | IPV4_DEVCONF(in_dev->cnf, RP_FILTER) = 0; | 432 | IPV4_DEVCONF(in_dev->cnf, RP_FILTER) = 0; |
| 432 | 433 | ||
| 433 | if (dev_open(dev)) | 434 | if (dev_open(dev)) |
| @@ -520,6 +521,7 @@ static struct net_device *ipmr_reg_vif(struct net *net, struct mr_table *mrt) | |||
| 520 | } | 521 | } |
| 521 | 522 | ||
| 522 | ipv4_devconf_setall(in_dev); | 523 | ipv4_devconf_setall(in_dev); |
| 524 | neigh_parms_data_state_setall(in_dev->arp_parms); | ||
| 523 | IPV4_DEVCONF(in_dev->cnf, RP_FILTER) = 0; | 525 | IPV4_DEVCONF(in_dev->cnf, RP_FILTER) = 0; |
| 524 | rcu_read_unlock(); | 526 | rcu_read_unlock(); |
| 525 | 527 | ||
diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index 40d56073cd19..81c6910cfa92 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig | |||
| @@ -39,23 +39,33 @@ config NF_CONNTRACK_PROC_COMPAT | |||
| 39 | config NF_TABLES_IPV4 | 39 | config NF_TABLES_IPV4 |
| 40 | depends on NF_TABLES | 40 | depends on NF_TABLES |
| 41 | tristate "IPv4 nf_tables support" | 41 | tristate "IPv4 nf_tables support" |
| 42 | 42 | help | |
| 43 | config NFT_REJECT_IPV4 | 43 | This option enables the IPv4 support for nf_tables. |
| 44 | depends on NF_TABLES_IPV4 | ||
| 45 | tristate "nf_tables IPv4 reject support" | ||
| 46 | 44 | ||
| 47 | config NFT_CHAIN_ROUTE_IPV4 | 45 | config NFT_CHAIN_ROUTE_IPV4 |
| 48 | depends on NF_TABLES_IPV4 | 46 | depends on NF_TABLES_IPV4 |
| 49 | tristate "IPv4 nf_tables route chain support" | 47 | tristate "IPv4 nf_tables route chain support" |
| 48 | help | ||
| 49 | This option enables the "route" chain for IPv4 in nf_tables. This | ||
| 50 | chain type is used to force packet re-routing after mangling header | ||
| 51 | fields such as the source, destination, type of service and | ||
| 52 | the packet mark. | ||
| 50 | 53 | ||
| 51 | config NFT_CHAIN_NAT_IPV4 | 54 | config NFT_CHAIN_NAT_IPV4 |
| 52 | depends on NF_TABLES_IPV4 | 55 | depends on NF_TABLES_IPV4 |
| 53 | depends on NF_NAT_IPV4 && NFT_NAT | 56 | depends on NF_NAT_IPV4 && NFT_NAT |
| 54 | tristate "IPv4 nf_tables nat chain support" | 57 | tristate "IPv4 nf_tables nat chain support" |
| 58 | help | ||
| 59 | This option enables the "nat" chain for IPv4 in nf_tables. This | ||
| 60 | chain type is used to perform Network Address Translation (NAT) | ||
| 61 | packet transformations such as the source, destination address and | ||
| 62 | source and destination ports. | ||
| 55 | 63 | ||
| 56 | config NF_TABLES_ARP | 64 | config NF_TABLES_ARP |
| 57 | depends on NF_TABLES | 65 | depends on NF_TABLES |
| 58 | tristate "ARP nf_tables support" | 66 | tristate "ARP nf_tables support" |
| 67 | help | ||
| 68 | This option enables the ARP support for nf_tables. | ||
| 59 | 69 | ||
| 60 | config IP_NF_IPTABLES | 70 | config IP_NF_IPTABLES |
| 61 | tristate "IP tables support (required for filtering/masq/NAT)" | 71 | tristate "IP tables support (required for filtering/masq/NAT)" |
diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile index 19df72b7ba88..c16be9d58420 100644 --- a/net/ipv4/netfilter/Makefile +++ b/net/ipv4/netfilter/Makefile | |||
| @@ -28,7 +28,6 @@ obj-$(CONFIG_NF_NAT_SNMP_BASIC) += nf_nat_snmp_basic.o | |||
| 28 | obj-$(CONFIG_NF_NAT_PROTO_GRE) += nf_nat_proto_gre.o | 28 | obj-$(CONFIG_NF_NAT_PROTO_GRE) += nf_nat_proto_gre.o |
| 29 | 29 | ||
| 30 | obj-$(CONFIG_NF_TABLES_IPV4) += nf_tables_ipv4.o | 30 | obj-$(CONFIG_NF_TABLES_IPV4) += nf_tables_ipv4.o |
| 31 | obj-$(CONFIG_NFT_REJECT_IPV4) += nft_reject_ipv4.o | ||
| 32 | obj-$(CONFIG_NFT_CHAIN_ROUTE_IPV4) += nft_chain_route_ipv4.o | 31 | obj-$(CONFIG_NFT_CHAIN_ROUTE_IPV4) += nft_chain_route_ipv4.o |
| 33 | obj-$(CONFIG_NFT_CHAIN_NAT_IPV4) += nft_chain_nat_ipv4.o | 32 | obj-$(CONFIG_NFT_CHAIN_NAT_IPV4) += nft_chain_nat_ipv4.o |
| 34 | obj-$(CONFIG_NF_TABLES_ARP) += nf_tables_arp.o | 33 | obj-$(CONFIG_NF_TABLES_ARP) += nf_tables_arp.o |
diff --git a/net/ipv4/netfilter/ipt_REJECT.c b/net/ipv4/netfilter/ipt_REJECT.c index b969131ad1c1..5b6e0df4ccff 100644 --- a/net/ipv4/netfilter/ipt_REJECT.c +++ b/net/ipv4/netfilter/ipt_REJECT.c | |||
| @@ -17,10 +17,6 @@ | |||
| 17 | #include <linux/udp.h> | 17 | #include <linux/udp.h> |
| 18 | #include <linux/icmp.h> | 18 | #include <linux/icmp.h> |
| 19 | #include <net/icmp.h> | 19 | #include <net/icmp.h> |
| 20 | #include <net/ip.h> | ||
| 21 | #include <net/tcp.h> | ||
| 22 | #include <net/route.h> | ||
| 23 | #include <net/dst.h> | ||
| 24 | #include <linux/netfilter/x_tables.h> | 20 | #include <linux/netfilter/x_tables.h> |
| 25 | #include <linux/netfilter_ipv4/ip_tables.h> | 21 | #include <linux/netfilter_ipv4/ip_tables.h> |
| 26 | #include <linux/netfilter_ipv4/ipt_REJECT.h> | 22 | #include <linux/netfilter_ipv4/ipt_REJECT.h> |
| @@ -28,128 +24,12 @@ | |||
| 28 | #include <linux/netfilter_bridge.h> | 24 | #include <linux/netfilter_bridge.h> |
| 29 | #endif | 25 | #endif |
| 30 | 26 | ||
| 27 | #include <net/netfilter/ipv4/nf_reject.h> | ||
| 28 | |||
| 31 | MODULE_LICENSE("GPL"); | 29 | MODULE_LICENSE("GPL"); |
| 32 | MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>"); | 30 | MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>"); |
| 33 | MODULE_DESCRIPTION("Xtables: packet \"rejection\" target for IPv4"); | 31 | MODULE_DESCRIPTION("Xtables: packet \"rejection\" target for IPv4"); |
| 34 | 32 | ||
| 35 | /* Send RST reply */ | ||
| 36 | static void send_reset(struct sk_buff *oldskb, int hook) | ||
| 37 | { | ||
| 38 | struct sk_buff *nskb; | ||
| 39 | const struct iphdr *oiph; | ||
| 40 | struct iphdr *niph; | ||
| 41 | const struct tcphdr *oth; | ||
| 42 | struct tcphdr _otcph, *tcph; | ||
| 43 | |||
| 44 | /* IP header checks: fragment. */ | ||
| 45 | if (ip_hdr(oldskb)->frag_off & htons(IP_OFFSET)) | ||
| 46 | return; | ||
| 47 | |||
| 48 | oth = skb_header_pointer(oldskb, ip_hdrlen(oldskb), | ||
| 49 | sizeof(_otcph), &_otcph); | ||
| 50 | if (oth == NULL) | ||
| 51 | return; | ||
| 52 | |||
| 53 | /* No RST for RST. */ | ||
| 54 | if (oth->rst) | ||
| 55 | return; | ||
| 56 | |||
| 57 | if (skb_rtable(oldskb)->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST)) | ||
| 58 | return; | ||
| 59 | |||
| 60 | /* Check checksum */ | ||
| 61 | if (nf_ip_checksum(oldskb, hook, ip_hdrlen(oldskb), IPPROTO_TCP)) | ||
| 62 | return; | ||
| 63 | oiph = ip_hdr(oldskb); | ||
| 64 | |||
| 65 | nskb = alloc_skb(sizeof(struct iphdr) + sizeof(struct tcphdr) + | ||
| 66 | LL_MAX_HEADER, GFP_ATOMIC); | ||
| 67 | if (!nskb) | ||
| 68 | return; | ||
| 69 | |||
| 70 | skb_reserve(nskb, LL_MAX_HEADER); | ||
| 71 | |||
| 72 | skb_reset_network_header(nskb); | ||
| 73 | niph = (struct iphdr *)skb_put(nskb, sizeof(struct iphdr)); | ||
| 74 | niph->version = 4; | ||
| 75 | niph->ihl = sizeof(struct iphdr) / 4; | ||
| 76 | niph->tos = 0; | ||
| 77 | niph->id = 0; | ||
| 78 | niph->frag_off = htons(IP_DF); | ||
| 79 | niph->protocol = IPPROTO_TCP; | ||
| 80 | niph->check = 0; | ||
| 81 | niph->saddr = oiph->daddr; | ||
| 82 | niph->daddr = oiph->saddr; | ||
| 83 | |||
| 84 | skb_reset_transport_header(nskb); | ||
| 85 | tcph = (struct tcphdr *)skb_put(nskb, sizeof(struct tcphdr)); | ||
| 86 | memset(tcph, 0, sizeof(*tcph)); | ||
| 87 | tcph->source = oth->dest; | ||
| 88 | tcph->dest = oth->source; | ||
| 89 | tcph->doff = sizeof(struct tcphdr) / 4; | ||
| 90 | |||
| 91 | if (oth->ack) | ||
| 92 | tcph->seq = oth->ack_seq; | ||
| 93 | else { | ||
| 94 | tcph->ack_seq = htonl(ntohl(oth->seq) + oth->syn + oth->fin + | ||
| 95 | oldskb->len - ip_hdrlen(oldskb) - | ||
| 96 | (oth->doff << 2)); | ||
| 97 | tcph->ack = 1; | ||
| 98 | } | ||
| 99 | |||
| 100 | tcph->rst = 1; | ||
| 101 | tcph->check = ~tcp_v4_check(sizeof(struct tcphdr), niph->saddr, | ||
| 102 | niph->daddr, 0); | ||
| 103 | nskb->ip_summed = CHECKSUM_PARTIAL; | ||
| 104 | nskb->csum_start = (unsigned char *)tcph - nskb->head; | ||
| 105 | nskb->csum_offset = offsetof(struct tcphdr, check); | ||
| 106 | |||
| 107 | /* ip_route_me_harder expects skb->dst to be set */ | ||
| 108 | skb_dst_set_noref(nskb, skb_dst(oldskb)); | ||
| 109 | |||
| 110 | nskb->protocol = htons(ETH_P_IP); | ||
| 111 | if (ip_route_me_harder(nskb, RTN_UNSPEC)) | ||
| 112 | goto free_nskb; | ||
| 113 | |||
| 114 | niph->ttl = ip4_dst_hoplimit(skb_dst(nskb)); | ||
| 115 | |||
| 116 | /* "Never happens" */ | ||
| 117 | if (nskb->len > dst_mtu(skb_dst(nskb))) | ||
| 118 | goto free_nskb; | ||
| 119 | |||
| 120 | nf_ct_attach(nskb, oldskb); | ||
| 121 | |||
| 122 | #ifdef CONFIG_BRIDGE_NETFILTER | ||
| 123 | /* If we use ip_local_out for bridged traffic, the MAC source on | ||
| 124 | * the RST will be ours, instead of the destination's. This confuses | ||
| 125 | * some routers/firewalls, and they drop the packet. So we need to | ||
| 126 | * build the eth header using the original destination's MAC as the | ||
| 127 | * source, and send the RST packet directly. | ||
| 128 | */ | ||
| 129 | if (oldskb->nf_bridge) { | ||
| 130 | struct ethhdr *oeth = eth_hdr(oldskb); | ||
| 131 | nskb->dev = oldskb->nf_bridge->physindev; | ||
| 132 | niph->tot_len = htons(nskb->len); | ||
| 133 | ip_send_check(niph); | ||
| 134 | if (dev_hard_header(nskb, nskb->dev, ntohs(nskb->protocol), | ||
| 135 | oeth->h_source, oeth->h_dest, nskb->len) < 0) | ||
| 136 | goto free_nskb; | ||
| 137 | dev_queue_xmit(nskb); | ||
| 138 | } else | ||
| 139 | #endif | ||
| 140 | ip_local_out(nskb); | ||
| 141 | |||
| 142 | return; | ||
| 143 | |||
| 144 | free_nskb: | ||
| 145 | kfree_skb(nskb); | ||
| 146 | } | ||
| 147 | |||
| 148 | static inline void send_unreach(struct sk_buff *skb_in, int code) | ||
| 149 | { | ||
| 150 | icmp_send(skb_in, ICMP_DEST_UNREACH, code, 0); | ||
| 151 | } | ||
| 152 | |||
| 153 | static unsigned int | 33 | static unsigned int |
| 154 | reject_tg(struct sk_buff *skb, const struct xt_action_param *par) | 34 | reject_tg(struct sk_buff *skb, const struct xt_action_param *par) |
| 155 | { | 35 | { |
| @@ -157,28 +37,28 @@ reject_tg(struct sk_buff *skb, const struct xt_action_param *par) | |||
| 157 | 37 | ||
| 158 | switch (reject->with) { | 38 | switch (reject->with) { |
| 159 | case IPT_ICMP_NET_UNREACHABLE: | 39 | case IPT_ICMP_NET_UNREACHABLE: |
| 160 | send_unreach(skb, ICMP_NET_UNREACH); | 40 | nf_send_unreach(skb, ICMP_NET_UNREACH); |
| 161 | break; | 41 | break; |
| 162 | case IPT_ICMP_HOST_UNREACHABLE: | 42 | case IPT_ICMP_HOST_UNREACHABLE: |
| 163 | send_unreach(skb, ICMP_HOST_UNREACH); | 43 | nf_send_unreach(skb, ICMP_HOST_UNREACH); |
| 164 | break; | 44 | break; |
| 165 | case IPT_ICMP_PROT_UNREACHABLE: | 45 | case IPT_ICMP_PROT_UNREACHABLE: |
| 166 | send_unreach(skb, ICMP_PROT_UNREACH); | 46 | nf_send_unreach(skb, ICMP_PROT_UNREACH); |
| 167 | break; | 47 | break; |
| 168 | case IPT_ICMP_PORT_UNREACHABLE: | 48 | case IPT_ICMP_PORT_UNREACHABLE: |
| 169 | send_unreach(skb, ICMP_PORT_UNREACH); | 49 | nf_send_unreach(skb, ICMP_PORT_UNREACH); |
| 170 | break; | 50 | break; |
| 171 | case IPT_ICMP_NET_PROHIBITED: | 51 | case IPT_ICMP_NET_PROHIBITED: |
| 172 | send_unreach(skb, ICMP_NET_ANO); | 52 | nf_send_unreach(skb, ICMP_NET_ANO); |
| 173 | break; | 53 | break; |
| 174 | case IPT_ICMP_HOST_PROHIBITED: | 54 | case IPT_ICMP_HOST_PROHIBITED: |
| 175 | send_unreach(skb, ICMP_HOST_ANO); | 55 | nf_send_unreach(skb, ICMP_HOST_ANO); |
| 176 | break; | 56 | break; |
| 177 | case IPT_ICMP_ADMIN_PROHIBITED: | 57 | case IPT_ICMP_ADMIN_PROHIBITED: |
| 178 | send_unreach(skb, ICMP_PKT_FILTERED); | 58 | nf_send_unreach(skb, ICMP_PKT_FILTERED); |
| 179 | break; | 59 | break; |
| 180 | case IPT_TCP_RESET: | 60 | case IPT_TCP_RESET: |
| 181 | send_reset(skb, par->hooknum); | 61 | nf_send_reset(skb, par->hooknum); |
| 182 | case IPT_ICMP_ECHOREPLY: | 62 | case IPT_ICMP_ECHOREPLY: |
| 183 | /* Doesn't happen. */ | 63 | /* Doesn't happen. */ |
| 184 | break; | 64 | break; |
diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c index ecd8bec411c9..8127dc802865 100644 --- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c +++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c | |||
| @@ -548,9 +548,3 @@ static void __exit nf_conntrack_l3proto_ipv4_fini(void) | |||
| 548 | 548 | ||
| 549 | module_init(nf_conntrack_l3proto_ipv4_init); | 549 | module_init(nf_conntrack_l3proto_ipv4_init); |
| 550 | module_exit(nf_conntrack_l3proto_ipv4_fini); | 550 | module_exit(nf_conntrack_l3proto_ipv4_fini); |
| 551 | |||
| 552 | void need_ipv4_conntrack(void) | ||
| 553 | { | ||
| 554 | return; | ||
| 555 | } | ||
| 556 | EXPORT_SYMBOL_GPL(need_ipv4_conntrack); | ||
diff --git a/net/ipv4/netfilter/nf_nat_snmp_basic.c b/net/ipv4/netfilter/nf_nat_snmp_basic.c index 5f011cc89cd9..d551e31b416e 100644 --- a/net/ipv4/netfilter/nf_nat_snmp_basic.c +++ b/net/ipv4/netfilter/nf_nat_snmp_basic.c | |||
| @@ -34,8 +34,7 @@ | |||
| 34 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 34 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 35 | * GNU General Public License for more details. | 35 | * GNU General Public License for more details. |
| 36 | * You should have received a copy of the GNU General Public License | 36 | * You should have received a copy of the GNU General Public License |
| 37 | * along with this program; if not, write to the Free Software | 37 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 38 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 39 | * | 38 | * |
| 40 | * Author: James Morris <jmorris@intercode.com.au> | 39 | * Author: James Morris <jmorris@intercode.com.au> |
| 41 | * | 40 | * |
| @@ -462,14 +461,14 @@ static unsigned char asn1_oid_decode(struct asn1_ctx *ctx, | |||
| 462 | } | 461 | } |
| 463 | 462 | ||
| 464 | if (subid < 40) { | 463 | if (subid < 40) { |
| 465 | optr [0] = 0; | 464 | optr[0] = 0; |
| 466 | optr [1] = subid; | 465 | optr[1] = subid; |
| 467 | } else if (subid < 80) { | 466 | } else if (subid < 80) { |
| 468 | optr [0] = 1; | 467 | optr[0] = 1; |
| 469 | optr [1] = subid - 40; | 468 | optr[1] = subid - 40; |
| 470 | } else { | 469 | } else { |
| 471 | optr [0] = 2; | 470 | optr[0] = 2; |
| 472 | optr [1] = subid - 80; | 471 | optr[1] = subid - 80; |
| 473 | } | 472 | } |
| 474 | 473 | ||
| 475 | *len = 2; | 474 | *len = 2; |
diff --git a/net/ipv4/netfilter/nf_tables_arp.c b/net/ipv4/netfilter/nf_tables_arp.c index 3e67ef1c676f..19412a4063fb 100644 --- a/net/ipv4/netfilter/nf_tables_arp.c +++ b/net/ipv4/netfilter/nf_tables_arp.c | |||
| @@ -14,10 +14,30 @@ | |||
| 14 | #include <linux/netfilter_arp.h> | 14 | #include <linux/netfilter_arp.h> |
| 15 | #include <net/netfilter/nf_tables.h> | 15 | #include <net/netfilter/nf_tables.h> |
| 16 | 16 | ||
| 17 | static unsigned int | ||
| 18 | nft_do_chain_arp(const struct nf_hook_ops *ops, | ||
| 19 | struct sk_buff *skb, | ||
| 20 | const struct net_device *in, | ||
| 21 | const struct net_device *out, | ||
| 22 | int (*okfn)(struct sk_buff *)) | ||
| 23 | { | ||
| 24 | struct nft_pktinfo pkt; | ||
| 25 | |||
| 26 | nft_set_pktinfo(&pkt, ops, skb, in, out); | ||
| 27 | |||
| 28 | return nft_do_chain(&pkt, ops); | ||
| 29 | } | ||
| 30 | |||
| 17 | static struct nft_af_info nft_af_arp __read_mostly = { | 31 | static struct nft_af_info nft_af_arp __read_mostly = { |
| 18 | .family = NFPROTO_ARP, | 32 | .family = NFPROTO_ARP, |
| 19 | .nhooks = NF_ARP_NUMHOOKS, | 33 | .nhooks = NF_ARP_NUMHOOKS, |
| 20 | .owner = THIS_MODULE, | 34 | .owner = THIS_MODULE, |
| 35 | .nops = 1, | ||
| 36 | .hooks = { | ||
| 37 | [NF_ARP_IN] = nft_do_chain_arp, | ||
| 38 | [NF_ARP_OUT] = nft_do_chain_arp, | ||
| 39 | [NF_ARP_FORWARD] = nft_do_chain_arp, | ||
| 40 | }, | ||
| 21 | }; | 41 | }; |
| 22 | 42 | ||
| 23 | static int nf_tables_arp_init_net(struct net *net) | 43 | static int nf_tables_arp_init_net(struct net *net) |
| @@ -48,32 +68,14 @@ static struct pernet_operations nf_tables_arp_net_ops = { | |||
| 48 | .exit = nf_tables_arp_exit_net, | 68 | .exit = nf_tables_arp_exit_net, |
| 49 | }; | 69 | }; |
| 50 | 70 | ||
| 51 | static unsigned int | 71 | static const struct nf_chain_type filter_arp = { |
| 52 | nft_do_chain_arp(const struct nf_hook_ops *ops, | ||
| 53 | struct sk_buff *skb, | ||
| 54 | const struct net_device *in, | ||
| 55 | const struct net_device *out, | ||
| 56 | int (*okfn)(struct sk_buff *)) | ||
| 57 | { | ||
| 58 | struct nft_pktinfo pkt; | ||
| 59 | |||
| 60 | nft_set_pktinfo(&pkt, ops, skb, in, out); | ||
| 61 | |||
| 62 | return nft_do_chain_pktinfo(&pkt, ops); | ||
| 63 | } | ||
| 64 | |||
| 65 | static struct nf_chain_type filter_arp = { | ||
| 66 | .family = NFPROTO_ARP, | ||
| 67 | .name = "filter", | 72 | .name = "filter", |
| 68 | .type = NFT_CHAIN_T_DEFAULT, | 73 | .type = NFT_CHAIN_T_DEFAULT, |
| 74 | .family = NFPROTO_ARP, | ||
| 75 | .owner = THIS_MODULE, | ||
| 69 | .hook_mask = (1 << NF_ARP_IN) | | 76 | .hook_mask = (1 << NF_ARP_IN) | |
| 70 | (1 << NF_ARP_OUT) | | 77 | (1 << NF_ARP_OUT) | |
| 71 | (1 << NF_ARP_FORWARD), | 78 | (1 << NF_ARP_FORWARD), |
| 72 | .fn = { | ||
| 73 | [NF_ARP_IN] = nft_do_chain_arp, | ||
| 74 | [NF_ARP_OUT] = nft_do_chain_arp, | ||
| 75 | [NF_ARP_FORWARD] = nft_do_chain_arp, | ||
| 76 | }, | ||
| 77 | }; | 79 | }; |
| 78 | 80 | ||
| 79 | static int __init nf_tables_arp_init(void) | 81 | static int __init nf_tables_arp_init(void) |
diff --git a/net/ipv4/netfilter/nf_tables_ipv4.c b/net/ipv4/netfilter/nf_tables_ipv4.c index 0f4cbfeb19bd..6820c8c40842 100644 --- a/net/ipv4/netfilter/nf_tables_ipv4.c +++ b/net/ipv4/netfilter/nf_tables_ipv4.c | |||
| @@ -18,14 +18,25 @@ | |||
| 18 | #include <net/ip.h> | 18 | #include <net/ip.h> |
| 19 | #include <net/netfilter/nf_tables_ipv4.h> | 19 | #include <net/netfilter/nf_tables_ipv4.h> |
| 20 | 20 | ||
| 21 | static unsigned int nft_do_chain_ipv4(const struct nf_hook_ops *ops, | ||
| 22 | struct sk_buff *skb, | ||
| 23 | const struct net_device *in, | ||
| 24 | const struct net_device *out, | ||
| 25 | int (*okfn)(struct sk_buff *)) | ||
| 26 | { | ||
| 27 | struct nft_pktinfo pkt; | ||
| 28 | |||
| 29 | nft_set_pktinfo_ipv4(&pkt, ops, skb, in, out); | ||
| 30 | |||
| 31 | return nft_do_chain(&pkt, ops); | ||
| 32 | } | ||
| 33 | |||
| 21 | static unsigned int nft_ipv4_output(const struct nf_hook_ops *ops, | 34 | static unsigned int nft_ipv4_output(const struct nf_hook_ops *ops, |
| 22 | struct sk_buff *skb, | 35 | struct sk_buff *skb, |
| 23 | const struct net_device *in, | 36 | const struct net_device *in, |
| 24 | const struct net_device *out, | 37 | const struct net_device *out, |
| 25 | int (*okfn)(struct sk_buff *)) | 38 | int (*okfn)(struct sk_buff *)) |
| 26 | { | 39 | { |
| 27 | struct nft_pktinfo pkt; | ||
| 28 | |||
| 29 | if (unlikely(skb->len < sizeof(struct iphdr) || | 40 | if (unlikely(skb->len < sizeof(struct iphdr) || |
| 30 | ip_hdr(skb)->ihl < sizeof(struct iphdr) / 4)) { | 41 | ip_hdr(skb)->ihl < sizeof(struct iphdr) / 4)) { |
| 31 | if (net_ratelimit()) | 42 | if (net_ratelimit()) |
| @@ -33,19 +44,24 @@ static unsigned int nft_ipv4_output(const struct nf_hook_ops *ops, | |||
| 33 | "packet\n"); | 44 | "packet\n"); |
| 34 | return NF_ACCEPT; | 45 | return NF_ACCEPT; |
| 35 | } | 46 | } |
| 36 | nft_set_pktinfo_ipv4(&pkt, ops, skb, in, out); | ||
| 37 | 47 | ||
| 38 | return nft_do_chain_pktinfo(&pkt, ops); | 48 | return nft_do_chain_ipv4(ops, skb, in, out, okfn); |
| 39 | } | 49 | } |
| 40 | 50 | ||
| 41 | static struct nft_af_info nft_af_ipv4 __read_mostly = { | 51 | struct nft_af_info nft_af_ipv4 __read_mostly = { |
| 42 | .family = NFPROTO_IPV4, | 52 | .family = NFPROTO_IPV4, |
| 43 | .nhooks = NF_INET_NUMHOOKS, | 53 | .nhooks = NF_INET_NUMHOOKS, |
| 44 | .owner = THIS_MODULE, | 54 | .owner = THIS_MODULE, |
| 55 | .nops = 1, | ||
| 45 | .hooks = { | 56 | .hooks = { |
| 57 | [NF_INET_LOCAL_IN] = nft_do_chain_ipv4, | ||
| 46 | [NF_INET_LOCAL_OUT] = nft_ipv4_output, | 58 | [NF_INET_LOCAL_OUT] = nft_ipv4_output, |
| 59 | [NF_INET_FORWARD] = nft_do_chain_ipv4, | ||
| 60 | [NF_INET_PRE_ROUTING] = nft_do_chain_ipv4, | ||
| 61 | [NF_INET_POST_ROUTING] = nft_do_chain_ipv4, | ||
| 47 | }, | 62 | }, |
| 48 | }; | 63 | }; |
| 64 | EXPORT_SYMBOL_GPL(nft_af_ipv4); | ||
| 49 | 65 | ||
| 50 | static int nf_tables_ipv4_init_net(struct net *net) | 66 | static int nf_tables_ipv4_init_net(struct net *net) |
| 51 | { | 67 | { |
| @@ -75,42 +91,28 @@ static struct pernet_operations nf_tables_ipv4_net_ops = { | |||
| 75 | .exit = nf_tables_ipv4_exit_net, | 91 | .exit = nf_tables_ipv4_exit_net, |
| 76 | }; | 92 | }; |
| 77 | 93 | ||
| 78 | static unsigned int | 94 | static const struct nf_chain_type filter_ipv4 = { |
| 79 | nft_do_chain_ipv4(const struct nf_hook_ops *ops, | ||
| 80 | struct sk_buff *skb, | ||
| 81 | const struct net_device *in, | ||
| 82 | const struct net_device *out, | ||
| 83 | int (*okfn)(struct sk_buff *)) | ||
| 84 | { | ||
| 85 | struct nft_pktinfo pkt; | ||
| 86 | |||
| 87 | nft_set_pktinfo_ipv4(&pkt, ops, skb, in, out); | ||
| 88 | |||
| 89 | return nft_do_chain_pktinfo(&pkt, ops); | ||
| 90 | } | ||
| 91 | |||
| 92 | static struct nf_chain_type filter_ipv4 = { | ||
| 93 | .family = NFPROTO_IPV4, | ||
| 94 | .name = "filter", | 95 | .name = "filter", |
| 95 | .type = NFT_CHAIN_T_DEFAULT, | 96 | .type = NFT_CHAIN_T_DEFAULT, |
| 97 | .family = NFPROTO_IPV4, | ||
| 98 | .owner = THIS_MODULE, | ||
| 96 | .hook_mask = (1 << NF_INET_LOCAL_IN) | | 99 | .hook_mask = (1 << NF_INET_LOCAL_IN) | |
| 97 | (1 << NF_INET_LOCAL_OUT) | | 100 | (1 << NF_INET_LOCAL_OUT) | |
| 98 | (1 << NF_INET_FORWARD) | | 101 | (1 << NF_INET_FORWARD) | |
| 99 | (1 << NF_INET_PRE_ROUTING) | | 102 | (1 << NF_INET_PRE_ROUTING) | |
| 100 | (1 << NF_INET_POST_ROUTING), | 103 | (1 << NF_INET_POST_ROUTING), |
| 101 | .fn = { | ||
| 102 | [NF_INET_LOCAL_IN] = nft_do_chain_ipv4, | ||
| 103 | [NF_INET_LOCAL_OUT] = nft_ipv4_output, | ||
| 104 | [NF_INET_FORWARD] = nft_do_chain_ipv4, | ||
| 105 | [NF_INET_PRE_ROUTING] = nft_do_chain_ipv4, | ||
| 106 | [NF_INET_POST_ROUTING] = nft_do_chain_ipv4, | ||
| 107 | }, | ||
| 108 | }; | 104 | }; |
| 109 | 105 | ||
| 110 | static int __init nf_tables_ipv4_init(void) | 106 | static int __init nf_tables_ipv4_init(void) |
| 111 | { | 107 | { |
| 108 | int ret; | ||
| 109 | |||
| 112 | nft_register_chain_type(&filter_ipv4); | 110 | nft_register_chain_type(&filter_ipv4); |
| 113 | return register_pernet_subsys(&nf_tables_ipv4_net_ops); | 111 | ret = register_pernet_subsys(&nf_tables_ipv4_net_ops); |
| 112 | if (ret < 0) | ||
| 113 | nft_unregister_chain_type(&filter_ipv4); | ||
| 114 | |||
| 115 | return ret; | ||
| 114 | } | 116 | } |
| 115 | 117 | ||
| 116 | static void __exit nf_tables_ipv4_exit(void) | 118 | static void __exit nf_tables_ipv4_exit(void) |
diff --git a/net/ipv4/netfilter/nft_chain_nat_ipv4.c b/net/ipv4/netfilter/nft_chain_nat_ipv4.c index cf2c792cd971..b5b256d45e67 100644 --- a/net/ipv4/netfilter/nft_chain_nat_ipv4.c +++ b/net/ipv4/netfilter/nft_chain_nat_ipv4.c | |||
| @@ -75,7 +75,7 @@ static unsigned int nf_nat_fn(const struct nf_hook_ops *ops, | |||
| 75 | 75 | ||
| 76 | nft_set_pktinfo_ipv4(&pkt, ops, skb, in, out); | 76 | nft_set_pktinfo_ipv4(&pkt, ops, skb, in, out); |
| 77 | 77 | ||
| 78 | ret = nft_do_chain_pktinfo(&pkt, ops); | 78 | ret = nft_do_chain(&pkt, ops); |
| 79 | if (ret != NF_ACCEPT) | 79 | if (ret != NF_ACCEPT) |
| 80 | return ret; | 80 | return ret; |
| 81 | if (!nf_nat_initialized(ct, maniptype)) { | 81 | if (!nf_nat_initialized(ct, maniptype)) { |
| @@ -164,21 +164,21 @@ static unsigned int nf_nat_output(const struct nf_hook_ops *ops, | |||
| 164 | return ret; | 164 | return ret; |
| 165 | } | 165 | } |
| 166 | 166 | ||
| 167 | static struct nf_chain_type nft_chain_nat_ipv4 = { | 167 | static const struct nf_chain_type nft_chain_nat_ipv4 = { |
| 168 | .family = NFPROTO_IPV4, | ||
| 169 | .name = "nat", | 168 | .name = "nat", |
| 170 | .type = NFT_CHAIN_T_NAT, | 169 | .type = NFT_CHAIN_T_NAT, |
| 170 | .family = NFPROTO_IPV4, | ||
| 171 | .owner = THIS_MODULE, | ||
| 171 | .hook_mask = (1 << NF_INET_PRE_ROUTING) | | 172 | .hook_mask = (1 << NF_INET_PRE_ROUTING) | |
| 172 | (1 << NF_INET_POST_ROUTING) | | 173 | (1 << NF_INET_POST_ROUTING) | |
| 173 | (1 << NF_INET_LOCAL_OUT) | | 174 | (1 << NF_INET_LOCAL_OUT) | |
| 174 | (1 << NF_INET_LOCAL_IN), | 175 | (1 << NF_INET_LOCAL_IN), |
| 175 | .fn = { | 176 | .hooks = { |
| 176 | [NF_INET_PRE_ROUTING] = nf_nat_prerouting, | 177 | [NF_INET_PRE_ROUTING] = nf_nat_prerouting, |
| 177 | [NF_INET_POST_ROUTING] = nf_nat_postrouting, | 178 | [NF_INET_POST_ROUTING] = nf_nat_postrouting, |
| 178 | [NF_INET_LOCAL_OUT] = nf_nat_output, | 179 | [NF_INET_LOCAL_OUT] = nf_nat_output, |
| 179 | [NF_INET_LOCAL_IN] = nf_nat_fn, | 180 | [NF_INET_LOCAL_IN] = nf_nat_fn, |
| 180 | }, | 181 | }, |
| 181 | .me = THIS_MODULE, | ||
| 182 | }; | 182 | }; |
| 183 | 183 | ||
| 184 | static int __init nft_chain_nat_init(void) | 184 | static int __init nft_chain_nat_init(void) |
diff --git a/net/ipv4/netfilter/nft_chain_route_ipv4.c b/net/ipv4/netfilter/nft_chain_route_ipv4.c index 4e6bf9a3d7aa..125b66766c0a 100644 --- a/net/ipv4/netfilter/nft_chain_route_ipv4.c +++ b/net/ipv4/netfilter/nft_chain_route_ipv4.c | |||
| @@ -47,7 +47,7 @@ static unsigned int nf_route_table_hook(const struct nf_hook_ops *ops, | |||
| 47 | daddr = iph->daddr; | 47 | daddr = iph->daddr; |
| 48 | tos = iph->tos; | 48 | tos = iph->tos; |
| 49 | 49 | ||
| 50 | ret = nft_do_chain_pktinfo(&pkt, ops); | 50 | ret = nft_do_chain(&pkt, ops); |
| 51 | if (ret != NF_DROP && ret != NF_QUEUE) { | 51 | if (ret != NF_DROP && ret != NF_QUEUE) { |
| 52 | iph = ip_hdr(skb); | 52 | iph = ip_hdr(skb); |
| 53 | 53 | ||
| @@ -61,15 +61,15 @@ static unsigned int nf_route_table_hook(const struct nf_hook_ops *ops, | |||
| 61 | return ret; | 61 | return ret; |
| 62 | } | 62 | } |
| 63 | 63 | ||
| 64 | static struct nf_chain_type nft_chain_route_ipv4 = { | 64 | static const struct nf_chain_type nft_chain_route_ipv4 = { |
| 65 | .family = NFPROTO_IPV4, | ||
| 66 | .name = "route", | 65 | .name = "route", |
| 67 | .type = NFT_CHAIN_T_ROUTE, | 66 | .type = NFT_CHAIN_T_ROUTE, |
| 67 | .family = NFPROTO_IPV4, | ||
| 68 | .owner = THIS_MODULE, | ||
| 68 | .hook_mask = (1 << NF_INET_LOCAL_OUT), | 69 | .hook_mask = (1 << NF_INET_LOCAL_OUT), |
| 69 | .fn = { | 70 | .hooks = { |
| 70 | [NF_INET_LOCAL_OUT] = nf_route_table_hook, | 71 | [NF_INET_LOCAL_OUT] = nf_route_table_hook, |
| 71 | }, | 72 | }, |
| 72 | .me = THIS_MODULE, | ||
| 73 | }; | 73 | }; |
| 74 | 74 | ||
| 75 | static int __init nft_chain_route_init(void) | 75 | static int __init nft_chain_route_init(void) |
diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c index 242e7f4ed6f4..2d11c094296e 100644 --- a/net/ipv4/ping.c +++ b/net/ipv4/ping.c | |||
| @@ -53,8 +53,12 @@ | |||
| 53 | #include <net/transp_v6.h> | 53 | #include <net/transp_v6.h> |
| 54 | #endif | 54 | #endif |
| 55 | 55 | ||
| 56 | struct ping_table { | ||
| 57 | struct hlist_nulls_head hash[PING_HTABLE_SIZE]; | ||
| 58 | rwlock_t lock; | ||
| 59 | }; | ||
| 56 | 60 | ||
| 57 | struct ping_table ping_table; | 61 | static struct ping_table ping_table; |
| 58 | struct pingv6_ops pingv6_ops; | 62 | struct pingv6_ops pingv6_ops; |
| 59 | EXPORT_SYMBOL_GPL(pingv6_ops); | 63 | EXPORT_SYMBOL_GPL(pingv6_ops); |
| 60 | 64 | ||
| @@ -316,6 +320,9 @@ static int ping_check_bind_addr(struct sock *sk, struct inet_sock *isk, | |||
| 316 | if (addr_len < sizeof(*addr)) | 320 | if (addr_len < sizeof(*addr)) |
| 317 | return -EINVAL; | 321 | return -EINVAL; |
| 318 | 322 | ||
| 323 | if (addr->sin6_family != AF_INET6) | ||
| 324 | return -EINVAL; | ||
| 325 | |||
| 319 | pr_debug("ping_check_bind_addr(sk=%p,addr=%pI6c,port=%d)\n", | 326 | pr_debug("ping_check_bind_addr(sk=%p,addr=%pI6c,port=%d)\n", |
| 320 | sk, addr->sin6_addr.s6_addr, ntohs(addr->sin6_port)); | 327 | sk, addr->sin6_addr.s6_addr, ntohs(addr->sin6_port)); |
| 321 | 328 | ||
| @@ -668,8 +675,8 @@ int ping_common_sendmsg(int family, struct msghdr *msg, size_t len, | |||
| 668 | } | 675 | } |
| 669 | EXPORT_SYMBOL_GPL(ping_common_sendmsg); | 676 | EXPORT_SYMBOL_GPL(ping_common_sendmsg); |
| 670 | 677 | ||
| 671 | int ping_v4_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | 678 | static int ping_v4_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, |
| 672 | size_t len) | 679 | size_t len) |
| 673 | { | 680 | { |
| 674 | struct net *net = sock_net(sk); | 681 | struct net *net = sock_net(sk); |
| 675 | struct flowi4 fl4; | 682 | struct flowi4 fl4; |
| @@ -696,7 +703,7 @@ int ping_v4_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
| 696 | */ | 703 | */ |
| 697 | 704 | ||
| 698 | if (msg->msg_name) { | 705 | if (msg->msg_name) { |
| 699 | struct sockaddr_in *usin = (struct sockaddr_in *)msg->msg_name; | 706 | DECLARE_SOCKADDR(struct sockaddr_in *, usin, msg->msg_name); |
| 700 | if (msg->msg_namelen < sizeof(*usin)) | 707 | if (msg->msg_namelen < sizeof(*usin)) |
| 701 | return -EINVAL; | 708 | return -EINVAL; |
| 702 | if (usin->sin_family != AF_INET) | 709 | if (usin->sin_family != AF_INET) |
| @@ -869,7 +876,7 @@ int ping_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
| 869 | 876 | ||
| 870 | /* Copy the address and add cmsg data. */ | 877 | /* Copy the address and add cmsg data. */ |
| 871 | if (family == AF_INET) { | 878 | if (family == AF_INET) { |
| 872 | struct sockaddr_in *sin = (struct sockaddr_in *)msg->msg_name; | 879 | DECLARE_SOCKADDR(struct sockaddr_in *, sin, msg->msg_name); |
| 873 | 880 | ||
| 874 | if (sin) { | 881 | if (sin) { |
| 875 | sin->sin_family = AF_INET; | 882 | sin->sin_family = AF_INET; |
| @@ -886,8 +893,7 @@ int ping_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
| 886 | } else if (family == AF_INET6) { | 893 | } else if (family == AF_INET6) { |
| 887 | struct ipv6_pinfo *np = inet6_sk(sk); | 894 | struct ipv6_pinfo *np = inet6_sk(sk); |
| 888 | struct ipv6hdr *ip6 = ipv6_hdr(skb); | 895 | struct ipv6hdr *ip6 = ipv6_hdr(skb); |
| 889 | struct sockaddr_in6 *sin6 = | 896 | DECLARE_SOCKADDR(struct sockaddr_in6 *, sin6, msg->msg_name); |
| 890 | (struct sockaddr_in6 *)msg->msg_name; | ||
| 891 | 897 | ||
| 892 | if (sin6) { | 898 | if (sin6) { |
| 893 | sin6->sin6_family = AF_INET6; | 899 | sin6->sin6_family = AF_INET6; |
| @@ -903,7 +909,12 @@ int ping_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
| 903 | } | 909 | } |
| 904 | 910 | ||
| 905 | if (inet6_sk(sk)->rxopt.all) | 911 | if (inet6_sk(sk)->rxopt.all) |
| 906 | pingv6_ops.ip6_datagram_recv_ctl(sk, msg, skb); | 912 | pingv6_ops.ip6_datagram_recv_common_ctl(sk, msg, skb); |
| 913 | if (skb->protocol == htons(ETH_P_IPV6) && | ||
| 914 | inet6_sk(sk)->rxopt.all) | ||
| 915 | pingv6_ops.ip6_datagram_recv_specific_ctl(sk, msg, skb); | ||
| 916 | else if (skb->protocol == htons(ETH_P_IP) && isk->cmsg_flags) | ||
| 917 | ip_cmsg_recv(msg, skb); | ||
| 907 | #endif | 918 | #endif |
| 908 | } else { | 919 | } else { |
| 909 | BUG(); | 920 | BUG(); |
diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c index 4a0335854b89..a6c8a80ec9d6 100644 --- a/net/ipv4/proc.c +++ b/net/ipv4/proc.c | |||
| @@ -279,6 +279,7 @@ static const struct snmp_mib snmp4_net_list[] = { | |||
| 279 | SNMP_MIB_ITEM("TCPFastOpenCookieReqd", LINUX_MIB_TCPFASTOPENCOOKIEREQD), | 279 | SNMP_MIB_ITEM("TCPFastOpenCookieReqd", LINUX_MIB_TCPFASTOPENCOOKIEREQD), |
| 280 | SNMP_MIB_ITEM("TCPSpuriousRtxHostQueues", LINUX_MIB_TCPSPURIOUS_RTX_HOSTQUEUES), | 280 | SNMP_MIB_ITEM("TCPSpuriousRtxHostQueues", LINUX_MIB_TCPSPURIOUS_RTX_HOSTQUEUES), |
| 281 | SNMP_MIB_ITEM("BusyPollRxPackets", LINUX_MIB_BUSYPOLLRXPACKETS), | 281 | SNMP_MIB_ITEM("BusyPollRxPackets", LINUX_MIB_BUSYPOLLRXPACKETS), |
| 282 | SNMP_MIB_ITEM("TCPAutoCorking", LINUX_MIB_TCPAUTOCORKING), | ||
| 282 | SNMP_MIB_SENTINEL | 283 | SNMP_MIB_SENTINEL |
| 283 | }; | 284 | }; |
| 284 | 285 | ||
| @@ -332,22 +333,22 @@ static void icmp_put(struct seq_file *seq) | |||
| 332 | atomic_long_t *ptr = net->mib.icmpmsg_statistics->mibs; | 333 | atomic_long_t *ptr = net->mib.icmpmsg_statistics->mibs; |
| 333 | 334 | ||
| 334 | seq_puts(seq, "\nIcmp: InMsgs InErrors InCsumErrors"); | 335 | seq_puts(seq, "\nIcmp: InMsgs InErrors InCsumErrors"); |
| 335 | for (i=0; icmpmibmap[i].name != NULL; i++) | 336 | for (i = 0; icmpmibmap[i].name != NULL; i++) |
| 336 | seq_printf(seq, " In%s", icmpmibmap[i].name); | 337 | seq_printf(seq, " In%s", icmpmibmap[i].name); |
| 337 | seq_printf(seq, " OutMsgs OutErrors"); | 338 | seq_printf(seq, " OutMsgs OutErrors"); |
| 338 | for (i=0; icmpmibmap[i].name != NULL; i++) | 339 | for (i = 0; icmpmibmap[i].name != NULL; i++) |
| 339 | seq_printf(seq, " Out%s", icmpmibmap[i].name); | 340 | seq_printf(seq, " Out%s", icmpmibmap[i].name); |
| 340 | seq_printf(seq, "\nIcmp: %lu %lu %lu", | 341 | seq_printf(seq, "\nIcmp: %lu %lu %lu", |
| 341 | snmp_fold_field((void __percpu **) net->mib.icmp_statistics, ICMP_MIB_INMSGS), | 342 | snmp_fold_field((void __percpu **) net->mib.icmp_statistics, ICMP_MIB_INMSGS), |
| 342 | snmp_fold_field((void __percpu **) net->mib.icmp_statistics, ICMP_MIB_INERRORS), | 343 | snmp_fold_field((void __percpu **) net->mib.icmp_statistics, ICMP_MIB_INERRORS), |
| 343 | snmp_fold_field((void __percpu **) net->mib.icmp_statistics, ICMP_MIB_CSUMERRORS)); | 344 | snmp_fold_field((void __percpu **) net->mib.icmp_statistics, ICMP_MIB_CSUMERRORS)); |
| 344 | for (i=0; icmpmibmap[i].name != NULL; i++) | 345 | for (i = 0; icmpmibmap[i].name != NULL; i++) |
| 345 | seq_printf(seq, " %lu", | 346 | seq_printf(seq, " %lu", |
| 346 | atomic_long_read(ptr + icmpmibmap[i].index)); | 347 | atomic_long_read(ptr + icmpmibmap[i].index)); |
| 347 | seq_printf(seq, " %lu %lu", | 348 | seq_printf(seq, " %lu %lu", |
| 348 | snmp_fold_field((void __percpu **) net->mib.icmp_statistics, ICMP_MIB_OUTMSGS), | 349 | snmp_fold_field((void __percpu **) net->mib.icmp_statistics, ICMP_MIB_OUTMSGS), |
| 349 | snmp_fold_field((void __percpu **) net->mib.icmp_statistics, ICMP_MIB_OUTERRORS)); | 350 | snmp_fold_field((void __percpu **) net->mib.icmp_statistics, ICMP_MIB_OUTERRORS)); |
| 350 | for (i=0; icmpmibmap[i].name != NULL; i++) | 351 | for (i = 0; icmpmibmap[i].name != NULL; i++) |
| 351 | seq_printf(seq, " %lu", | 352 | seq_printf(seq, " %lu", |
| 352 | atomic_long_read(ptr + (icmpmibmap[i].index | 0x100))); | 353 | atomic_long_read(ptr + (icmpmibmap[i].index | 0x100))); |
| 353 | } | 354 | } |
diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index 23c3e5b5bb53..c04518f4850a 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c | |||
| @@ -493,7 +493,7 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
| 493 | */ | 493 | */ |
| 494 | 494 | ||
| 495 | if (msg->msg_namelen) { | 495 | if (msg->msg_namelen) { |
| 496 | struct sockaddr_in *usin = (struct sockaddr_in *)msg->msg_name; | 496 | DECLARE_SOCKADDR(struct sockaddr_in *, usin, msg->msg_name); |
| 497 | err = -EINVAL; | 497 | err = -EINVAL; |
| 498 | if (msg->msg_namelen < sizeof(*usin)) | 498 | if (msg->msg_namelen < sizeof(*usin)) |
| 499 | goto out; | 499 | goto out; |
| @@ -575,7 +575,7 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
| 575 | flowi4_init_output(&fl4, ipc.oif, sk->sk_mark, tos, | 575 | flowi4_init_output(&fl4, ipc.oif, sk->sk_mark, tos, |
| 576 | RT_SCOPE_UNIVERSE, | 576 | RT_SCOPE_UNIVERSE, |
| 577 | inet->hdrincl ? IPPROTO_RAW : sk->sk_protocol, | 577 | inet->hdrincl ? IPPROTO_RAW : sk->sk_protocol, |
| 578 | inet_sk_flowi_flags(sk) | FLOWI_FLAG_CAN_SLEEP | | 578 | inet_sk_flowi_flags(sk) | |
| 579 | (inet->hdrincl ? FLOWI_FLAG_KNOWN_NH : 0), | 579 | (inet->hdrincl ? FLOWI_FLAG_KNOWN_NH : 0), |
| 580 | daddr, saddr, 0, 0); | 580 | daddr, saddr, 0, 0); |
| 581 | 581 | ||
| @@ -690,7 +690,7 @@ static int raw_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
| 690 | struct inet_sock *inet = inet_sk(sk); | 690 | struct inet_sock *inet = inet_sk(sk); |
| 691 | size_t copied = 0; | 691 | size_t copied = 0; |
| 692 | int err = -EOPNOTSUPP; | 692 | int err = -EOPNOTSUPP; |
| 693 | struct sockaddr_in *sin = (struct sockaddr_in *)msg->msg_name; | 693 | DECLARE_SOCKADDR(struct sockaddr_in *, sin, msg->msg_name); |
| 694 | struct sk_buff *skb; | 694 | struct sk_buff *skb; |
| 695 | 695 | ||
| 696 | if (flags & MSG_OOB) | 696 | if (flags & MSG_OOB) |
diff --git a/net/ipv4/route.c b/net/ipv4/route.c index f8da28278014..25071b48921c 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c | |||
| @@ -112,9 +112,6 @@ | |||
| 112 | #define RT_FL_TOS(oldflp4) \ | 112 | #define RT_FL_TOS(oldflp4) \ |
| 113 | ((oldflp4)->flowi4_tos & (IPTOS_RT_MASK | RTO_ONLINK)) | 113 | ((oldflp4)->flowi4_tos & (IPTOS_RT_MASK | RTO_ONLINK)) |
| 114 | 114 | ||
| 115 | /* IPv4 datagram length is stored into 16bit field (tot_len) */ | ||
| 116 | #define IP_MAX_MTU 0xFFFF | ||
| 117 | |||
| 118 | #define RT_GC_TIMEOUT (300*HZ) | 115 | #define RT_GC_TIMEOUT (300*HZ) |
| 119 | 116 | ||
| 120 | static int ip_rt_max_size; | 117 | static int ip_rt_max_size; |
diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c index b95331e6c077..f2ed13c2125f 100644 --- a/net/ipv4/syncookies.c +++ b/net/ipv4/syncookies.c | |||
| @@ -121,7 +121,7 @@ static __u32 check_tcp_syn_cookie(__u32 cookie, __be32 saddr, __be32 daddr, | |||
| 121 | cookie -= cookie_hash(saddr, daddr, sport, dport, 0, 0) + sseq; | 121 | cookie -= cookie_hash(saddr, daddr, sport, dport, 0, 0) + sseq; |
| 122 | 122 | ||
| 123 | /* Cookie is now reduced to (count * 2^24) ^ (hash % 2^24) */ | 123 | /* Cookie is now reduced to (count * 2^24) ^ (hash % 2^24) */ |
| 124 | diff = (count - (cookie >> COOKIEBITS)) & ((__u32) - 1 >> COOKIEBITS); | 124 | diff = (count - (cookie >> COOKIEBITS)) & ((__u32) -1 >> COOKIEBITS); |
| 125 | if (diff >= MAX_SYNCOOKIE_AGE) | 125 | if (diff >= MAX_SYNCOOKIE_AGE) |
| 126 | return (__u32)-1; | 126 | return (__u32)-1; |
| 127 | 127 | ||
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index 3d69ec8dac57..44eba052b43d 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c | |||
| @@ -286,13 +286,6 @@ static struct ctl_table ipv4_table[] = { | |||
| 286 | .extra2 = &ip_ttl_max, | 286 | .extra2 = &ip_ttl_max, |
| 287 | }, | 287 | }, |
| 288 | { | 288 | { |
| 289 | .procname = "ip_no_pmtu_disc", | ||
| 290 | .data = &ipv4_config.no_pmtu_disc, | ||
| 291 | .maxlen = sizeof(int), | ||
| 292 | .mode = 0644, | ||
| 293 | .proc_handler = proc_dointvec | ||
| 294 | }, | ||
| 295 | { | ||
| 296 | .procname = "ip_nonlocal_bind", | 289 | .procname = "ip_nonlocal_bind", |
| 297 | .data = &sysctl_ip_nonlocal_bind, | 290 | .data = &sysctl_ip_nonlocal_bind, |
| 298 | .maxlen = sizeof(int), | 291 | .maxlen = sizeof(int), |
| @@ -707,7 +700,7 @@ static struct ctl_table ipv4_table[] = { | |||
| 707 | .mode = 0644, | 700 | .mode = 0644, |
| 708 | .proc_handler = proc_dointvec | 701 | .proc_handler = proc_dointvec |
| 709 | }, | 702 | }, |
| 710 | { | 703 | { |
| 711 | .procname = "tcp_thin_dupack", | 704 | .procname = "tcp_thin_dupack", |
| 712 | .data = &sysctl_tcp_thin_dupack, | 705 | .data = &sysctl_tcp_thin_dupack, |
| 713 | .maxlen = sizeof(int), | 706 | .maxlen = sizeof(int), |
| @@ -733,6 +726,15 @@ static struct ctl_table ipv4_table[] = { | |||
| 733 | .extra2 = &gso_max_segs, | 726 | .extra2 = &gso_max_segs, |
| 734 | }, | 727 | }, |
| 735 | { | 728 | { |
| 729 | .procname = "tcp_autocorking", | ||
| 730 | .data = &sysctl_tcp_autocorking, | ||
| 731 | .maxlen = sizeof(int), | ||
| 732 | .mode = 0644, | ||
| 733 | .proc_handler = proc_dointvec_minmax, | ||
| 734 | .extra1 = &zero, | ||
| 735 | .extra2 = &one, | ||
| 736 | }, | ||
| 737 | { | ||
| 736 | .procname = "udp_mem", | 738 | .procname = "udp_mem", |
| 737 | .data = &sysctl_udp_mem, | 739 | .data = &sysctl_udp_mem, |
| 738 | .maxlen = sizeof(sysctl_udp_mem), | 740 | .maxlen = sizeof(sysctl_udp_mem), |
| @@ -822,6 +824,20 @@ static struct ctl_table ipv4_net_table[] = { | |||
| 822 | .mode = 0644, | 824 | .mode = 0644, |
| 823 | .proc_handler = ipv4_local_port_range, | 825 | .proc_handler = ipv4_local_port_range, |
| 824 | }, | 826 | }, |
| 827 | { | ||
| 828 | .procname = "ip_no_pmtu_disc", | ||
| 829 | .data = &init_net.ipv4.sysctl_ip_no_pmtu_disc, | ||
| 830 | .maxlen = sizeof(int), | ||
| 831 | .mode = 0644, | ||
| 832 | .proc_handler = proc_dointvec | ||
| 833 | }, | ||
| 834 | { | ||
| 835 | .procname = "ip_forward_use_pmtu", | ||
| 836 | .data = &init_net.ipv4.sysctl_ip_fwd_use_pmtu, | ||
| 837 | .maxlen = sizeof(int), | ||
| 838 | .mode = 0644, | ||
| 839 | .proc_handler = proc_dointvec, | ||
| 840 | }, | ||
| 825 | { } | 841 | { } |
| 826 | }; | 842 | }; |
| 827 | 843 | ||
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index c4638e6f0238..4475b3bb494d 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c | |||
| @@ -285,6 +285,8 @@ int sysctl_tcp_fin_timeout __read_mostly = TCP_FIN_TIMEOUT; | |||
| 285 | 285 | ||
| 286 | int sysctl_tcp_min_tso_segs __read_mostly = 2; | 286 | int sysctl_tcp_min_tso_segs __read_mostly = 2; |
| 287 | 287 | ||
| 288 | int sysctl_tcp_autocorking __read_mostly = 1; | ||
| 289 | |||
| 288 | struct percpu_counter tcp_orphan_count; | 290 | struct percpu_counter tcp_orphan_count; |
| 289 | EXPORT_SYMBOL_GPL(tcp_orphan_count); | 291 | EXPORT_SYMBOL_GPL(tcp_orphan_count); |
| 290 | 292 | ||
| @@ -379,7 +381,7 @@ void tcp_init_sock(struct sock *sk) | |||
| 379 | struct inet_connection_sock *icsk = inet_csk(sk); | 381 | struct inet_connection_sock *icsk = inet_csk(sk); |
| 380 | struct tcp_sock *tp = tcp_sk(sk); | 382 | struct tcp_sock *tp = tcp_sk(sk); |
| 381 | 383 | ||
| 382 | skb_queue_head_init(&tp->out_of_order_queue); | 384 | __skb_queue_head_init(&tp->out_of_order_queue); |
| 383 | tcp_init_xmit_timers(sk); | 385 | tcp_init_xmit_timers(sk); |
| 384 | tcp_prequeue_init(tp); | 386 | tcp_prequeue_init(tp); |
| 385 | INIT_LIST_HEAD(&tp->tsq_node); | 387 | INIT_LIST_HEAD(&tp->tsq_node); |
| @@ -619,19 +621,58 @@ static inline void tcp_mark_urg(struct tcp_sock *tp, int flags) | |||
| 619 | tp->snd_up = tp->write_seq; | 621 | tp->snd_up = tp->write_seq; |
| 620 | } | 622 | } |
| 621 | 623 | ||
| 622 | static inline void tcp_push(struct sock *sk, int flags, int mss_now, | 624 | /* If a not yet filled skb is pushed, do not send it if |
| 623 | int nonagle) | 625 | * we have data packets in Qdisc or NIC queues : |
| 626 | * Because TX completion will happen shortly, it gives a chance | ||
| 627 | * to coalesce future sendmsg() payload into this skb, without | ||
| 628 | * need for a timer, and with no latency trade off. | ||
| 629 | * As packets containing data payload have a bigger truesize | ||
| 630 | * than pure acks (dataless) packets, the last checks prevent | ||
| 631 | * autocorking if we only have an ACK in Qdisc/NIC queues, | ||
| 632 | * or if TX completion was delayed after we processed ACK packet. | ||
| 633 | */ | ||
| 634 | static bool tcp_should_autocork(struct sock *sk, struct sk_buff *skb, | ||
| 635 | int size_goal) | ||
| 624 | { | 636 | { |
| 625 | if (tcp_send_head(sk)) { | 637 | return skb->len < size_goal && |
| 626 | struct tcp_sock *tp = tcp_sk(sk); | 638 | sysctl_tcp_autocorking && |
| 639 | skb != tcp_write_queue_head(sk) && | ||
| 640 | atomic_read(&sk->sk_wmem_alloc) > skb->truesize; | ||
| 641 | } | ||
| 642 | |||
| 643 | static void tcp_push(struct sock *sk, int flags, int mss_now, | ||
| 644 | int nonagle, int size_goal) | ||
| 645 | { | ||
| 646 | struct tcp_sock *tp = tcp_sk(sk); | ||
| 647 | struct sk_buff *skb; | ||
| 627 | 648 | ||
| 628 | if (!(flags & MSG_MORE) || forced_push(tp)) | 649 | if (!tcp_send_head(sk)) |
| 629 | tcp_mark_push(tp, tcp_write_queue_tail(sk)); | 650 | return; |
| 651 | |||
| 652 | skb = tcp_write_queue_tail(sk); | ||
| 653 | if (!(flags & MSG_MORE) || forced_push(tp)) | ||
| 654 | tcp_mark_push(tp, skb); | ||
| 655 | |||
| 656 | tcp_mark_urg(tp, flags); | ||
| 657 | |||
| 658 | if (tcp_should_autocork(sk, skb, size_goal)) { | ||
| 630 | 659 | ||
| 631 | tcp_mark_urg(tp, flags); | 660 | /* avoid atomic op if TSQ_THROTTLED bit is already set */ |
| 632 | __tcp_push_pending_frames(sk, mss_now, | 661 | if (!test_bit(TSQ_THROTTLED, &tp->tsq_flags)) { |
| 633 | (flags & MSG_MORE) ? TCP_NAGLE_CORK : nonagle); | 662 | NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPAUTOCORKING); |
| 663 | set_bit(TSQ_THROTTLED, &tp->tsq_flags); | ||
| 664 | } | ||
| 665 | /* It is possible TX completion already happened | ||
| 666 | * before we set TSQ_THROTTLED. | ||
| 667 | */ | ||
| 668 | if (atomic_read(&sk->sk_wmem_alloc) > skb->truesize) | ||
| 669 | return; | ||
| 634 | } | 670 | } |
| 671 | |||
| 672 | if (flags & MSG_MORE) | ||
| 673 | nonagle = TCP_NAGLE_CORK; | ||
| 674 | |||
| 675 | __tcp_push_pending_frames(sk, mss_now, nonagle); | ||
| 635 | } | 676 | } |
| 636 | 677 | ||
| 637 | static int tcp_splice_data_recv(read_descriptor_t *rd_desc, struct sk_buff *skb, | 678 | static int tcp_splice_data_recv(read_descriptor_t *rd_desc, struct sk_buff *skb, |
| @@ -934,7 +975,8 @@ new_segment: | |||
| 934 | wait_for_sndbuf: | 975 | wait_for_sndbuf: |
| 935 | set_bit(SOCK_NOSPACE, &sk->sk_socket->flags); | 976 | set_bit(SOCK_NOSPACE, &sk->sk_socket->flags); |
| 936 | wait_for_memory: | 977 | wait_for_memory: |
| 937 | tcp_push(sk, flags & ~MSG_MORE, mss_now, TCP_NAGLE_PUSH); | 978 | tcp_push(sk, flags & ~MSG_MORE, mss_now, |
| 979 | TCP_NAGLE_PUSH, size_goal); | ||
| 938 | 980 | ||
| 939 | if ((err = sk_stream_wait_memory(sk, &timeo)) != 0) | 981 | if ((err = sk_stream_wait_memory(sk, &timeo)) != 0) |
| 940 | goto do_error; | 982 | goto do_error; |
| @@ -944,7 +986,7 @@ wait_for_memory: | |||
| 944 | 986 | ||
| 945 | out: | 987 | out: |
| 946 | if (copied && !(flags & MSG_SENDPAGE_NOTLAST)) | 988 | if (copied && !(flags & MSG_SENDPAGE_NOTLAST)) |
| 947 | tcp_push(sk, flags, mss_now, tp->nonagle); | 989 | tcp_push(sk, flags, mss_now, tp->nonagle, size_goal); |
| 948 | return copied; | 990 | return copied; |
| 949 | 991 | ||
| 950 | do_error: | 992 | do_error: |
| @@ -1225,7 +1267,8 @@ wait_for_sndbuf: | |||
| 1225 | set_bit(SOCK_NOSPACE, &sk->sk_socket->flags); | 1267 | set_bit(SOCK_NOSPACE, &sk->sk_socket->flags); |
| 1226 | wait_for_memory: | 1268 | wait_for_memory: |
| 1227 | if (copied) | 1269 | if (copied) |
| 1228 | tcp_push(sk, flags & ~MSG_MORE, mss_now, TCP_NAGLE_PUSH); | 1270 | tcp_push(sk, flags & ~MSG_MORE, mss_now, |
| 1271 | TCP_NAGLE_PUSH, size_goal); | ||
| 1229 | 1272 | ||
| 1230 | if ((err = sk_stream_wait_memory(sk, &timeo)) != 0) | 1273 | if ((err = sk_stream_wait_memory(sk, &timeo)) != 0) |
| 1231 | goto do_error; | 1274 | goto do_error; |
| @@ -1236,7 +1279,7 @@ wait_for_memory: | |||
| 1236 | 1279 | ||
| 1237 | out: | 1280 | out: |
| 1238 | if (copied) | 1281 | if (copied) |
| 1239 | tcp_push(sk, flags, mss_now, tp->nonagle); | 1282 | tcp_push(sk, flags, mss_now, tp->nonagle, size_goal); |
| 1240 | release_sock(sk); | 1283 | release_sock(sk); |
| 1241 | return copied + copied_syn; | 1284 | return copied + copied_syn; |
| 1242 | 1285 | ||
| @@ -1623,11 +1666,11 @@ int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
| 1623 | (len > sysctl_tcp_dma_copybreak) && !(flags & MSG_PEEK) && | 1666 | (len > sysctl_tcp_dma_copybreak) && !(flags & MSG_PEEK) && |
| 1624 | !sysctl_tcp_low_latency && | 1667 | !sysctl_tcp_low_latency && |
| 1625 | net_dma_find_channel()) { | 1668 | net_dma_find_channel()) { |
| 1626 | preempt_enable_no_resched(); | 1669 | preempt_enable(); |
| 1627 | tp->ucopy.pinned_list = | 1670 | tp->ucopy.pinned_list = |
| 1628 | dma_pin_iovec_pages(msg->msg_iov, len); | 1671 | dma_pin_iovec_pages(msg->msg_iov, len); |
| 1629 | } else { | 1672 | } else { |
| 1630 | preempt_enable_no_resched(); | 1673 | preempt_enable(); |
| 1631 | } | 1674 | } |
| 1632 | } | 1675 | } |
| 1633 | #endif | 1676 | #endif |
diff --git a/net/ipv4/tcp_illinois.c b/net/ipv4/tcp_illinois.c index 8a520996f3d2..e498a62b8f97 100644 --- a/net/ipv4/tcp_illinois.c +++ b/net/ipv4/tcp_illinois.c | |||
| @@ -23,7 +23,6 @@ | |||
| 23 | #define ALPHA_MIN ((3*ALPHA_SCALE)/10) /* ~0.3 */ | 23 | #define ALPHA_MIN ((3*ALPHA_SCALE)/10) /* ~0.3 */ |
| 24 | #define ALPHA_MAX (10*ALPHA_SCALE) /* 10.0 */ | 24 | #define ALPHA_MAX (10*ALPHA_SCALE) /* 10.0 */ |
| 25 | #define ALPHA_BASE ALPHA_SCALE /* 1.0 */ | 25 | #define ALPHA_BASE ALPHA_SCALE /* 1.0 */ |
| 26 | #define U32_MAX ((u32)~0U) | ||
| 27 | #define RTT_MAX (U32_MAX / ALPHA_MAX) /* 3.3 secs */ | 26 | #define RTT_MAX (U32_MAX / ALPHA_MAX) /* 3.3 secs */ |
| 28 | 27 | ||
| 29 | #define BETA_SHIFT 6 | 28 | #define BETA_SHIFT 6 |
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index c53b7f35c51d..65cf90e063d5 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c | |||
| @@ -766,7 +766,7 @@ static void tcp_update_pacing_rate(struct sock *sk) | |||
| 766 | /* Calculate rto without backoff. This is the second half of Van Jacobson's | 766 | /* Calculate rto without backoff. This is the second half of Van Jacobson's |
| 767 | * routine referred to above. | 767 | * routine referred to above. |
| 768 | */ | 768 | */ |
| 769 | void tcp_set_rto(struct sock *sk) | 769 | static void tcp_set_rto(struct sock *sk) |
| 770 | { | 770 | { |
| 771 | const struct tcp_sock *tp = tcp_sk(sk); | 771 | const struct tcp_sock *tp = tcp_sk(sk); |
| 772 | /* Old crap is replaced with new one. 8) | 772 | /* Old crap is replaced with new one. 8) |
| @@ -3686,7 +3686,7 @@ const u8 *tcp_parse_md5sig_option(const struct tcphdr *th) | |||
| 3686 | int opcode = *ptr++; | 3686 | int opcode = *ptr++; |
| 3687 | int opsize; | 3687 | int opsize; |
| 3688 | 3688 | ||
| 3689 | switch(opcode) { | 3689 | switch (opcode) { |
| 3690 | case TCPOPT_EOL: | 3690 | case TCPOPT_EOL: |
| 3691 | return NULL; | 3691 | return NULL; |
| 3692 | case TCPOPT_NOP: | 3692 | case TCPOPT_NOP: |
| @@ -4046,7 +4046,7 @@ static void tcp_sack_remove(struct tcp_sock *tp) | |||
| 4046 | WARN_ON(before(tp->rcv_nxt, sp->end_seq)); | 4046 | WARN_ON(before(tp->rcv_nxt, sp->end_seq)); |
| 4047 | 4047 | ||
| 4048 | /* Zap this SACK, by moving forward any other SACKS. */ | 4048 | /* Zap this SACK, by moving forward any other SACKS. */ |
| 4049 | for (i=this_sack+1; i < num_sacks; i++) | 4049 | for (i = this_sack+1; i < num_sacks; i++) |
| 4050 | tp->selective_acks[i-1] = tp->selective_acks[i]; | 4050 | tp->selective_acks[i-1] = tp->selective_acks[i]; |
| 4051 | num_sacks--; | 4051 | num_sacks--; |
| 4052 | continue; | 4052 | continue; |
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 067213924751..3cf976510497 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c | |||
| @@ -173,7 +173,7 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) | |||
| 173 | rt = ip_route_connect(fl4, nexthop, inet->inet_saddr, | 173 | rt = ip_route_connect(fl4, nexthop, inet->inet_saddr, |
| 174 | RT_CONN_FLAGS(sk), sk->sk_bound_dev_if, | 174 | RT_CONN_FLAGS(sk), sk->sk_bound_dev_if, |
| 175 | IPPROTO_TCP, | 175 | IPPROTO_TCP, |
| 176 | orig_sport, orig_dport, sk, true); | 176 | orig_sport, orig_dport, sk); |
| 177 | if (IS_ERR(rt)) { | 177 | if (IS_ERR(rt)) { |
| 178 | err = PTR_ERR(rt); | 178 | err = PTR_ERR(rt); |
| 179 | if (err == -ENETUNREACH) | 179 | if (err == -ENETUNREACH) |
| @@ -827,7 +827,7 @@ static int tcp_v4_send_synack(struct sock *sk, struct dst_entry *dst, | |||
| 827 | const struct inet_request_sock *ireq = inet_rsk(req); | 827 | const struct inet_request_sock *ireq = inet_rsk(req); |
| 828 | struct flowi4 fl4; | 828 | struct flowi4 fl4; |
| 829 | int err = -1; | 829 | int err = -1; |
| 830 | struct sk_buff * skb; | 830 | struct sk_buff *skb; |
| 831 | 831 | ||
| 832 | /* First, grab a route. */ | 832 | /* First, grab a route. */ |
| 833 | if (!dst && (dst = inet_csk_route_req(sk, &fl4, req)) == NULL) | 833 | if (!dst && (dst = inet_csk_route_req(sk, &fl4, req)) == NULL) |
| @@ -1668,7 +1668,6 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb, | |||
| 1668 | } | 1668 | } |
| 1669 | sk_setup_caps(newsk, dst); | 1669 | sk_setup_caps(newsk, dst); |
| 1670 | 1670 | ||
| 1671 | tcp_mtup_init(newsk); | ||
| 1672 | tcp_sync_mss(newsk, dst_mtu(dst)); | 1671 | tcp_sync_mss(newsk, dst_mtu(dst)); |
| 1673 | newtp->advmss = dst_metric_advmss(dst); | 1672 | newtp->advmss = dst_metric_advmss(dst); |
| 1674 | if (tcp_sk(sk)->rx_opt.user_mss && | 1673 | if (tcp_sk(sk)->rx_opt.user_mss && |
diff --git a/net/ipv4/tcp_metrics.c b/net/ipv4/tcp_metrics.c index 098b3a29f6f3..d547075d8300 100644 --- a/net/ipv4/tcp_metrics.c +++ b/net/ipv4/tcp_metrics.c | |||
| @@ -22,7 +22,8 @@ | |||
| 22 | 22 | ||
| 23 | int sysctl_tcp_nometrics_save __read_mostly; | 23 | int sysctl_tcp_nometrics_save __read_mostly; |
| 24 | 24 | ||
| 25 | static struct tcp_metrics_block *__tcp_get_metrics(const struct inetpeer_addr *addr, | 25 | static struct tcp_metrics_block *__tcp_get_metrics(const struct inetpeer_addr *saddr, |
| 26 | const struct inetpeer_addr *daddr, | ||
| 26 | struct net *net, unsigned int hash); | 27 | struct net *net, unsigned int hash); |
| 27 | 28 | ||
| 28 | struct tcp_fastopen_metrics { | 29 | struct tcp_fastopen_metrics { |
| @@ -34,7 +35,8 @@ struct tcp_fastopen_metrics { | |||
| 34 | 35 | ||
| 35 | struct tcp_metrics_block { | 36 | struct tcp_metrics_block { |
| 36 | struct tcp_metrics_block __rcu *tcpm_next; | 37 | struct tcp_metrics_block __rcu *tcpm_next; |
| 37 | struct inetpeer_addr tcpm_addr; | 38 | struct inetpeer_addr tcpm_saddr; |
| 39 | struct inetpeer_addr tcpm_daddr; | ||
| 38 | unsigned long tcpm_stamp; | 40 | unsigned long tcpm_stamp; |
| 39 | u32 tcpm_ts; | 41 | u32 tcpm_ts; |
| 40 | u32 tcpm_ts_stamp; | 42 | u32 tcpm_ts_stamp; |
| @@ -145,7 +147,8 @@ static void tcpm_check_stamp(struct tcp_metrics_block *tm, struct dst_entry *dst | |||
| 145 | #define TCP_METRICS_RECLAIM_PTR (struct tcp_metrics_block *) 0x1UL | 147 | #define TCP_METRICS_RECLAIM_PTR (struct tcp_metrics_block *) 0x1UL |
| 146 | 148 | ||
| 147 | static struct tcp_metrics_block *tcpm_new(struct dst_entry *dst, | 149 | static struct tcp_metrics_block *tcpm_new(struct dst_entry *dst, |
| 148 | struct inetpeer_addr *addr, | 150 | struct inetpeer_addr *saddr, |
| 151 | struct inetpeer_addr *daddr, | ||
| 149 | unsigned int hash) | 152 | unsigned int hash) |
| 150 | { | 153 | { |
| 151 | struct tcp_metrics_block *tm; | 154 | struct tcp_metrics_block *tm; |
| @@ -158,7 +161,7 @@ static struct tcp_metrics_block *tcpm_new(struct dst_entry *dst, | |||
| 158 | /* While waiting for the spin-lock the cache might have been populated | 161 | /* While waiting for the spin-lock the cache might have been populated |
| 159 | * with this entry and so we have to check again. | 162 | * with this entry and so we have to check again. |
| 160 | */ | 163 | */ |
| 161 | tm = __tcp_get_metrics(addr, net, hash); | 164 | tm = __tcp_get_metrics(saddr, daddr, net, hash); |
| 162 | if (tm == TCP_METRICS_RECLAIM_PTR) { | 165 | if (tm == TCP_METRICS_RECLAIM_PTR) { |
| 163 | reclaim = true; | 166 | reclaim = true; |
| 164 | tm = NULL; | 167 | tm = NULL; |
| @@ -183,7 +186,8 @@ static struct tcp_metrics_block *tcpm_new(struct dst_entry *dst, | |||
| 183 | if (!tm) | 186 | if (!tm) |
| 184 | goto out_unlock; | 187 | goto out_unlock; |
| 185 | } | 188 | } |
| 186 | tm->tcpm_addr = *addr; | 189 | tm->tcpm_saddr = *saddr; |
| 190 | tm->tcpm_daddr = *daddr; | ||
| 187 | 191 | ||
| 188 | tcpm_suck_dst(tm, dst, true); | 192 | tcpm_suck_dst(tm, dst, true); |
| 189 | 193 | ||
| @@ -206,7 +210,8 @@ static struct tcp_metrics_block *tcp_get_encode(struct tcp_metrics_block *tm, in | |||
| 206 | return NULL; | 210 | return NULL; |
| 207 | } | 211 | } |
| 208 | 212 | ||
| 209 | static struct tcp_metrics_block *__tcp_get_metrics(const struct inetpeer_addr *addr, | 213 | static struct tcp_metrics_block *__tcp_get_metrics(const struct inetpeer_addr *saddr, |
| 214 | const struct inetpeer_addr *daddr, | ||
| 210 | struct net *net, unsigned int hash) | 215 | struct net *net, unsigned int hash) |
| 211 | { | 216 | { |
| 212 | struct tcp_metrics_block *tm; | 217 | struct tcp_metrics_block *tm; |
| @@ -214,7 +219,8 @@ static struct tcp_metrics_block *__tcp_get_metrics(const struct inetpeer_addr *a | |||
| 214 | 219 | ||
| 215 | for (tm = rcu_dereference(net->ipv4.tcp_metrics_hash[hash].chain); tm; | 220 | for (tm = rcu_dereference(net->ipv4.tcp_metrics_hash[hash].chain); tm; |
| 216 | tm = rcu_dereference(tm->tcpm_next)) { | 221 | tm = rcu_dereference(tm->tcpm_next)) { |
| 217 | if (addr_same(&tm->tcpm_addr, addr)) | 222 | if (addr_same(&tm->tcpm_saddr, saddr) && |
| 223 | addr_same(&tm->tcpm_daddr, daddr)) | ||
| 218 | break; | 224 | break; |
| 219 | depth++; | 225 | depth++; |
| 220 | } | 226 | } |
| @@ -225,19 +231,22 @@ static struct tcp_metrics_block *__tcp_get_metrics_req(struct request_sock *req, | |||
| 225 | struct dst_entry *dst) | 231 | struct dst_entry *dst) |
| 226 | { | 232 | { |
| 227 | struct tcp_metrics_block *tm; | 233 | struct tcp_metrics_block *tm; |
| 228 | struct inetpeer_addr addr; | 234 | struct inetpeer_addr saddr, daddr; |
| 229 | unsigned int hash; | 235 | unsigned int hash; |
| 230 | struct net *net; | 236 | struct net *net; |
| 231 | 237 | ||
| 232 | addr.family = req->rsk_ops->family; | 238 | saddr.family = req->rsk_ops->family; |
| 233 | switch (addr.family) { | 239 | daddr.family = req->rsk_ops->family; |
| 240 | switch (daddr.family) { | ||
| 234 | case AF_INET: | 241 | case AF_INET: |
| 235 | addr.addr.a4 = inet_rsk(req)->ir_rmt_addr; | 242 | saddr.addr.a4 = inet_rsk(req)->ir_loc_addr; |
| 236 | hash = (__force unsigned int) addr.addr.a4; | 243 | daddr.addr.a4 = inet_rsk(req)->ir_rmt_addr; |
| 244 | hash = (__force unsigned int) daddr.addr.a4; | ||
| 237 | break; | 245 | break; |
| 238 | #if IS_ENABLED(CONFIG_IPV6) | 246 | #if IS_ENABLED(CONFIG_IPV6) |
| 239 | case AF_INET6: | 247 | case AF_INET6: |
| 240 | *(struct in6_addr *)addr.addr.a6 = inet_rsk(req)->ir_v6_rmt_addr; | 248 | *(struct in6_addr *)saddr.addr.a6 = inet_rsk(req)->ir_v6_loc_addr; |
| 249 | *(struct in6_addr *)daddr.addr.a6 = inet_rsk(req)->ir_v6_rmt_addr; | ||
| 241 | hash = ipv6_addr_hash(&inet_rsk(req)->ir_v6_rmt_addr); | 250 | hash = ipv6_addr_hash(&inet_rsk(req)->ir_v6_rmt_addr); |
| 242 | break; | 251 | break; |
| 243 | #endif | 252 | #endif |
| @@ -250,7 +259,8 @@ static struct tcp_metrics_block *__tcp_get_metrics_req(struct request_sock *req, | |||
| 250 | 259 | ||
| 251 | for (tm = rcu_dereference(net->ipv4.tcp_metrics_hash[hash].chain); tm; | 260 | for (tm = rcu_dereference(net->ipv4.tcp_metrics_hash[hash].chain); tm; |
| 252 | tm = rcu_dereference(tm->tcpm_next)) { | 261 | tm = rcu_dereference(tm->tcpm_next)) { |
| 253 | if (addr_same(&tm->tcpm_addr, &addr)) | 262 | if (addr_same(&tm->tcpm_saddr, &saddr) && |
| 263 | addr_same(&tm->tcpm_daddr, &daddr)) | ||
| 254 | break; | 264 | break; |
| 255 | } | 265 | } |
| 256 | tcpm_check_stamp(tm, dst); | 266 | tcpm_check_stamp(tm, dst); |
| @@ -260,32 +270,44 @@ static struct tcp_metrics_block *__tcp_get_metrics_req(struct request_sock *req, | |||
| 260 | static struct tcp_metrics_block *__tcp_get_metrics_tw(struct inet_timewait_sock *tw) | 270 | static struct tcp_metrics_block *__tcp_get_metrics_tw(struct inet_timewait_sock *tw) |
| 261 | { | 271 | { |
| 262 | struct tcp_metrics_block *tm; | 272 | struct tcp_metrics_block *tm; |
| 263 | struct inetpeer_addr addr; | 273 | struct inetpeer_addr saddr, daddr; |
| 264 | unsigned int hash; | 274 | unsigned int hash; |
| 265 | struct net *net; | 275 | struct net *net; |
| 266 | 276 | ||
| 267 | addr.family = tw->tw_family; | 277 | if (tw->tw_family == AF_INET) { |
| 268 | switch (addr.family) { | 278 | saddr.family = AF_INET; |
| 269 | case AF_INET: | 279 | saddr.addr.a4 = tw->tw_rcv_saddr; |
| 270 | addr.addr.a4 = tw->tw_daddr; | 280 | daddr.family = AF_INET; |
| 271 | hash = (__force unsigned int) addr.addr.a4; | 281 | daddr.addr.a4 = tw->tw_daddr; |
| 272 | break; | 282 | hash = (__force unsigned int) daddr.addr.a4; |
| 283 | } | ||
| 273 | #if IS_ENABLED(CONFIG_IPV6) | 284 | #if IS_ENABLED(CONFIG_IPV6) |
| 274 | case AF_INET6: | 285 | else if (tw->tw_family == AF_INET6) { |
| 275 | *(struct in6_addr *)addr.addr.a6 = tw->tw_v6_daddr; | 286 | if (ipv6_addr_v4mapped(&tw->tw_v6_daddr)) { |
| 276 | hash = ipv6_addr_hash(&tw->tw_v6_daddr); | 287 | saddr.family = AF_INET; |
| 277 | break; | 288 | saddr.addr.a4 = tw->tw_rcv_saddr; |
| 289 | daddr.family = AF_INET; | ||
| 290 | daddr.addr.a4 = tw->tw_daddr; | ||
| 291 | hash = (__force unsigned int) daddr.addr.a4; | ||
| 292 | } else { | ||
| 293 | saddr.family = AF_INET6; | ||
| 294 | *(struct in6_addr *)saddr.addr.a6 = tw->tw_v6_rcv_saddr; | ||
| 295 | daddr.family = AF_INET6; | ||
| 296 | *(struct in6_addr *)daddr.addr.a6 = tw->tw_v6_daddr; | ||
| 297 | hash = ipv6_addr_hash(&tw->tw_v6_daddr); | ||
| 298 | } | ||
| 299 | } | ||
| 278 | #endif | 300 | #endif |
| 279 | default: | 301 | else |
| 280 | return NULL; | 302 | return NULL; |
| 281 | } | ||
| 282 | 303 | ||
| 283 | net = twsk_net(tw); | 304 | net = twsk_net(tw); |
| 284 | hash = hash_32(hash, net->ipv4.tcp_metrics_hash_log); | 305 | hash = hash_32(hash, net->ipv4.tcp_metrics_hash_log); |
| 285 | 306 | ||
| 286 | for (tm = rcu_dereference(net->ipv4.tcp_metrics_hash[hash].chain); tm; | 307 | for (tm = rcu_dereference(net->ipv4.tcp_metrics_hash[hash].chain); tm; |
| 287 | tm = rcu_dereference(tm->tcpm_next)) { | 308 | tm = rcu_dereference(tm->tcpm_next)) { |
| 288 | if (addr_same(&tm->tcpm_addr, &addr)) | 309 | if (addr_same(&tm->tcpm_saddr, &saddr) && |
| 310 | addr_same(&tm->tcpm_daddr, &daddr)) | ||
| 289 | break; | 311 | break; |
| 290 | } | 312 | } |
| 291 | return tm; | 313 | return tm; |
| @@ -296,34 +318,45 @@ static struct tcp_metrics_block *tcp_get_metrics(struct sock *sk, | |||
| 296 | bool create) | 318 | bool create) |
| 297 | { | 319 | { |
| 298 | struct tcp_metrics_block *tm; | 320 | struct tcp_metrics_block *tm; |
| 299 | struct inetpeer_addr addr; | 321 | struct inetpeer_addr saddr, daddr; |
| 300 | unsigned int hash; | 322 | unsigned int hash; |
| 301 | struct net *net; | 323 | struct net *net; |
| 302 | 324 | ||
| 303 | addr.family = sk->sk_family; | 325 | if (sk->sk_family == AF_INET) { |
| 304 | switch (addr.family) { | 326 | saddr.family = AF_INET; |
| 305 | case AF_INET: | 327 | saddr.addr.a4 = inet_sk(sk)->inet_saddr; |
| 306 | addr.addr.a4 = inet_sk(sk)->inet_daddr; | 328 | daddr.family = AF_INET; |
| 307 | hash = (__force unsigned int) addr.addr.a4; | 329 | daddr.addr.a4 = inet_sk(sk)->inet_daddr; |
| 308 | break; | 330 | hash = (__force unsigned int) daddr.addr.a4; |
| 331 | } | ||
| 309 | #if IS_ENABLED(CONFIG_IPV6) | 332 | #if IS_ENABLED(CONFIG_IPV6) |
| 310 | case AF_INET6: | 333 | else if (sk->sk_family == AF_INET6) { |
| 311 | *(struct in6_addr *)addr.addr.a6 = sk->sk_v6_daddr; | 334 | if (ipv6_addr_v4mapped(&sk->sk_v6_daddr)) { |
| 312 | hash = ipv6_addr_hash(&sk->sk_v6_daddr); | 335 | saddr.family = AF_INET; |
| 313 | break; | 336 | saddr.addr.a4 = inet_sk(sk)->inet_saddr; |
| 337 | daddr.family = AF_INET; | ||
| 338 | daddr.addr.a4 = inet_sk(sk)->inet_daddr; | ||
| 339 | hash = (__force unsigned int) daddr.addr.a4; | ||
| 340 | } else { | ||
| 341 | saddr.family = AF_INET6; | ||
| 342 | *(struct in6_addr *)saddr.addr.a6 = sk->sk_v6_rcv_saddr; | ||
| 343 | daddr.family = AF_INET6; | ||
| 344 | *(struct in6_addr *)daddr.addr.a6 = sk->sk_v6_daddr; | ||
| 345 | hash = ipv6_addr_hash(&sk->sk_v6_daddr); | ||
| 346 | } | ||
| 347 | } | ||
| 314 | #endif | 348 | #endif |
| 315 | default: | 349 | else |
| 316 | return NULL; | 350 | return NULL; |
| 317 | } | ||
| 318 | 351 | ||
| 319 | net = dev_net(dst->dev); | 352 | net = dev_net(dst->dev); |
| 320 | hash = hash_32(hash, net->ipv4.tcp_metrics_hash_log); | 353 | hash = hash_32(hash, net->ipv4.tcp_metrics_hash_log); |
| 321 | 354 | ||
| 322 | tm = __tcp_get_metrics(&addr, net, hash); | 355 | tm = __tcp_get_metrics(&saddr, &daddr, net, hash); |
| 323 | if (tm == TCP_METRICS_RECLAIM_PTR) | 356 | if (tm == TCP_METRICS_RECLAIM_PTR) |
| 324 | tm = NULL; | 357 | tm = NULL; |
| 325 | if (!tm && create) | 358 | if (!tm && create) |
| 326 | tm = tcpm_new(dst, &addr, hash); | 359 | tm = tcpm_new(dst, &saddr, &daddr, hash); |
| 327 | else | 360 | else |
| 328 | tcpm_check_stamp(tm, dst); | 361 | tcpm_check_stamp(tm, dst); |
| 329 | 362 | ||
| @@ -737,15 +770,21 @@ static int tcp_metrics_fill_info(struct sk_buff *msg, | |||
| 737 | struct nlattr *nest; | 770 | struct nlattr *nest; |
| 738 | int i; | 771 | int i; |
| 739 | 772 | ||
| 740 | switch (tm->tcpm_addr.family) { | 773 | switch (tm->tcpm_daddr.family) { |
| 741 | case AF_INET: | 774 | case AF_INET: |
| 742 | if (nla_put_be32(msg, TCP_METRICS_ATTR_ADDR_IPV4, | 775 | if (nla_put_be32(msg, TCP_METRICS_ATTR_ADDR_IPV4, |
| 743 | tm->tcpm_addr.addr.a4) < 0) | 776 | tm->tcpm_daddr.addr.a4) < 0) |
| 777 | goto nla_put_failure; | ||
| 778 | if (nla_put_be32(msg, TCP_METRICS_ATTR_SADDR_IPV4, | ||
| 779 | tm->tcpm_saddr.addr.a4) < 0) | ||
| 744 | goto nla_put_failure; | 780 | goto nla_put_failure; |
| 745 | break; | 781 | break; |
| 746 | case AF_INET6: | 782 | case AF_INET6: |
| 747 | if (nla_put(msg, TCP_METRICS_ATTR_ADDR_IPV6, 16, | 783 | if (nla_put(msg, TCP_METRICS_ATTR_ADDR_IPV6, 16, |
| 748 | tm->tcpm_addr.addr.a6) < 0) | 784 | tm->tcpm_daddr.addr.a6) < 0) |
| 785 | goto nla_put_failure; | ||
| 786 | if (nla_put(msg, TCP_METRICS_ATTR_SADDR_IPV6, 16, | ||
| 787 | tm->tcpm_saddr.addr.a6) < 0) | ||
| 749 | goto nla_put_failure; | 788 | goto nla_put_failure; |
| 750 | break; | 789 | break; |
| 751 | default: | 790 | default: |
| @@ -868,44 +907,66 @@ done: | |||
| 868 | return skb->len; | 907 | return skb->len; |
| 869 | } | 908 | } |
| 870 | 909 | ||
| 871 | static int parse_nl_addr(struct genl_info *info, struct inetpeer_addr *addr, | 910 | static int __parse_nl_addr(struct genl_info *info, struct inetpeer_addr *addr, |
| 872 | unsigned int *hash, int optional) | 911 | unsigned int *hash, int optional, int v4, int v6) |
| 873 | { | 912 | { |
| 874 | struct nlattr *a; | 913 | struct nlattr *a; |
| 875 | 914 | ||
| 876 | a = info->attrs[TCP_METRICS_ATTR_ADDR_IPV4]; | 915 | a = info->attrs[v4]; |
| 877 | if (a) { | 916 | if (a) { |
| 878 | addr->family = AF_INET; | 917 | addr->family = AF_INET; |
| 879 | addr->addr.a4 = nla_get_be32(a); | 918 | addr->addr.a4 = nla_get_be32(a); |
| 880 | *hash = (__force unsigned int) addr->addr.a4; | 919 | if (hash) |
| 920 | *hash = (__force unsigned int) addr->addr.a4; | ||
| 881 | return 0; | 921 | return 0; |
| 882 | } | 922 | } |
| 883 | a = info->attrs[TCP_METRICS_ATTR_ADDR_IPV6]; | 923 | a = info->attrs[v6]; |
| 884 | if (a) { | 924 | if (a) { |
| 885 | if (nla_len(a) != sizeof(struct in6_addr)) | 925 | if (nla_len(a) != sizeof(struct in6_addr)) |
| 886 | return -EINVAL; | 926 | return -EINVAL; |
| 887 | addr->family = AF_INET6; | 927 | addr->family = AF_INET6; |
| 888 | memcpy(addr->addr.a6, nla_data(a), sizeof(addr->addr.a6)); | 928 | memcpy(addr->addr.a6, nla_data(a), sizeof(addr->addr.a6)); |
| 889 | *hash = ipv6_addr_hash((struct in6_addr *) addr->addr.a6); | 929 | if (hash) |
| 930 | *hash = ipv6_addr_hash((struct in6_addr *) addr->addr.a6); | ||
| 890 | return 0; | 931 | return 0; |
| 891 | } | 932 | } |
| 892 | return optional ? 1 : -EAFNOSUPPORT; | 933 | return optional ? 1 : -EAFNOSUPPORT; |
| 893 | } | 934 | } |
| 894 | 935 | ||
| 936 | static int parse_nl_addr(struct genl_info *info, struct inetpeer_addr *addr, | ||
| 937 | unsigned int *hash, int optional) | ||
| 938 | { | ||
| 939 | return __parse_nl_addr(info, addr, hash, optional, | ||
| 940 | TCP_METRICS_ATTR_ADDR_IPV4, | ||
| 941 | TCP_METRICS_ATTR_ADDR_IPV6); | ||
| 942 | } | ||
| 943 | |||
| 944 | static int parse_nl_saddr(struct genl_info *info, struct inetpeer_addr *addr) | ||
| 945 | { | ||
| 946 | return __parse_nl_addr(info, addr, NULL, 0, | ||
| 947 | TCP_METRICS_ATTR_SADDR_IPV4, | ||
| 948 | TCP_METRICS_ATTR_SADDR_IPV6); | ||
| 949 | } | ||
| 950 | |||
| 895 | static int tcp_metrics_nl_cmd_get(struct sk_buff *skb, struct genl_info *info) | 951 | static int tcp_metrics_nl_cmd_get(struct sk_buff *skb, struct genl_info *info) |
| 896 | { | 952 | { |
| 897 | struct tcp_metrics_block *tm; | 953 | struct tcp_metrics_block *tm; |
| 898 | struct inetpeer_addr addr; | 954 | struct inetpeer_addr saddr, daddr; |
| 899 | unsigned int hash; | 955 | unsigned int hash; |
| 900 | struct sk_buff *msg; | 956 | struct sk_buff *msg; |
| 901 | struct net *net = genl_info_net(info); | 957 | struct net *net = genl_info_net(info); |
| 902 | void *reply; | 958 | void *reply; |
| 903 | int ret; | 959 | int ret; |
| 960 | bool src = true; | ||
| 904 | 961 | ||
| 905 | ret = parse_nl_addr(info, &addr, &hash, 0); | 962 | ret = parse_nl_addr(info, &daddr, &hash, 0); |
| 906 | if (ret < 0) | 963 | if (ret < 0) |
| 907 | return ret; | 964 | return ret; |
| 908 | 965 | ||
| 966 | ret = parse_nl_saddr(info, &saddr); | ||
| 967 | if (ret < 0) | ||
| 968 | src = false; | ||
| 969 | |||
| 909 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 970 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
| 910 | if (!msg) | 971 | if (!msg) |
| 911 | return -ENOMEM; | 972 | return -ENOMEM; |
| @@ -920,7 +981,8 @@ static int tcp_metrics_nl_cmd_get(struct sk_buff *skb, struct genl_info *info) | |||
| 920 | rcu_read_lock(); | 981 | rcu_read_lock(); |
| 921 | for (tm = rcu_dereference(net->ipv4.tcp_metrics_hash[hash].chain); tm; | 982 | for (tm = rcu_dereference(net->ipv4.tcp_metrics_hash[hash].chain); tm; |
| 922 | tm = rcu_dereference(tm->tcpm_next)) { | 983 | tm = rcu_dereference(tm->tcpm_next)) { |
| 923 | if (addr_same(&tm->tcpm_addr, &addr)) { | 984 | if (addr_same(&tm->tcpm_daddr, &daddr) && |
| 985 | (!src || addr_same(&tm->tcpm_saddr, &saddr))) { | ||
| 924 | ret = tcp_metrics_fill_info(msg, tm); | 986 | ret = tcp_metrics_fill_info(msg, tm); |
| 925 | break; | 987 | break; |
| 926 | } | 988 | } |
| @@ -975,32 +1037,38 @@ static int tcp_metrics_nl_cmd_del(struct sk_buff *skb, struct genl_info *info) | |||
| 975 | struct tcpm_hash_bucket *hb; | 1037 | struct tcpm_hash_bucket *hb; |
| 976 | struct tcp_metrics_block *tm; | 1038 | struct tcp_metrics_block *tm; |
| 977 | struct tcp_metrics_block __rcu **pp; | 1039 | struct tcp_metrics_block __rcu **pp; |
| 978 | struct inetpeer_addr addr; | 1040 | struct inetpeer_addr saddr, daddr; |
| 979 | unsigned int hash; | 1041 | unsigned int hash; |
| 980 | struct net *net = genl_info_net(info); | 1042 | struct net *net = genl_info_net(info); |
| 981 | int ret; | 1043 | int ret; |
| 1044 | bool src = true, found = false; | ||
| 982 | 1045 | ||
| 983 | ret = parse_nl_addr(info, &addr, &hash, 1); | 1046 | ret = parse_nl_addr(info, &daddr, &hash, 1); |
| 984 | if (ret < 0) | 1047 | if (ret < 0) |
| 985 | return ret; | 1048 | return ret; |
| 986 | if (ret > 0) | 1049 | if (ret > 0) |
| 987 | return tcp_metrics_flush_all(net); | 1050 | return tcp_metrics_flush_all(net); |
| 1051 | ret = parse_nl_saddr(info, &saddr); | ||
| 1052 | if (ret < 0) | ||
| 1053 | src = false; | ||
| 988 | 1054 | ||
| 989 | hash = hash_32(hash, net->ipv4.tcp_metrics_hash_log); | 1055 | hash = hash_32(hash, net->ipv4.tcp_metrics_hash_log); |
| 990 | hb = net->ipv4.tcp_metrics_hash + hash; | 1056 | hb = net->ipv4.tcp_metrics_hash + hash; |
| 991 | pp = &hb->chain; | 1057 | pp = &hb->chain; |
| 992 | spin_lock_bh(&tcp_metrics_lock); | 1058 | spin_lock_bh(&tcp_metrics_lock); |
| 993 | for (tm = deref_locked_genl(*pp); tm; | 1059 | for (tm = deref_locked_genl(*pp); tm; tm = deref_locked_genl(*pp)) { |
| 994 | pp = &tm->tcpm_next, tm = deref_locked_genl(*pp)) { | 1060 | if (addr_same(&tm->tcpm_daddr, &daddr) && |
| 995 | if (addr_same(&tm->tcpm_addr, &addr)) { | 1061 | (!src || addr_same(&tm->tcpm_saddr, &saddr))) { |
| 996 | *pp = tm->tcpm_next; | 1062 | *pp = tm->tcpm_next; |
| 997 | break; | 1063 | kfree_rcu(tm, rcu_head); |
| 1064 | found = true; | ||
| 1065 | } else { | ||
| 1066 | pp = &tm->tcpm_next; | ||
| 998 | } | 1067 | } |
| 999 | } | 1068 | } |
| 1000 | spin_unlock_bh(&tcp_metrics_lock); | 1069 | spin_unlock_bh(&tcp_metrics_lock); |
| 1001 | if (!tm) | 1070 | if (!found) |
| 1002 | return -ESRCH; | 1071 | return -ESRCH; |
| 1003 | kfree_rcu(tm, rcu_head); | ||
| 1004 | return 0; | 1072 | return 0; |
| 1005 | } | 1073 | } |
| 1006 | 1074 | ||
diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c index 97b684159861..7a436c517e44 100644 --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c | |||
| @@ -297,6 +297,7 @@ void tcp_time_wait(struct sock *sk, int state, int timeo) | |||
| 297 | tw->tw_v6_daddr = sk->sk_v6_daddr; | 297 | tw->tw_v6_daddr = sk->sk_v6_daddr; |
| 298 | tw->tw_v6_rcv_saddr = sk->sk_v6_rcv_saddr; | 298 | tw->tw_v6_rcv_saddr = sk->sk_v6_rcv_saddr; |
| 299 | tw->tw_tclass = np->tclass; | 299 | tw->tw_tclass = np->tclass; |
| 300 | tw->tw_flowlabel = np->flow_label >> 12; | ||
| 300 | tw->tw_ipv6only = np->ipv6only; | 301 | tw->tw_ipv6only = np->ipv6only; |
| 301 | } | 302 | } |
| 302 | #endif | 303 | #endif |
| @@ -425,7 +426,7 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req, | |||
| 425 | 426 | ||
| 426 | tcp_set_ca_state(newsk, TCP_CA_Open); | 427 | tcp_set_ca_state(newsk, TCP_CA_Open); |
| 427 | tcp_init_xmit_timers(newsk); | 428 | tcp_init_xmit_timers(newsk); |
| 428 | skb_queue_head_init(&newtp->out_of_order_queue); | 429 | __skb_queue_head_init(&newtp->out_of_order_queue); |
| 429 | newtp->write_seq = newtp->pushed_seq = treq->snt_isn + 1; | 430 | newtp->write_seq = newtp->pushed_seq = treq->snt_isn + 1; |
| 430 | 431 | ||
| 431 | newtp->rx_opt.saw_tstamp = 0; | 432 | newtp->rx_opt.saw_tstamp = 0; |
diff --git a/net/ipv4/tcp_offload.c b/net/ipv4/tcp_offload.c index 05606353c7e7..b92b81718ca4 100644 --- a/net/ipv4/tcp_offload.c +++ b/net/ipv4/tcp_offload.c | |||
| @@ -138,7 +138,6 @@ struct sk_buff *tcp_gso_segment(struct sk_buff *skb, | |||
| 138 | out: | 138 | out: |
| 139 | return segs; | 139 | return segs; |
| 140 | } | 140 | } |
| 141 | EXPORT_SYMBOL(tcp_gso_segment); | ||
| 142 | 141 | ||
| 143 | struct sk_buff **tcp_gro_receive(struct sk_buff **head, struct sk_buff *skb) | 142 | struct sk_buff **tcp_gro_receive(struct sk_buff **head, struct sk_buff *skb) |
| 144 | { | 143 | { |
| @@ -197,7 +196,8 @@ struct sk_buff **tcp_gro_receive(struct sk_buff **head, struct sk_buff *skb) | |||
| 197 | goto out_check_final; | 196 | goto out_check_final; |
| 198 | 197 | ||
| 199 | found: | 198 | found: |
| 200 | flush = NAPI_GRO_CB(p)->flush; | 199 | /* Include the IP ID check below from the inner most IP hdr */ |
| 200 | flush = NAPI_GRO_CB(p)->flush | NAPI_GRO_CB(p)->flush_id; | ||
| 201 | flush |= (__force int)(flags & TCP_FLAG_CWR); | 201 | flush |= (__force int)(flags & TCP_FLAG_CWR); |
| 202 | flush |= (__force int)((flags ^ tcp_flag_word(th2)) & | 202 | flush |= (__force int)((flags ^ tcp_flag_word(th2)) & |
| 203 | ~(TCP_FLAG_CWR | TCP_FLAG_FIN | TCP_FLAG_PSH)); | 203 | ~(TCP_FLAG_CWR | TCP_FLAG_FIN | TCP_FLAG_PSH)); |
| @@ -230,17 +230,16 @@ out_check_final: | |||
| 230 | pp = head; | 230 | pp = head; |
| 231 | 231 | ||
| 232 | out: | 232 | out: |
| 233 | NAPI_GRO_CB(skb)->flush |= flush; | 233 | NAPI_GRO_CB(skb)->flush |= (flush != 0); |
| 234 | 234 | ||
| 235 | return pp; | 235 | return pp; |
| 236 | } | 236 | } |
| 237 | EXPORT_SYMBOL(tcp_gro_receive); | ||
| 238 | 237 | ||
| 239 | int tcp_gro_complete(struct sk_buff *skb) | 238 | int tcp_gro_complete(struct sk_buff *skb) |
| 240 | { | 239 | { |
| 241 | struct tcphdr *th = tcp_hdr(skb); | 240 | struct tcphdr *th = tcp_hdr(skb); |
| 242 | 241 | ||
| 243 | skb->csum_start = skb_transport_header(skb) - skb->head; | 242 | skb->csum_start = (unsigned char *)th - skb->head; |
| 244 | skb->csum_offset = offsetof(struct tcphdr, check); | 243 | skb->csum_offset = offsetof(struct tcphdr, check); |
| 245 | skb->ip_summed = CHECKSUM_PARTIAL; | 244 | skb->ip_summed = CHECKSUM_PARTIAL; |
| 246 | 245 | ||
| @@ -272,6 +271,7 @@ static int tcp_v4_gso_send_check(struct sk_buff *skb) | |||
| 272 | 271 | ||
| 273 | static struct sk_buff **tcp4_gro_receive(struct sk_buff **head, struct sk_buff *skb) | 272 | static struct sk_buff **tcp4_gro_receive(struct sk_buff **head, struct sk_buff *skb) |
| 274 | { | 273 | { |
| 274 | /* Use the IP hdr immediately proceeding for this transport */ | ||
| 275 | const struct iphdr *iph = skb_gro_network_header(skb); | 275 | const struct iphdr *iph = skb_gro_network_header(skb); |
| 276 | __wsum wsum; | 276 | __wsum wsum; |
| 277 | 277 | ||
| @@ -279,7 +279,7 @@ static struct sk_buff **tcp4_gro_receive(struct sk_buff **head, struct sk_buff * | |||
| 279 | if (NAPI_GRO_CB(skb)->flush) | 279 | if (NAPI_GRO_CB(skb)->flush) |
| 280 | goto skip_csum; | 280 | goto skip_csum; |
| 281 | 281 | ||
| 282 | wsum = skb->csum; | 282 | wsum = NAPI_GRO_CB(skb)->csum; |
| 283 | 283 | ||
| 284 | switch (skb->ip_summed) { | 284 | switch (skb->ip_summed) { |
| 285 | case CHECKSUM_NONE: | 285 | case CHECKSUM_NONE: |
| @@ -303,13 +303,13 @@ skip_csum: | |||
| 303 | return tcp_gro_receive(head, skb); | 303 | return tcp_gro_receive(head, skb); |
| 304 | } | 304 | } |
| 305 | 305 | ||
| 306 | static int tcp4_gro_complete(struct sk_buff *skb) | 306 | static int tcp4_gro_complete(struct sk_buff *skb, int thoff) |
| 307 | { | 307 | { |
| 308 | const struct iphdr *iph = ip_hdr(skb); | 308 | const struct iphdr *iph = ip_hdr(skb); |
| 309 | struct tcphdr *th = tcp_hdr(skb); | 309 | struct tcphdr *th = tcp_hdr(skb); |
| 310 | 310 | ||
| 311 | th->check = ~tcp_v4_check(skb->len - skb_transport_offset(skb), | 311 | th->check = ~tcp_v4_check(skb->len - thoff, iph->saddr, |
| 312 | iph->saddr, iph->daddr, 0); | 312 | iph->daddr, 0); |
| 313 | skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4; | 313 | skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4; |
| 314 | 314 | ||
| 315 | return tcp_gro_complete(skb); | 315 | return tcp_gro_complete(skb); |
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 7820f3a7dd70..03d26b85eab8 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c | |||
| @@ -363,15 +363,17 @@ static inline void TCP_ECN_send(struct sock *sk, struct sk_buff *skb, | |||
| 363 | */ | 363 | */ |
| 364 | static void tcp_init_nondata_skb(struct sk_buff *skb, u32 seq, u8 flags) | 364 | static void tcp_init_nondata_skb(struct sk_buff *skb, u32 seq, u8 flags) |
| 365 | { | 365 | { |
| 366 | struct skb_shared_info *shinfo = skb_shinfo(skb); | ||
| 367 | |||
| 366 | skb->ip_summed = CHECKSUM_PARTIAL; | 368 | skb->ip_summed = CHECKSUM_PARTIAL; |
| 367 | skb->csum = 0; | 369 | skb->csum = 0; |
| 368 | 370 | ||
| 369 | TCP_SKB_CB(skb)->tcp_flags = flags; | 371 | TCP_SKB_CB(skb)->tcp_flags = flags; |
| 370 | TCP_SKB_CB(skb)->sacked = 0; | 372 | TCP_SKB_CB(skb)->sacked = 0; |
| 371 | 373 | ||
| 372 | skb_shinfo(skb)->gso_segs = 1; | 374 | shinfo->gso_segs = 1; |
| 373 | skb_shinfo(skb)->gso_size = 0; | 375 | shinfo->gso_size = 0; |
| 374 | skb_shinfo(skb)->gso_type = 0; | 376 | shinfo->gso_type = 0; |
| 375 | 377 | ||
| 376 | TCP_SKB_CB(skb)->seq = seq; | 378 | TCP_SKB_CB(skb)->seq = seq; |
| 377 | if (flags & (TCPHDR_SYN | TCPHDR_FIN)) | 379 | if (flags & (TCPHDR_SYN | TCPHDR_FIN)) |
| @@ -406,7 +408,7 @@ struct tcp_out_options { | |||
| 406 | * Beware: Something in the Internet is very sensitive to the ordering of | 408 | * Beware: Something in the Internet is very sensitive to the ordering of |
| 407 | * TCP options, we learned this through the hard way, so be careful here. | 409 | * TCP options, we learned this through the hard way, so be careful here. |
| 408 | * Luckily we can at least blame others for their non-compliance but from | 410 | * Luckily we can at least blame others for their non-compliance but from |
| 409 | * inter-operatibility perspective it seems that we're somewhat stuck with | 411 | * inter-operability perspective it seems that we're somewhat stuck with |
| 410 | * the ordering which we have been using if we want to keep working with | 412 | * the ordering which we have been using if we want to keep working with |
| 411 | * those broken things (not that it currently hurts anybody as there isn't | 413 | * those broken things (not that it currently hurts anybody as there isn't |
| 412 | * particular reason why the ordering would need to be changed). | 414 | * particular reason why the ordering would need to be changed). |
| @@ -679,7 +681,7 @@ static unsigned int tcp_established_options(struct sock *sk, struct sk_buff *skb | |||
| 679 | * | 681 | * |
| 680 | * Its important tcp_wfree() can be replaced by sock_wfree() in the event skb | 682 | * Its important tcp_wfree() can be replaced by sock_wfree() in the event skb |
| 681 | * needs to be reallocated in a driver. | 683 | * needs to be reallocated in a driver. |
| 682 | * The invariant being skb->truesize substracted from sk->sk_wmem_alloc | 684 | * The invariant being skb->truesize subtracted from sk->sk_wmem_alloc |
| 683 | * | 685 | * |
| 684 | * Since transmit from skb destructor is forbidden, we use a tasklet | 686 | * Since transmit from skb destructor is forbidden, we use a tasklet |
| 685 | * to process all sockets that eventually need to send more skbs. | 687 | * to process all sockets that eventually need to send more skbs. |
| @@ -699,9 +701,9 @@ static void tcp_tsq_handler(struct sock *sk) | |||
| 699 | tcp_write_xmit(sk, tcp_current_mss(sk), 0, 0, GFP_ATOMIC); | 701 | tcp_write_xmit(sk, tcp_current_mss(sk), 0, 0, GFP_ATOMIC); |
| 700 | } | 702 | } |
| 701 | /* | 703 | /* |
| 702 | * One tasklest per cpu tries to send more skbs. | 704 | * One tasklet per cpu tries to send more skbs. |
| 703 | * We run in tasklet context but need to disable irqs when | 705 | * We run in tasklet context but need to disable irqs when |
| 704 | * transfering tsq->head because tcp_wfree() might | 706 | * transferring tsq->head because tcp_wfree() might |
| 705 | * interrupt us (non NAPI drivers) | 707 | * interrupt us (non NAPI drivers) |
| 706 | */ | 708 | */ |
| 707 | static void tcp_tasklet_func(unsigned long data) | 709 | static void tcp_tasklet_func(unsigned long data) |
| @@ -795,7 +797,7 @@ void __init tcp_tasklet_init(void) | |||
| 795 | 797 | ||
| 796 | /* | 798 | /* |
| 797 | * Write buffer destructor automatically called from kfree_skb. | 799 | * Write buffer destructor automatically called from kfree_skb. |
| 798 | * We cant xmit new skbs from this context, as we might already | 800 | * We can't xmit new skbs from this context, as we might already |
| 799 | * hold qdisc lock. | 801 | * hold qdisc lock. |
| 800 | */ | 802 | */ |
| 801 | void tcp_wfree(struct sk_buff *skb) | 803 | void tcp_wfree(struct sk_buff *skb) |
| @@ -986,6 +988,8 @@ static void tcp_queue_skb(struct sock *sk, struct sk_buff *skb) | |||
| 986 | static void tcp_set_skb_tso_segs(const struct sock *sk, struct sk_buff *skb, | 988 | static void tcp_set_skb_tso_segs(const struct sock *sk, struct sk_buff *skb, |
| 987 | unsigned int mss_now) | 989 | unsigned int mss_now) |
| 988 | { | 990 | { |
| 991 | struct skb_shared_info *shinfo = skb_shinfo(skb); | ||
| 992 | |||
| 989 | /* Make sure we own this skb before messing gso_size/gso_segs */ | 993 | /* Make sure we own this skb before messing gso_size/gso_segs */ |
| 990 | WARN_ON_ONCE(skb_cloned(skb)); | 994 | WARN_ON_ONCE(skb_cloned(skb)); |
| 991 | 995 | ||
| @@ -993,13 +997,13 @@ static void tcp_set_skb_tso_segs(const struct sock *sk, struct sk_buff *skb, | |||
| 993 | /* Avoid the costly divide in the normal | 997 | /* Avoid the costly divide in the normal |
| 994 | * non-TSO case. | 998 | * non-TSO case. |
| 995 | */ | 999 | */ |
| 996 | skb_shinfo(skb)->gso_segs = 1; | 1000 | shinfo->gso_segs = 1; |
| 997 | skb_shinfo(skb)->gso_size = 0; | 1001 | shinfo->gso_size = 0; |
| 998 | skb_shinfo(skb)->gso_type = 0; | 1002 | shinfo->gso_type = 0; |
| 999 | } else { | 1003 | } else { |
| 1000 | skb_shinfo(skb)->gso_segs = DIV_ROUND_UP(skb->len, mss_now); | 1004 | shinfo->gso_segs = DIV_ROUND_UP(skb->len, mss_now); |
| 1001 | skb_shinfo(skb)->gso_size = mss_now; | 1005 | shinfo->gso_size = mss_now; |
| 1002 | skb_shinfo(skb)->gso_type = sk->sk_gso_type; | 1006 | shinfo->gso_type = sk->sk_gso_type; |
| 1003 | } | 1007 | } |
| 1004 | } | 1008 | } |
| 1005 | 1009 | ||
| @@ -1146,6 +1150,7 @@ int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len, | |||
| 1146 | */ | 1150 | */ |
| 1147 | static void __pskb_trim_head(struct sk_buff *skb, int len) | 1151 | static void __pskb_trim_head(struct sk_buff *skb, int len) |
| 1148 | { | 1152 | { |
| 1153 | struct skb_shared_info *shinfo; | ||
| 1149 | int i, k, eat; | 1154 | int i, k, eat; |
| 1150 | 1155 | ||
| 1151 | eat = min_t(int, len, skb_headlen(skb)); | 1156 | eat = min_t(int, len, skb_headlen(skb)); |
| @@ -1157,23 +1162,24 @@ static void __pskb_trim_head(struct sk_buff *skb, int len) | |||
| 1157 | } | 1162 | } |
| 1158 | eat = len; | 1163 | eat = len; |
| 1159 | k = 0; | 1164 | k = 0; |
| 1160 | for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { | 1165 | shinfo = skb_shinfo(skb); |
| 1161 | int size = skb_frag_size(&skb_shinfo(skb)->frags[i]); | 1166 | for (i = 0; i < shinfo->nr_frags; i++) { |
| 1167 | int size = skb_frag_size(&shinfo->frags[i]); | ||
| 1162 | 1168 | ||
| 1163 | if (size <= eat) { | 1169 | if (size <= eat) { |
| 1164 | skb_frag_unref(skb, i); | 1170 | skb_frag_unref(skb, i); |
| 1165 | eat -= size; | 1171 | eat -= size; |
| 1166 | } else { | 1172 | } else { |
| 1167 | skb_shinfo(skb)->frags[k] = skb_shinfo(skb)->frags[i]; | 1173 | shinfo->frags[k] = shinfo->frags[i]; |
| 1168 | if (eat) { | 1174 | if (eat) { |
| 1169 | skb_shinfo(skb)->frags[k].page_offset += eat; | 1175 | shinfo->frags[k].page_offset += eat; |
| 1170 | skb_frag_size_sub(&skb_shinfo(skb)->frags[k], eat); | 1176 | skb_frag_size_sub(&shinfo->frags[k], eat); |
| 1171 | eat = 0; | 1177 | eat = 0; |
| 1172 | } | 1178 | } |
| 1173 | k++; | 1179 | k++; |
| 1174 | } | 1180 | } |
| 1175 | } | 1181 | } |
| 1176 | skb_shinfo(skb)->nr_frags = k; | 1182 | shinfo->nr_frags = k; |
| 1177 | 1183 | ||
| 1178 | skb_reset_tail_pointer(skb); | 1184 | skb_reset_tail_pointer(skb); |
| 1179 | skb->data_len -= len; | 1185 | skb->data_len -= len; |
| @@ -1378,23 +1384,51 @@ static void tcp_cwnd_validate(struct sock *sk) | |||
| 1378 | } | 1384 | } |
| 1379 | } | 1385 | } |
| 1380 | 1386 | ||
| 1381 | /* Returns the portion of skb which can be sent right away without | 1387 | /* Minshall's variant of the Nagle send check. */ |
| 1382 | * introducing MSS oddities to segment boundaries. In rare cases where | 1388 | static bool tcp_minshall_check(const struct tcp_sock *tp) |
| 1383 | * mss_now != mss_cache, we will request caller to create a small skb | 1389 | { |
| 1384 | * per input skb which could be mostly avoided here (if desired). | 1390 | return after(tp->snd_sml, tp->snd_una) && |
| 1385 | * | 1391 | !after(tp->snd_sml, tp->snd_nxt); |
| 1386 | * We explicitly want to create a request for splitting write queue tail | 1392 | } |
| 1387 | * to a small skb for Nagle purposes while avoiding unnecessary modulos, | 1393 | |
| 1388 | * thus all the complexity (cwnd_len is always MSS multiple which we | 1394 | /* Update snd_sml if this skb is under mss |
| 1389 | * return whenever allowed by the other factors). Basically we need the | 1395 | * Note that a TSO packet might end with a sub-mss segment |
| 1390 | * modulo only when the receiver window alone is the limiting factor or | 1396 | * The test is really : |
| 1391 | * when we would be allowed to send the split-due-to-Nagle skb fully. | 1397 | * if ((skb->len % mss) != 0) |
| 1398 | * tp->snd_sml = TCP_SKB_CB(skb)->end_seq; | ||
| 1399 | * But we can avoid doing the divide again given we already have | ||
| 1400 | * skb_pcount = skb->len / mss_now | ||
| 1401 | */ | ||
| 1402 | static void tcp_minshall_update(struct tcp_sock *tp, unsigned int mss_now, | ||
| 1403 | const struct sk_buff *skb) | ||
| 1404 | { | ||
| 1405 | if (skb->len < tcp_skb_pcount(skb) * mss_now) | ||
| 1406 | tp->snd_sml = TCP_SKB_CB(skb)->end_seq; | ||
| 1407 | } | ||
| 1408 | |||
| 1409 | /* Return false, if packet can be sent now without violation Nagle's rules: | ||
| 1410 | * 1. It is full sized. (provided by caller in %partial bool) | ||
| 1411 | * 2. Or it contains FIN. (already checked by caller) | ||
| 1412 | * 3. Or TCP_CORK is not set, and TCP_NODELAY is set. | ||
| 1413 | * 4. Or TCP_CORK is not set, and all sent packets are ACKed. | ||
| 1414 | * With Minshall's modification: all sent small packets are ACKed. | ||
| 1392 | */ | 1415 | */ |
| 1393 | static unsigned int tcp_mss_split_point(const struct sock *sk, const struct sk_buff *skb, | 1416 | static bool tcp_nagle_check(bool partial, const struct tcp_sock *tp, |
| 1394 | unsigned int mss_now, unsigned int max_segs) | 1417 | unsigned int mss_now, int nonagle) |
| 1418 | { | ||
| 1419 | return partial && | ||
| 1420 | ((nonagle & TCP_NAGLE_CORK) || | ||
| 1421 | (!nonagle && tp->packets_out && tcp_minshall_check(tp))); | ||
| 1422 | } | ||
| 1423 | /* Returns the portion of skb which can be sent right away */ | ||
| 1424 | static unsigned int tcp_mss_split_point(const struct sock *sk, | ||
| 1425 | const struct sk_buff *skb, | ||
| 1426 | unsigned int mss_now, | ||
| 1427 | unsigned int max_segs, | ||
| 1428 | int nonagle) | ||
| 1395 | { | 1429 | { |
| 1396 | const struct tcp_sock *tp = tcp_sk(sk); | 1430 | const struct tcp_sock *tp = tcp_sk(sk); |
| 1397 | u32 needed, window, max_len; | 1431 | u32 partial, needed, window, max_len; |
| 1398 | 1432 | ||
| 1399 | window = tcp_wnd_end(tp) - TCP_SKB_CB(skb)->seq; | 1433 | window = tcp_wnd_end(tp) - TCP_SKB_CB(skb)->seq; |
| 1400 | max_len = mss_now * max_segs; | 1434 | max_len = mss_now * max_segs; |
| @@ -1407,7 +1441,15 @@ static unsigned int tcp_mss_split_point(const struct sock *sk, const struct sk_b | |||
| 1407 | if (max_len <= needed) | 1441 | if (max_len <= needed) |
| 1408 | return max_len; | 1442 | return max_len; |
| 1409 | 1443 | ||
| 1410 | return needed - needed % mss_now; | 1444 | partial = needed % mss_now; |
| 1445 | /* If last segment is not a full MSS, check if Nagle rules allow us | ||
| 1446 | * to include this last segment in this skb. | ||
| 1447 | * Otherwise, we'll split the skb at last MSS boundary | ||
| 1448 | */ | ||
| 1449 | if (tcp_nagle_check(partial != 0, tp, mss_now, nonagle)) | ||
| 1450 | return needed - partial; | ||
| 1451 | |||
| 1452 | return needed; | ||
| 1411 | } | 1453 | } |
| 1412 | 1454 | ||
| 1413 | /* Can at least one segment of SKB be sent right now, according to the | 1455 | /* Can at least one segment of SKB be sent right now, according to the |
| @@ -1447,28 +1489,6 @@ static int tcp_init_tso_segs(const struct sock *sk, struct sk_buff *skb, | |||
| 1447 | return tso_segs; | 1489 | return tso_segs; |
| 1448 | } | 1490 | } |
| 1449 | 1491 | ||
| 1450 | /* Minshall's variant of the Nagle send check. */ | ||
| 1451 | static inline bool tcp_minshall_check(const struct tcp_sock *tp) | ||
| 1452 | { | ||
| 1453 | return after(tp->snd_sml, tp->snd_una) && | ||
| 1454 | !after(tp->snd_sml, tp->snd_nxt); | ||
| 1455 | } | ||
| 1456 | |||
| 1457 | /* Return false, if packet can be sent now without violation Nagle's rules: | ||
| 1458 | * 1. It is full sized. | ||
| 1459 | * 2. Or it contains FIN. (already checked by caller) | ||
| 1460 | * 3. Or TCP_CORK is not set, and TCP_NODELAY is set. | ||
| 1461 | * 4. Or TCP_CORK is not set, and all sent packets are ACKed. | ||
| 1462 | * With Minshall's modification: all sent small packets are ACKed. | ||
| 1463 | */ | ||
| 1464 | static inline bool tcp_nagle_check(const struct tcp_sock *tp, | ||
| 1465 | const struct sk_buff *skb, | ||
| 1466 | unsigned int mss_now, int nonagle) | ||
| 1467 | { | ||
| 1468 | return skb->len < mss_now && | ||
| 1469 | ((nonagle & TCP_NAGLE_CORK) || | ||
| 1470 | (!nonagle && tp->packets_out && tcp_minshall_check(tp))); | ||
| 1471 | } | ||
| 1472 | 1492 | ||
| 1473 | /* Return true if the Nagle test allows this packet to be | 1493 | /* Return true if the Nagle test allows this packet to be |
| 1474 | * sent now. | 1494 | * sent now. |
| @@ -1489,7 +1509,7 @@ static inline bool tcp_nagle_test(const struct tcp_sock *tp, const struct sk_buf | |||
| 1489 | if (tcp_urg_mode(tp) || (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN)) | 1509 | if (tcp_urg_mode(tp) || (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN)) |
| 1490 | return true; | 1510 | return true; |
| 1491 | 1511 | ||
| 1492 | if (!tcp_nagle_check(tp, skb, cur_mss, nonagle)) | 1512 | if (!tcp_nagle_check(skb->len < cur_mss, tp, cur_mss, nonagle)) |
| 1493 | return true; | 1513 | return true; |
| 1494 | 1514 | ||
| 1495 | return false; | 1515 | return false; |
| @@ -1892,7 +1912,8 @@ static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle, | |||
| 1892 | limit = tcp_mss_split_point(sk, skb, mss_now, | 1912 | limit = tcp_mss_split_point(sk, skb, mss_now, |
| 1893 | min_t(unsigned int, | 1913 | min_t(unsigned int, |
| 1894 | cwnd_quota, | 1914 | cwnd_quota, |
| 1895 | sk->sk_gso_max_segs)); | 1915 | sk->sk_gso_max_segs), |
| 1916 | nonagle); | ||
| 1896 | 1917 | ||
| 1897 | if (skb->len > limit && | 1918 | if (skb->len > limit && |
| 1898 | unlikely(tso_fragment(sk, skb, limit, mss_now, gfp))) | 1919 | unlikely(tso_fragment(sk, skb, limit, mss_now, gfp))) |
| @@ -2756,7 +2777,7 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst, | |||
| 2756 | EXPORT_SYMBOL(tcp_make_synack); | 2777 | EXPORT_SYMBOL(tcp_make_synack); |
| 2757 | 2778 | ||
| 2758 | /* Do all connect socket setups that can be done AF independent. */ | 2779 | /* Do all connect socket setups that can be done AF independent. */ |
| 2759 | void tcp_connect_init(struct sock *sk) | 2780 | static void tcp_connect_init(struct sock *sk) |
| 2760 | { | 2781 | { |
| 2761 | const struct dst_entry *dst = __sk_dst_get(sk); | 2782 | const struct dst_entry *dst = __sk_dst_get(sk); |
| 2762 | struct tcp_sock *tp = tcp_sk(sk); | 2783 | struct tcp_sock *tp = tcp_sk(sk); |
diff --git a/net/ipv4/tcp_probe.c b/net/ipv4/tcp_probe.c index 8b97d71e193b..1f2d37613c9e 100644 --- a/net/ipv4/tcp_probe.c +++ b/net/ipv4/tcp_probe.c | |||
| @@ -38,7 +38,7 @@ MODULE_DESCRIPTION("TCP cwnd snooper"); | |||
| 38 | MODULE_LICENSE("GPL"); | 38 | MODULE_LICENSE("GPL"); |
| 39 | MODULE_VERSION("1.1"); | 39 | MODULE_VERSION("1.1"); |
| 40 | 40 | ||
| 41 | static int port __read_mostly = 0; | 41 | static int port __read_mostly; |
| 42 | MODULE_PARM_DESC(port, "Port to match (0=all)"); | 42 | MODULE_PARM_DESC(port, "Port to match (0=all)"); |
| 43 | module_param(port, int, 0); | 43 | module_param(port, int, 0); |
| 44 | 44 | ||
| @@ -46,7 +46,7 @@ static unsigned int bufsize __read_mostly = 4096; | |||
| 46 | MODULE_PARM_DESC(bufsize, "Log buffer size in packets (4096)"); | 46 | MODULE_PARM_DESC(bufsize, "Log buffer size in packets (4096)"); |
| 47 | module_param(bufsize, uint, 0); | 47 | module_param(bufsize, uint, 0); |
| 48 | 48 | ||
| 49 | static unsigned int fwmark __read_mostly = 0; | 49 | static unsigned int fwmark __read_mostly; |
| 50 | MODULE_PARM_DESC(fwmark, "skb mark to match (0=no mark)"); | 50 | MODULE_PARM_DESC(fwmark, "skb mark to match (0=no mark)"); |
| 51 | module_param(fwmark, uint, 0); | 51 | module_param(fwmark, uint, 0); |
| 52 | 52 | ||
diff --git a/net/ipv4/tcp_yeah.c b/net/ipv4/tcp_yeah.c index a347a078ee07..1a8d271f994d 100644 --- a/net/ipv4/tcp_yeah.c +++ b/net/ipv4/tcp_yeah.c | |||
| @@ -3,7 +3,7 @@ | |||
| 3 | * YeAH TCP | 3 | * YeAH TCP |
| 4 | * | 4 | * |
| 5 | * For further details look at: | 5 | * For further details look at: |
| 6 | * http://wil.cs.caltech.edu/pfldnet2007/paper/YeAH_TCP.pdf | 6 | * https://web.archive.org/web/20080316215752/http://wil.cs.caltech.edu/pfldnet2007/paper/YeAH_TCP.pdf |
| 7 | * | 7 | * |
| 8 | */ | 8 | */ |
| 9 | #include <linux/mm.h> | 9 | #include <linux/mm.h> |
| @@ -15,13 +15,13 @@ | |||
| 15 | 15 | ||
| 16 | #include "tcp_vegas.h" | 16 | #include "tcp_vegas.h" |
| 17 | 17 | ||
| 18 | #define TCP_YEAH_ALPHA 80 //lin number of packets queued at the bottleneck | 18 | #define TCP_YEAH_ALPHA 80 /* number of packets queued at the bottleneck */ |
| 19 | #define TCP_YEAH_GAMMA 1 //lin fraction of queue to be removed per rtt | 19 | #define TCP_YEAH_GAMMA 1 /* fraction of queue to be removed per rtt */ |
| 20 | #define TCP_YEAH_DELTA 3 //log minimum fraction of cwnd to be removed on loss | 20 | #define TCP_YEAH_DELTA 3 /* log minimum fraction of cwnd to be removed on loss */ |
| 21 | #define TCP_YEAH_EPSILON 1 //log maximum fraction to be removed on early decongestion | 21 | #define TCP_YEAH_EPSILON 1 /* log maximum fraction to be removed on early decongestion */ |
| 22 | #define TCP_YEAH_PHY 8 //lin maximum delta from base | 22 | #define TCP_YEAH_PHY 8 /* maximum delta from base */ |
| 23 | #define TCP_YEAH_RHO 16 //lin minimum number of consecutive rtt to consider competition on loss | 23 | #define TCP_YEAH_RHO 16 /* minimum number of consecutive rtt to consider competition on loss */ |
| 24 | #define TCP_YEAH_ZETA 50 //lin minimum number of state switchs to reset reno_count | 24 | #define TCP_YEAH_ZETA 50 /* minimum number of state switches to reset reno_count */ |
| 25 | 25 | ||
| 26 | #define TCP_SCALABLE_AI_CNT 100U | 26 | #define TCP_SCALABLE_AI_CNT 100U |
| 27 | 27 | ||
| @@ -214,9 +214,9 @@ static u32 tcp_yeah_ssthresh(struct sock *sk) { | |||
| 214 | if (yeah->doing_reno_now < TCP_YEAH_RHO) { | 214 | if (yeah->doing_reno_now < TCP_YEAH_RHO) { |
| 215 | reduction = yeah->lastQ; | 215 | reduction = yeah->lastQ; |
| 216 | 216 | ||
| 217 | reduction = min( reduction, max(tp->snd_cwnd>>1, 2U) ); | 217 | reduction = min(reduction, max(tp->snd_cwnd>>1, 2U)); |
| 218 | 218 | ||
| 219 | reduction = max( reduction, tp->snd_cwnd >> TCP_YEAH_DELTA); | 219 | reduction = max(reduction, tp->snd_cwnd >> TCP_YEAH_DELTA); |
| 220 | } else | 220 | } else |
| 221 | reduction = max(tp->snd_cwnd>>1, 2U); | 221 | reduction = max(tp->snd_cwnd>>1, 2U); |
| 222 | 222 | ||
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index a7e4729e974b..77bd16fa9f34 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c | |||
| @@ -223,7 +223,7 @@ int udp_lib_get_port(struct sock *sk, unsigned short snum, | |||
| 223 | inet_get_local_port_range(net, &low, &high); | 223 | inet_get_local_port_range(net, &low, &high); |
| 224 | remaining = (high - low) + 1; | 224 | remaining = (high - low) + 1; |
| 225 | 225 | ||
| 226 | rand = net_random(); | 226 | rand = prandom_u32(); |
| 227 | first = (((u64)rand * remaining) >> 32) + low; | 227 | first = (((u64)rand * remaining) >> 32) + low; |
| 228 | /* | 228 | /* |
| 229 | * force rand to be an odd multiple of UDP_HTABLE_SIZE | 229 | * force rand to be an odd multiple of UDP_HTABLE_SIZE |
| @@ -902,7 +902,7 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
| 902 | * Get and verify the address. | 902 | * Get and verify the address. |
| 903 | */ | 903 | */ |
| 904 | if (msg->msg_name) { | 904 | if (msg->msg_name) { |
| 905 | struct sockaddr_in *usin = (struct sockaddr_in *)msg->msg_name; | 905 | DECLARE_SOCKADDR(struct sockaddr_in *, usin, msg->msg_name); |
| 906 | if (msg->msg_namelen < sizeof(*usin)) | 906 | if (msg->msg_namelen < sizeof(*usin)) |
| 907 | return -EINVAL; | 907 | return -EINVAL; |
| 908 | if (usin->sin_family != AF_INET) { | 908 | if (usin->sin_family != AF_INET) { |
| @@ -986,7 +986,7 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
| 986 | fl4 = &fl4_stack; | 986 | fl4 = &fl4_stack; |
| 987 | flowi4_init_output(fl4, ipc.oif, sk->sk_mark, tos, | 987 | flowi4_init_output(fl4, ipc.oif, sk->sk_mark, tos, |
| 988 | RT_SCOPE_UNIVERSE, sk->sk_protocol, | 988 | RT_SCOPE_UNIVERSE, sk->sk_protocol, |
| 989 | inet_sk_flowi_flags(sk)|FLOWI_FLAG_CAN_SLEEP, | 989 | inet_sk_flowi_flags(sk), |
| 990 | faddr, saddr, dport, inet->inet_sport); | 990 | faddr, saddr, dport, inet->inet_sport); |
| 991 | 991 | ||
| 992 | security_sk_classify_flow(sk, flowi4_to_flowi(fl4)); | 992 | security_sk_classify_flow(sk, flowi4_to_flowi(fl4)); |
| @@ -1226,7 +1226,7 @@ int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
| 1226 | size_t len, int noblock, int flags, int *addr_len) | 1226 | size_t len, int noblock, int flags, int *addr_len) |
| 1227 | { | 1227 | { |
| 1228 | struct inet_sock *inet = inet_sk(sk); | 1228 | struct inet_sock *inet = inet_sk(sk); |
| 1229 | struct sockaddr_in *sin = (struct sockaddr_in *)msg->msg_name; | 1229 | DECLARE_SOCKADDR(struct sockaddr_in *, sin, msg->msg_name); |
| 1230 | struct sk_buff *skb; | 1230 | struct sk_buff *skb; |
| 1231 | unsigned int ulen, copied; | 1231 | unsigned int ulen, copied; |
| 1232 | int peeked, off = 0; | 1232 | int peeked, off = 0; |
diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c index 79c62bdcd3c5..25f5cee3a08a 100644 --- a/net/ipv4/udp_offload.c +++ b/net/ipv4/udp_offload.c | |||
| @@ -14,6 +14,15 @@ | |||
| 14 | #include <net/udp.h> | 14 | #include <net/udp.h> |
| 15 | #include <net/protocol.h> | 15 | #include <net/protocol.h> |
| 16 | 16 | ||
| 17 | static DEFINE_SPINLOCK(udp_offload_lock); | ||
| 18 | static struct udp_offload_priv __rcu *udp_offload_base __read_mostly; | ||
| 19 | |||
| 20 | struct udp_offload_priv { | ||
| 21 | struct udp_offload *offload; | ||
| 22 | struct rcu_head rcu; | ||
| 23 | struct udp_offload_priv __rcu *next; | ||
| 24 | }; | ||
| 25 | |||
| 17 | static int udp4_ufo_send_check(struct sk_buff *skb) | 26 | static int udp4_ufo_send_check(struct sk_buff *skb) |
| 18 | { | 27 | { |
| 19 | if (!pskb_may_pull(skb, sizeof(struct udphdr))) | 28 | if (!pskb_may_pull(skb, sizeof(struct udphdr))) |
| @@ -89,10 +98,144 @@ out: | |||
| 89 | return segs; | 98 | return segs; |
| 90 | } | 99 | } |
| 91 | 100 | ||
| 101 | int udp_add_offload(struct udp_offload *uo) | ||
| 102 | { | ||
| 103 | struct udp_offload_priv __rcu **head = &udp_offload_base; | ||
| 104 | struct udp_offload_priv *new_offload = kzalloc(sizeof(*new_offload), GFP_KERNEL); | ||
| 105 | |||
| 106 | if (!new_offload) | ||
| 107 | return -ENOMEM; | ||
| 108 | |||
| 109 | new_offload->offload = uo; | ||
| 110 | |||
| 111 | spin_lock(&udp_offload_lock); | ||
| 112 | rcu_assign_pointer(new_offload->next, rcu_dereference(*head)); | ||
| 113 | rcu_assign_pointer(*head, new_offload); | ||
| 114 | spin_unlock(&udp_offload_lock); | ||
| 115 | |||
| 116 | return 0; | ||
| 117 | } | ||
| 118 | EXPORT_SYMBOL(udp_add_offload); | ||
| 119 | |||
| 120 | static void udp_offload_free_routine(struct rcu_head *head) | ||
| 121 | { | ||
| 122 | struct udp_offload_priv *ou_priv = container_of(head, struct udp_offload_priv, rcu); | ||
| 123 | kfree(ou_priv); | ||
| 124 | } | ||
| 125 | |||
| 126 | void udp_del_offload(struct udp_offload *uo) | ||
| 127 | { | ||
| 128 | struct udp_offload_priv __rcu **head = &udp_offload_base; | ||
| 129 | struct udp_offload_priv *uo_priv; | ||
| 130 | |||
| 131 | spin_lock(&udp_offload_lock); | ||
| 132 | |||
| 133 | uo_priv = rcu_dereference(*head); | ||
| 134 | for (; uo_priv != NULL; | ||
| 135 | uo_priv = rcu_dereference(*head)) { | ||
| 136 | |||
| 137 | if (uo_priv->offload == uo) { | ||
| 138 | rcu_assign_pointer(*head, rcu_dereference(uo_priv->next)); | ||
| 139 | goto unlock; | ||
| 140 | } | ||
| 141 | head = &uo_priv->next; | ||
| 142 | } | ||
| 143 | pr_warn("udp_del_offload: didn't find offload for port %d\n", ntohs(uo->port)); | ||
| 144 | unlock: | ||
| 145 | spin_unlock(&udp_offload_lock); | ||
| 146 | if (uo_priv != NULL) | ||
| 147 | call_rcu(&uo_priv->rcu, udp_offload_free_routine); | ||
| 148 | } | ||
| 149 | EXPORT_SYMBOL(udp_del_offload); | ||
| 150 | |||
| 151 | static struct sk_buff **udp_gro_receive(struct sk_buff **head, struct sk_buff *skb) | ||
| 152 | { | ||
| 153 | struct udp_offload_priv *uo_priv; | ||
| 154 | struct sk_buff *p, **pp = NULL; | ||
| 155 | struct udphdr *uh, *uh2; | ||
| 156 | unsigned int hlen, off; | ||
| 157 | int flush = 1; | ||
| 158 | |||
| 159 | if (NAPI_GRO_CB(skb)->udp_mark || | ||
| 160 | (!skb->encapsulation && skb->ip_summed != CHECKSUM_COMPLETE)) | ||
| 161 | goto out; | ||
| 162 | |||
| 163 | /* mark that this skb passed once through the udp gro layer */ | ||
| 164 | NAPI_GRO_CB(skb)->udp_mark = 1; | ||
| 165 | |||
| 166 | off = skb_gro_offset(skb); | ||
| 167 | hlen = off + sizeof(*uh); | ||
| 168 | uh = skb_gro_header_fast(skb, off); | ||
| 169 | if (skb_gro_header_hard(skb, hlen)) { | ||
| 170 | uh = skb_gro_header_slow(skb, hlen, off); | ||
| 171 | if (unlikely(!uh)) | ||
| 172 | goto out; | ||
| 173 | } | ||
| 174 | |||
| 175 | rcu_read_lock(); | ||
| 176 | uo_priv = rcu_dereference(udp_offload_base); | ||
| 177 | for (; uo_priv != NULL; uo_priv = rcu_dereference(uo_priv->next)) { | ||
| 178 | if (uo_priv->offload->port == uh->dest && | ||
| 179 | uo_priv->offload->callbacks.gro_receive) | ||
| 180 | goto unflush; | ||
| 181 | } | ||
| 182 | goto out_unlock; | ||
| 183 | |||
| 184 | unflush: | ||
| 185 | flush = 0; | ||
| 186 | |||
| 187 | for (p = *head; p; p = p->next) { | ||
| 188 | if (!NAPI_GRO_CB(p)->same_flow) | ||
| 189 | continue; | ||
| 190 | |||
| 191 | uh2 = (struct udphdr *)(p->data + off); | ||
| 192 | if ((*(u32 *)&uh->source != *(u32 *)&uh2->source)) { | ||
| 193 | NAPI_GRO_CB(p)->same_flow = 0; | ||
| 194 | continue; | ||
| 195 | } | ||
| 196 | } | ||
| 197 | |||
| 198 | skb_gro_pull(skb, sizeof(struct udphdr)); /* pull encapsulating udp header */ | ||
| 199 | pp = uo_priv->offload->callbacks.gro_receive(head, skb); | ||
| 200 | |||
| 201 | out_unlock: | ||
| 202 | rcu_read_unlock(); | ||
| 203 | out: | ||
| 204 | NAPI_GRO_CB(skb)->flush |= flush; | ||
| 205 | return pp; | ||
| 206 | } | ||
| 207 | |||
| 208 | static int udp_gro_complete(struct sk_buff *skb, int nhoff) | ||
| 209 | { | ||
| 210 | struct udp_offload_priv *uo_priv; | ||
| 211 | __be16 newlen = htons(skb->len - nhoff); | ||
| 212 | struct udphdr *uh = (struct udphdr *)(skb->data + nhoff); | ||
| 213 | int err = -ENOSYS; | ||
| 214 | |||
| 215 | uh->len = newlen; | ||
| 216 | |||
| 217 | rcu_read_lock(); | ||
| 218 | |||
| 219 | uo_priv = rcu_dereference(udp_offload_base); | ||
| 220 | for (; uo_priv != NULL; uo_priv = rcu_dereference(uo_priv->next)) { | ||
| 221 | if (uo_priv->offload->port == uh->dest && | ||
| 222 | uo_priv->offload->callbacks.gro_complete) | ||
| 223 | break; | ||
| 224 | } | ||
| 225 | |||
| 226 | if (uo_priv != NULL) | ||
| 227 | err = uo_priv->offload->callbacks.gro_complete(skb, nhoff + sizeof(struct udphdr)); | ||
| 228 | |||
| 229 | rcu_read_unlock(); | ||
| 230 | return err; | ||
| 231 | } | ||
| 232 | |||
| 92 | static const struct net_offload udpv4_offload = { | 233 | static const struct net_offload udpv4_offload = { |
| 93 | .callbacks = { | 234 | .callbacks = { |
| 94 | .gso_send_check = udp4_ufo_send_check, | 235 | .gso_send_check = udp4_ufo_send_check, |
| 95 | .gso_segment = udp4_ufo_fragment, | 236 | .gso_segment = udp4_ufo_fragment, |
| 237 | .gro_receive = udp_gro_receive, | ||
| 238 | .gro_complete = udp_gro_complete, | ||
| 96 | }, | 239 | }, |
| 97 | }; | 240 | }; |
| 98 | 241 | ||
diff --git a/net/ipv4/xfrm4_mode_beet.c b/net/ipv4/xfrm4_mode_beet.c index e3db3f915114..71acd0014f2d 100644 --- a/net/ipv4/xfrm4_mode_beet.c +++ b/net/ipv4/xfrm4_mode_beet.c | |||
| @@ -48,7 +48,7 @@ static int xfrm4_beet_output(struct xfrm_state *x, struct sk_buff *skb) | |||
| 48 | hdrlen += IPV4_BEET_PHMAXLEN - (optlen & 4); | 48 | hdrlen += IPV4_BEET_PHMAXLEN - (optlen & 4); |
| 49 | 49 | ||
| 50 | skb_set_network_header(skb, -x->props.header_len - | 50 | skb_set_network_header(skb, -x->props.header_len - |
| 51 | hdrlen + (XFRM_MODE_SKB_CB(skb)->ihl - sizeof(*top_iph))); | 51 | hdrlen + (XFRM_MODE_SKB_CB(skb)->ihl - sizeof(*top_iph))); |
| 52 | if (x->sel.family != AF_INET6) | 52 | if (x->sel.family != AF_INET6) |
| 53 | skb->network_header += IPV4_BEET_PHMAXLEN; | 53 | skb->network_header += IPV4_BEET_PHMAXLEN; |
| 54 | skb->mac_header = skb->network_header + | 54 | skb->mac_header = skb->network_header + |
diff --git a/net/ipv4/xfrm4_state.c b/net/ipv4/xfrm4_state.c index 0b2a0641526a..542074c00c78 100644 --- a/net/ipv4/xfrm4_state.c +++ b/net/ipv4/xfrm4_state.c | |||
| @@ -16,7 +16,7 @@ | |||
| 16 | 16 | ||
| 17 | static int xfrm4_init_flags(struct xfrm_state *x) | 17 | static int xfrm4_init_flags(struct xfrm_state *x) |
| 18 | { | 18 | { |
| 19 | if (ipv4_config.no_pmtu_disc) | 19 | if (xs_net(x)->ipv4.sysctl_ip_no_pmtu_disc) |
| 20 | x->props.flags |= XFRM_STATE_NOPMTUDISC; | 20 | x->props.flags |= XFRM_STATE_NOPMTUDISC; |
| 21 | return 0; | 21 | return 0; |
| 22 | } | 22 | } |
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 4b6b720971b9..ad235690684c 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
| @@ -442,6 +442,8 @@ static int inet6_netconf_msgsize_devconf(int type) | |||
| 442 | if (type == -1 || type == NETCONFA_MC_FORWARDING) | 442 | if (type == -1 || type == NETCONFA_MC_FORWARDING) |
| 443 | size += nla_total_size(4); | 443 | size += nla_total_size(4); |
| 444 | #endif | 444 | #endif |
| 445 | if (type == -1 || type == NETCONFA_PROXY_NEIGH) | ||
| 446 | size += nla_total_size(4); | ||
| 445 | 447 | ||
| 446 | return size; | 448 | return size; |
| 447 | } | 449 | } |
| @@ -475,6 +477,10 @@ static int inet6_netconf_fill_devconf(struct sk_buff *skb, int ifindex, | |||
| 475 | devconf->mc_forwarding) < 0) | 477 | devconf->mc_forwarding) < 0) |
| 476 | goto nla_put_failure; | 478 | goto nla_put_failure; |
| 477 | #endif | 479 | #endif |
| 480 | if ((type == -1 || type == NETCONFA_PROXY_NEIGH) && | ||
| 481 | nla_put_s32(skb, NETCONFA_PROXY_NEIGH, devconf->proxy_ndp) < 0) | ||
| 482 | goto nla_put_failure; | ||
| 483 | |||
| 478 | return nlmsg_end(skb, nlh); | 484 | return nlmsg_end(skb, nlh); |
| 479 | 485 | ||
| 480 | nla_put_failure: | 486 | nla_put_failure: |
| @@ -509,6 +515,7 @@ errout: | |||
| 509 | static const struct nla_policy devconf_ipv6_policy[NETCONFA_MAX+1] = { | 515 | static const struct nla_policy devconf_ipv6_policy[NETCONFA_MAX+1] = { |
| 510 | [NETCONFA_IFINDEX] = { .len = sizeof(int) }, | 516 | [NETCONFA_IFINDEX] = { .len = sizeof(int) }, |
| 511 | [NETCONFA_FORWARDING] = { .len = sizeof(int) }, | 517 | [NETCONFA_FORWARDING] = { .len = sizeof(int) }, |
| 518 | [NETCONFA_PROXY_NEIGH] = { .len = sizeof(int) }, | ||
| 512 | }; | 519 | }; |
| 513 | 520 | ||
| 514 | static int inet6_netconf_get_devconf(struct sk_buff *in_skb, | 521 | static int inet6_netconf_get_devconf(struct sk_buff *in_skb, |
| @@ -834,6 +841,8 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, | |||
| 834 | goto out; | 841 | goto out; |
| 835 | } | 842 | } |
| 836 | 843 | ||
| 844 | neigh_parms_data_state_setall(idev->nd_parms); | ||
| 845 | |||
| 837 | ifa->addr = *addr; | 846 | ifa->addr = *addr; |
| 838 | if (peer_addr) | 847 | if (peer_addr) |
| 839 | ifa->peer_addr = *peer_addr; | 848 | ifa->peer_addr = *peer_addr; |
| @@ -891,15 +900,95 @@ out: | |||
| 891 | goto out2; | 900 | goto out2; |
| 892 | } | 901 | } |
| 893 | 902 | ||
| 903 | enum cleanup_prefix_rt_t { | ||
| 904 | CLEANUP_PREFIX_RT_NOP, /* no cleanup action for prefix route */ | ||
| 905 | CLEANUP_PREFIX_RT_DEL, /* delete the prefix route */ | ||
| 906 | CLEANUP_PREFIX_RT_EXPIRE, /* update the lifetime of the prefix route */ | ||
| 907 | }; | ||
| 908 | |||
| 909 | /* | ||
| 910 | * Check, whether the prefix for ifp would still need a prefix route | ||
| 911 | * after deleting ifp. The function returns one of the CLEANUP_PREFIX_RT_* | ||
| 912 | * constants. | ||
| 913 | * | ||
| 914 | * 1) we don't purge prefix if address was not permanent. | ||
| 915 | * prefix is managed by its own lifetime. | ||
| 916 | * 2) we also don't purge, if the address was IFA_F_NOPREFIXROUTE. | ||
| 917 | * 3) if there are no addresses, delete prefix. | ||
| 918 | * 4) if there are still other permanent address(es), | ||
| 919 | * corresponding prefix is still permanent. | ||
| 920 | * 5) if there are still other addresses with IFA_F_NOPREFIXROUTE, | ||
| 921 | * don't purge the prefix, assume user space is managing it. | ||
| 922 | * 6) otherwise, update prefix lifetime to the | ||
| 923 | * longest valid lifetime among the corresponding | ||
| 924 | * addresses on the device. | ||
| 925 | * Note: subsequent RA will update lifetime. | ||
| 926 | **/ | ||
| 927 | static enum cleanup_prefix_rt_t | ||
| 928 | check_cleanup_prefix_route(struct inet6_ifaddr *ifp, unsigned long *expires) | ||
| 929 | { | ||
| 930 | struct inet6_ifaddr *ifa; | ||
| 931 | struct inet6_dev *idev = ifp->idev; | ||
| 932 | unsigned long lifetime; | ||
| 933 | enum cleanup_prefix_rt_t action = CLEANUP_PREFIX_RT_DEL; | ||
| 934 | |||
| 935 | *expires = jiffies; | ||
| 936 | |||
| 937 | list_for_each_entry(ifa, &idev->addr_list, if_list) { | ||
| 938 | if (ifa == ifp) | ||
| 939 | continue; | ||
| 940 | if (!ipv6_prefix_equal(&ifa->addr, &ifp->addr, | ||
| 941 | ifp->prefix_len)) | ||
| 942 | continue; | ||
| 943 | if (ifa->flags & (IFA_F_PERMANENT | IFA_F_NOPREFIXROUTE)) | ||
| 944 | return CLEANUP_PREFIX_RT_NOP; | ||
| 945 | |||
| 946 | action = CLEANUP_PREFIX_RT_EXPIRE; | ||
| 947 | |||
| 948 | spin_lock(&ifa->lock); | ||
| 949 | |||
| 950 | lifetime = addrconf_timeout_fixup(ifa->valid_lft, HZ); | ||
| 951 | /* | ||
| 952 | * Note: Because this address is | ||
| 953 | * not permanent, lifetime < | ||
| 954 | * LONG_MAX / HZ here. | ||
| 955 | */ | ||
| 956 | if (time_before(*expires, ifa->tstamp + lifetime * HZ)) | ||
| 957 | *expires = ifa->tstamp + lifetime * HZ; | ||
| 958 | spin_unlock(&ifa->lock); | ||
| 959 | } | ||
| 960 | |||
| 961 | return action; | ||
| 962 | } | ||
| 963 | |||
| 964 | static void | ||
| 965 | cleanup_prefix_route(struct inet6_ifaddr *ifp, unsigned long expires, bool del_rt) | ||
| 966 | { | ||
| 967 | struct rt6_info *rt; | ||
| 968 | |||
| 969 | rt = addrconf_get_prefix_route(&ifp->addr, | ||
| 970 | ifp->prefix_len, | ||
| 971 | ifp->idev->dev, | ||
| 972 | 0, RTF_GATEWAY | RTF_DEFAULT); | ||
| 973 | if (rt) { | ||
| 974 | if (del_rt) | ||
| 975 | ip6_del_rt(rt); | ||
| 976 | else { | ||
| 977 | if (!(rt->rt6i_flags & RTF_EXPIRES)) | ||
| 978 | rt6_set_expires(rt, expires); | ||
| 979 | ip6_rt_put(rt); | ||
| 980 | } | ||
| 981 | } | ||
| 982 | } | ||
| 983 | |||
| 984 | |||
| 894 | /* This function wants to get referenced ifp and releases it before return */ | 985 | /* This function wants to get referenced ifp and releases it before return */ |
| 895 | 986 | ||
| 896 | static void ipv6_del_addr(struct inet6_ifaddr *ifp) | 987 | static void ipv6_del_addr(struct inet6_ifaddr *ifp) |
| 897 | { | 988 | { |
| 898 | struct inet6_ifaddr *ifa, *ifn; | ||
| 899 | struct inet6_dev *idev = ifp->idev; | ||
| 900 | int state; | 989 | int state; |
| 901 | int deleted = 0, onlink = 0; | 990 | enum cleanup_prefix_rt_t action = CLEANUP_PREFIX_RT_NOP; |
| 902 | unsigned long expires = jiffies; | 991 | unsigned long expires; |
| 903 | 992 | ||
| 904 | spin_lock_bh(&ifp->state_lock); | 993 | spin_lock_bh(&ifp->state_lock); |
| 905 | state = ifp->state; | 994 | state = ifp->state; |
| @@ -913,7 +1002,7 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp) | |||
| 913 | hlist_del_init_rcu(&ifp->addr_lst); | 1002 | hlist_del_init_rcu(&ifp->addr_lst); |
| 914 | spin_unlock_bh(&addrconf_hash_lock); | 1003 | spin_unlock_bh(&addrconf_hash_lock); |
| 915 | 1004 | ||
| 916 | write_lock_bh(&idev->lock); | 1005 | write_lock_bh(&ifp->idev->lock); |
| 917 | 1006 | ||
| 918 | if (ifp->flags&IFA_F_TEMPORARY) { | 1007 | if (ifp->flags&IFA_F_TEMPORARY) { |
| 919 | list_del(&ifp->tmp_list); | 1008 | list_del(&ifp->tmp_list); |
| @@ -924,45 +1013,13 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp) | |||
| 924 | __in6_ifa_put(ifp); | 1013 | __in6_ifa_put(ifp); |
| 925 | } | 1014 | } |
| 926 | 1015 | ||
| 927 | list_for_each_entry_safe(ifa, ifn, &idev->addr_list, if_list) { | 1016 | if (ifp->flags & IFA_F_PERMANENT && !(ifp->flags & IFA_F_NOPREFIXROUTE)) |
| 928 | if (ifa == ifp) { | 1017 | action = check_cleanup_prefix_route(ifp, &expires); |
| 929 | list_del_init(&ifp->if_list); | ||
| 930 | __in6_ifa_put(ifp); | ||
| 931 | 1018 | ||
| 932 | if (!(ifp->flags & IFA_F_PERMANENT) || onlink > 0) | 1019 | list_del_init(&ifp->if_list); |
| 933 | break; | 1020 | __in6_ifa_put(ifp); |
| 934 | deleted = 1; | 1021 | |
| 935 | continue; | 1022 | write_unlock_bh(&ifp->idev->lock); |
| 936 | } else if (ifp->flags & IFA_F_PERMANENT) { | ||
| 937 | if (ipv6_prefix_equal(&ifa->addr, &ifp->addr, | ||
| 938 | ifp->prefix_len)) { | ||
| 939 | if (ifa->flags & IFA_F_PERMANENT) { | ||
| 940 | onlink = 1; | ||
| 941 | if (deleted) | ||
| 942 | break; | ||
| 943 | } else { | ||
| 944 | unsigned long lifetime; | ||
| 945 | |||
| 946 | if (!onlink) | ||
| 947 | onlink = -1; | ||
| 948 | |||
| 949 | spin_lock(&ifa->lock); | ||
| 950 | |||
| 951 | lifetime = addrconf_timeout_fixup(ifa->valid_lft, HZ); | ||
| 952 | /* | ||
| 953 | * Note: Because this address is | ||
| 954 | * not permanent, lifetime < | ||
| 955 | * LONG_MAX / HZ here. | ||
| 956 | */ | ||
| 957 | if (time_before(expires, | ||
| 958 | ifa->tstamp + lifetime * HZ)) | ||
| 959 | expires = ifa->tstamp + lifetime * HZ; | ||
| 960 | spin_unlock(&ifa->lock); | ||
| 961 | } | ||
| 962 | } | ||
| 963 | } | ||
| 964 | } | ||
| 965 | write_unlock_bh(&idev->lock); | ||
| 966 | 1023 | ||
| 967 | addrconf_del_dad_timer(ifp); | 1024 | addrconf_del_dad_timer(ifp); |
| 968 | 1025 | ||
| @@ -970,41 +1027,9 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp) | |||
| 970 | 1027 | ||
| 971 | inet6addr_notifier_call_chain(NETDEV_DOWN, ifp); | 1028 | inet6addr_notifier_call_chain(NETDEV_DOWN, ifp); |
| 972 | 1029 | ||
| 973 | /* | 1030 | if (action != CLEANUP_PREFIX_RT_NOP) { |
| 974 | * Purge or update corresponding prefix | 1031 | cleanup_prefix_route(ifp, expires, |
| 975 | * | 1032 | action == CLEANUP_PREFIX_RT_DEL); |
| 976 | * 1) we don't purge prefix here if address was not permanent. | ||
| 977 | * prefix is managed by its own lifetime. | ||
| 978 | * 2) if there're no addresses, delete prefix. | ||
| 979 | * 3) if there're still other permanent address(es), | ||
| 980 | * corresponding prefix is still permanent. | ||
| 981 | * 4) otherwise, update prefix lifetime to the | ||
| 982 | * longest valid lifetime among the corresponding | ||
| 983 | * addresses on the device. | ||
| 984 | * Note: subsequent RA will update lifetime. | ||
| 985 | * | ||
| 986 | * --yoshfuji | ||
| 987 | */ | ||
| 988 | if ((ifp->flags & IFA_F_PERMANENT) && onlink < 1) { | ||
| 989 | struct in6_addr prefix; | ||
| 990 | struct rt6_info *rt; | ||
| 991 | |||
| 992 | ipv6_addr_prefix(&prefix, &ifp->addr, ifp->prefix_len); | ||
| 993 | |||
| 994 | rt = addrconf_get_prefix_route(&prefix, | ||
| 995 | ifp->prefix_len, | ||
| 996 | ifp->idev->dev, | ||
| 997 | 0, RTF_GATEWAY | RTF_DEFAULT); | ||
| 998 | |||
| 999 | if (rt) { | ||
| 1000 | if (onlink == 0) { | ||
| 1001 | ip6_del_rt(rt); | ||
| 1002 | rt = NULL; | ||
| 1003 | } else if (!(rt->rt6i_flags & RTF_EXPIRES)) { | ||
| 1004 | rt6_set_expires(rt, expires); | ||
| 1005 | } | ||
| 1006 | } | ||
| 1007 | ip6_rt_put(rt); | ||
| 1008 | } | 1033 | } |
| 1009 | 1034 | ||
| 1010 | /* clean up prefsrc entries */ | 1035 | /* clean up prefsrc entries */ |
| @@ -1024,7 +1049,7 @@ static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, struct inet6_ifaddr *i | |||
| 1024 | u32 addr_flags; | 1049 | u32 addr_flags; |
| 1025 | unsigned long now = jiffies; | 1050 | unsigned long now = jiffies; |
| 1026 | 1051 | ||
| 1027 | write_lock(&idev->lock); | 1052 | write_lock_bh(&idev->lock); |
| 1028 | if (ift) { | 1053 | if (ift) { |
| 1029 | spin_lock_bh(&ift->lock); | 1054 | spin_lock_bh(&ift->lock); |
| 1030 | memcpy(&addr.s6_addr[8], &ift->addr.s6_addr[8], 8); | 1055 | memcpy(&addr.s6_addr[8], &ift->addr.s6_addr[8], 8); |
| @@ -1036,7 +1061,7 @@ static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, struct inet6_ifaddr *i | |||
| 1036 | retry: | 1061 | retry: |
| 1037 | in6_dev_hold(idev); | 1062 | in6_dev_hold(idev); |
| 1038 | if (idev->cnf.use_tempaddr <= 0) { | 1063 | if (idev->cnf.use_tempaddr <= 0) { |
| 1039 | write_unlock(&idev->lock); | 1064 | write_unlock_bh(&idev->lock); |
| 1040 | pr_info("%s: use_tempaddr is disabled\n", __func__); | 1065 | pr_info("%s: use_tempaddr is disabled\n", __func__); |
| 1041 | in6_dev_put(idev); | 1066 | in6_dev_put(idev); |
| 1042 | ret = -1; | 1067 | ret = -1; |
| @@ -1046,7 +1071,7 @@ retry: | |||
| 1046 | if (ifp->regen_count++ >= idev->cnf.regen_max_retry) { | 1071 | if (ifp->regen_count++ >= idev->cnf.regen_max_retry) { |
| 1047 | idev->cnf.use_tempaddr = -1; /*XXX*/ | 1072 | idev->cnf.use_tempaddr = -1; /*XXX*/ |
| 1048 | spin_unlock_bh(&ifp->lock); | 1073 | spin_unlock_bh(&ifp->lock); |
| 1049 | write_unlock(&idev->lock); | 1074 | write_unlock_bh(&idev->lock); |
| 1050 | pr_warn("%s: regeneration time exceeded - disabled temporary address support\n", | 1075 | pr_warn("%s: regeneration time exceeded - disabled temporary address support\n", |
| 1051 | __func__); | 1076 | __func__); |
| 1052 | in6_dev_put(idev); | 1077 | in6_dev_put(idev); |
| @@ -1071,8 +1096,8 @@ retry: | |||
| 1071 | 1096 | ||
| 1072 | regen_advance = idev->cnf.regen_max_retry * | 1097 | regen_advance = idev->cnf.regen_max_retry * |
| 1073 | idev->cnf.dad_transmits * | 1098 | idev->cnf.dad_transmits * |
| 1074 | idev->nd_parms->retrans_time / HZ; | 1099 | NEIGH_VAR(idev->nd_parms, RETRANS_TIME) / HZ; |
| 1075 | write_unlock(&idev->lock); | 1100 | write_unlock_bh(&idev->lock); |
| 1076 | 1101 | ||
| 1077 | /* A temporary address is created only if this calculated Preferred | 1102 | /* A temporary address is created only if this calculated Preferred |
| 1078 | * Lifetime is greater than REGEN_ADVANCE time units. In particular, | 1103 | * Lifetime is greater than REGEN_ADVANCE time units. In particular, |
| @@ -1099,7 +1124,7 @@ retry: | |||
| 1099 | in6_dev_put(idev); | 1124 | in6_dev_put(idev); |
| 1100 | pr_info("%s: retry temporary address regeneration\n", __func__); | 1125 | pr_info("%s: retry temporary address regeneration\n", __func__); |
| 1101 | tmpaddr = &addr; | 1126 | tmpaddr = &addr; |
| 1102 | write_lock(&idev->lock); | 1127 | write_lock_bh(&idev->lock); |
| 1103 | goto retry; | 1128 | goto retry; |
| 1104 | } | 1129 | } |
| 1105 | 1130 | ||
| @@ -1200,7 +1225,7 @@ static int ipv6_get_saddr_eval(struct net *net, | |||
| 1200 | * | d is scope of the destination. | 1225 | * | d is scope of the destination. |
| 1201 | * B-d | \ | 1226 | * B-d | \ |
| 1202 | * | \ <- smaller scope is better if | 1227 | * | \ <- smaller scope is better if |
| 1203 | * B-15 | \ if scope is enough for destinaion. | 1228 | * B-15 | \ if scope is enough for destination. |
| 1204 | * | ret = B - scope (-1 <= scope >= d <= 15). | 1229 | * | ret = B - scope (-1 <= scope >= d <= 15). |
| 1205 | * d-C-1 | / | 1230 | * d-C-1 | / |
| 1206 | * |/ <- greater is better | 1231 | * |/ <- greater is better |
| @@ -1407,12 +1432,14 @@ try_nextdev: | |||
| 1407 | EXPORT_SYMBOL(ipv6_dev_get_saddr); | 1432 | EXPORT_SYMBOL(ipv6_dev_get_saddr); |
| 1408 | 1433 | ||
| 1409 | int __ipv6_get_lladdr(struct inet6_dev *idev, struct in6_addr *addr, | 1434 | int __ipv6_get_lladdr(struct inet6_dev *idev, struct in6_addr *addr, |
| 1410 | unsigned char banned_flags) | 1435 | u32 banned_flags) |
| 1411 | { | 1436 | { |
| 1412 | struct inet6_ifaddr *ifp; | 1437 | struct inet6_ifaddr *ifp; |
| 1413 | int err = -EADDRNOTAVAIL; | 1438 | int err = -EADDRNOTAVAIL; |
| 1414 | 1439 | ||
| 1415 | list_for_each_entry(ifp, &idev->addr_list, if_list) { | 1440 | list_for_each_entry_reverse(ifp, &idev->addr_list, if_list) { |
| 1441 | if (ifp->scope > IFA_LINK) | ||
| 1442 | break; | ||
| 1416 | if (ifp->scope == IFA_LINK && | 1443 | if (ifp->scope == IFA_LINK && |
| 1417 | !(ifp->flags & banned_flags)) { | 1444 | !(ifp->flags & banned_flags)) { |
| 1418 | *addr = ifp->addr; | 1445 | *addr = ifp->addr; |
| @@ -1424,7 +1451,7 @@ int __ipv6_get_lladdr(struct inet6_dev *idev, struct in6_addr *addr, | |||
| 1424 | } | 1451 | } |
| 1425 | 1452 | ||
| 1426 | int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr, | 1453 | int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr, |
| 1427 | unsigned char banned_flags) | 1454 | u32 banned_flags) |
| 1428 | { | 1455 | { |
| 1429 | struct inet6_dev *idev; | 1456 | struct inet6_dev *idev; |
| 1430 | int err = -EADDRNOTAVAIL; | 1457 | int err = -EADDRNOTAVAIL; |
| @@ -1816,6 +1843,7 @@ static int ipv6_generate_eui64(u8 *eui, struct net_device *dev) | |||
| 1816 | return addrconf_ifid_sit(eui, dev); | 1843 | return addrconf_ifid_sit(eui, dev); |
| 1817 | case ARPHRD_IPGRE: | 1844 | case ARPHRD_IPGRE: |
| 1818 | return addrconf_ifid_gre(eui, dev); | 1845 | return addrconf_ifid_gre(eui, dev); |
| 1846 | case ARPHRD_6LOWPAN: | ||
| 1819 | case ARPHRD_IEEE802154: | 1847 | case ARPHRD_IEEE802154: |
| 1820 | return addrconf_ifid_eui64(eui, dev); | 1848 | return addrconf_ifid_eui64(eui, dev); |
| 1821 | case ARPHRD_IEEE1394: | 1849 | case ARPHRD_IEEE1394: |
| @@ -1832,7 +1860,9 @@ static int ipv6_inherit_eui64(u8 *eui, struct inet6_dev *idev) | |||
| 1832 | struct inet6_ifaddr *ifp; | 1860 | struct inet6_ifaddr *ifp; |
| 1833 | 1861 | ||
| 1834 | read_lock_bh(&idev->lock); | 1862 | read_lock_bh(&idev->lock); |
| 1835 | list_for_each_entry(ifp, &idev->addr_list, if_list) { | 1863 | list_for_each_entry_reverse(ifp, &idev->addr_list, if_list) { |
| 1864 | if (ifp->scope > IFA_LINK) | ||
| 1865 | break; | ||
| 1836 | if (ifp->scope == IFA_LINK && !(ifp->flags&IFA_F_TENTATIVE)) { | 1866 | if (ifp->scope == IFA_LINK && !(ifp->flags&IFA_F_TENTATIVE)) { |
| 1837 | memcpy(eui, ifp->addr.s6_addr+8, 8); | 1867 | memcpy(eui, ifp->addr.s6_addr+8, 8); |
| 1838 | err = 0; | 1868 | err = 0; |
| @@ -1888,7 +1918,8 @@ static void ipv6_regen_rndid(unsigned long data) | |||
| 1888 | 1918 | ||
| 1889 | expires = jiffies + | 1919 | expires = jiffies + |
| 1890 | idev->cnf.temp_prefered_lft * HZ - | 1920 | idev->cnf.temp_prefered_lft * HZ - |
| 1891 | idev->cnf.regen_max_retry * idev->cnf.dad_transmits * idev->nd_parms->retrans_time - | 1921 | idev->cnf.regen_max_retry * idev->cnf.dad_transmits * |
| 1922 | NEIGH_VAR(idev->nd_parms, RETRANS_TIME) - | ||
| 1892 | idev->cnf.max_desync_factor * HZ; | 1923 | idev->cnf.max_desync_factor * HZ; |
| 1893 | if (time_before(expires, jiffies)) { | 1924 | if (time_before(expires, jiffies)) { |
| 1894 | pr_warn("%s: too short regeneration interval; timer disabled for %s\n", | 1925 | pr_warn("%s: too short regeneration interval; timer disabled for %s\n", |
| @@ -2016,6 +2047,73 @@ static struct inet6_dev *addrconf_add_dev(struct net_device *dev) | |||
| 2016 | return idev; | 2047 | return idev; |
| 2017 | } | 2048 | } |
| 2018 | 2049 | ||
| 2050 | static void manage_tempaddrs(struct inet6_dev *idev, | ||
| 2051 | struct inet6_ifaddr *ifp, | ||
| 2052 | __u32 valid_lft, __u32 prefered_lft, | ||
| 2053 | bool create, unsigned long now) | ||
| 2054 | { | ||
| 2055 | u32 flags; | ||
| 2056 | struct inet6_ifaddr *ift; | ||
| 2057 | |||
| 2058 | read_lock_bh(&idev->lock); | ||
| 2059 | /* update all temporary addresses in the list */ | ||
| 2060 | list_for_each_entry(ift, &idev->tempaddr_list, tmp_list) { | ||
| 2061 | int age, max_valid, max_prefered; | ||
| 2062 | |||
| 2063 | if (ifp != ift->ifpub) | ||
| 2064 | continue; | ||
| 2065 | |||
| 2066 | /* RFC 4941 section 3.3: | ||
| 2067 | * If a received option will extend the lifetime of a public | ||
| 2068 | * address, the lifetimes of temporary addresses should | ||
| 2069 | * be extended, subject to the overall constraint that no | ||
| 2070 | * temporary addresses should ever remain "valid" or "preferred" | ||
| 2071 | * for a time longer than (TEMP_VALID_LIFETIME) or | ||
| 2072 | * (TEMP_PREFERRED_LIFETIME - DESYNC_FACTOR), respectively. | ||
| 2073 | */ | ||
| 2074 | age = (now - ift->cstamp) / HZ; | ||
| 2075 | max_valid = idev->cnf.temp_valid_lft - age; | ||
| 2076 | if (max_valid < 0) | ||
| 2077 | max_valid = 0; | ||
| 2078 | |||
| 2079 | max_prefered = idev->cnf.temp_prefered_lft - | ||
| 2080 | idev->cnf.max_desync_factor - age; | ||
| 2081 | if (max_prefered < 0) | ||
| 2082 | max_prefered = 0; | ||
| 2083 | |||
| 2084 | if (valid_lft > max_valid) | ||
| 2085 | valid_lft = max_valid; | ||
| 2086 | |||
| 2087 | if (prefered_lft > max_prefered) | ||
| 2088 | prefered_lft = max_prefered; | ||
| 2089 | |||
| 2090 | spin_lock(&ift->lock); | ||
| 2091 | flags = ift->flags; | ||
| 2092 | ift->valid_lft = valid_lft; | ||
| 2093 | ift->prefered_lft = prefered_lft; | ||
| 2094 | ift->tstamp = now; | ||
| 2095 | if (prefered_lft > 0) | ||
| 2096 | ift->flags &= ~IFA_F_DEPRECATED; | ||
| 2097 | |||
| 2098 | spin_unlock(&ift->lock); | ||
| 2099 | if (!(flags&IFA_F_TENTATIVE)) | ||
| 2100 | ipv6_ifa_notify(0, ift); | ||
| 2101 | } | ||
| 2102 | |||
| 2103 | if ((create || list_empty(&idev->tempaddr_list)) && | ||
| 2104 | idev->cnf.use_tempaddr > 0) { | ||
| 2105 | /* When a new public address is created as described | ||
| 2106 | * in [ADDRCONF], also create a new temporary address. | ||
| 2107 | * Also create a temporary address if it's enabled but | ||
| 2108 | * no temporary address currently exists. | ||
| 2109 | */ | ||
| 2110 | read_unlock_bh(&idev->lock); | ||
| 2111 | ipv6_create_tempaddr(ifp, NULL); | ||
| 2112 | } else { | ||
| 2113 | read_unlock_bh(&idev->lock); | ||
| 2114 | } | ||
| 2115 | } | ||
| 2116 | |||
| 2019 | void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len, bool sllao) | 2117 | void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len, bool sllao) |
| 2020 | { | 2118 | { |
| 2021 | struct prefix_info *pinfo; | 2119 | struct prefix_info *pinfo; |
| @@ -2170,6 +2268,7 @@ ok: | |||
| 2170 | return; | 2268 | return; |
| 2171 | } | 2269 | } |
| 2172 | 2270 | ||
| 2271 | ifp->flags |= IFA_F_MANAGETEMPADDR; | ||
| 2173 | update_lft = 0; | 2272 | update_lft = 0; |
| 2174 | create = 1; | 2273 | create = 1; |
| 2175 | ifp->cstamp = jiffies; | 2274 | ifp->cstamp = jiffies; |
| @@ -2178,9 +2277,8 @@ ok: | |||
| 2178 | } | 2277 | } |
| 2179 | 2278 | ||
| 2180 | if (ifp) { | 2279 | if (ifp) { |
| 2181 | int flags; | 2280 | u32 flags; |
| 2182 | unsigned long now; | 2281 | unsigned long now; |
| 2183 | struct inet6_ifaddr *ift; | ||
| 2184 | u32 stored_lft; | 2282 | u32 stored_lft; |
| 2185 | 2283 | ||
| 2186 | /* update lifetime (RFC2462 5.5.3 e) */ | 2284 | /* update lifetime (RFC2462 5.5.3 e) */ |
| @@ -2221,70 +2319,8 @@ ok: | |||
| 2221 | } else | 2319 | } else |
| 2222 | spin_unlock(&ifp->lock); | 2320 | spin_unlock(&ifp->lock); |
| 2223 | 2321 | ||
| 2224 | read_lock_bh(&in6_dev->lock); | 2322 | manage_tempaddrs(in6_dev, ifp, valid_lft, prefered_lft, |
| 2225 | /* update all temporary addresses in the list */ | 2323 | create, now); |
| 2226 | list_for_each_entry(ift, &in6_dev->tempaddr_list, | ||
| 2227 | tmp_list) { | ||
| 2228 | int age, max_valid, max_prefered; | ||
| 2229 | |||
| 2230 | if (ifp != ift->ifpub) | ||
| 2231 | continue; | ||
| 2232 | |||
| 2233 | /* | ||
| 2234 | * RFC 4941 section 3.3: | ||
| 2235 | * If a received option will extend the lifetime | ||
| 2236 | * of a public address, the lifetimes of | ||
| 2237 | * temporary addresses should be extended, | ||
| 2238 | * subject to the overall constraint that no | ||
| 2239 | * temporary addresses should ever remain | ||
| 2240 | * "valid" or "preferred" for a time longer than | ||
| 2241 | * (TEMP_VALID_LIFETIME) or | ||
| 2242 | * (TEMP_PREFERRED_LIFETIME - DESYNC_FACTOR), | ||
| 2243 | * respectively. | ||
| 2244 | */ | ||
| 2245 | age = (now - ift->cstamp) / HZ; | ||
| 2246 | max_valid = in6_dev->cnf.temp_valid_lft - age; | ||
| 2247 | if (max_valid < 0) | ||
| 2248 | max_valid = 0; | ||
| 2249 | |||
| 2250 | max_prefered = in6_dev->cnf.temp_prefered_lft - | ||
| 2251 | in6_dev->cnf.max_desync_factor - | ||
| 2252 | age; | ||
| 2253 | if (max_prefered < 0) | ||
| 2254 | max_prefered = 0; | ||
| 2255 | |||
| 2256 | if (valid_lft > max_valid) | ||
| 2257 | valid_lft = max_valid; | ||
| 2258 | |||
| 2259 | if (prefered_lft > max_prefered) | ||
| 2260 | prefered_lft = max_prefered; | ||
| 2261 | |||
| 2262 | spin_lock(&ift->lock); | ||
| 2263 | flags = ift->flags; | ||
| 2264 | ift->valid_lft = valid_lft; | ||
| 2265 | ift->prefered_lft = prefered_lft; | ||
| 2266 | ift->tstamp = now; | ||
| 2267 | if (prefered_lft > 0) | ||
| 2268 | ift->flags &= ~IFA_F_DEPRECATED; | ||
| 2269 | |||
| 2270 | spin_unlock(&ift->lock); | ||
| 2271 | if (!(flags&IFA_F_TENTATIVE)) | ||
| 2272 | ipv6_ifa_notify(0, ift); | ||
| 2273 | } | ||
| 2274 | |||
| 2275 | if ((create || list_empty(&in6_dev->tempaddr_list)) && in6_dev->cnf.use_tempaddr > 0) { | ||
| 2276 | /* | ||
| 2277 | * When a new public address is created as | ||
| 2278 | * described in [ADDRCONF], also create a new | ||
| 2279 | * temporary address. Also create a temporary | ||
| 2280 | * address if it's enabled but no temporary | ||
| 2281 | * address currently exists. | ||
| 2282 | */ | ||
| 2283 | read_unlock_bh(&in6_dev->lock); | ||
| 2284 | ipv6_create_tempaddr(ifp, NULL); | ||
| 2285 | } else { | ||
| 2286 | read_unlock_bh(&in6_dev->lock); | ||
| 2287 | } | ||
| 2288 | 2324 | ||
| 2289 | in6_ifa_put(ifp); | 2325 | in6_ifa_put(ifp); |
| 2290 | addrconf_verify(0); | 2326 | addrconf_verify(0); |
| @@ -2363,10 +2399,11 @@ err_exit: | |||
| 2363 | /* | 2399 | /* |
| 2364 | * Manual configuration of address on an interface | 2400 | * Manual configuration of address on an interface |
| 2365 | */ | 2401 | */ |
| 2366 | static int inet6_addr_add(struct net *net, int ifindex, const struct in6_addr *pfx, | 2402 | static int inet6_addr_add(struct net *net, int ifindex, |
| 2403 | const struct in6_addr *pfx, | ||
| 2367 | const struct in6_addr *peer_pfx, | 2404 | const struct in6_addr *peer_pfx, |
| 2368 | unsigned int plen, __u8 ifa_flags, __u32 prefered_lft, | 2405 | unsigned int plen, __u32 ifa_flags, |
| 2369 | __u32 valid_lft) | 2406 | __u32 prefered_lft, __u32 valid_lft) |
| 2370 | { | 2407 | { |
| 2371 | struct inet6_ifaddr *ifp; | 2408 | struct inet6_ifaddr *ifp; |
| 2372 | struct inet6_dev *idev; | 2409 | struct inet6_dev *idev; |
| @@ -2385,6 +2422,9 @@ static int inet6_addr_add(struct net *net, int ifindex, const struct in6_addr *p | |||
| 2385 | if (!valid_lft || prefered_lft > valid_lft) | 2422 | if (!valid_lft || prefered_lft > valid_lft) |
| 2386 | return -EINVAL; | 2423 | return -EINVAL; |
| 2387 | 2424 | ||
| 2425 | if (ifa_flags & IFA_F_MANAGETEMPADDR && plen != 64) | ||
| 2426 | return -EINVAL; | ||
| 2427 | |||
| 2388 | dev = __dev_get_by_index(net, ifindex); | 2428 | dev = __dev_get_by_index(net, ifindex); |
| 2389 | if (!dev) | 2429 | if (!dev) |
| 2390 | return -ENODEV; | 2430 | return -ENODEV; |
| @@ -2417,14 +2457,20 @@ static int inet6_addr_add(struct net *net, int ifindex, const struct in6_addr *p | |||
| 2417 | valid_lft, prefered_lft); | 2457 | valid_lft, prefered_lft); |
| 2418 | 2458 | ||
| 2419 | if (!IS_ERR(ifp)) { | 2459 | if (!IS_ERR(ifp)) { |
| 2420 | addrconf_prefix_route(&ifp->addr, ifp->prefix_len, dev, | 2460 | if (!(ifa_flags & IFA_F_NOPREFIXROUTE)) { |
| 2421 | expires, flags); | 2461 | addrconf_prefix_route(&ifp->addr, ifp->prefix_len, dev, |
| 2462 | expires, flags); | ||
| 2463 | } | ||
| 2464 | |||
| 2422 | /* | 2465 | /* |
| 2423 | * Note that section 3.1 of RFC 4429 indicates | 2466 | * Note that section 3.1 of RFC 4429 indicates |
| 2424 | * that the Optimistic flag should not be set for | 2467 | * that the Optimistic flag should not be set for |
| 2425 | * manually configured addresses | 2468 | * manually configured addresses |
| 2426 | */ | 2469 | */ |
| 2427 | addrconf_dad_start(ifp); | 2470 | addrconf_dad_start(ifp); |
| 2471 | if (ifa_flags & IFA_F_MANAGETEMPADDR) | ||
| 2472 | manage_tempaddrs(idev, ifp, valid_lft, prefered_lft, | ||
| 2473 | true, jiffies); | ||
| 2428 | in6_ifa_put(ifp); | 2474 | in6_ifa_put(ifp); |
| 2429 | addrconf_verify(0); | 2475 | addrconf_verify(0); |
| 2430 | return 0; | 2476 | return 0; |
| @@ -2611,8 +2657,18 @@ static void init_loopback(struct net_device *dev) | |||
| 2611 | if (sp_ifa->flags & (IFA_F_DADFAILED | IFA_F_TENTATIVE)) | 2657 | if (sp_ifa->flags & (IFA_F_DADFAILED | IFA_F_TENTATIVE)) |
| 2612 | continue; | 2658 | continue; |
| 2613 | 2659 | ||
| 2614 | if (sp_ifa->rt) | 2660 | if (sp_ifa->rt) { |
| 2615 | continue; | 2661 | /* This dst has been added to garbage list when |
| 2662 | * lo device down, release this obsolete dst and | ||
| 2663 | * reallocate a new router for ifa. | ||
| 2664 | */ | ||
| 2665 | if (sp_ifa->rt->dst.obsolete > 0) { | ||
| 2666 | ip6_rt_put(sp_ifa->rt); | ||
| 2667 | sp_ifa->rt = NULL; | ||
| 2668 | } else { | ||
| 2669 | continue; | ||
| 2670 | } | ||
| 2671 | } | ||
| 2616 | 2672 | ||
| 2617 | sp_rt = addrconf_dst_alloc(idev, &sp_ifa->addr, false); | 2673 | sp_rt = addrconf_dst_alloc(idev, &sp_ifa->addr, false); |
| 2618 | 2674 | ||
| @@ -2660,7 +2716,8 @@ static void addrconf_dev_config(struct net_device *dev) | |||
| 2660 | (dev->type != ARPHRD_INFINIBAND) && | 2716 | (dev->type != ARPHRD_INFINIBAND) && |
| 2661 | (dev->type != ARPHRD_IEEE802154) && | 2717 | (dev->type != ARPHRD_IEEE802154) && |
| 2662 | (dev->type != ARPHRD_IEEE1394) && | 2718 | (dev->type != ARPHRD_IEEE1394) && |
| 2663 | (dev->type != ARPHRD_TUNNEL6)) { | 2719 | (dev->type != ARPHRD_TUNNEL6) && |
| 2720 | (dev->type != ARPHRD_6LOWPAN)) { | ||
| 2664 | /* Alas, we support only Ethernet autoconfiguration. */ | 2721 | /* Alas, we support only Ethernet autoconfiguration. */ |
| 2665 | return; | 2722 | return; |
| 2666 | } | 2723 | } |
| @@ -2857,7 +2914,7 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event, | |||
| 2857 | } | 2914 | } |
| 2858 | 2915 | ||
| 2859 | /* | 2916 | /* |
| 2860 | * MTU falled under IPV6_MIN_MTU. | 2917 | * if MTU under IPV6_MIN_MTU. |
| 2861 | * Stop IPv6 on this interface. | 2918 | * Stop IPv6 on this interface. |
| 2862 | */ | 2919 | */ |
| 2863 | 2920 | ||
| @@ -3083,7 +3140,7 @@ static void addrconf_dad_kick(struct inet6_ifaddr *ifp) | |||
| 3083 | if (ifp->flags & IFA_F_OPTIMISTIC) | 3140 | if (ifp->flags & IFA_F_OPTIMISTIC) |
| 3084 | rand_num = 0; | 3141 | rand_num = 0; |
| 3085 | else | 3142 | else |
| 3086 | rand_num = net_random() % (idev->cnf.rtr_solicit_delay ? : 1); | 3143 | rand_num = prandom_u32() % (idev->cnf.rtr_solicit_delay ? : 1); |
| 3087 | 3144 | ||
| 3088 | ifp->dad_probes = idev->cnf.dad_transmits; | 3145 | ifp->dad_probes = idev->cnf.dad_transmits; |
| 3089 | addrconf_mod_dad_timer(ifp, rand_num); | 3146 | addrconf_mod_dad_timer(ifp, rand_num); |
| @@ -3096,7 +3153,7 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp) | |||
| 3096 | 3153 | ||
| 3097 | addrconf_join_solict(dev, &ifp->addr); | 3154 | addrconf_join_solict(dev, &ifp->addr); |
| 3098 | 3155 | ||
| 3099 | net_srandom(ifp->addr.s6_addr32[3]); | 3156 | prandom_seed((__force u32) ifp->addr.s6_addr32[3]); |
| 3100 | 3157 | ||
| 3101 | read_lock_bh(&idev->lock); | 3158 | read_lock_bh(&idev->lock); |
| 3102 | spin_lock(&ifp->lock); | 3159 | spin_lock(&ifp->lock); |
| @@ -3178,7 +3235,8 @@ static void addrconf_dad_timer(unsigned long data) | |||
| 3178 | } | 3235 | } |
| 3179 | 3236 | ||
| 3180 | ifp->dad_probes--; | 3237 | ifp->dad_probes--; |
| 3181 | addrconf_mod_dad_timer(ifp, ifp->idev->nd_parms->retrans_time); | 3238 | addrconf_mod_dad_timer(ifp, |
| 3239 | NEIGH_VAR(ifp->idev->nd_parms, RETRANS_TIME)); | ||
| 3182 | spin_unlock(&ifp->lock); | 3240 | spin_unlock(&ifp->lock); |
| 3183 | write_unlock(&idev->lock); | 3241 | write_unlock(&idev->lock); |
| 3184 | 3242 | ||
| @@ -3195,7 +3253,9 @@ static bool ipv6_lonely_lladdr(struct inet6_ifaddr *ifp) | |||
| 3195 | struct inet6_ifaddr *ifpiter; | 3253 | struct inet6_ifaddr *ifpiter; |
| 3196 | struct inet6_dev *idev = ifp->idev; | 3254 | struct inet6_dev *idev = ifp->idev; |
| 3197 | 3255 | ||
| 3198 | list_for_each_entry(ifpiter, &idev->addr_list, if_list) { | 3256 | list_for_each_entry_reverse(ifpiter, &idev->addr_list, if_list) { |
| 3257 | if (ifpiter->scope > IFA_LINK) | ||
| 3258 | break; | ||
| 3199 | if (ifp != ifpiter && ifpiter->scope == IFA_LINK && | 3259 | if (ifp != ifpiter && ifpiter->scope == IFA_LINK && |
| 3200 | (ifpiter->flags & (IFA_F_PERMANENT|IFA_F_TENTATIVE| | 3260 | (ifpiter->flags & (IFA_F_PERMANENT|IFA_F_TENTATIVE| |
| 3201 | IFA_F_OPTIMISTIC|IFA_F_DADFAILED)) == | 3261 | IFA_F_OPTIMISTIC|IFA_F_DADFAILED)) == |
| @@ -3371,7 +3431,7 @@ static int if6_seq_show(struct seq_file *seq, void *v) | |||
| 3371 | ifp->idev->dev->ifindex, | 3431 | ifp->idev->dev->ifindex, |
| 3372 | ifp->prefix_len, | 3432 | ifp->prefix_len, |
| 3373 | ifp->scope, | 3433 | ifp->scope, |
| 3374 | ifp->flags, | 3434 | (u8) ifp->flags, |
| 3375 | ifp->idev->dev->name); | 3435 | ifp->idev->dev->name); |
| 3376 | return 0; | 3436 | return 0; |
| 3377 | } | 3437 | } |
| @@ -3518,7 +3578,7 @@ restart: | |||
| 3518 | !(ifp->flags&IFA_F_TENTATIVE)) { | 3578 | !(ifp->flags&IFA_F_TENTATIVE)) { |
| 3519 | unsigned long regen_advance = ifp->idev->cnf.regen_max_retry * | 3579 | unsigned long regen_advance = ifp->idev->cnf.regen_max_retry * |
| 3520 | ifp->idev->cnf.dad_transmits * | 3580 | ifp->idev->cnf.dad_transmits * |
| 3521 | ifp->idev->nd_parms->retrans_time / HZ; | 3581 | NEIGH_VAR(ifp->idev->nd_parms, RETRANS_TIME) / HZ; |
| 3522 | 3582 | ||
| 3523 | if (age >= ifp->prefered_lft - regen_advance) { | 3583 | if (age >= ifp->prefered_lft - regen_advance) { |
| 3524 | struct inet6_ifaddr *ifpub = ifp->ifpub; | 3584 | struct inet6_ifaddr *ifpub = ifp->ifpub; |
| @@ -3593,6 +3653,7 @@ static const struct nla_policy ifa_ipv6_policy[IFA_MAX+1] = { | |||
| 3593 | [IFA_ADDRESS] = { .len = sizeof(struct in6_addr) }, | 3653 | [IFA_ADDRESS] = { .len = sizeof(struct in6_addr) }, |
| 3594 | [IFA_LOCAL] = { .len = sizeof(struct in6_addr) }, | 3654 | [IFA_LOCAL] = { .len = sizeof(struct in6_addr) }, |
| 3595 | [IFA_CACHEINFO] = { .len = sizeof(struct ifa_cacheinfo) }, | 3655 | [IFA_CACHEINFO] = { .len = sizeof(struct ifa_cacheinfo) }, |
| 3656 | [IFA_FLAGS] = { .len = sizeof(u32) }, | ||
| 3596 | }; | 3657 | }; |
| 3597 | 3658 | ||
| 3598 | static int | 3659 | static int |
| @@ -3616,16 +3677,22 @@ inet6_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
| 3616 | return inet6_addr_del(net, ifm->ifa_index, pfx, ifm->ifa_prefixlen); | 3677 | return inet6_addr_del(net, ifm->ifa_index, pfx, ifm->ifa_prefixlen); |
| 3617 | } | 3678 | } |
| 3618 | 3679 | ||
| 3619 | static int inet6_addr_modify(struct inet6_ifaddr *ifp, u8 ifa_flags, | 3680 | static int inet6_addr_modify(struct inet6_ifaddr *ifp, u32 ifa_flags, |
| 3620 | u32 prefered_lft, u32 valid_lft) | 3681 | u32 prefered_lft, u32 valid_lft) |
| 3621 | { | 3682 | { |
| 3622 | u32 flags; | 3683 | u32 flags; |
| 3623 | clock_t expires; | 3684 | clock_t expires; |
| 3624 | unsigned long timeout; | 3685 | unsigned long timeout; |
| 3686 | bool was_managetempaddr; | ||
| 3687 | bool had_prefixroute; | ||
| 3625 | 3688 | ||
| 3626 | if (!valid_lft || (prefered_lft > valid_lft)) | 3689 | if (!valid_lft || (prefered_lft > valid_lft)) |
| 3627 | return -EINVAL; | 3690 | return -EINVAL; |
| 3628 | 3691 | ||
| 3692 | if (ifa_flags & IFA_F_MANAGETEMPADDR && | ||
| 3693 | (ifp->flags & IFA_F_TEMPORARY || ifp->prefix_len != 64)) | ||
| 3694 | return -EINVAL; | ||
| 3695 | |||
| 3629 | timeout = addrconf_timeout_fixup(valid_lft, HZ); | 3696 | timeout = addrconf_timeout_fixup(valid_lft, HZ); |
| 3630 | if (addrconf_finite_timeout(timeout)) { | 3697 | if (addrconf_finite_timeout(timeout)) { |
| 3631 | expires = jiffies_to_clock_t(timeout * HZ); | 3698 | expires = jiffies_to_clock_t(timeout * HZ); |
| @@ -3645,7 +3712,13 @@ static int inet6_addr_modify(struct inet6_ifaddr *ifp, u8 ifa_flags, | |||
| 3645 | } | 3712 | } |
| 3646 | 3713 | ||
| 3647 | spin_lock_bh(&ifp->lock); | 3714 | spin_lock_bh(&ifp->lock); |
| 3648 | ifp->flags = (ifp->flags & ~(IFA_F_DEPRECATED | IFA_F_PERMANENT | IFA_F_NODAD | IFA_F_HOMEADDRESS)) | ifa_flags; | 3715 | was_managetempaddr = ifp->flags & IFA_F_MANAGETEMPADDR; |
| 3716 | had_prefixroute = ifp->flags & IFA_F_PERMANENT && | ||
| 3717 | !(ifp->flags & IFA_F_NOPREFIXROUTE); | ||
| 3718 | ifp->flags &= ~(IFA_F_DEPRECATED | IFA_F_PERMANENT | IFA_F_NODAD | | ||
| 3719 | IFA_F_HOMEADDRESS | IFA_F_MANAGETEMPADDR | | ||
| 3720 | IFA_F_NOPREFIXROUTE); | ||
| 3721 | ifp->flags |= ifa_flags; | ||
| 3649 | ifp->tstamp = jiffies; | 3722 | ifp->tstamp = jiffies; |
| 3650 | ifp->valid_lft = valid_lft; | 3723 | ifp->valid_lft = valid_lft; |
| 3651 | ifp->prefered_lft = prefered_lft; | 3724 | ifp->prefered_lft = prefered_lft; |
| @@ -3654,8 +3727,30 @@ static int inet6_addr_modify(struct inet6_ifaddr *ifp, u8 ifa_flags, | |||
| 3654 | if (!(ifp->flags&IFA_F_TENTATIVE)) | 3727 | if (!(ifp->flags&IFA_F_TENTATIVE)) |
| 3655 | ipv6_ifa_notify(0, ifp); | 3728 | ipv6_ifa_notify(0, ifp); |
| 3656 | 3729 | ||
| 3657 | addrconf_prefix_route(&ifp->addr, ifp->prefix_len, ifp->idev->dev, | 3730 | if (!(ifa_flags & IFA_F_NOPREFIXROUTE)) { |
| 3658 | expires, flags); | 3731 | addrconf_prefix_route(&ifp->addr, ifp->prefix_len, ifp->idev->dev, |
| 3732 | expires, flags); | ||
| 3733 | } else if (had_prefixroute) { | ||
| 3734 | enum cleanup_prefix_rt_t action; | ||
| 3735 | unsigned long rt_expires; | ||
| 3736 | |||
| 3737 | write_lock_bh(&ifp->idev->lock); | ||
| 3738 | action = check_cleanup_prefix_route(ifp, &rt_expires); | ||
| 3739 | write_unlock_bh(&ifp->idev->lock); | ||
| 3740 | |||
| 3741 | if (action != CLEANUP_PREFIX_RT_NOP) { | ||
| 3742 | cleanup_prefix_route(ifp, rt_expires, | ||
| 3743 | action == CLEANUP_PREFIX_RT_DEL); | ||
| 3744 | } | ||
| 3745 | } | ||
| 3746 | |||
| 3747 | if (was_managetempaddr || ifp->flags & IFA_F_MANAGETEMPADDR) { | ||
| 3748 | if (was_managetempaddr && !(ifp->flags & IFA_F_MANAGETEMPADDR)) | ||
| 3749 | valid_lft = prefered_lft = 0; | ||
| 3750 | manage_tempaddrs(ifp->idev, ifp, valid_lft, prefered_lft, | ||
| 3751 | !was_managetempaddr, jiffies); | ||
| 3752 | } | ||
| 3753 | |||
| 3659 | addrconf_verify(0); | 3754 | addrconf_verify(0); |
| 3660 | 3755 | ||
| 3661 | return 0; | 3756 | return 0; |
| @@ -3671,7 +3766,7 @@ inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
| 3671 | struct inet6_ifaddr *ifa; | 3766 | struct inet6_ifaddr *ifa; |
| 3672 | struct net_device *dev; | 3767 | struct net_device *dev; |
| 3673 | u32 valid_lft = INFINITY_LIFE_TIME, preferred_lft = INFINITY_LIFE_TIME; | 3768 | u32 valid_lft = INFINITY_LIFE_TIME, preferred_lft = INFINITY_LIFE_TIME; |
| 3674 | u8 ifa_flags; | 3769 | u32 ifa_flags; |
| 3675 | int err; | 3770 | int err; |
| 3676 | 3771 | ||
| 3677 | err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv6_policy); | 3772 | err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv6_policy); |
| @@ -3698,14 +3793,17 @@ inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
| 3698 | if (dev == NULL) | 3793 | if (dev == NULL) |
| 3699 | return -ENODEV; | 3794 | return -ENODEV; |
| 3700 | 3795 | ||
| 3796 | ifa_flags = tb[IFA_FLAGS] ? nla_get_u32(tb[IFA_FLAGS]) : ifm->ifa_flags; | ||
| 3797 | |||
| 3701 | /* We ignore other flags so far. */ | 3798 | /* We ignore other flags so far. */ |
| 3702 | ifa_flags = ifm->ifa_flags & (IFA_F_NODAD | IFA_F_HOMEADDRESS); | 3799 | ifa_flags &= IFA_F_NODAD | IFA_F_HOMEADDRESS | IFA_F_MANAGETEMPADDR | |
| 3800 | IFA_F_NOPREFIXROUTE; | ||
| 3703 | 3801 | ||
| 3704 | ifa = ipv6_get_ifaddr(net, pfx, dev, 1); | 3802 | ifa = ipv6_get_ifaddr(net, pfx, dev, 1); |
| 3705 | if (ifa == NULL) { | 3803 | if (ifa == NULL) { |
| 3706 | /* | 3804 | /* |
| 3707 | * It would be best to check for !NLM_F_CREATE here but | 3805 | * It would be best to check for !NLM_F_CREATE here but |
| 3708 | * userspace alreay relies on not having to provide this. | 3806 | * userspace already relies on not having to provide this. |
| 3709 | */ | 3807 | */ |
| 3710 | return inet6_addr_add(net, ifm->ifa_index, pfx, peer_pfx, | 3808 | return inet6_addr_add(net, ifm->ifa_index, pfx, peer_pfx, |
| 3711 | ifm->ifa_prefixlen, ifa_flags, | 3809 | ifm->ifa_prefixlen, ifa_flags, |
| @@ -3723,7 +3821,7 @@ inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
| 3723 | return err; | 3821 | return err; |
| 3724 | } | 3822 | } |
| 3725 | 3823 | ||
| 3726 | static void put_ifaddrmsg(struct nlmsghdr *nlh, u8 prefixlen, u8 flags, | 3824 | static void put_ifaddrmsg(struct nlmsghdr *nlh, u8 prefixlen, u32 flags, |
| 3727 | u8 scope, int ifindex) | 3825 | u8 scope, int ifindex) |
| 3728 | { | 3826 | { |
| 3729 | struct ifaddrmsg *ifm; | 3827 | struct ifaddrmsg *ifm; |
| @@ -3766,7 +3864,8 @@ static inline int inet6_ifaddr_msgsize(void) | |||
| 3766 | return NLMSG_ALIGN(sizeof(struct ifaddrmsg)) | 3864 | return NLMSG_ALIGN(sizeof(struct ifaddrmsg)) |
| 3767 | + nla_total_size(16) /* IFA_LOCAL */ | 3865 | + nla_total_size(16) /* IFA_LOCAL */ |
| 3768 | + nla_total_size(16) /* IFA_ADDRESS */ | 3866 | + nla_total_size(16) /* IFA_ADDRESS */ |
| 3769 | + nla_total_size(sizeof(struct ifa_cacheinfo)); | 3867 | + nla_total_size(sizeof(struct ifa_cacheinfo)) |
| 3868 | + nla_total_size(4) /* IFA_FLAGS */; | ||
| 3770 | } | 3869 | } |
| 3771 | 3870 | ||
| 3772 | static int inet6_fill_ifaddr(struct sk_buff *skb, struct inet6_ifaddr *ifa, | 3871 | static int inet6_fill_ifaddr(struct sk_buff *skb, struct inet6_ifaddr *ifa, |
| @@ -3815,6 +3914,9 @@ static int inet6_fill_ifaddr(struct sk_buff *skb, struct inet6_ifaddr *ifa, | |||
| 3815 | if (put_cacheinfo(skb, ifa->cstamp, ifa->tstamp, preferred, valid) < 0) | 3914 | if (put_cacheinfo(skb, ifa->cstamp, ifa->tstamp, preferred, valid) < 0) |
| 3816 | goto error; | 3915 | goto error; |
| 3817 | 3916 | ||
| 3917 | if (nla_put_u32(skb, IFA_FLAGS, ifa->flags) < 0) | ||
| 3918 | goto error; | ||
| 3919 | |||
| 3818 | return nlmsg_end(skb, nlh); | 3920 | return nlmsg_end(skb, nlh); |
| 3819 | 3921 | ||
| 3820 | error: | 3922 | error: |
| @@ -4218,7 +4320,7 @@ static int inet6_fill_ifla6_attrs(struct sk_buff *skb, struct inet6_dev *idev) | |||
| 4218 | ci.max_reasm_len = IPV6_MAXPLEN; | 4320 | ci.max_reasm_len = IPV6_MAXPLEN; |
| 4219 | ci.tstamp = cstamp_delta(idev->tstamp); | 4321 | ci.tstamp = cstamp_delta(idev->tstamp); |
| 4220 | ci.reachable_time = jiffies_to_msecs(idev->nd_parms->reachable_time); | 4322 | ci.reachable_time = jiffies_to_msecs(idev->nd_parms->reachable_time); |
| 4221 | ci.retrans_time = jiffies_to_msecs(idev->nd_parms->retrans_time); | 4323 | ci.retrans_time = jiffies_to_msecs(NEIGH_VAR(idev->nd_parms, RETRANS_TIME)); |
| 4222 | if (nla_put(skb, IFLA_INET6_CACHEINFO, sizeof(ci), &ci)) | 4324 | if (nla_put(skb, IFLA_INET6_CACHEINFO, sizeof(ci), &ci)) |
| 4223 | goto nla_put_failure; | 4325 | goto nla_put_failure; |
| 4224 | nla = nla_reserve(skb, IFLA_INET6_CONF, DEVCONF_MAX * sizeof(s32)); | 4326 | nla = nla_reserve(skb, IFLA_INET6_CONF, DEVCONF_MAX * sizeof(s32)); |
| @@ -4694,6 +4796,46 @@ int addrconf_sysctl_disable(struct ctl_table *ctl, int write, | |||
| 4694 | return ret; | 4796 | return ret; |
| 4695 | } | 4797 | } |
| 4696 | 4798 | ||
| 4799 | static | ||
| 4800 | int addrconf_sysctl_proxy_ndp(struct ctl_table *ctl, int write, | ||
| 4801 | void __user *buffer, size_t *lenp, loff_t *ppos) | ||
| 4802 | { | ||
| 4803 | int *valp = ctl->data; | ||
| 4804 | int ret; | ||
| 4805 | int old, new; | ||
| 4806 | |||
| 4807 | old = *valp; | ||
| 4808 | ret = proc_dointvec(ctl, write, buffer, lenp, ppos); | ||
| 4809 | new = *valp; | ||
| 4810 | |||
| 4811 | if (write && old != new) { | ||
| 4812 | struct net *net = ctl->extra2; | ||
| 4813 | |||
| 4814 | if (!rtnl_trylock()) | ||
| 4815 | return restart_syscall(); | ||
| 4816 | |||
| 4817 | if (valp == &net->ipv6.devconf_dflt->proxy_ndp) | ||
| 4818 | inet6_netconf_notify_devconf(net, NETCONFA_PROXY_NEIGH, | ||
| 4819 | NETCONFA_IFINDEX_DEFAULT, | ||
| 4820 | net->ipv6.devconf_dflt); | ||
| 4821 | else if (valp == &net->ipv6.devconf_all->proxy_ndp) | ||
| 4822 | inet6_netconf_notify_devconf(net, NETCONFA_PROXY_NEIGH, | ||
| 4823 | NETCONFA_IFINDEX_ALL, | ||
| 4824 | net->ipv6.devconf_all); | ||
| 4825 | else { | ||
| 4826 | struct inet6_dev *idev = ctl->extra1; | ||
| 4827 | |||
| 4828 | inet6_netconf_notify_devconf(net, NETCONFA_PROXY_NEIGH, | ||
| 4829 | idev->dev->ifindex, | ||
| 4830 | &idev->cnf); | ||
| 4831 | } | ||
| 4832 | rtnl_unlock(); | ||
| 4833 | } | ||
| 4834 | |||
| 4835 | return ret; | ||
| 4836 | } | ||
| 4837 | |||
| 4838 | |||
| 4697 | static struct addrconf_sysctl_table | 4839 | static struct addrconf_sysctl_table |
| 4698 | { | 4840 | { |
| 4699 | struct ctl_table_header *sysctl_header; | 4841 | struct ctl_table_header *sysctl_header; |
| @@ -4880,7 +5022,7 @@ static struct addrconf_sysctl_table | |||
| 4880 | .data = &ipv6_devconf.proxy_ndp, | 5022 | .data = &ipv6_devconf.proxy_ndp, |
| 4881 | .maxlen = sizeof(int), | 5023 | .maxlen = sizeof(int), |
| 4882 | .mode = 0644, | 5024 | .mode = 0644, |
| 4883 | .proc_handler = proc_dointvec, | 5025 | .proc_handler = addrconf_sysctl_proxy_ndp, |
| 4884 | }, | 5026 | }, |
| 4885 | { | 5027 | { |
| 4886 | .procname = "accept_source_route", | 5028 | .procname = "accept_source_route", |
| @@ -4996,7 +5138,7 @@ static void __addrconf_sysctl_unregister(struct ipv6_devconf *p) | |||
| 4996 | 5138 | ||
| 4997 | static void addrconf_sysctl_register(struct inet6_dev *idev) | 5139 | static void addrconf_sysctl_register(struct inet6_dev *idev) |
| 4998 | { | 5140 | { |
| 4999 | neigh_sysctl_register(idev->dev, idev->nd_parms, "ipv6", | 5141 | neigh_sysctl_register(idev->dev, idev->nd_parms, |
| 5000 | &ndisc_ifinfo_sysctl_change); | 5142 | &ndisc_ifinfo_sysctl_change); |
| 5001 | __addrconf_sysctl_register(dev_net(idev->dev), idev->dev->name, | 5143 | __addrconf_sysctl_register(dev_net(idev->dev), idev->dev->name, |
| 5002 | idev, &idev->cnf); | 5144 | idev, &idev->cnf); |
| @@ -5129,9 +5271,7 @@ int __init addrconf_init(void) | |||
| 5129 | 5271 | ||
| 5130 | addrconf_verify(0); | 5272 | addrconf_verify(0); |
| 5131 | 5273 | ||
| 5132 | err = rtnl_af_register(&inet6_ops); | 5274 | rtnl_af_register(&inet6_ops); |
| 5133 | if (err < 0) | ||
| 5134 | goto errout_af; | ||
| 5135 | 5275 | ||
| 5136 | err = __rtnl_register(PF_INET6, RTM_GETLINK, NULL, inet6_dump_ifinfo, | 5276 | err = __rtnl_register(PF_INET6, RTM_GETLINK, NULL, inet6_dump_ifinfo, |
| 5137 | NULL); | 5277 | NULL); |
| @@ -5155,7 +5295,6 @@ int __init addrconf_init(void) | |||
| 5155 | return 0; | 5295 | return 0; |
| 5156 | errout: | 5296 | errout: |
| 5157 | rtnl_af_unregister(&inet6_ops); | 5297 | rtnl_af_unregister(&inet6_ops); |
| 5158 | errout_af: | ||
| 5159 | unregister_netdevice_notifier(&ipv6_dev_notf); | 5298 | unregister_netdevice_notifier(&ipv6_dev_notf); |
| 5160 | errlo: | 5299 | errlo: |
| 5161 | unregister_pernet_subsys(&addrconf_ops); | 5300 | unregister_pernet_subsys(&addrconf_ops); |
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 4fbdb7046d28..d935889f1008 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c | |||
| @@ -213,7 +213,7 @@ lookup_protocol: | |||
| 213 | inet->mc_list = NULL; | 213 | inet->mc_list = NULL; |
| 214 | inet->rcv_tos = 0; | 214 | inet->rcv_tos = 0; |
| 215 | 215 | ||
| 216 | if (ipv4_config.no_pmtu_disc) | 216 | if (net->ipv4.sysctl_ip_no_pmtu_disc) |
| 217 | inet->pmtudisc = IP_PMTUDISC_DONT; | 217 | inet->pmtudisc = IP_PMTUDISC_DONT; |
| 218 | else | 218 | else |
| 219 | inet->pmtudisc = IP_PMTUDISC_WANT; | 219 | inet->pmtudisc = IP_PMTUDISC_WANT; |
| @@ -661,7 +661,7 @@ int inet6_sk_rebuild_header(struct sock *sk) | |||
| 661 | 661 | ||
| 662 | final_p = fl6_update_dst(&fl6, np->opt, &final); | 662 | final_p = fl6_update_dst(&fl6, np->opt, &final); |
| 663 | 663 | ||
| 664 | dst = ip6_dst_lookup_flow(sk, &fl6, final_p, false); | 664 | dst = ip6_dst_lookup_flow(sk, &fl6, final_p); |
| 665 | if (IS_ERR(dst)) { | 665 | if (IS_ERR(dst)) { |
| 666 | sk->sk_route_caps = 0; | 666 | sk->sk_route_caps = 0; |
| 667 | sk->sk_err_soft = -PTR_ERR(dst); | 667 | sk->sk_err_soft = -PTR_ERR(dst); |
| @@ -683,8 +683,7 @@ bool ipv6_opt_accepted(const struct sock *sk, const struct sk_buff *skb) | |||
| 683 | if (np->rxopt.all) { | 683 | if (np->rxopt.all) { |
| 684 | if ((opt->hop && (np->rxopt.bits.hopopts || | 684 | if ((opt->hop && (np->rxopt.bits.hopopts || |
| 685 | np->rxopt.bits.ohopopts)) || | 685 | np->rxopt.bits.ohopopts)) || |
| 686 | ((IPV6_FLOWINFO_MASK & | 686 | (ip6_flowinfo((struct ipv6hdr *) skb_network_header(skb)) && |
| 687 | *(__be32 *)skb_network_header(skb)) && | ||
| 688 | np->rxopt.bits.rxflow) || | 687 | np->rxopt.bits.rxflow) || |
| 689 | (opt->srcrt && (np->rxopt.bits.srcrt || | 688 | (opt->srcrt && (np->rxopt.bits.srcrt || |
| 690 | np->rxopt.bits.osrcrt)) || | 689 | np->rxopt.bits.osrcrt)) || |
| @@ -776,6 +775,7 @@ static int __net_init inet6_net_init(struct net *net) | |||
| 776 | 775 | ||
| 777 | net->ipv6.sysctl.bindv6only = 0; | 776 | net->ipv6.sysctl.bindv6only = 0; |
| 778 | net->ipv6.sysctl.icmpv6_time = 1*HZ; | 777 | net->ipv6.sysctl.icmpv6_time = 1*HZ; |
| 778 | net->ipv6.sysctl.flowlabel_consistency = 1; | ||
| 779 | atomic_set(&net->ipv6.rt_genid, 0); | 779 | atomic_set(&net->ipv6.rt_genid, 0); |
| 780 | 780 | ||
| 781 | err = ipv6_init_mibs(net); | 781 | err = ipv6_init_mibs(net); |
diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c index 82e1da3a40b9..81e496a2e008 100644 --- a/net/ipv6/ah6.c +++ b/net/ipv6/ah6.c | |||
| @@ -12,8 +12,7 @@ | |||
| 12 | * GNU General Public License for more details. | 12 | * GNU General Public License for more details. |
| 13 | * | 13 | * |
| 14 | * You should have received a copy of the GNU General Public License | 14 | * You should have received a copy of the GNU General Public License |
| 15 | * along with this program; if not, write to the Free Software | 15 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 17 | * | 16 | * |
| 18 | * Authors | 17 | * Authors |
| 19 | * | 18 | * |
diff --git a/net/ipv6/anycast.c b/net/ipv6/anycast.c index 5a80f15a9de2..210183244689 100644 --- a/net/ipv6/anycast.c +++ b/net/ipv6/anycast.c | |||
| @@ -383,6 +383,17 @@ bool ipv6_chk_acast_addr(struct net *net, struct net_device *dev, | |||
| 383 | return found; | 383 | return found; |
| 384 | } | 384 | } |
| 385 | 385 | ||
| 386 | /* check if this anycast address is link-local on given interface or | ||
| 387 | * is global | ||
| 388 | */ | ||
| 389 | bool ipv6_chk_acast_addr_src(struct net *net, struct net_device *dev, | ||
| 390 | const struct in6_addr *addr) | ||
| 391 | { | ||
| 392 | return ipv6_chk_acast_addr(net, | ||
| 393 | (ipv6_addr_type(addr) & IPV6_ADDR_LINKLOCAL ? | ||
| 394 | dev : NULL), | ||
| 395 | addr); | ||
| 396 | } | ||
| 386 | 397 | ||
| 387 | #ifdef CONFIG_PROC_FS | 398 | #ifdef CONFIG_PROC_FS |
| 388 | struct ac6_iter_state { | 399 | struct ac6_iter_state { |
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c index 93b1aa34c432..c3bf2d2e519e 100644 --- a/net/ipv6/datagram.c +++ b/net/ipv6/datagram.c | |||
| @@ -170,7 +170,7 @@ ipv4_connected: | |||
| 170 | opt = flowlabel ? flowlabel->opt : np->opt; | 170 | opt = flowlabel ? flowlabel->opt : np->opt; |
| 171 | final_p = fl6_update_dst(&fl6, opt, &final); | 171 | final_p = fl6_update_dst(&fl6, opt, &final); |
| 172 | 172 | ||
| 173 | dst = ip6_dst_lookup_flow(sk, &fl6, final_p, true); | 173 | dst = ip6_dst_lookup_flow(sk, &fl6, final_p); |
| 174 | err = 0; | 174 | err = 0; |
| 175 | if (IS_ERR(dst)) { | 175 | if (IS_ERR(dst)) { |
| 176 | err = PTR_ERR(dst); | 176 | err = PTR_ERR(dst); |
| @@ -205,6 +205,16 @@ out: | |||
| 205 | } | 205 | } |
| 206 | EXPORT_SYMBOL_GPL(ip6_datagram_connect); | 206 | EXPORT_SYMBOL_GPL(ip6_datagram_connect); |
| 207 | 207 | ||
| 208 | int ip6_datagram_connect_v6_only(struct sock *sk, struct sockaddr *uaddr, | ||
| 209 | int addr_len) | ||
| 210 | { | ||
| 211 | DECLARE_SOCKADDR(struct sockaddr_in6 *, sin6, uaddr); | ||
| 212 | if (sin6->sin6_family != AF_INET6) | ||
| 213 | return -EAFNOSUPPORT; | ||
| 214 | return ip6_datagram_connect(sk, uaddr, addr_len); | ||
| 215 | } | ||
| 216 | EXPORT_SYMBOL_GPL(ip6_datagram_connect_v6_only); | ||
| 217 | |||
| 208 | void ipv6_icmp_error(struct sock *sk, struct sk_buff *skb, int err, | 218 | void ipv6_icmp_error(struct sock *sk, struct sk_buff *skb, int err, |
| 209 | __be16 port, u32 info, u8 *payload) | 219 | __be16 port, u32 info, u8 *payload) |
| 210 | { | 220 | { |
| @@ -322,7 +332,7 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len) | |||
| 322 | struct ipv6_pinfo *np = inet6_sk(sk); | 332 | struct ipv6_pinfo *np = inet6_sk(sk); |
| 323 | struct sock_exterr_skb *serr; | 333 | struct sock_exterr_skb *serr; |
| 324 | struct sk_buff *skb, *skb2; | 334 | struct sk_buff *skb, *skb2; |
| 325 | struct sockaddr_in6 *sin; | 335 | DECLARE_SOCKADDR(struct sockaddr_in6 *, sin, msg->msg_name); |
| 326 | struct { | 336 | struct { |
| 327 | struct sock_extended_err ee; | 337 | struct sock_extended_err ee; |
| 328 | struct sockaddr_in6 offender; | 338 | struct sockaddr_in6 offender; |
| @@ -348,7 +358,6 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len) | |||
| 348 | 358 | ||
| 349 | serr = SKB_EXT_ERR(skb); | 359 | serr = SKB_EXT_ERR(skb); |
| 350 | 360 | ||
| 351 | sin = (struct sockaddr_in6 *)msg->msg_name; | ||
| 352 | if (sin) { | 361 | if (sin) { |
| 353 | const unsigned char *nh = skb_network_header(skb); | 362 | const unsigned char *nh = skb_network_header(skb); |
| 354 | sin->sin6_family = AF_INET6; | 363 | sin->sin6_family = AF_INET6; |
| @@ -378,10 +387,12 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len) | |||
| 378 | sin->sin6_family = AF_INET6; | 387 | sin->sin6_family = AF_INET6; |
| 379 | sin->sin6_flowinfo = 0; | 388 | sin->sin6_flowinfo = 0; |
| 380 | sin->sin6_port = 0; | 389 | sin->sin6_port = 0; |
| 390 | if (np->rxopt.all) | ||
| 391 | ip6_datagram_recv_common_ctl(sk, msg, skb); | ||
| 381 | if (skb->protocol == htons(ETH_P_IPV6)) { | 392 | if (skb->protocol == htons(ETH_P_IPV6)) { |
| 382 | sin->sin6_addr = ipv6_hdr(skb)->saddr; | 393 | sin->sin6_addr = ipv6_hdr(skb)->saddr; |
| 383 | if (np->rxopt.all) | 394 | if (np->rxopt.all) |
| 384 | ip6_datagram_recv_ctl(sk, msg, skb); | 395 | ip6_datagram_recv_specific_ctl(sk, msg, skb); |
| 385 | sin->sin6_scope_id = | 396 | sin->sin6_scope_id = |
| 386 | ipv6_iface_scope_id(&sin->sin6_addr, | 397 | ipv6_iface_scope_id(&sin->sin6_addr, |
| 387 | IP6CB(skb)->iif); | 398 | IP6CB(skb)->iif); |
| @@ -429,8 +440,8 @@ int ipv6_recv_rxpmtu(struct sock *sk, struct msghdr *msg, int len, | |||
| 429 | { | 440 | { |
| 430 | struct ipv6_pinfo *np = inet6_sk(sk); | 441 | struct ipv6_pinfo *np = inet6_sk(sk); |
| 431 | struct sk_buff *skb; | 442 | struct sk_buff *skb; |
| 432 | struct sockaddr_in6 *sin; | ||
| 433 | struct ip6_mtuinfo mtu_info; | 443 | struct ip6_mtuinfo mtu_info; |
| 444 | DECLARE_SOCKADDR(struct sockaddr_in6 *, sin, msg->msg_name); | ||
| 434 | int err; | 445 | int err; |
| 435 | int copied; | 446 | int copied; |
| 436 | 447 | ||
| @@ -452,7 +463,6 @@ int ipv6_recv_rxpmtu(struct sock *sk, struct msghdr *msg, int len, | |||
| 452 | 463 | ||
| 453 | memcpy(&mtu_info, IP6CBMTU(skb), sizeof(mtu_info)); | 464 | memcpy(&mtu_info, IP6CBMTU(skb), sizeof(mtu_info)); |
| 454 | 465 | ||
| 455 | sin = (struct sockaddr_in6 *)msg->msg_name; | ||
| 456 | if (sin) { | 466 | if (sin) { |
| 457 | sin->sin6_family = AF_INET6; | 467 | sin->sin6_family = AF_INET6; |
| 458 | sin->sin6_flowinfo = 0; | 468 | sin->sin6_flowinfo = 0; |
| @@ -473,20 +483,34 @@ out: | |||
| 473 | } | 483 | } |
| 474 | 484 | ||
| 475 | 485 | ||
| 476 | int ip6_datagram_recv_ctl(struct sock *sk, struct msghdr *msg, | 486 | void ip6_datagram_recv_common_ctl(struct sock *sk, struct msghdr *msg, |
| 477 | struct sk_buff *skb) | 487 | struct sk_buff *skb) |
| 478 | { | 488 | { |
| 479 | struct ipv6_pinfo *np = inet6_sk(sk); | 489 | struct ipv6_pinfo *np = inet6_sk(sk); |
| 480 | struct inet6_skb_parm *opt = IP6CB(skb); | 490 | bool is_ipv6 = skb->protocol == htons(ETH_P_IPV6); |
| 481 | unsigned char *nh = skb_network_header(skb); | ||
| 482 | 491 | ||
| 483 | if (np->rxopt.bits.rxinfo) { | 492 | if (np->rxopt.bits.rxinfo) { |
| 484 | struct in6_pktinfo src_info; | 493 | struct in6_pktinfo src_info; |
| 485 | 494 | ||
| 486 | src_info.ipi6_ifindex = opt->iif; | 495 | if (is_ipv6) { |
| 487 | src_info.ipi6_addr = ipv6_hdr(skb)->daddr; | 496 | src_info.ipi6_ifindex = IP6CB(skb)->iif; |
| 497 | src_info.ipi6_addr = ipv6_hdr(skb)->daddr; | ||
| 498 | } else { | ||
| 499 | src_info.ipi6_ifindex = | ||
| 500 | PKTINFO_SKB_CB(skb)->ipi_ifindex; | ||
| 501 | ipv6_addr_set_v4mapped(ip_hdr(skb)->daddr, | ||
| 502 | &src_info.ipi6_addr); | ||
| 503 | } | ||
| 488 | put_cmsg(msg, SOL_IPV6, IPV6_PKTINFO, sizeof(src_info), &src_info); | 504 | put_cmsg(msg, SOL_IPV6, IPV6_PKTINFO, sizeof(src_info), &src_info); |
| 489 | } | 505 | } |
| 506 | } | ||
| 507 | |||
| 508 | void ip6_datagram_recv_specific_ctl(struct sock *sk, struct msghdr *msg, | ||
| 509 | struct sk_buff *skb) | ||
| 510 | { | ||
| 511 | struct ipv6_pinfo *np = inet6_sk(sk); | ||
| 512 | struct inet6_skb_parm *opt = IP6CB(skb); | ||
| 513 | unsigned char *nh = skb_network_header(skb); | ||
| 490 | 514 | ||
| 491 | if (np->rxopt.bits.rxhlim) { | 515 | if (np->rxopt.bits.rxhlim) { |
| 492 | int hlim = ipv6_hdr(skb)->hop_limit; | 516 | int hlim = ipv6_hdr(skb)->hop_limit; |
| @@ -604,7 +628,13 @@ int ip6_datagram_recv_ctl(struct sock *sk, struct msghdr *msg, | |||
| 604 | put_cmsg(msg, SOL_IPV6, IPV6_ORIGDSTADDR, sizeof(sin6), &sin6); | 628 | put_cmsg(msg, SOL_IPV6, IPV6_ORIGDSTADDR, sizeof(sin6), &sin6); |
| 605 | } | 629 | } |
| 606 | } | 630 | } |
| 607 | return 0; | 631 | } |
| 632 | |||
| 633 | void ip6_datagram_recv_ctl(struct sock *sk, struct msghdr *msg, | ||
| 634 | struct sk_buff *skb) | ||
| 635 | { | ||
| 636 | ip6_datagram_recv_common_ctl(sk, msg, skb); | ||
| 637 | ip6_datagram_recv_specific_ctl(sk, msg, skb); | ||
| 608 | } | 638 | } |
| 609 | EXPORT_SYMBOL_GPL(ip6_datagram_recv_ctl); | 639 | EXPORT_SYMBOL_GPL(ip6_datagram_recv_ctl); |
| 610 | 640 | ||
| @@ -669,7 +699,9 @@ int ip6_datagram_send_ctl(struct net *net, struct sock *sk, | |||
| 669 | int strict = __ipv6_addr_src_scope(addr_type) <= IPV6_ADDR_SCOPE_LINKLOCAL; | 699 | int strict = __ipv6_addr_src_scope(addr_type) <= IPV6_ADDR_SCOPE_LINKLOCAL; |
| 670 | if (!(inet_sk(sk)->freebind || inet_sk(sk)->transparent) && | 700 | if (!(inet_sk(sk)->freebind || inet_sk(sk)->transparent) && |
| 671 | !ipv6_chk_addr(net, &src_info->ipi6_addr, | 701 | !ipv6_chk_addr(net, &src_info->ipi6_addr, |
| 672 | strict ? dev : NULL, 0)) | 702 | strict ? dev : NULL, 0) && |
| 703 | !ipv6_chk_acast_addr_src(net, dev, | ||
| 704 | &src_info->ipi6_addr)) | ||
| 673 | err = -EINVAL; | 705 | err = -EINVAL; |
| 674 | else | 706 | else |
| 675 | fl6->saddr = src_info->ipi6_addr; | 707 | fl6->saddr = src_info->ipi6_addr; |
diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c index b8719df0366e..6eef8a7e35f2 100644 --- a/net/ipv6/esp6.c +++ b/net/ipv6/esp6.c | |||
| @@ -12,8 +12,7 @@ | |||
| 12 | * GNU General Public License for more details. | 12 | * GNU General Public License for more details. |
| 13 | * | 13 | * |
| 14 | * You should have received a copy of the GNU General Public License | 14 | * You should have received a copy of the GNU General Public License |
| 15 | * along with this program; if not, write to the Free Software | 15 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 17 | * | 16 | * |
| 18 | * Authors | 17 | * Authors |
| 19 | * | 18 | * |
diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c index 3fd0a578329e..b4d5e1d97c1b 100644 --- a/net/ipv6/fib6_rules.c +++ b/net/ipv6/fib6_rules.c | |||
| @@ -169,7 +169,7 @@ static int fib6_rule_match(struct fib_rule *rule, struct flowi *fl, int flags) | |||
| 169 | return 0; | 169 | return 0; |
| 170 | } | 170 | } |
| 171 | 171 | ||
| 172 | if (r->tclass && r->tclass != ((ntohl(fl6->flowlabel) >> 20) & 0xff)) | 172 | if (r->tclass && r->tclass != ip6_tclass(fl6->flowlabel)) |
| 173 | return 0; | 173 | return 0; |
| 174 | 174 | ||
| 175 | return 1; | 175 | return 1; |
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index eef8d945b362..f81f59686f21 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c | |||
| @@ -67,6 +67,7 @@ | |||
| 67 | #include <net/icmp.h> | 67 | #include <net/icmp.h> |
| 68 | #include <net/xfrm.h> | 68 | #include <net/xfrm.h> |
| 69 | #include <net/inet_common.h> | 69 | #include <net/inet_common.h> |
| 70 | #include <net/dsfield.h> | ||
| 70 | 71 | ||
| 71 | #include <asm/uaccess.h> | 72 | #include <asm/uaccess.h> |
| 72 | 73 | ||
| @@ -315,8 +316,10 @@ static void mip6_addr_swap(struct sk_buff *skb) | |||
| 315 | static inline void mip6_addr_swap(struct sk_buff *skb) {} | 316 | static inline void mip6_addr_swap(struct sk_buff *skb) {} |
| 316 | #endif | 317 | #endif |
| 317 | 318 | ||
| 318 | struct dst_entry *icmpv6_route_lookup(struct net *net, struct sk_buff *skb, | 319 | static struct dst_entry *icmpv6_route_lookup(struct net *net, |
| 319 | struct sock *sk, struct flowi6 *fl6) | 320 | struct sk_buff *skb, |
| 321 | struct sock *sk, | ||
| 322 | struct flowi6 *fl6) | ||
| 320 | { | 323 | { |
| 321 | struct dst_entry *dst, *dst2; | 324 | struct dst_entry *dst, *dst2; |
| 322 | struct flowi6 fl2; | 325 | struct flowi6 fl2; |
| @@ -410,7 +413,8 @@ static void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info) | |||
| 410 | */ | 413 | */ |
| 411 | addr_type = ipv6_addr_type(&hdr->daddr); | 414 | addr_type = ipv6_addr_type(&hdr->daddr); |
| 412 | 415 | ||
| 413 | if (ipv6_chk_addr(net, &hdr->daddr, skb->dev, 0)) | 416 | if (ipv6_chk_addr(net, &hdr->daddr, skb->dev, 0) || |
| 417 | ipv6_anycast_destination(skb)) | ||
| 414 | saddr = &hdr->daddr; | 418 | saddr = &hdr->daddr; |
| 415 | 419 | ||
| 416 | /* | 420 | /* |
| @@ -551,10 +555,13 @@ static void icmpv6_echo_reply(struct sk_buff *skb) | |||
| 551 | struct dst_entry *dst; | 555 | struct dst_entry *dst; |
| 552 | int err = 0; | 556 | int err = 0; |
| 553 | int hlimit; | 557 | int hlimit; |
| 558 | u8 tclass; | ||
| 554 | 559 | ||
| 555 | saddr = &ipv6_hdr(skb)->daddr; | 560 | saddr = &ipv6_hdr(skb)->daddr; |
| 556 | 561 | ||
| 557 | if (!ipv6_unicast_destination(skb)) | 562 | if (!ipv6_unicast_destination(skb) && |
| 563 | !(net->ipv6.sysctl.anycast_src_echo_reply && | ||
| 564 | ipv6_anycast_destination(skb))) | ||
| 558 | saddr = NULL; | 565 | saddr = NULL; |
| 559 | 566 | ||
| 560 | memcpy(&tmp_hdr, icmph, sizeof(tmp_hdr)); | 567 | memcpy(&tmp_hdr, icmph, sizeof(tmp_hdr)); |
| @@ -599,8 +606,9 @@ static void icmpv6_echo_reply(struct sk_buff *skb) | |||
| 599 | msg.offset = 0; | 606 | msg.offset = 0; |
| 600 | msg.type = ICMPV6_ECHO_REPLY; | 607 | msg.type = ICMPV6_ECHO_REPLY; |
| 601 | 608 | ||
| 609 | tclass = ipv6_get_dsfield(ipv6_hdr(skb)); | ||
| 602 | err = ip6_append_data(sk, icmpv6_getfrag, &msg, skb->len + sizeof(struct icmp6hdr), | 610 | err = ip6_append_data(sk, icmpv6_getfrag, &msg, skb->len + sizeof(struct icmp6hdr), |
| 603 | sizeof(struct icmp6hdr), hlimit, np->tclass, NULL, &fl6, | 611 | sizeof(struct icmp6hdr), hlimit, tclass, NULL, &fl6, |
| 604 | (struct rt6_info *)dst, MSG_DONTWAIT, | 612 | (struct rt6_info *)dst, MSG_DONTWAIT, |
| 605 | np->dontfrag); | 613 | np->dontfrag); |
| 606 | 614 | ||
| @@ -984,7 +992,7 @@ int icmpv6_err_convert(u8 type, u8 code, int *err) | |||
| 984 | EXPORT_SYMBOL(icmpv6_err_convert); | 992 | EXPORT_SYMBOL(icmpv6_err_convert); |
| 985 | 993 | ||
| 986 | #ifdef CONFIG_SYSCTL | 994 | #ifdef CONFIG_SYSCTL |
| 987 | struct ctl_table ipv6_icmp_table_template[] = { | 995 | static struct ctl_table ipv6_icmp_table_template[] = { |
| 988 | { | 996 | { |
| 989 | .procname = "ratelimit", | 997 | .procname = "ratelimit", |
| 990 | .data = &init_net.ipv6.sysctl.icmpv6_time, | 998 | .data = &init_net.ipv6.sysctl.icmpv6_time, |
diff --git a/net/ipv6/inet6_connection_sock.c b/net/ipv6/inet6_connection_sock.c index 77bb8afb141d..c9138189415a 100644 --- a/net/ipv6/inet6_connection_sock.c +++ b/net/ipv6/inet6_connection_sock.c | |||
| @@ -86,7 +86,7 @@ struct dst_entry *inet6_csk_route_req(struct sock *sk, | |||
| 86 | fl6->fl6_sport = htons(ireq->ir_num); | 86 | fl6->fl6_sport = htons(ireq->ir_num); |
| 87 | security_req_classify_flow(req, flowi6_to_flowi(fl6)); | 87 | security_req_classify_flow(req, flowi6_to_flowi(fl6)); |
| 88 | 88 | ||
| 89 | dst = ip6_dst_lookup_flow(sk, fl6, final_p, false); | 89 | dst = ip6_dst_lookup_flow(sk, fl6, final_p); |
| 90 | if (IS_ERR(dst)) | 90 | if (IS_ERR(dst)) |
| 91 | return NULL; | 91 | return NULL; |
| 92 | 92 | ||
| @@ -216,7 +216,7 @@ static struct dst_entry *inet6_csk_route_socket(struct sock *sk, | |||
| 216 | 216 | ||
| 217 | dst = __inet6_csk_dst_check(sk, np->dst_cookie); | 217 | dst = __inet6_csk_dst_check(sk, np->dst_cookie); |
| 218 | if (!dst) { | 218 | if (!dst) { |
| 219 | dst = ip6_dst_lookup_flow(sk, fl6, final_p, false); | 219 | dst = ip6_dst_lookup_flow(sk, fl6, final_p); |
| 220 | 220 | ||
| 221 | if (!IS_ERR(dst)) | 221 | if (!IS_ERR(dst)) |
| 222 | __inet6_csk_dst_store(sk, dst, NULL, NULL); | 222 | __inet6_csk_dst_store(sk, dst, NULL, NULL); |
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index 5550a8113a6d..075602fc6b6a 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c | |||
| @@ -1530,7 +1530,7 @@ static void fib6_clean_tree(struct net *net, struct fib6_node *root, | |||
| 1530 | } | 1530 | } |
| 1531 | 1531 | ||
| 1532 | void fib6_clean_all(struct net *net, int (*func)(struct rt6_info *, void *arg), | 1532 | void fib6_clean_all(struct net *net, int (*func)(struct rt6_info *, void *arg), |
| 1533 | int prune, void *arg) | 1533 | void *arg) |
| 1534 | { | 1534 | { |
| 1535 | struct fib6_table *table; | 1535 | struct fib6_table *table; |
| 1536 | struct hlist_head *head; | 1536 | struct hlist_head *head; |
| @@ -1542,7 +1542,7 @@ void fib6_clean_all(struct net *net, int (*func)(struct rt6_info *, void *arg), | |||
| 1542 | hlist_for_each_entry_rcu(table, head, tb6_hlist) { | 1542 | hlist_for_each_entry_rcu(table, head, tb6_hlist) { |
| 1543 | write_lock_bh(&table->tb6_lock); | 1543 | write_lock_bh(&table->tb6_lock); |
| 1544 | fib6_clean_tree(net, &table->tb6_root, | 1544 | fib6_clean_tree(net, &table->tb6_root, |
| 1545 | func, prune, arg); | 1545 | func, 0, arg); |
| 1546 | write_unlock_bh(&table->tb6_lock); | 1546 | write_unlock_bh(&table->tb6_lock); |
| 1547 | } | 1547 | } |
| 1548 | } | 1548 | } |
| @@ -1636,7 +1636,7 @@ void fib6_run_gc(unsigned long expires, struct net *net, bool force) | |||
| 1636 | 1636 | ||
| 1637 | gc_args.more = icmp6_dst_gc(); | 1637 | gc_args.more = icmp6_dst_gc(); |
| 1638 | 1638 | ||
| 1639 | fib6_clean_all(net, fib6_age, 0, NULL); | 1639 | fib6_clean_all(net, fib6_age, NULL); |
| 1640 | now = jiffies; | 1640 | now = jiffies; |
| 1641 | net->ipv6.ip6_rt_last_gc = now; | 1641 | net->ipv6.ip6_rt_last_gc = now; |
| 1642 | 1642 | ||
diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c index e7fb7106550f..dfa41bb4e0dc 100644 --- a/net/ipv6/ip6_flowlabel.c +++ b/net/ipv6/ip6_flowlabel.c | |||
| @@ -210,7 +210,7 @@ static struct ip6_flowlabel *fl_intern(struct net *net, | |||
| 210 | spin_lock_bh(&ip6_fl_lock); | 210 | spin_lock_bh(&ip6_fl_lock); |
| 211 | if (label == 0) { | 211 | if (label == 0) { |
| 212 | for (;;) { | 212 | for (;;) { |
| 213 | fl->label = htonl(net_random())&IPV6_FLOWLABEL_MASK; | 213 | fl->label = htonl(prandom_u32())&IPV6_FLOWLABEL_MASK; |
| 214 | if (fl->label) { | 214 | if (fl->label) { |
| 215 | lfl = __fl_lookup(net, fl->label); | 215 | lfl = __fl_lookup(net, fl->label); |
| 216 | if (lfl == NULL) | 216 | if (lfl == NULL) |
| @@ -481,11 +481,22 @@ static inline void fl_link(struct ipv6_pinfo *np, struct ipv6_fl_socklist *sfl, | |||
| 481 | spin_unlock_bh(&ip6_sk_fl_lock); | 481 | spin_unlock_bh(&ip6_sk_fl_lock); |
| 482 | } | 482 | } |
| 483 | 483 | ||
| 484 | int ipv6_flowlabel_opt_get(struct sock *sk, struct in6_flowlabel_req *freq) | 484 | int ipv6_flowlabel_opt_get(struct sock *sk, struct in6_flowlabel_req *freq, |
| 485 | int flags) | ||
| 485 | { | 486 | { |
| 486 | struct ipv6_pinfo *np = inet6_sk(sk); | 487 | struct ipv6_pinfo *np = inet6_sk(sk); |
| 487 | struct ipv6_fl_socklist *sfl; | 488 | struct ipv6_fl_socklist *sfl; |
| 488 | 489 | ||
| 490 | if (flags & IPV6_FL_F_REMOTE) { | ||
| 491 | freq->flr_label = np->rcv_flowinfo & IPV6_FLOWLABEL_MASK; | ||
| 492 | return 0; | ||
| 493 | } | ||
| 494 | |||
| 495 | if (np->repflow) { | ||
| 496 | freq->flr_label = np->flow_label; | ||
| 497 | return 0; | ||
| 498 | } | ||
| 499 | |||
| 489 | rcu_read_lock_bh(); | 500 | rcu_read_lock_bh(); |
| 490 | 501 | ||
| 491 | for_each_sk_fl_rcu(np, sfl) { | 502 | for_each_sk_fl_rcu(np, sfl) { |
| @@ -527,6 +538,15 @@ int ipv6_flowlabel_opt(struct sock *sk, char __user *optval, int optlen) | |||
| 527 | 538 | ||
| 528 | switch (freq.flr_action) { | 539 | switch (freq.flr_action) { |
| 529 | case IPV6_FL_A_PUT: | 540 | case IPV6_FL_A_PUT: |
| 541 | if (freq.flr_flags & IPV6_FL_F_REFLECT) { | ||
| 542 | if (sk->sk_protocol != IPPROTO_TCP) | ||
| 543 | return -ENOPROTOOPT; | ||
| 544 | if (!np->repflow) | ||
| 545 | return -ESRCH; | ||
| 546 | np->flow_label = 0; | ||
| 547 | np->repflow = 0; | ||
| 548 | return 0; | ||
| 549 | } | ||
| 530 | spin_lock_bh(&ip6_sk_fl_lock); | 550 | spin_lock_bh(&ip6_sk_fl_lock); |
| 531 | for (sflp = &np->ipv6_fl_list; | 551 | for (sflp = &np->ipv6_fl_list; |
| 532 | (sfl = rcu_dereference(*sflp))!=NULL; | 552 | (sfl = rcu_dereference(*sflp))!=NULL; |
| @@ -567,6 +587,20 @@ int ipv6_flowlabel_opt(struct sock *sk, char __user *optval, int optlen) | |||
| 567 | return -ESRCH; | 587 | return -ESRCH; |
| 568 | 588 | ||
| 569 | case IPV6_FL_A_GET: | 589 | case IPV6_FL_A_GET: |
| 590 | if (freq.flr_flags & IPV6_FL_F_REFLECT) { | ||
| 591 | struct net *net = sock_net(sk); | ||
| 592 | if (net->ipv6.sysctl.flowlabel_consistency) { | ||
| 593 | net_info_ratelimited("Can not set IPV6_FL_F_REFLECT if flowlabel_consistency sysctl is enable\n"); | ||
| 594 | return -EPERM; | ||
| 595 | } | ||
| 596 | |||
| 597 | if (sk->sk_protocol != IPPROTO_TCP) | ||
| 598 | return -ENOPROTOOPT; | ||
| 599 | |||
| 600 | np->repflow = 1; | ||
| 601 | return 0; | ||
| 602 | } | ||
| 603 | |||
| 570 | if (freq.flr_label & ~IPV6_FLOWLABEL_MASK) | 604 | if (freq.flr_label & ~IPV6_FLOWLABEL_MASK) |
| 571 | return -EINVAL; | 605 | return -EINVAL; |
| 572 | 606 | ||
diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c index 8acb28621f9c..f3ffb43f59c0 100644 --- a/net/ipv6/ip6_gre.c +++ b/net/ipv6/ip6_gre.c | |||
| @@ -61,9 +61,6 @@ static bool log_ecn_error = true; | |||
| 61 | module_param(log_ecn_error, bool, 0644); | 61 | module_param(log_ecn_error, bool, 0644); |
| 62 | MODULE_PARM_DESC(log_ecn_error, "Log packets received with corrupted ECN"); | 62 | MODULE_PARM_DESC(log_ecn_error, "Log packets received with corrupted ECN"); |
| 63 | 63 | ||
| 64 | #define IPV6_TCLASS_MASK (IPV6_FLOWINFO_MASK & ~IPV6_FLOWLABEL_MASK) | ||
| 65 | #define IPV6_TCLASS_SHIFT 20 | ||
| 66 | |||
| 67 | #define HASH_SIZE_SHIFT 5 | 64 | #define HASH_SIZE_SHIFT 5 |
| 68 | #define HASH_SIZE (1 << HASH_SIZE_SHIFT) | 65 | #define HASH_SIZE (1 << HASH_SIZE_SHIFT) |
| 69 | 66 | ||
| @@ -499,7 +496,7 @@ static int ip6gre_rcv(struct sk_buff *skb) | |||
| 499 | &ipv6h->saddr, &ipv6h->daddr, key, | 496 | &ipv6h->saddr, &ipv6h->daddr, key, |
| 500 | gre_proto); | 497 | gre_proto); |
| 501 | if (tunnel) { | 498 | if (tunnel) { |
| 502 | struct pcpu_tstats *tstats; | 499 | struct pcpu_sw_netstats *tstats; |
| 503 | 500 | ||
| 504 | if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) | 501 | if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) |
| 505 | goto drop; | 502 | goto drop; |
| @@ -846,7 +843,7 @@ static inline int ip6gre_xmit_ipv6(struct sk_buff *skb, struct net_device *dev) | |||
| 846 | if (t->parms.flags & IP6_TNL_F_USE_ORIG_TCLASS) | 843 | if (t->parms.flags & IP6_TNL_F_USE_ORIG_TCLASS) |
| 847 | fl6.flowlabel |= (*(__be32 *) ipv6h & IPV6_TCLASS_MASK); | 844 | fl6.flowlabel |= (*(__be32 *) ipv6h & IPV6_TCLASS_MASK); |
| 848 | if (t->parms.flags & IP6_TNL_F_USE_ORIG_FLOWLABEL) | 845 | if (t->parms.flags & IP6_TNL_F_USE_ORIG_FLOWLABEL) |
| 849 | fl6.flowlabel |= (*(__be32 *) ipv6h & IPV6_FLOWLABEL_MASK); | 846 | fl6.flowlabel |= ip6_flowlabel(ipv6h); |
| 850 | if (t->parms.flags & IP6_TNL_F_USE_ORIG_FWMARK) | 847 | if (t->parms.flags & IP6_TNL_F_USE_ORIG_FWMARK) |
| 851 | fl6.flowi6_mark = skb->mark; | 848 | fl6.flowi6_mark = skb->mark; |
| 852 | 849 | ||
| @@ -1266,12 +1263,12 @@ static int ip6gre_tunnel_init(struct net_device *dev) | |||
| 1266 | if (ipv6_addr_any(&tunnel->parms.raddr)) | 1263 | if (ipv6_addr_any(&tunnel->parms.raddr)) |
| 1267 | dev->header_ops = &ip6gre_header_ops; | 1264 | dev->header_ops = &ip6gre_header_ops; |
| 1268 | 1265 | ||
| 1269 | dev->tstats = alloc_percpu(struct pcpu_tstats); | 1266 | dev->tstats = alloc_percpu(struct pcpu_sw_netstats); |
| 1270 | if (!dev->tstats) | 1267 | if (!dev->tstats) |
| 1271 | return -ENOMEM; | 1268 | return -ENOMEM; |
| 1272 | 1269 | ||
| 1273 | for_each_possible_cpu(i) { | 1270 | for_each_possible_cpu(i) { |
| 1274 | struct pcpu_tstats *ip6gre_tunnel_stats; | 1271 | struct pcpu_sw_netstats *ip6gre_tunnel_stats; |
| 1275 | ip6gre_tunnel_stats = per_cpu_ptr(dev->tstats, i); | 1272 | ip6gre_tunnel_stats = per_cpu_ptr(dev->tstats, i); |
| 1276 | u64_stats_init(&ip6gre_tunnel_stats->syncp); | 1273 | u64_stats_init(&ip6gre_tunnel_stats->syncp); |
| 1277 | } | 1274 | } |
| @@ -1467,12 +1464,12 @@ static int ip6gre_tap_init(struct net_device *dev) | |||
| 1467 | 1464 | ||
| 1468 | ip6gre_tnl_link_config(tunnel, 1); | 1465 | ip6gre_tnl_link_config(tunnel, 1); |
| 1469 | 1466 | ||
| 1470 | dev->tstats = alloc_percpu(struct pcpu_tstats); | 1467 | dev->tstats = alloc_percpu(struct pcpu_sw_netstats); |
| 1471 | if (!dev->tstats) | 1468 | if (!dev->tstats) |
| 1472 | return -ENOMEM; | 1469 | return -ENOMEM; |
| 1473 | 1470 | ||
| 1474 | for_each_possible_cpu(i) { | 1471 | for_each_possible_cpu(i) { |
| 1475 | struct pcpu_tstats *ip6gre_tap_stats; | 1472 | struct pcpu_sw_netstats *ip6gre_tap_stats; |
| 1476 | ip6gre_tap_stats = per_cpu_ptr(dev->tstats, i); | 1473 | ip6gre_tap_stats = per_cpu_ptr(dev->tstats, i); |
| 1477 | u64_stats_init(&ip6gre_tap_stats->syncp); | 1474 | u64_stats_init(&ip6gre_tap_stats->syncp); |
| 1478 | } | 1475 | } |
diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c index 302d6fb1ff2b..51d54dc376f3 100644 --- a/net/ipv6/ip6_input.c +++ b/net/ipv6/ip6_input.c | |||
| @@ -49,7 +49,7 @@ | |||
| 49 | 49 | ||
| 50 | int ip6_rcv_finish(struct sk_buff *skb) | 50 | int ip6_rcv_finish(struct sk_buff *skb) |
| 51 | { | 51 | { |
| 52 | if (sysctl_ip_early_demux && !skb_dst(skb)) { | 52 | if (sysctl_ip_early_demux && !skb_dst(skb) && skb->sk == NULL) { |
| 53 | const struct inet6_protocol *ipprot; | 53 | const struct inet6_protocol *ipprot; |
| 54 | 54 | ||
| 55 | ipprot = rcu_dereference(inet6_protos[ipv6_hdr(skb)->nexthdr]); | 55 | ipprot = rcu_dereference(inet6_protos[ipv6_hdr(skb)->nexthdr]); |
diff --git a/net/ipv6/ip6_offload.c b/net/ipv6/ip6_offload.c index 4b851692b1f6..1e8683b135bb 100644 --- a/net/ipv6/ip6_offload.c +++ b/net/ipv6/ip6_offload.c | |||
| @@ -154,6 +154,32 @@ out: | |||
| 154 | return segs; | 154 | return segs; |
| 155 | } | 155 | } |
| 156 | 156 | ||
| 157 | /* Return the total length of all the extension hdrs, following the same | ||
| 158 | * logic in ipv6_gso_pull_exthdrs() when parsing ext-hdrs. | ||
| 159 | */ | ||
| 160 | static int ipv6_exthdrs_len(struct ipv6hdr *iph, | ||
| 161 | const struct net_offload **opps) | ||
| 162 | { | ||
| 163 | struct ipv6_opt_hdr *opth = (void *)iph; | ||
| 164 | int len = 0, proto, optlen = sizeof(*iph); | ||
| 165 | |||
| 166 | proto = iph->nexthdr; | ||
| 167 | for (;;) { | ||
| 168 | if (proto != NEXTHDR_HOP) { | ||
| 169 | *opps = rcu_dereference(inet6_offloads[proto]); | ||
| 170 | if (unlikely(!(*opps))) | ||
| 171 | break; | ||
| 172 | if (!((*opps)->flags & INET6_PROTO_GSO_EXTHDR)) | ||
| 173 | break; | ||
| 174 | } | ||
| 175 | opth = (void *)opth + optlen; | ||
| 176 | optlen = ipv6_optlen(opth); | ||
| 177 | len += optlen; | ||
| 178 | proto = opth->nexthdr; | ||
| 179 | } | ||
| 180 | return len; | ||
| 181 | } | ||
| 182 | |||
| 157 | static struct sk_buff **ipv6_gro_receive(struct sk_buff **head, | 183 | static struct sk_buff **ipv6_gro_receive(struct sk_buff **head, |
| 158 | struct sk_buff *skb) | 184 | struct sk_buff *skb) |
| 159 | { | 185 | { |
| @@ -164,7 +190,7 @@ static struct sk_buff **ipv6_gro_receive(struct sk_buff **head, | |||
| 164 | unsigned int nlen; | 190 | unsigned int nlen; |
| 165 | unsigned int hlen; | 191 | unsigned int hlen; |
| 166 | unsigned int off; | 192 | unsigned int off; |
| 167 | int flush = 1; | 193 | u16 flush = 1; |
| 168 | int proto; | 194 | int proto; |
| 169 | __wsum csum; | 195 | __wsum csum; |
| 170 | 196 | ||
| @@ -177,6 +203,7 @@ static struct sk_buff **ipv6_gro_receive(struct sk_buff **head, | |||
| 177 | goto out; | 203 | goto out; |
| 178 | } | 204 | } |
| 179 | 205 | ||
| 206 | skb_set_network_header(skb, off); | ||
| 180 | skb_gro_pull(skb, sizeof(*iph)); | 207 | skb_gro_pull(skb, sizeof(*iph)); |
| 181 | skb_set_transport_header(skb, skb_gro_offset(skb)); | 208 | skb_set_transport_header(skb, skb_gro_offset(skb)); |
| 182 | 209 | ||
| @@ -211,12 +238,16 @@ static struct sk_buff **ipv6_gro_receive(struct sk_buff **head, | |||
| 211 | if (!NAPI_GRO_CB(p)->same_flow) | 238 | if (!NAPI_GRO_CB(p)->same_flow) |
| 212 | continue; | 239 | continue; |
| 213 | 240 | ||
| 214 | iph2 = ipv6_hdr(p); | 241 | iph2 = (struct ipv6hdr *)(p->data + off); |
| 215 | first_word = *(__be32 *)iph ^ *(__be32 *)iph2 ; | 242 | first_word = *(__be32 *)iph ^ *(__be32 *)iph2 ; |
| 216 | 243 | ||
| 217 | /* All fields must match except length and Traffic Class. */ | 244 | /* All fields must match except length and Traffic Class. |
| 218 | if (nlen != skb_network_header_len(p) || | 245 | * XXX skbs on the gro_list have all been parsed and pulled |
| 219 | (first_word & htonl(0xF00FFFFF)) || | 246 | * already so we don't need to compare nlen |
| 247 | * (nlen != (sizeof(*iph2) + ipv6_exthdrs_len(iph2, &ops))) | ||
| 248 | * memcmp() alone below is suffcient, right? | ||
| 249 | */ | ||
| 250 | if ((first_word & htonl(0xF00FFFFF)) || | ||
| 220 | memcmp(&iph->nexthdr, &iph2->nexthdr, | 251 | memcmp(&iph->nexthdr, &iph2->nexthdr, |
| 221 | nlen - offsetof(struct ipv6hdr, nexthdr))) { | 252 | nlen - offsetof(struct ipv6hdr, nexthdr))) { |
| 222 | NAPI_GRO_CB(p)->same_flow = 0; | 253 | NAPI_GRO_CB(p)->same_flow = 0; |
| @@ -245,21 +276,21 @@ out: | |||
| 245 | return pp; | 276 | return pp; |
| 246 | } | 277 | } |
| 247 | 278 | ||
| 248 | static int ipv6_gro_complete(struct sk_buff *skb) | 279 | static int ipv6_gro_complete(struct sk_buff *skb, int nhoff) |
| 249 | { | 280 | { |
| 250 | const struct net_offload *ops; | 281 | const struct net_offload *ops; |
| 251 | struct ipv6hdr *iph = ipv6_hdr(skb); | 282 | struct ipv6hdr *iph = (struct ipv6hdr *)(skb->data + nhoff); |
| 252 | int err = -ENOSYS; | 283 | int err = -ENOSYS; |
| 253 | 284 | ||
| 254 | iph->payload_len = htons(skb->len - skb_network_offset(skb) - | 285 | iph->payload_len = htons(skb->len - nhoff - sizeof(*iph)); |
| 255 | sizeof(*iph)); | ||
| 256 | 286 | ||
| 257 | rcu_read_lock(); | 287 | rcu_read_lock(); |
| 258 | ops = rcu_dereference(inet6_offloads[NAPI_GRO_CB(skb)->proto]); | 288 | |
| 289 | nhoff += sizeof(*iph) + ipv6_exthdrs_len(iph, &ops); | ||
| 259 | if (WARN_ON(!ops || !ops->callbacks.gro_complete)) | 290 | if (WARN_ON(!ops || !ops->callbacks.gro_complete)) |
| 260 | goto out_unlock; | 291 | goto out_unlock; |
| 261 | 292 | ||
| 262 | err = ops->callbacks.gro_complete(skb); | 293 | err = ops->callbacks.gro_complete(skb, nhoff); |
| 263 | 294 | ||
| 264 | out_unlock: | 295 | out_unlock: |
| 265 | rcu_read_unlock(); | 296 | rcu_read_unlock(); |
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index e6f931997996..ef02b26ccf81 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c | |||
| @@ -321,6 +321,27 @@ static inline int ip6_forward_finish(struct sk_buff *skb) | |||
| 321 | return dst_output(skb); | 321 | return dst_output(skb); |
| 322 | } | 322 | } |
| 323 | 323 | ||
| 324 | static unsigned int ip6_dst_mtu_forward(const struct dst_entry *dst) | ||
| 325 | { | ||
| 326 | unsigned int mtu; | ||
| 327 | struct inet6_dev *idev; | ||
| 328 | |||
| 329 | if (dst_metric_locked(dst, RTAX_MTU)) { | ||
| 330 | mtu = dst_metric_raw(dst, RTAX_MTU); | ||
| 331 | if (mtu) | ||
| 332 | return mtu; | ||
| 333 | } | ||
| 334 | |||
| 335 | mtu = IPV6_MIN_MTU; | ||
| 336 | rcu_read_lock(); | ||
| 337 | idev = __in6_dev_get(dst->dev); | ||
| 338 | if (idev) | ||
| 339 | mtu = idev->cnf.mtu6; | ||
| 340 | rcu_read_unlock(); | ||
| 341 | |||
| 342 | return mtu; | ||
| 343 | } | ||
| 344 | |||
| 324 | int ip6_forward(struct sk_buff *skb) | 345 | int ip6_forward(struct sk_buff *skb) |
| 325 | { | 346 | { |
| 326 | struct dst_entry *dst = skb_dst(skb); | 347 | struct dst_entry *dst = skb_dst(skb); |
| @@ -336,7 +357,8 @@ int ip6_forward(struct sk_buff *skb) | |||
| 336 | goto drop; | 357 | goto drop; |
| 337 | 358 | ||
| 338 | if (!xfrm6_policy_check(NULL, XFRM_POLICY_FWD, skb)) { | 359 | if (!xfrm6_policy_check(NULL, XFRM_POLICY_FWD, skb)) { |
| 339 | IP6_INC_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_INDISCARDS); | 360 | IP6_INC_STATS_BH(net, ip6_dst_idev(dst), |
| 361 | IPSTATS_MIB_INDISCARDS); | ||
| 340 | goto drop; | 362 | goto drop; |
| 341 | } | 363 | } |
| 342 | 364 | ||
| @@ -370,8 +392,8 @@ int ip6_forward(struct sk_buff *skb) | |||
| 370 | /* Force OUTPUT device used as source address */ | 392 | /* Force OUTPUT device used as source address */ |
| 371 | skb->dev = dst->dev; | 393 | skb->dev = dst->dev; |
| 372 | icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT, 0); | 394 | icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT, 0); |
| 373 | IP6_INC_STATS_BH(net, | 395 | IP6_INC_STATS_BH(net, ip6_dst_idev(dst), |
| 374 | ip6_dst_idev(dst), IPSTATS_MIB_INHDRERRORS); | 396 | IPSTATS_MIB_INHDRERRORS); |
| 375 | 397 | ||
| 376 | kfree_skb(skb); | 398 | kfree_skb(skb); |
| 377 | return -ETIMEDOUT; | 399 | return -ETIMEDOUT; |
| @@ -384,14 +406,15 @@ int ip6_forward(struct sk_buff *skb) | |||
| 384 | if (proxied > 0) | 406 | if (proxied > 0) |
| 385 | return ip6_input(skb); | 407 | return ip6_input(skb); |
| 386 | else if (proxied < 0) { | 408 | else if (proxied < 0) { |
| 387 | IP6_INC_STATS(net, ip6_dst_idev(dst), | 409 | IP6_INC_STATS_BH(net, ip6_dst_idev(dst), |
| 388 | IPSTATS_MIB_INDISCARDS); | 410 | IPSTATS_MIB_INDISCARDS); |
| 389 | goto drop; | 411 | goto drop; |
| 390 | } | 412 | } |
| 391 | } | 413 | } |
| 392 | 414 | ||
| 393 | if (!xfrm6_route_forward(skb)) { | 415 | if (!xfrm6_route_forward(skb)) { |
| 394 | IP6_INC_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_INDISCARDS); | 416 | IP6_INC_STATS_BH(net, ip6_dst_idev(dst), |
| 417 | IPSTATS_MIB_INDISCARDS); | ||
| 395 | goto drop; | 418 | goto drop; |
| 396 | } | 419 | } |
| 397 | dst = skb_dst(skb); | 420 | dst = skb_dst(skb); |
| @@ -439,7 +462,7 @@ int ip6_forward(struct sk_buff *skb) | |||
| 439 | } | 462 | } |
| 440 | } | 463 | } |
| 441 | 464 | ||
| 442 | mtu = dst_mtu(dst); | 465 | mtu = ip6_dst_mtu_forward(dst); |
| 443 | if (mtu < IPV6_MIN_MTU) | 466 | if (mtu < IPV6_MIN_MTU) |
| 444 | mtu = IPV6_MIN_MTU; | 467 | mtu = IPV6_MIN_MTU; |
| 445 | 468 | ||
| @@ -448,16 +471,17 @@ int ip6_forward(struct sk_buff *skb) | |||
| 448 | /* Again, force OUTPUT device used as source address */ | 471 | /* Again, force OUTPUT device used as source address */ |
| 449 | skb->dev = dst->dev; | 472 | skb->dev = dst->dev; |
| 450 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); | 473 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); |
| 451 | IP6_INC_STATS_BH(net, | 474 | IP6_INC_STATS_BH(net, ip6_dst_idev(dst), |
| 452 | ip6_dst_idev(dst), IPSTATS_MIB_INTOOBIGERRORS); | 475 | IPSTATS_MIB_INTOOBIGERRORS); |
| 453 | IP6_INC_STATS_BH(net, | 476 | IP6_INC_STATS_BH(net, ip6_dst_idev(dst), |
| 454 | ip6_dst_idev(dst), IPSTATS_MIB_FRAGFAILS); | 477 | IPSTATS_MIB_FRAGFAILS); |
| 455 | kfree_skb(skb); | 478 | kfree_skb(skb); |
| 456 | return -EMSGSIZE; | 479 | return -EMSGSIZE; |
| 457 | } | 480 | } |
| 458 | 481 | ||
| 459 | if (skb_cow(skb, dst->dev->hard_header_len)) { | 482 | if (skb_cow(skb, dst->dev->hard_header_len)) { |
| 460 | IP6_INC_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTDISCARDS); | 483 | IP6_INC_STATS_BH(net, ip6_dst_idev(dst), |
| 484 | IPSTATS_MIB_OUTDISCARDS); | ||
| 461 | goto drop; | 485 | goto drop; |
| 462 | } | 486 | } |
| 463 | 487 | ||
| @@ -938,7 +962,6 @@ EXPORT_SYMBOL_GPL(ip6_dst_lookup); | |||
| 938 | * @sk: socket which provides route info | 962 | * @sk: socket which provides route info |
| 939 | * @fl6: flow to lookup | 963 | * @fl6: flow to lookup |
| 940 | * @final_dst: final destination address for ipsec lookup | 964 | * @final_dst: final destination address for ipsec lookup |
| 941 | * @can_sleep: we are in a sleepable context | ||
| 942 | * | 965 | * |
| 943 | * This function performs a route lookup on the given flow. | 966 | * This function performs a route lookup on the given flow. |
| 944 | * | 967 | * |
| @@ -946,8 +969,7 @@ EXPORT_SYMBOL_GPL(ip6_dst_lookup); | |||
| 946 | * error code. | 969 | * error code. |
| 947 | */ | 970 | */ |
| 948 | struct dst_entry *ip6_dst_lookup_flow(struct sock *sk, struct flowi6 *fl6, | 971 | struct dst_entry *ip6_dst_lookup_flow(struct sock *sk, struct flowi6 *fl6, |
| 949 | const struct in6_addr *final_dst, | 972 | const struct in6_addr *final_dst) |
| 950 | bool can_sleep) | ||
| 951 | { | 973 | { |
| 952 | struct dst_entry *dst = NULL; | 974 | struct dst_entry *dst = NULL; |
| 953 | int err; | 975 | int err; |
| @@ -957,8 +979,6 @@ struct dst_entry *ip6_dst_lookup_flow(struct sock *sk, struct flowi6 *fl6, | |||
| 957 | return ERR_PTR(err); | 979 | return ERR_PTR(err); |
| 958 | if (final_dst) | 980 | if (final_dst) |
| 959 | fl6->daddr = *final_dst; | 981 | fl6->daddr = *final_dst; |
| 960 | if (can_sleep) | ||
| 961 | fl6->flowi6_flags |= FLOWI_FLAG_CAN_SLEEP; | ||
| 962 | 982 | ||
| 963 | return xfrm_lookup(sock_net(sk), dst, flowi6_to_flowi(fl6), sk, 0); | 983 | return xfrm_lookup(sock_net(sk), dst, flowi6_to_flowi(fl6), sk, 0); |
| 964 | } | 984 | } |
| @@ -969,7 +989,6 @@ EXPORT_SYMBOL_GPL(ip6_dst_lookup_flow); | |||
| 969 | * @sk: socket which provides the dst cache and route info | 989 | * @sk: socket which provides the dst cache and route info |
| 970 | * @fl6: flow to lookup | 990 | * @fl6: flow to lookup |
| 971 | * @final_dst: final destination address for ipsec lookup | 991 | * @final_dst: final destination address for ipsec lookup |
| 972 | * @can_sleep: we are in a sleepable context | ||
| 973 | * | 992 | * |
| 974 | * This function performs a route lookup on the given flow with the | 993 | * This function performs a route lookup on the given flow with the |
| 975 | * possibility of using the cached route in the socket if it is valid. | 994 | * possibility of using the cached route in the socket if it is valid. |
| @@ -980,8 +999,7 @@ EXPORT_SYMBOL_GPL(ip6_dst_lookup_flow); | |||
| 980 | * error code. | 999 | * error code. |
| 981 | */ | 1000 | */ |
| 982 | struct dst_entry *ip6_sk_dst_lookup_flow(struct sock *sk, struct flowi6 *fl6, | 1001 | struct dst_entry *ip6_sk_dst_lookup_flow(struct sock *sk, struct flowi6 *fl6, |
| 983 | const struct in6_addr *final_dst, | 1002 | const struct in6_addr *final_dst) |
| 984 | bool can_sleep) | ||
| 985 | { | 1003 | { |
| 986 | struct dst_entry *dst = sk_dst_check(sk, inet6_sk(sk)->dst_cookie); | 1004 | struct dst_entry *dst = sk_dst_check(sk, inet6_sk(sk)->dst_cookie); |
| 987 | int err; | 1005 | int err; |
| @@ -993,8 +1011,6 @@ struct dst_entry *ip6_sk_dst_lookup_flow(struct sock *sk, struct flowi6 *fl6, | |||
| 993 | return ERR_PTR(err); | 1011 | return ERR_PTR(err); |
| 994 | if (final_dst) | 1012 | if (final_dst) |
| 995 | fl6->daddr = *final_dst; | 1013 | fl6->daddr = *final_dst; |
| 996 | if (can_sleep) | ||
| 997 | fl6->flowi6_flags |= FLOWI_FLAG_CAN_SLEEP; | ||
| 998 | 1014 | ||
| 999 | return xfrm_lookup(sock_net(sk), dst, flowi6_to_flowi(fl6), sk, 0); | 1015 | return xfrm_lookup(sock_net(sk), dst, flowi6_to_flowi(fl6), sk, 0); |
| 1000 | } | 1016 | } |
| @@ -1162,10 +1178,10 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, | |||
| 1162 | np->cork.hop_limit = hlimit; | 1178 | np->cork.hop_limit = hlimit; |
| 1163 | np->cork.tclass = tclass; | 1179 | np->cork.tclass = tclass; |
| 1164 | if (rt->dst.flags & DST_XFRM_TUNNEL) | 1180 | if (rt->dst.flags & DST_XFRM_TUNNEL) |
| 1165 | mtu = np->pmtudisc == IPV6_PMTUDISC_PROBE ? | 1181 | mtu = np->pmtudisc >= IPV6_PMTUDISC_PROBE ? |
| 1166 | rt->dst.dev->mtu : dst_mtu(&rt->dst); | 1182 | rt->dst.dev->mtu : dst_mtu(&rt->dst); |
| 1167 | else | 1183 | else |
| 1168 | mtu = np->pmtudisc == IPV6_PMTUDISC_PROBE ? | 1184 | mtu = np->pmtudisc >= IPV6_PMTUDISC_PROBE ? |
| 1169 | rt->dst.dev->mtu : dst_mtu(rt->dst.path); | 1185 | rt->dst.dev->mtu : dst_mtu(rt->dst.path); |
| 1170 | if (np->frag_size < mtu) { | 1186 | if (np->frag_size < mtu) { |
| 1171 | if (np->frag_size) | 1187 | if (np->frag_size) |
| @@ -1285,7 +1301,7 @@ alloc_new_skb: | |||
| 1285 | if (skb == NULL || skb_prev == NULL) | 1301 | if (skb == NULL || skb_prev == NULL) |
| 1286 | ip6_append_data_mtu(&mtu, &maxfraglen, | 1302 | ip6_append_data_mtu(&mtu, &maxfraglen, |
| 1287 | fragheaderlen, skb, rt, | 1303 | fragheaderlen, skb, rt, |
| 1288 | np->pmtudisc == | 1304 | np->pmtudisc >= |
| 1289 | IPV6_PMTUDISC_PROBE); | 1305 | IPV6_PMTUDISC_PROBE); |
| 1290 | 1306 | ||
| 1291 | skb_prev = skb; | 1307 | skb_prev = skb; |
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index 7881965a8248..5db8d310f9c0 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c | |||
| @@ -29,7 +29,6 @@ | |||
| 29 | #include <linux/if.h> | 29 | #include <linux/if.h> |
| 30 | #include <linux/in.h> | 30 | #include <linux/in.h> |
| 31 | #include <linux/ip.h> | 31 | #include <linux/ip.h> |
| 32 | #include <linux/if_tunnel.h> | ||
| 33 | #include <linux/net.h> | 32 | #include <linux/net.h> |
| 34 | #include <linux/in6.h> | 33 | #include <linux/in6.h> |
| 35 | #include <linux/netdevice.h> | 34 | #include <linux/netdevice.h> |
| @@ -70,9 +69,6 @@ MODULE_ALIAS_NETDEV("ip6tnl0"); | |||
| 70 | #define IP6_TNL_TRACE(x...) do {;} while(0) | 69 | #define IP6_TNL_TRACE(x...) do {;} while(0) |
| 71 | #endif | 70 | #endif |
| 72 | 71 | ||
| 73 | #define IPV6_TCLASS_MASK (IPV6_FLOWINFO_MASK & ~IPV6_FLOWLABEL_MASK) | ||
| 74 | #define IPV6_TCLASS_SHIFT 20 | ||
| 75 | |||
| 76 | #define HASH_SIZE_SHIFT 5 | 72 | #define HASH_SIZE_SHIFT 5 |
| 77 | #define HASH_SIZE (1 << HASH_SIZE_SHIFT) | 73 | #define HASH_SIZE (1 << HASH_SIZE_SHIFT) |
| 78 | 74 | ||
| @@ -103,12 +99,13 @@ struct ip6_tnl_net { | |||
| 103 | 99 | ||
| 104 | static struct net_device_stats *ip6_get_stats(struct net_device *dev) | 100 | static struct net_device_stats *ip6_get_stats(struct net_device *dev) |
| 105 | { | 101 | { |
| 106 | struct pcpu_tstats tmp, sum = { 0 }; | 102 | struct pcpu_sw_netstats tmp, sum = { 0 }; |
| 107 | int i; | 103 | int i; |
| 108 | 104 | ||
| 109 | for_each_possible_cpu(i) { | 105 | for_each_possible_cpu(i) { |
| 110 | unsigned int start; | 106 | unsigned int start; |
| 111 | const struct pcpu_tstats *tstats = per_cpu_ptr(dev->tstats, i); | 107 | const struct pcpu_sw_netstats *tstats = |
| 108 | per_cpu_ptr(dev->tstats, i); | ||
| 112 | 109 | ||
| 113 | do { | 110 | do { |
| 114 | start = u64_stats_fetch_begin_bh(&tstats->syncp); | 111 | start = u64_stats_fetch_begin_bh(&tstats->syncp); |
| @@ -794,7 +791,7 @@ static int ip6_tnl_rcv(struct sk_buff *skb, __u16 protocol, | |||
| 794 | 791 | ||
| 795 | if ((t = ip6_tnl_lookup(dev_net(skb->dev), &ipv6h->saddr, | 792 | if ((t = ip6_tnl_lookup(dev_net(skb->dev), &ipv6h->saddr, |
| 796 | &ipv6h->daddr)) != NULL) { | 793 | &ipv6h->daddr)) != NULL) { |
| 797 | struct pcpu_tstats *tstats; | 794 | struct pcpu_sw_netstats *tstats; |
| 798 | 795 | ||
| 799 | if (t->parms.proto != ipproto && t->parms.proto != 0) { | 796 | if (t->parms.proto != ipproto && t->parms.proto != 0) { |
| 800 | rcu_read_unlock(); | 797 | rcu_read_unlock(); |
| @@ -1142,7 +1139,7 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev) | |||
| 1142 | if (t->parms.flags & IP6_TNL_F_USE_ORIG_TCLASS) | 1139 | if (t->parms.flags & IP6_TNL_F_USE_ORIG_TCLASS) |
| 1143 | fl6.flowlabel |= (*(__be32 *) ipv6h & IPV6_TCLASS_MASK); | 1140 | fl6.flowlabel |= (*(__be32 *) ipv6h & IPV6_TCLASS_MASK); |
| 1144 | if (t->parms.flags & IP6_TNL_F_USE_ORIG_FLOWLABEL) | 1141 | if (t->parms.flags & IP6_TNL_F_USE_ORIG_FLOWLABEL) |
| 1145 | fl6.flowlabel |= (*(__be32 *) ipv6h & IPV6_FLOWLABEL_MASK); | 1142 | fl6.flowlabel |= ip6_flowlabel(ipv6h); |
| 1146 | if (t->parms.flags & IP6_TNL_F_USE_ORIG_FWMARK) | 1143 | if (t->parms.flags & IP6_TNL_F_USE_ORIG_FWMARK) |
| 1147 | fl6.flowi6_mark = skb->mark; | 1144 | fl6.flowi6_mark = skb->mark; |
| 1148 | 1145 | ||
| @@ -1509,12 +1506,12 @@ ip6_tnl_dev_init_gen(struct net_device *dev) | |||
| 1509 | 1506 | ||
| 1510 | t->dev = dev; | 1507 | t->dev = dev; |
| 1511 | t->net = dev_net(dev); | 1508 | t->net = dev_net(dev); |
| 1512 | dev->tstats = alloc_percpu(struct pcpu_tstats); | 1509 | dev->tstats = alloc_percpu(struct pcpu_sw_netstats); |
| 1513 | if (!dev->tstats) | 1510 | if (!dev->tstats) |
| 1514 | return -ENOMEM; | 1511 | return -ENOMEM; |
| 1515 | 1512 | ||
| 1516 | for_each_possible_cpu(i) { | 1513 | for_each_possible_cpu(i) { |
| 1517 | struct pcpu_tstats *ip6_tnl_stats; | 1514 | struct pcpu_sw_netstats *ip6_tnl_stats; |
| 1518 | ip6_tnl_stats = per_cpu_ptr(dev->tstats, i); | 1515 | ip6_tnl_stats = per_cpu_ptr(dev->tstats, i); |
| 1519 | u64_stats_init(&ip6_tnl_stats->syncp); | 1516 | u64_stats_init(&ip6_tnl_stats->syncp); |
| 1520 | } | 1517 | } |
diff --git a/net/ipv6/ip6_vti.c b/net/ipv6/ip6_vti.c index 7b42d5ef868d..2d19272b8cee 100644 --- a/net/ipv6/ip6_vti.c +++ b/net/ipv6/ip6_vti.c | |||
| @@ -24,7 +24,6 @@ | |||
| 24 | #include <linux/if.h> | 24 | #include <linux/if.h> |
| 25 | #include <linux/in.h> | 25 | #include <linux/in.h> |
| 26 | #include <linux/ip.h> | 26 | #include <linux/ip.h> |
| 27 | #include <linux/if_tunnel.h> | ||
| 28 | #include <linux/net.h> | 27 | #include <linux/net.h> |
| 29 | #include <linux/in6.h> | 28 | #include <linux/in6.h> |
| 30 | #include <linux/netdevice.h> | 29 | #include <linux/netdevice.h> |
| @@ -292,7 +291,7 @@ static int vti6_rcv(struct sk_buff *skb) | |||
| 292 | 291 | ||
| 293 | if ((t = vti6_tnl_lookup(dev_net(skb->dev), &ipv6h->saddr, | 292 | if ((t = vti6_tnl_lookup(dev_net(skb->dev), &ipv6h->saddr, |
| 294 | &ipv6h->daddr)) != NULL) { | 293 | &ipv6h->daddr)) != NULL) { |
| 295 | struct pcpu_tstats *tstats; | 294 | struct pcpu_sw_netstats *tstats; |
| 296 | 295 | ||
| 297 | if (t->parms.proto != IPPROTO_IPV6 && t->parms.proto != 0) { | 296 | if (t->parms.proto != IPPROTO_IPV6 && t->parms.proto != 0) { |
| 298 | rcu_read_unlock(); | 297 | rcu_read_unlock(); |
| @@ -736,11 +735,11 @@ static inline int vti6_dev_init_gen(struct net_device *dev) | |||
| 736 | 735 | ||
| 737 | t->dev = dev; | 736 | t->dev = dev; |
| 738 | t->net = dev_net(dev); | 737 | t->net = dev_net(dev); |
| 739 | dev->tstats = alloc_percpu(struct pcpu_tstats); | 738 | dev->tstats = alloc_percpu(struct pcpu_sw_netstats); |
| 740 | if (!dev->tstats) | 739 | if (!dev->tstats) |
| 741 | return -ENOMEM; | 740 | return -ENOMEM; |
| 742 | for_each_possible_cpu(i) { | 741 | for_each_possible_cpu(i) { |
| 743 | struct pcpu_tstats *stats; | 742 | struct pcpu_sw_netstats *stats; |
| 744 | stats = per_cpu_ptr(dev->tstats, i); | 743 | stats = per_cpu_ptr(dev->tstats, i); |
| 745 | u64_stats_init(&stats->syncp); | 744 | u64_stats_init(&stats->syncp); |
| 746 | } | 745 | } |
diff --git a/net/ipv6/ipcomp6.c b/net/ipv6/ipcomp6.c index ce507d9e1c90..da9becb42e81 100644 --- a/net/ipv6/ipcomp6.c +++ b/net/ipv6/ipcomp6.c | |||
| @@ -16,8 +16,7 @@ | |||
| 16 | * GNU General Public License for more details. | 16 | * GNU General Public License for more details. |
| 17 | * | 17 | * |
| 18 | * You should have received a copy of the GNU General Public License | 18 | * You should have received a copy of the GNU General Public License |
| 19 | * along with this program; if not, write to the Free Software | 19 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 21 | */ | 20 | */ |
| 22 | /* | 21 | /* |
| 23 | * [Memo] | 22 | * [Memo] |
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index 1c6ce3119ff8..0a00f449de5e 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c | |||
| @@ -722,7 +722,7 @@ done: | |||
| 722 | case IPV6_MTU_DISCOVER: | 722 | case IPV6_MTU_DISCOVER: |
| 723 | if (optlen < sizeof(int)) | 723 | if (optlen < sizeof(int)) |
| 724 | goto e_inval; | 724 | goto e_inval; |
| 725 | if (val < IP_PMTUDISC_DONT || val > IP_PMTUDISC_PROBE) | 725 | if (val < IPV6_PMTUDISC_DONT || val > IPV6_PMTUDISC_INTERFACE) |
| 726 | goto e_inval; | 726 | goto e_inval; |
| 727 | np->pmtudisc = val; | 727 | np->pmtudisc = val; |
| 728 | retv = 0; | 728 | retv = 0; |
| @@ -1002,10 +1002,8 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, | |||
| 1002 | release_sock(sk); | 1002 | release_sock(sk); |
| 1003 | 1003 | ||
| 1004 | if (skb) { | 1004 | if (skb) { |
| 1005 | int err = ip6_datagram_recv_ctl(sk, &msg, skb); | 1005 | ip6_datagram_recv_ctl(sk, &msg, skb); |
| 1006 | kfree_skb(skb); | 1006 | kfree_skb(skb); |
| 1007 | if (err) | ||
| 1008 | return err; | ||
| 1009 | } else { | 1007 | } else { |
| 1010 | if (np->rxopt.bits.rxinfo) { | 1008 | if (np->rxopt.bits.rxinfo) { |
| 1011 | struct in6_pktinfo src_info; | 1009 | struct in6_pktinfo src_info; |
| @@ -1019,7 +1017,8 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, | |||
| 1019 | put_cmsg(&msg, SOL_IPV6, IPV6_HOPLIMIT, sizeof(hlim), &hlim); | 1017 | put_cmsg(&msg, SOL_IPV6, IPV6_HOPLIMIT, sizeof(hlim), &hlim); |
| 1020 | } | 1018 | } |
| 1021 | if (np->rxopt.bits.rxtclass) { | 1019 | if (np->rxopt.bits.rxtclass) { |
| 1022 | int tclass = np->rcv_tclass; | 1020 | int tclass = (int)ip6_tclass(np->rcv_flowinfo); |
| 1021 | |||
| 1023 | put_cmsg(&msg, SOL_IPV6, IPV6_TCLASS, sizeof(tclass), &tclass); | 1022 | put_cmsg(&msg, SOL_IPV6, IPV6_TCLASS, sizeof(tclass), &tclass); |
| 1024 | } | 1023 | } |
| 1025 | if (np->rxopt.bits.rxoinfo) { | 1024 | if (np->rxopt.bits.rxoinfo) { |
| @@ -1034,6 +1033,11 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, | |||
| 1034 | int hlim = np->mcast_hops; | 1033 | int hlim = np->mcast_hops; |
| 1035 | put_cmsg(&msg, SOL_IPV6, IPV6_2292HOPLIMIT, sizeof(hlim), &hlim); | 1034 | put_cmsg(&msg, SOL_IPV6, IPV6_2292HOPLIMIT, sizeof(hlim), &hlim); |
| 1036 | } | 1035 | } |
| 1036 | if (np->rxopt.bits.rxflow) { | ||
| 1037 | __be32 flowinfo = np->rcv_flowinfo; | ||
| 1038 | |||
| 1039 | put_cmsg(&msg, SOL_IPV6, IPV6_FLOWINFO, sizeof(flowinfo), &flowinfo); | ||
| 1040 | } | ||
| 1037 | } | 1041 | } |
| 1038 | len -= msg.msg_controllen; | 1042 | len -= msg.msg_controllen; |
| 1039 | return put_user(len, optlen); | 1043 | return put_user(len, optlen); |
| @@ -1215,6 +1219,7 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, | |||
| 1215 | case IPV6_FLOWLABEL_MGR: | 1219 | case IPV6_FLOWLABEL_MGR: |
| 1216 | { | 1220 | { |
| 1217 | struct in6_flowlabel_req freq; | 1221 | struct in6_flowlabel_req freq; |
| 1222 | int flags; | ||
| 1218 | 1223 | ||
| 1219 | if (len < sizeof(freq)) | 1224 | if (len < sizeof(freq)) |
| 1220 | return -EINVAL; | 1225 | return -EINVAL; |
| @@ -1226,9 +1231,11 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, | |||
| 1226 | return -EINVAL; | 1231 | return -EINVAL; |
| 1227 | 1232 | ||
| 1228 | len = sizeof(freq); | 1233 | len = sizeof(freq); |
| 1234 | flags = freq.flr_flags; | ||
| 1235 | |||
| 1229 | memset(&freq, 0, sizeof(freq)); | 1236 | memset(&freq, 0, sizeof(freq)); |
| 1230 | 1237 | ||
| 1231 | val = ipv6_flowlabel_opt_get(sk, &freq); | 1238 | val = ipv6_flowlabel_opt_get(sk, &freq, flags); |
| 1232 | if (val < 0) | 1239 | if (val < 0) |
| 1233 | return val; | 1240 | return val; |
| 1234 | 1241 | ||
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index d18f9f903db6..e1e47350784b 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c | |||
| @@ -999,7 +999,7 @@ bool ipv6_chk_mcast_addr(struct net_device *dev, const struct in6_addr *group, | |||
| 999 | 999 | ||
| 1000 | static void mld_gq_start_timer(struct inet6_dev *idev) | 1000 | static void mld_gq_start_timer(struct inet6_dev *idev) |
| 1001 | { | 1001 | { |
| 1002 | unsigned long tv = net_random() % idev->mc_maxdelay; | 1002 | unsigned long tv = prandom_u32() % idev->mc_maxdelay; |
| 1003 | 1003 | ||
| 1004 | idev->mc_gq_running = 1; | 1004 | idev->mc_gq_running = 1; |
| 1005 | if (!mod_timer(&idev->mc_gq_timer, jiffies+tv+2)) | 1005 | if (!mod_timer(&idev->mc_gq_timer, jiffies+tv+2)) |
| @@ -1015,7 +1015,7 @@ static void mld_gq_stop_timer(struct inet6_dev *idev) | |||
| 1015 | 1015 | ||
| 1016 | static void mld_ifc_start_timer(struct inet6_dev *idev, unsigned long delay) | 1016 | static void mld_ifc_start_timer(struct inet6_dev *idev, unsigned long delay) |
| 1017 | { | 1017 | { |
| 1018 | unsigned long tv = net_random() % delay; | 1018 | unsigned long tv = prandom_u32() % delay; |
| 1019 | 1019 | ||
| 1020 | if (!mod_timer(&idev->mc_ifc_timer, jiffies+tv+2)) | 1020 | if (!mod_timer(&idev->mc_ifc_timer, jiffies+tv+2)) |
| 1021 | in6_dev_hold(idev); | 1021 | in6_dev_hold(idev); |
| @@ -1030,7 +1030,7 @@ static void mld_ifc_stop_timer(struct inet6_dev *idev) | |||
| 1030 | 1030 | ||
| 1031 | static void mld_dad_start_timer(struct inet6_dev *idev, unsigned long delay) | 1031 | static void mld_dad_start_timer(struct inet6_dev *idev, unsigned long delay) |
| 1032 | { | 1032 | { |
| 1033 | unsigned long tv = net_random() % delay; | 1033 | unsigned long tv = prandom_u32() % delay; |
| 1034 | 1034 | ||
| 1035 | if (!mod_timer(&idev->mc_dad_timer, jiffies+tv+2)) | 1035 | if (!mod_timer(&idev->mc_dad_timer, jiffies+tv+2)) |
| 1036 | in6_dev_hold(idev); | 1036 | in6_dev_hold(idev); |
| @@ -1061,7 +1061,7 @@ static void igmp6_group_queried(struct ifmcaddr6 *ma, unsigned long resptime) | |||
| 1061 | } | 1061 | } |
| 1062 | 1062 | ||
| 1063 | if (delay >= resptime) | 1063 | if (delay >= resptime) |
| 1064 | delay = net_random() % resptime; | 1064 | delay = prandom_u32() % resptime; |
| 1065 | 1065 | ||
| 1066 | ma->mca_timer.expires = jiffies + delay; | 1066 | ma->mca_timer.expires = jiffies + delay; |
| 1067 | if (!mod_timer(&ma->mca_timer, jiffies + delay)) | 1067 | if (!mod_timer(&ma->mca_timer, jiffies + delay)) |
| @@ -1665,7 +1665,7 @@ static struct sk_buff *add_grhead(struct sk_buff *skb, struct ifmcaddr6 *pmc, | |||
| 1665 | skb_tailroom(skb)) : 0) | 1665 | skb_tailroom(skb)) : 0) |
| 1666 | 1666 | ||
| 1667 | static struct sk_buff *add_grec(struct sk_buff *skb, struct ifmcaddr6 *pmc, | 1667 | static struct sk_buff *add_grec(struct sk_buff *skb, struct ifmcaddr6 *pmc, |
| 1668 | int type, int gdeleted, int sdeleted) | 1668 | int type, int gdeleted, int sdeleted, int crsend) |
| 1669 | { | 1669 | { |
| 1670 | struct inet6_dev *idev = pmc->idev; | 1670 | struct inet6_dev *idev = pmc->idev; |
| 1671 | struct net_device *dev = idev->dev; | 1671 | struct net_device *dev = idev->dev; |
| @@ -1757,7 +1757,7 @@ empty_source: | |||
| 1757 | if (type == MLD2_ALLOW_NEW_SOURCES || | 1757 | if (type == MLD2_ALLOW_NEW_SOURCES || |
| 1758 | type == MLD2_BLOCK_OLD_SOURCES) | 1758 | type == MLD2_BLOCK_OLD_SOURCES) |
| 1759 | return skb; | 1759 | return skb; |
| 1760 | if (pmc->mca_crcount || isquery) { | 1760 | if (pmc->mca_crcount || isquery || crsend) { |
| 1761 | /* make sure we have room for group header */ | 1761 | /* make sure we have room for group header */ |
| 1762 | if (skb && AVAILABLE(skb) < sizeof(struct mld2_grec)) { | 1762 | if (skb && AVAILABLE(skb) < sizeof(struct mld2_grec)) { |
| 1763 | mld_sendpack(skb); | 1763 | mld_sendpack(skb); |
| @@ -1789,7 +1789,7 @@ static void mld_send_report(struct inet6_dev *idev, struct ifmcaddr6 *pmc) | |||
| 1789 | type = MLD2_MODE_IS_EXCLUDE; | 1789 | type = MLD2_MODE_IS_EXCLUDE; |
| 1790 | else | 1790 | else |
| 1791 | type = MLD2_MODE_IS_INCLUDE; | 1791 | type = MLD2_MODE_IS_INCLUDE; |
| 1792 | skb = add_grec(skb, pmc, type, 0, 0); | 1792 | skb = add_grec(skb, pmc, type, 0, 0, 0); |
| 1793 | spin_unlock_bh(&pmc->mca_lock); | 1793 | spin_unlock_bh(&pmc->mca_lock); |
| 1794 | } | 1794 | } |
| 1795 | } else { | 1795 | } else { |
| @@ -1798,7 +1798,7 @@ static void mld_send_report(struct inet6_dev *idev, struct ifmcaddr6 *pmc) | |||
| 1798 | type = MLD2_MODE_IS_EXCLUDE; | 1798 | type = MLD2_MODE_IS_EXCLUDE; |
| 1799 | else | 1799 | else |
| 1800 | type = MLD2_MODE_IS_INCLUDE; | 1800 | type = MLD2_MODE_IS_INCLUDE; |
| 1801 | skb = add_grec(skb, pmc, type, 0, 0); | 1801 | skb = add_grec(skb, pmc, type, 0, 0, 0); |
| 1802 | spin_unlock_bh(&pmc->mca_lock); | 1802 | spin_unlock_bh(&pmc->mca_lock); |
| 1803 | } | 1803 | } |
| 1804 | read_unlock_bh(&idev->lock); | 1804 | read_unlock_bh(&idev->lock); |
| @@ -1843,13 +1843,13 @@ static void mld_send_cr(struct inet6_dev *idev) | |||
| 1843 | if (pmc->mca_sfmode == MCAST_INCLUDE) { | 1843 | if (pmc->mca_sfmode == MCAST_INCLUDE) { |
| 1844 | type = MLD2_BLOCK_OLD_SOURCES; | 1844 | type = MLD2_BLOCK_OLD_SOURCES; |
| 1845 | dtype = MLD2_BLOCK_OLD_SOURCES; | 1845 | dtype = MLD2_BLOCK_OLD_SOURCES; |
| 1846 | skb = add_grec(skb, pmc, type, 1, 0); | 1846 | skb = add_grec(skb, pmc, type, 1, 0, 0); |
| 1847 | skb = add_grec(skb, pmc, dtype, 1, 1); | 1847 | skb = add_grec(skb, pmc, dtype, 1, 1, 0); |
| 1848 | } | 1848 | } |
| 1849 | if (pmc->mca_crcount) { | 1849 | if (pmc->mca_crcount) { |
| 1850 | if (pmc->mca_sfmode == MCAST_EXCLUDE) { | 1850 | if (pmc->mca_sfmode == MCAST_EXCLUDE) { |
| 1851 | type = MLD2_CHANGE_TO_INCLUDE; | 1851 | type = MLD2_CHANGE_TO_INCLUDE; |
| 1852 | skb = add_grec(skb, pmc, type, 1, 0); | 1852 | skb = add_grec(skb, pmc, type, 1, 0, 0); |
| 1853 | } | 1853 | } |
| 1854 | pmc->mca_crcount--; | 1854 | pmc->mca_crcount--; |
| 1855 | if (pmc->mca_crcount == 0) { | 1855 | if (pmc->mca_crcount == 0) { |
| @@ -1880,8 +1880,8 @@ static void mld_send_cr(struct inet6_dev *idev) | |||
| 1880 | type = MLD2_ALLOW_NEW_SOURCES; | 1880 | type = MLD2_ALLOW_NEW_SOURCES; |
| 1881 | dtype = MLD2_BLOCK_OLD_SOURCES; | 1881 | dtype = MLD2_BLOCK_OLD_SOURCES; |
| 1882 | } | 1882 | } |
| 1883 | skb = add_grec(skb, pmc, type, 0, 0); | 1883 | skb = add_grec(skb, pmc, type, 0, 0, 0); |
| 1884 | skb = add_grec(skb, pmc, dtype, 0, 1); /* deleted sources */ | 1884 | skb = add_grec(skb, pmc, dtype, 0, 1, 0); /* deleted sources */ |
| 1885 | 1885 | ||
| 1886 | /* filter mode changes */ | 1886 | /* filter mode changes */ |
| 1887 | if (pmc->mca_crcount) { | 1887 | if (pmc->mca_crcount) { |
| @@ -1889,7 +1889,7 @@ static void mld_send_cr(struct inet6_dev *idev) | |||
| 1889 | type = MLD2_CHANGE_TO_EXCLUDE; | 1889 | type = MLD2_CHANGE_TO_EXCLUDE; |
| 1890 | else | 1890 | else |
| 1891 | type = MLD2_CHANGE_TO_INCLUDE; | 1891 | type = MLD2_CHANGE_TO_INCLUDE; |
| 1892 | skb = add_grec(skb, pmc, type, 0, 0); | 1892 | skb = add_grec(skb, pmc, type, 0, 0, 0); |
| 1893 | pmc->mca_crcount--; | 1893 | pmc->mca_crcount--; |
| 1894 | } | 1894 | } |
| 1895 | spin_unlock_bh(&pmc->mca_lock); | 1895 | spin_unlock_bh(&pmc->mca_lock); |
| @@ -1997,27 +1997,36 @@ err_out: | |||
| 1997 | goto out; | 1997 | goto out; |
| 1998 | } | 1998 | } |
| 1999 | 1999 | ||
| 2000 | static void mld_resend_report(struct inet6_dev *idev) | 2000 | static void mld_send_initial_cr(struct inet6_dev *idev) |
| 2001 | { | 2001 | { |
| 2002 | if (mld_in_v1_mode(idev)) { | 2002 | struct sk_buff *skb; |
| 2003 | struct ifmcaddr6 *mcaddr; | 2003 | struct ifmcaddr6 *pmc; |
| 2004 | read_lock_bh(&idev->lock); | 2004 | int type; |
| 2005 | for (mcaddr = idev->mc_list; mcaddr; mcaddr = mcaddr->next) { | 2005 | |
| 2006 | if (!(mcaddr->mca_flags & MAF_NOREPORT)) | 2006 | if (mld_in_v1_mode(idev)) |
| 2007 | igmp6_send(&mcaddr->mca_addr, idev->dev, | 2007 | return; |
| 2008 | ICMPV6_MGM_REPORT); | 2008 | |
| 2009 | } | 2009 | skb = NULL; |
| 2010 | read_unlock_bh(&idev->lock); | 2010 | read_lock_bh(&idev->lock); |
| 2011 | } else { | 2011 | for (pmc=idev->mc_list; pmc; pmc=pmc->next) { |
| 2012 | mld_send_report(idev, NULL); | 2012 | spin_lock_bh(&pmc->mca_lock); |
| 2013 | if (pmc->mca_sfcount[MCAST_EXCLUDE]) | ||
| 2014 | type = MLD2_CHANGE_TO_EXCLUDE; | ||
| 2015 | else | ||
| 2016 | type = MLD2_CHANGE_TO_INCLUDE; | ||
| 2017 | skb = add_grec(skb, pmc, type, 0, 0, 1); | ||
| 2018 | spin_unlock_bh(&pmc->mca_lock); | ||
| 2013 | } | 2019 | } |
| 2020 | read_unlock_bh(&idev->lock); | ||
| 2021 | if (skb) | ||
| 2022 | mld_sendpack(skb); | ||
| 2014 | } | 2023 | } |
| 2015 | 2024 | ||
| 2016 | void ipv6_mc_dad_complete(struct inet6_dev *idev) | 2025 | void ipv6_mc_dad_complete(struct inet6_dev *idev) |
| 2017 | { | 2026 | { |
| 2018 | idev->mc_dad_count = idev->mc_qrv; | 2027 | idev->mc_dad_count = idev->mc_qrv; |
| 2019 | if (idev->mc_dad_count) { | 2028 | if (idev->mc_dad_count) { |
| 2020 | mld_resend_report(idev); | 2029 | mld_send_initial_cr(idev); |
| 2021 | idev->mc_dad_count--; | 2030 | idev->mc_dad_count--; |
| 2022 | if (idev->mc_dad_count) | 2031 | if (idev->mc_dad_count) |
| 2023 | mld_dad_start_timer(idev, idev->mc_maxdelay); | 2032 | mld_dad_start_timer(idev, idev->mc_maxdelay); |
| @@ -2028,7 +2037,7 @@ static void mld_dad_timer_expire(unsigned long data) | |||
| 2028 | { | 2037 | { |
| 2029 | struct inet6_dev *idev = (struct inet6_dev *)data; | 2038 | struct inet6_dev *idev = (struct inet6_dev *)data; |
| 2030 | 2039 | ||
| 2031 | mld_resend_report(idev); | 2040 | mld_send_initial_cr(idev); |
| 2032 | if (idev->mc_dad_count) { | 2041 | if (idev->mc_dad_count) { |
| 2033 | idev->mc_dad_count--; | 2042 | idev->mc_dad_count--; |
| 2034 | if (idev->mc_dad_count) | 2043 | if (idev->mc_dad_count) |
| @@ -2328,7 +2337,7 @@ static void igmp6_join_group(struct ifmcaddr6 *ma) | |||
| 2328 | 2337 | ||
| 2329 | igmp6_send(&ma->mca_addr, ma->idev->dev, ICMPV6_MGM_REPORT); | 2338 | igmp6_send(&ma->mca_addr, ma->idev->dev, ICMPV6_MGM_REPORT); |
| 2330 | 2339 | ||
| 2331 | delay = net_random() % unsolicited_report_interval(ma->idev); | 2340 | delay = prandom_u32() % unsolicited_report_interval(ma->idev); |
| 2332 | 2341 | ||
| 2333 | spin_lock_bh(&ma->mca_lock); | 2342 | spin_lock_bh(&ma->mca_lock); |
| 2334 | if (del_timer(&ma->mca_timer)) { | 2343 | if (del_timer(&ma->mca_timer)) { |
diff --git a/net/ipv6/mip6.c b/net/ipv6/mip6.c index 9ac01dc9402e..db9b6cbc9db3 100644 --- a/net/ipv6/mip6.c +++ b/net/ipv6/mip6.c | |||
| @@ -13,8 +13,7 @@ | |||
| 13 | * GNU General Public License for more details. | 13 | * GNU General Public License for more details. |
| 14 | * | 14 | * |
| 15 | * You should have received a copy of the GNU General Public License | 15 | * You should have received a copy of the GNU General Public License |
| 16 | * along with this program; if not, write to the Free Software | 16 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 18 | */ | 17 | */ |
| 19 | /* | 18 | /* |
| 20 | * Authors: | 19 | * Authors: |
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 300865171394..09a22f4f36c9 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c | |||
| @@ -125,17 +125,19 @@ struct neigh_table nd_tbl = { | |||
| 125 | .id = "ndisc_cache", | 125 | .id = "ndisc_cache", |
| 126 | .parms = { | 126 | .parms = { |
| 127 | .tbl = &nd_tbl, | 127 | .tbl = &nd_tbl, |
| 128 | .base_reachable_time = ND_REACHABLE_TIME, | ||
| 129 | .retrans_time = ND_RETRANS_TIMER, | ||
| 130 | .gc_staletime = 60 * HZ, | ||
| 131 | .reachable_time = ND_REACHABLE_TIME, | 128 | .reachable_time = ND_REACHABLE_TIME, |
| 132 | .delay_probe_time = 5 * HZ, | 129 | .data = { |
| 133 | .queue_len_bytes = 64*1024, | 130 | [NEIGH_VAR_MCAST_PROBES] = 3, |
| 134 | .ucast_probes = 3, | 131 | [NEIGH_VAR_UCAST_PROBES] = 3, |
| 135 | .mcast_probes = 3, | 132 | [NEIGH_VAR_RETRANS_TIME] = ND_RETRANS_TIMER, |
| 136 | .anycast_delay = 1 * HZ, | 133 | [NEIGH_VAR_BASE_REACHABLE_TIME] = ND_REACHABLE_TIME, |
| 137 | .proxy_delay = (8 * HZ) / 10, | 134 | [NEIGH_VAR_DELAY_PROBE_TIME] = 5 * HZ, |
| 138 | .proxy_qlen = 64, | 135 | [NEIGH_VAR_GC_STALETIME] = 60 * HZ, |
| 136 | [NEIGH_VAR_QUEUE_LEN_BYTES] = 64 * 1024, | ||
| 137 | [NEIGH_VAR_PROXY_QLEN] = 64, | ||
| 138 | [NEIGH_VAR_ANYCAST_DELAY] = 1 * HZ, | ||
| 139 | [NEIGH_VAR_PROXY_DELAY] = (8 * HZ) / 10, | ||
| 140 | }, | ||
| 139 | }, | 141 | }, |
| 140 | .gc_interval = 30 * HZ, | 142 | .gc_interval = 30 * HZ, |
| 141 | .gc_thresh1 = 128, | 143 | .gc_thresh1 = 128, |
| @@ -656,14 +658,14 @@ static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb) | |||
| 656 | if (skb && ipv6_chk_addr(dev_net(dev), &ipv6_hdr(skb)->saddr, dev, 1)) | 658 | if (skb && ipv6_chk_addr(dev_net(dev), &ipv6_hdr(skb)->saddr, dev, 1)) |
| 657 | saddr = &ipv6_hdr(skb)->saddr; | 659 | saddr = &ipv6_hdr(skb)->saddr; |
| 658 | 660 | ||
| 659 | if ((probes -= neigh->parms->ucast_probes) < 0) { | 661 | if ((probes -= NEIGH_VAR(neigh->parms, UCAST_PROBES)) < 0) { |
| 660 | if (!(neigh->nud_state & NUD_VALID)) { | 662 | if (!(neigh->nud_state & NUD_VALID)) { |
| 661 | ND_PRINTK(1, dbg, | 663 | ND_PRINTK(1, dbg, |
| 662 | "%s: trying to ucast probe in NUD_INVALID: %pI6\n", | 664 | "%s: trying to ucast probe in NUD_INVALID: %pI6\n", |
| 663 | __func__, target); | 665 | __func__, target); |
| 664 | } | 666 | } |
| 665 | ndisc_send_ns(dev, neigh, target, target, saddr); | 667 | ndisc_send_ns(dev, neigh, target, target, saddr); |
| 666 | } else if ((probes -= neigh->parms->app_probes) < 0) { | 668 | } else if ((probes -= NEIGH_VAR(neigh->parms, APP_PROBES)) < 0) { |
| 667 | neigh_app_ns(neigh); | 669 | neigh_app_ns(neigh); |
| 668 | } else { | 670 | } else { |
| 669 | addrconf_addr_solict_mult(target, &mcaddr); | 671 | addrconf_addr_solict_mult(target, &mcaddr); |
| @@ -790,7 +792,7 @@ static void ndisc_recv_ns(struct sk_buff *skb) | |||
| 790 | if (!(NEIGH_CB(skb)->flags & LOCALLY_ENQUEUED) && | 792 | if (!(NEIGH_CB(skb)->flags & LOCALLY_ENQUEUED) && |
| 791 | skb->pkt_type != PACKET_HOST && | 793 | skb->pkt_type != PACKET_HOST && |
| 792 | inc && | 794 | inc && |
| 793 | idev->nd_parms->proxy_delay != 0) { | 795 | NEIGH_VAR(idev->nd_parms, PROXY_DELAY) != 0) { |
| 794 | /* | 796 | /* |
| 795 | * for anycast or proxy, | 797 | * for anycast or proxy, |
| 796 | * sender should delay its response | 798 | * sender should delay its response |
| @@ -1210,7 +1212,7 @@ skip_defrtr: | |||
| 1210 | rtime = (rtime*HZ)/1000; | 1212 | rtime = (rtime*HZ)/1000; |
| 1211 | if (rtime < HZ/10) | 1213 | if (rtime < HZ/10) |
| 1212 | rtime = HZ/10; | 1214 | rtime = HZ/10; |
| 1213 | in6_dev->nd_parms->retrans_time = rtime; | 1215 | NEIGH_VAR_SET(in6_dev->nd_parms, RETRANS_TIME, rtime); |
| 1214 | in6_dev->tstamp = jiffies; | 1216 | in6_dev->tstamp = jiffies; |
| 1215 | inet6_ifinfo_notify(RTM_NEWLINK, in6_dev); | 1217 | inet6_ifinfo_notify(RTM_NEWLINK, in6_dev); |
| 1216 | } | 1218 | } |
| @@ -1222,9 +1224,11 @@ skip_defrtr: | |||
| 1222 | if (rtime < HZ/10) | 1224 | if (rtime < HZ/10) |
| 1223 | rtime = HZ/10; | 1225 | rtime = HZ/10; |
| 1224 | 1226 | ||
| 1225 | if (rtime != in6_dev->nd_parms->base_reachable_time) { | 1227 | if (rtime != NEIGH_VAR(in6_dev->nd_parms, BASE_REACHABLE_TIME)) { |
| 1226 | in6_dev->nd_parms->base_reachable_time = rtime; | 1228 | NEIGH_VAR_SET(in6_dev->nd_parms, |
| 1227 | in6_dev->nd_parms->gc_staletime = 3 * rtime; | 1229 | BASE_REACHABLE_TIME, rtime); |
| 1230 | NEIGH_VAR_SET(in6_dev->nd_parms, | ||
| 1231 | GC_STALETIME, 3 * rtime); | ||
| 1228 | in6_dev->nd_parms->reachable_time = neigh_rand_reach_time(rtime); | 1232 | in6_dev->nd_parms->reachable_time = neigh_rand_reach_time(rtime); |
| 1229 | in6_dev->tstamp = jiffies; | 1233 | in6_dev->tstamp = jiffies; |
| 1230 | inet6_ifinfo_notify(RTM_NEWLINK, in6_dev); | 1234 | inet6_ifinfo_notify(RTM_NEWLINK, in6_dev); |
| @@ -1651,22 +1655,23 @@ int ndisc_ifinfo_sysctl_change(struct ctl_table *ctl, int write, void __user *bu | |||
| 1651 | ndisc_warn_deprecated_sysctl(ctl, "syscall", dev ? dev->name : "default"); | 1655 | ndisc_warn_deprecated_sysctl(ctl, "syscall", dev ? dev->name : "default"); |
| 1652 | 1656 | ||
| 1653 | if (strcmp(ctl->procname, "retrans_time") == 0) | 1657 | if (strcmp(ctl->procname, "retrans_time") == 0) |
| 1654 | ret = proc_dointvec(ctl, write, buffer, lenp, ppos); | 1658 | ret = neigh_proc_dointvec(ctl, write, buffer, lenp, ppos); |
| 1655 | 1659 | ||
| 1656 | else if (strcmp(ctl->procname, "base_reachable_time") == 0) | 1660 | else if (strcmp(ctl->procname, "base_reachable_time") == 0) |
| 1657 | ret = proc_dointvec_jiffies(ctl, write, | 1661 | ret = neigh_proc_dointvec_jiffies(ctl, write, |
| 1658 | buffer, lenp, ppos); | 1662 | buffer, lenp, ppos); |
| 1659 | 1663 | ||
| 1660 | else if ((strcmp(ctl->procname, "retrans_time_ms") == 0) || | 1664 | else if ((strcmp(ctl->procname, "retrans_time_ms") == 0) || |
| 1661 | (strcmp(ctl->procname, "base_reachable_time_ms") == 0)) | 1665 | (strcmp(ctl->procname, "base_reachable_time_ms") == 0)) |
| 1662 | ret = proc_dointvec_ms_jiffies(ctl, write, | 1666 | ret = neigh_proc_dointvec_ms_jiffies(ctl, write, |
| 1663 | buffer, lenp, ppos); | 1667 | buffer, lenp, ppos); |
| 1664 | else | 1668 | else |
| 1665 | ret = -1; | 1669 | ret = -1; |
| 1666 | 1670 | ||
| 1667 | if (write && ret == 0 && dev && (idev = in6_dev_get(dev)) != NULL) { | 1671 | if (write && ret == 0 && dev && (idev = in6_dev_get(dev)) != NULL) { |
| 1668 | if (ctl->data == &idev->nd_parms->base_reachable_time) | 1672 | if (ctl->data == &NEIGH_VAR(idev->nd_parms, BASE_REACHABLE_TIME)) |
| 1669 | idev->nd_parms->reachable_time = neigh_rand_reach_time(idev->nd_parms->base_reachable_time); | 1673 | idev->nd_parms->reachable_time = |
| 1674 | neigh_rand_reach_time(NEIGH_VAR(idev->nd_parms, BASE_REACHABLE_TIME)); | ||
| 1670 | idev->tstamp = jiffies; | 1675 | idev->tstamp = jiffies; |
| 1671 | inet6_ifinfo_notify(RTM_NEWLINK, idev); | 1676 | inet6_ifinfo_notify(RTM_NEWLINK, idev); |
| 1672 | in6_dev_put(idev); | 1677 | in6_dev_put(idev); |
| @@ -1725,7 +1730,7 @@ int __init ndisc_init(void) | |||
| 1725 | neigh_table_init(&nd_tbl); | 1730 | neigh_table_init(&nd_tbl); |
| 1726 | 1731 | ||
| 1727 | #ifdef CONFIG_SYSCTL | 1732 | #ifdef CONFIG_SYSCTL |
| 1728 | err = neigh_sysctl_register(NULL, &nd_tbl.parms, "ipv6", | 1733 | err = neigh_sysctl_register(NULL, &nd_tbl.parms, |
| 1729 | &ndisc_ifinfo_sysctl_change); | 1734 | &ndisc_ifinfo_sysctl_change); |
| 1730 | if (err) | 1735 | if (err) |
| 1731 | goto out_unregister_pernet; | 1736 | goto out_unregister_pernet; |
diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig index 7702f9e90a04..35750df744dc 100644 --- a/net/ipv6/netfilter/Kconfig +++ b/net/ipv6/netfilter/Kconfig | |||
| @@ -28,15 +28,27 @@ config NF_CONNTRACK_IPV6 | |||
| 28 | config NF_TABLES_IPV6 | 28 | config NF_TABLES_IPV6 |
| 29 | depends on NF_TABLES | 29 | depends on NF_TABLES |
| 30 | tristate "IPv6 nf_tables support" | 30 | tristate "IPv6 nf_tables support" |
| 31 | help | ||
| 32 | This option enables the IPv6 support for nf_tables. | ||
| 31 | 33 | ||
| 32 | config NFT_CHAIN_ROUTE_IPV6 | 34 | config NFT_CHAIN_ROUTE_IPV6 |
| 33 | depends on NF_TABLES_IPV6 | 35 | depends on NF_TABLES_IPV6 |
| 34 | tristate "IPv6 nf_tables route chain support" | 36 | tristate "IPv6 nf_tables route chain support" |
| 37 | help | ||
| 38 | This option enables the "route" chain for IPv6 in nf_tables. This | ||
| 39 | chain type is used to force packet re-routing after mangling header | ||
| 40 | fields such as the source, destination, flowlabel, hop-limit and | ||
| 41 | the packet mark. | ||
| 35 | 42 | ||
| 36 | config NFT_CHAIN_NAT_IPV6 | 43 | config NFT_CHAIN_NAT_IPV6 |
| 37 | depends on NF_TABLES_IPV6 | 44 | depends on NF_TABLES_IPV6 |
| 38 | depends on NF_NAT_IPV6 && NFT_NAT | 45 | depends on NF_NAT_IPV6 && NFT_NAT |
| 39 | tristate "IPv6 nf_tables nat chain support" | 46 | tristate "IPv6 nf_tables nat chain support" |
| 47 | help | ||
| 48 | This option enables the "nat" chain for IPv6 in nf_tables. This | ||
| 49 | chain type is used to perform Network Address Translation (NAT) | ||
| 50 | packet transformations such as the source, destination address and | ||
| 51 | source and destination ports. | ||
| 40 | 52 | ||
| 41 | config IP6_NF_IPTABLES | 53 | config IP6_NF_IPTABLES |
| 42 | tristate "IP6 tables support (required for filtering)" | 54 | tristate "IP6 tables support (required for filtering)" |
diff --git a/net/ipv6/netfilter/ip6t_REJECT.c b/net/ipv6/netfilter/ip6t_REJECT.c index da00a2ecde55..544b0a9da1b5 100644 --- a/net/ipv6/netfilter/ip6t_REJECT.c +++ b/net/ipv6/netfilter/ip6t_REJECT.c | |||
| @@ -23,181 +23,18 @@ | |||
| 23 | #include <linux/skbuff.h> | 23 | #include <linux/skbuff.h> |
| 24 | #include <linux/icmpv6.h> | 24 | #include <linux/icmpv6.h> |
| 25 | #include <linux/netdevice.h> | 25 | #include <linux/netdevice.h> |
| 26 | #include <net/ipv6.h> | ||
| 27 | #include <net/tcp.h> | ||
| 28 | #include <net/icmp.h> | 26 | #include <net/icmp.h> |
| 29 | #include <net/ip6_checksum.h> | ||
| 30 | #include <net/ip6_fib.h> | ||
| 31 | #include <net/ip6_route.h> | ||
| 32 | #include <net/flow.h> | 27 | #include <net/flow.h> |
| 33 | #include <linux/netfilter/x_tables.h> | 28 | #include <linux/netfilter/x_tables.h> |
| 34 | #include <linux/netfilter_ipv6/ip6_tables.h> | 29 | #include <linux/netfilter_ipv6/ip6_tables.h> |
| 35 | #include <linux/netfilter_ipv6/ip6t_REJECT.h> | 30 | #include <linux/netfilter_ipv6/ip6t_REJECT.h> |
| 36 | 31 | ||
| 32 | #include <net/netfilter/ipv6/nf_reject.h> | ||
| 33 | |||
| 37 | MODULE_AUTHOR("Yasuyuki KOZAKAI <yasuyuki.kozakai@toshiba.co.jp>"); | 34 | MODULE_AUTHOR("Yasuyuki KOZAKAI <yasuyuki.kozakai@toshiba.co.jp>"); |
| 38 | MODULE_DESCRIPTION("Xtables: packet \"rejection\" target for IPv6"); | 35 | MODULE_DESCRIPTION("Xtables: packet \"rejection\" target for IPv6"); |
| 39 | MODULE_LICENSE("GPL"); | 36 | MODULE_LICENSE("GPL"); |
| 40 | 37 | ||
| 41 | /* Send RST reply */ | ||
| 42 | static void send_reset(struct net *net, struct sk_buff *oldskb, int hook) | ||
| 43 | { | ||
| 44 | struct sk_buff *nskb; | ||
| 45 | struct tcphdr otcph, *tcph; | ||
| 46 | unsigned int otcplen, hh_len; | ||
| 47 | int tcphoff, needs_ack; | ||
| 48 | const struct ipv6hdr *oip6h = ipv6_hdr(oldskb); | ||
| 49 | struct ipv6hdr *ip6h; | ||
| 50 | #define DEFAULT_TOS_VALUE 0x0U | ||
| 51 | const __u8 tclass = DEFAULT_TOS_VALUE; | ||
| 52 | struct dst_entry *dst = NULL; | ||
| 53 | u8 proto; | ||
| 54 | __be16 frag_off; | ||
| 55 | struct flowi6 fl6; | ||
| 56 | |||
| 57 | if ((!(ipv6_addr_type(&oip6h->saddr) & IPV6_ADDR_UNICAST)) || | ||
| 58 | (!(ipv6_addr_type(&oip6h->daddr) & IPV6_ADDR_UNICAST))) { | ||
| 59 | pr_debug("addr is not unicast.\n"); | ||
| 60 | return; | ||
| 61 | } | ||
| 62 | |||
| 63 | proto = oip6h->nexthdr; | ||
| 64 | tcphoff = ipv6_skip_exthdr(oldskb, ((u8*)(oip6h+1) - oldskb->data), &proto, &frag_off); | ||
| 65 | |||
| 66 | if ((tcphoff < 0) || (tcphoff > oldskb->len)) { | ||
| 67 | pr_debug("Cannot get TCP header.\n"); | ||
| 68 | return; | ||
| 69 | } | ||
| 70 | |||
| 71 | otcplen = oldskb->len - tcphoff; | ||
| 72 | |||
| 73 | /* IP header checks: fragment, too short. */ | ||
| 74 | if (proto != IPPROTO_TCP || otcplen < sizeof(struct tcphdr)) { | ||
| 75 | pr_debug("proto(%d) != IPPROTO_TCP, " | ||
| 76 | "or too short. otcplen = %d\n", | ||
| 77 | proto, otcplen); | ||
| 78 | return; | ||
| 79 | } | ||
| 80 | |||
| 81 | if (skb_copy_bits(oldskb, tcphoff, &otcph, sizeof(struct tcphdr))) | ||
| 82 | BUG(); | ||
| 83 | |||
| 84 | /* No RST for RST. */ | ||
| 85 | if (otcph.rst) { | ||
| 86 | pr_debug("RST is set\n"); | ||
| 87 | return; | ||
| 88 | } | ||
| 89 | |||
| 90 | /* Check checksum. */ | ||
| 91 | if (nf_ip6_checksum(oldskb, hook, tcphoff, IPPROTO_TCP)) { | ||
| 92 | pr_debug("TCP checksum is invalid\n"); | ||
| 93 | return; | ||
| 94 | } | ||
| 95 | |||
| 96 | memset(&fl6, 0, sizeof(fl6)); | ||
| 97 | fl6.flowi6_proto = IPPROTO_TCP; | ||
| 98 | fl6.saddr = oip6h->daddr; | ||
| 99 | fl6.daddr = oip6h->saddr; | ||
| 100 | fl6.fl6_sport = otcph.dest; | ||
| 101 | fl6.fl6_dport = otcph.source; | ||
| 102 | security_skb_classify_flow(oldskb, flowi6_to_flowi(&fl6)); | ||
| 103 | dst = ip6_route_output(net, NULL, &fl6); | ||
| 104 | if (dst == NULL || dst->error) { | ||
| 105 | dst_release(dst); | ||
| 106 | return; | ||
| 107 | } | ||
| 108 | dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), NULL, 0); | ||
| 109 | if (IS_ERR(dst)) | ||
| 110 | return; | ||
| 111 | |||
| 112 | hh_len = (dst->dev->hard_header_len + 15)&~15; | ||
| 113 | nskb = alloc_skb(hh_len + 15 + dst->header_len + sizeof(struct ipv6hdr) | ||
| 114 | + sizeof(struct tcphdr) + dst->trailer_len, | ||
| 115 | GFP_ATOMIC); | ||
| 116 | |||
| 117 | if (!nskb) { | ||
| 118 | net_dbg_ratelimited("cannot alloc skb\n"); | ||
| 119 | dst_release(dst); | ||
| 120 | return; | ||
| 121 | } | ||
| 122 | |||
| 123 | skb_dst_set(nskb, dst); | ||
| 124 | |||
| 125 | skb_reserve(nskb, hh_len + dst->header_len); | ||
| 126 | |||
| 127 | skb_put(nskb, sizeof(struct ipv6hdr)); | ||
| 128 | skb_reset_network_header(nskb); | ||
| 129 | ip6h = ipv6_hdr(nskb); | ||
| 130 | ip6_flow_hdr(ip6h, tclass, 0); | ||
| 131 | ip6h->hop_limit = ip6_dst_hoplimit(dst); | ||
| 132 | ip6h->nexthdr = IPPROTO_TCP; | ||
| 133 | ip6h->saddr = oip6h->daddr; | ||
| 134 | ip6h->daddr = oip6h->saddr; | ||
| 135 | |||
| 136 | skb_reset_transport_header(nskb); | ||
| 137 | tcph = (struct tcphdr *)skb_put(nskb, sizeof(struct tcphdr)); | ||
| 138 | /* Truncate to length (no data) */ | ||
| 139 | tcph->doff = sizeof(struct tcphdr)/4; | ||
| 140 | tcph->source = otcph.dest; | ||
| 141 | tcph->dest = otcph.source; | ||
| 142 | |||
| 143 | if (otcph.ack) { | ||
| 144 | needs_ack = 0; | ||
| 145 | tcph->seq = otcph.ack_seq; | ||
| 146 | tcph->ack_seq = 0; | ||
| 147 | } else { | ||
| 148 | needs_ack = 1; | ||
| 149 | tcph->ack_seq = htonl(ntohl(otcph.seq) + otcph.syn + otcph.fin | ||
| 150 | + otcplen - (otcph.doff<<2)); | ||
| 151 | tcph->seq = 0; | ||
| 152 | } | ||
| 153 | |||
| 154 | /* Reset flags */ | ||
| 155 | ((u_int8_t *)tcph)[13] = 0; | ||
| 156 | tcph->rst = 1; | ||
| 157 | tcph->ack = needs_ack; | ||
| 158 | tcph->window = 0; | ||
| 159 | tcph->urg_ptr = 0; | ||
| 160 | tcph->check = 0; | ||
| 161 | |||
| 162 | /* Adjust TCP checksum */ | ||
| 163 | tcph->check = csum_ipv6_magic(&ipv6_hdr(nskb)->saddr, | ||
| 164 | &ipv6_hdr(nskb)->daddr, | ||
| 165 | sizeof(struct tcphdr), IPPROTO_TCP, | ||
| 166 | csum_partial(tcph, | ||
| 167 | sizeof(struct tcphdr), 0)); | ||
| 168 | |||
| 169 | nf_ct_attach(nskb, oldskb); | ||
| 170 | |||
| 171 | #ifdef CONFIG_BRIDGE_NETFILTER | ||
| 172 | /* If we use ip6_local_out for bridged traffic, the MAC source on | ||
| 173 | * the RST will be ours, instead of the destination's. This confuses | ||
| 174 | * some routers/firewalls, and they drop the packet. So we need to | ||
| 175 | * build the eth header using the original destination's MAC as the | ||
| 176 | * source, and send the RST packet directly. | ||
| 177 | */ | ||
| 178 | if (oldskb->nf_bridge) { | ||
| 179 | struct ethhdr *oeth = eth_hdr(oldskb); | ||
| 180 | nskb->dev = oldskb->nf_bridge->physindev; | ||
| 181 | nskb->protocol = htons(ETH_P_IPV6); | ||
| 182 | ip6h->payload_len = htons(sizeof(struct tcphdr)); | ||
| 183 | if (dev_hard_header(nskb, nskb->dev, ntohs(nskb->protocol), | ||
| 184 | oeth->h_source, oeth->h_dest, nskb->len) < 0) | ||
| 185 | return; | ||
| 186 | dev_queue_xmit(nskb); | ||
| 187 | } else | ||
| 188 | #endif | ||
| 189 | ip6_local_out(nskb); | ||
| 190 | } | ||
| 191 | |||
| 192 | static inline void | ||
| 193 | send_unreach(struct net *net, struct sk_buff *skb_in, unsigned char code, | ||
| 194 | unsigned int hooknum) | ||
| 195 | { | ||
| 196 | if (hooknum == NF_INET_LOCAL_OUT && skb_in->dev == NULL) | ||
| 197 | skb_in->dev = net->loopback_dev; | ||
| 198 | |||
| 199 | icmpv6_send(skb_in, ICMPV6_DEST_UNREACH, code, 0); | ||
| 200 | } | ||
| 201 | 38 | ||
| 202 | static unsigned int | 39 | static unsigned int |
| 203 | reject_tg6(struct sk_buff *skb, const struct xt_action_param *par) | 40 | reject_tg6(struct sk_buff *skb, const struct xt_action_param *par) |
| @@ -208,25 +45,25 @@ reject_tg6(struct sk_buff *skb, const struct xt_action_param *par) | |||
| 208 | pr_debug("%s: medium point\n", __func__); | 45 | pr_debug("%s: medium point\n", __func__); |
| 209 | switch (reject->with) { | 46 | switch (reject->with) { |
| 210 | case IP6T_ICMP6_NO_ROUTE: | 47 | case IP6T_ICMP6_NO_ROUTE: |
| 211 | send_unreach(net, skb, ICMPV6_NOROUTE, par->hooknum); | 48 | nf_send_unreach6(net, skb, ICMPV6_NOROUTE, par->hooknum); |
| 212 | break; | 49 | break; |
| 213 | case IP6T_ICMP6_ADM_PROHIBITED: | 50 | case IP6T_ICMP6_ADM_PROHIBITED: |
| 214 | send_unreach(net, skb, ICMPV6_ADM_PROHIBITED, par->hooknum); | 51 | nf_send_unreach6(net, skb, ICMPV6_ADM_PROHIBITED, par->hooknum); |
| 215 | break; | 52 | break; |
| 216 | case IP6T_ICMP6_NOT_NEIGHBOUR: | 53 | case IP6T_ICMP6_NOT_NEIGHBOUR: |
| 217 | send_unreach(net, skb, ICMPV6_NOT_NEIGHBOUR, par->hooknum); | 54 | nf_send_unreach6(net, skb, ICMPV6_NOT_NEIGHBOUR, par->hooknum); |
| 218 | break; | 55 | break; |
| 219 | case IP6T_ICMP6_ADDR_UNREACH: | 56 | case IP6T_ICMP6_ADDR_UNREACH: |
| 220 | send_unreach(net, skb, ICMPV6_ADDR_UNREACH, par->hooknum); | 57 | nf_send_unreach6(net, skb, ICMPV6_ADDR_UNREACH, par->hooknum); |
| 221 | break; | 58 | break; |
| 222 | case IP6T_ICMP6_PORT_UNREACH: | 59 | case IP6T_ICMP6_PORT_UNREACH: |
| 223 | send_unreach(net, skb, ICMPV6_PORT_UNREACH, par->hooknum); | 60 | nf_send_unreach6(net, skb, ICMPV6_PORT_UNREACH, par->hooknum); |
| 224 | break; | 61 | break; |
| 225 | case IP6T_ICMP6_ECHOREPLY: | 62 | case IP6T_ICMP6_ECHOREPLY: |
| 226 | /* Do nothing */ | 63 | /* Do nothing */ |
| 227 | break; | 64 | break; |
| 228 | case IP6T_TCP_RESET: | 65 | case IP6T_TCP_RESET: |
| 229 | send_reset(net, skb, par->hooknum); | 66 | nf_send_reset6(net, skb, par->hooknum); |
| 230 | break; | 67 | break; |
| 231 | default: | 68 | default: |
| 232 | net_info_ratelimited("case %u not handled yet\n", reject->with); | 69 | net_info_ratelimited("case %u not handled yet\n", reject->with); |
diff --git a/net/ipv6/netfilter/nf_tables_ipv6.c b/net/ipv6/netfilter/nf_tables_ipv6.c index d77db8a13505..0d812b31277d 100644 --- a/net/ipv6/netfilter/nf_tables_ipv6.c +++ b/net/ipv6/netfilter/nf_tables_ipv6.c | |||
| @@ -16,34 +16,51 @@ | |||
| 16 | #include <net/netfilter/nf_tables.h> | 16 | #include <net/netfilter/nf_tables.h> |
| 17 | #include <net/netfilter/nf_tables_ipv6.h> | 17 | #include <net/netfilter/nf_tables_ipv6.h> |
| 18 | 18 | ||
| 19 | static unsigned int nft_do_chain_ipv6(const struct nf_hook_ops *ops, | ||
| 20 | struct sk_buff *skb, | ||
| 21 | const struct net_device *in, | ||
| 22 | const struct net_device *out, | ||
| 23 | int (*okfn)(struct sk_buff *)) | ||
| 24 | { | ||
| 25 | struct nft_pktinfo pkt; | ||
| 26 | |||
| 27 | /* malformed packet, drop it */ | ||
| 28 | if (nft_set_pktinfo_ipv6(&pkt, ops, skb, in, out) < 0) | ||
| 29 | return NF_DROP; | ||
| 30 | |||
| 31 | return nft_do_chain(&pkt, ops); | ||
| 32 | } | ||
| 33 | |||
| 19 | static unsigned int nft_ipv6_output(const struct nf_hook_ops *ops, | 34 | static unsigned int nft_ipv6_output(const struct nf_hook_ops *ops, |
| 20 | struct sk_buff *skb, | 35 | struct sk_buff *skb, |
| 21 | const struct net_device *in, | 36 | const struct net_device *in, |
| 22 | const struct net_device *out, | 37 | const struct net_device *out, |
| 23 | int (*okfn)(struct sk_buff *)) | 38 | int (*okfn)(struct sk_buff *)) |
| 24 | { | 39 | { |
| 25 | struct nft_pktinfo pkt; | ||
| 26 | |||
| 27 | if (unlikely(skb->len < sizeof(struct ipv6hdr))) { | 40 | if (unlikely(skb->len < sizeof(struct ipv6hdr))) { |
| 28 | if (net_ratelimit()) | 41 | if (net_ratelimit()) |
| 29 | pr_info("nf_tables_ipv6: ignoring short SOCK_RAW " | 42 | pr_info("nf_tables_ipv6: ignoring short SOCK_RAW " |
| 30 | "packet\n"); | 43 | "packet\n"); |
| 31 | return NF_ACCEPT; | 44 | return NF_ACCEPT; |
| 32 | } | 45 | } |
| 33 | if (nft_set_pktinfo_ipv6(&pkt, ops, skb, in, out) < 0) | ||
| 34 | return NF_DROP; | ||
| 35 | 46 | ||
| 36 | return nft_do_chain_pktinfo(&pkt, ops); | 47 | return nft_do_chain_ipv6(ops, skb, in, out, okfn); |
| 37 | } | 48 | } |
| 38 | 49 | ||
| 39 | static struct nft_af_info nft_af_ipv6 __read_mostly = { | 50 | struct nft_af_info nft_af_ipv6 __read_mostly = { |
| 40 | .family = NFPROTO_IPV6, | 51 | .family = NFPROTO_IPV6, |
| 41 | .nhooks = NF_INET_NUMHOOKS, | 52 | .nhooks = NF_INET_NUMHOOKS, |
| 42 | .owner = THIS_MODULE, | 53 | .owner = THIS_MODULE, |
| 54 | .nops = 1, | ||
| 43 | .hooks = { | 55 | .hooks = { |
| 56 | [NF_INET_LOCAL_IN] = nft_do_chain_ipv6, | ||
| 44 | [NF_INET_LOCAL_OUT] = nft_ipv6_output, | 57 | [NF_INET_LOCAL_OUT] = nft_ipv6_output, |
| 58 | [NF_INET_FORWARD] = nft_do_chain_ipv6, | ||
| 59 | [NF_INET_PRE_ROUTING] = nft_do_chain_ipv6, | ||
| 60 | [NF_INET_POST_ROUTING] = nft_do_chain_ipv6, | ||
| 45 | }, | 61 | }, |
| 46 | }; | 62 | }; |
| 63 | EXPORT_SYMBOL_GPL(nft_af_ipv6); | ||
| 47 | 64 | ||
| 48 | static int nf_tables_ipv6_init_net(struct net *net) | 65 | static int nf_tables_ipv6_init_net(struct net *net) |
| 49 | { | 66 | { |
| @@ -73,44 +90,28 @@ static struct pernet_operations nf_tables_ipv6_net_ops = { | |||
| 73 | .exit = nf_tables_ipv6_exit_net, | 90 | .exit = nf_tables_ipv6_exit_net, |
| 74 | }; | 91 | }; |
| 75 | 92 | ||
| 76 | static unsigned int | 93 | static const struct nf_chain_type filter_ipv6 = { |
| 77 | nft_do_chain_ipv6(const struct nf_hook_ops *ops, | ||
| 78 | struct sk_buff *skb, | ||
| 79 | const struct net_device *in, | ||
| 80 | const struct net_device *out, | ||
| 81 | int (*okfn)(struct sk_buff *)) | ||
| 82 | { | ||
| 83 | struct nft_pktinfo pkt; | ||
| 84 | |||
| 85 | /* malformed packet, drop it */ | ||
| 86 | if (nft_set_pktinfo_ipv6(&pkt, ops, skb, in, out) < 0) | ||
| 87 | return NF_DROP; | ||
| 88 | |||
| 89 | return nft_do_chain_pktinfo(&pkt, ops); | ||
| 90 | } | ||
| 91 | |||
| 92 | static struct nf_chain_type filter_ipv6 = { | ||
| 93 | .family = NFPROTO_IPV6, | ||
| 94 | .name = "filter", | 94 | .name = "filter", |
| 95 | .type = NFT_CHAIN_T_DEFAULT, | 95 | .type = NFT_CHAIN_T_DEFAULT, |
| 96 | .family = NFPROTO_IPV6, | ||
| 97 | .owner = THIS_MODULE, | ||
| 96 | .hook_mask = (1 << NF_INET_LOCAL_IN) | | 98 | .hook_mask = (1 << NF_INET_LOCAL_IN) | |
| 97 | (1 << NF_INET_LOCAL_OUT) | | 99 | (1 << NF_INET_LOCAL_OUT) | |
| 98 | (1 << NF_INET_FORWARD) | | 100 | (1 << NF_INET_FORWARD) | |
| 99 | (1 << NF_INET_PRE_ROUTING) | | 101 | (1 << NF_INET_PRE_ROUTING) | |
| 100 | (1 << NF_INET_POST_ROUTING), | 102 | (1 << NF_INET_POST_ROUTING), |
| 101 | .fn = { | ||
| 102 | [NF_INET_LOCAL_IN] = nft_do_chain_ipv6, | ||
| 103 | [NF_INET_LOCAL_OUT] = nft_ipv6_output, | ||
| 104 | [NF_INET_FORWARD] = nft_do_chain_ipv6, | ||
| 105 | [NF_INET_PRE_ROUTING] = nft_do_chain_ipv6, | ||
| 106 | [NF_INET_POST_ROUTING] = nft_do_chain_ipv6, | ||
| 107 | }, | ||
| 108 | }; | 103 | }; |
| 109 | 104 | ||
| 110 | static int __init nf_tables_ipv6_init(void) | 105 | static int __init nf_tables_ipv6_init(void) |
| 111 | { | 106 | { |
| 107 | int ret; | ||
| 108 | |||
| 112 | nft_register_chain_type(&filter_ipv6); | 109 | nft_register_chain_type(&filter_ipv6); |
| 113 | return register_pernet_subsys(&nf_tables_ipv6_net_ops); | 110 | ret = register_pernet_subsys(&nf_tables_ipv6_net_ops); |
| 111 | if (ret < 0) | ||
| 112 | nft_unregister_chain_type(&filter_ipv6); | ||
| 113 | |||
| 114 | return ret; | ||
| 114 | } | 115 | } |
| 115 | 116 | ||
| 116 | static void __exit nf_tables_ipv6_exit(void) | 117 | static void __exit nf_tables_ipv6_exit(void) |
diff --git a/net/ipv6/netfilter/nft_chain_nat_ipv6.c b/net/ipv6/netfilter/nft_chain_nat_ipv6.c index e86dcd70dc76..9c3297a768fd 100644 --- a/net/ipv6/netfilter/nft_chain_nat_ipv6.c +++ b/net/ipv6/netfilter/nft_chain_nat_ipv6.c | |||
| @@ -79,7 +79,7 @@ static unsigned int nf_nat_ipv6_fn(const struct nf_hook_ops *ops, | |||
| 79 | 79 | ||
| 80 | nft_set_pktinfo_ipv6(&pkt, ops, skb, in, out); | 80 | nft_set_pktinfo_ipv6(&pkt, ops, skb, in, out); |
| 81 | 81 | ||
| 82 | ret = nft_do_chain_pktinfo(&pkt, ops); | 82 | ret = nft_do_chain(&pkt, ops); |
| 83 | if (ret != NF_ACCEPT) | 83 | if (ret != NF_ACCEPT) |
| 84 | return ret; | 84 | return ret; |
| 85 | if (!nf_nat_initialized(ct, maniptype)) { | 85 | if (!nf_nat_initialized(ct, maniptype)) { |
| @@ -170,21 +170,21 @@ static unsigned int nf_nat_ipv6_output(const struct nf_hook_ops *ops, | |||
| 170 | return ret; | 170 | return ret; |
| 171 | } | 171 | } |
| 172 | 172 | ||
| 173 | static struct nf_chain_type nft_chain_nat_ipv6 = { | 173 | static const struct nf_chain_type nft_chain_nat_ipv6 = { |
| 174 | .family = NFPROTO_IPV6, | ||
| 175 | .name = "nat", | 174 | .name = "nat", |
| 176 | .type = NFT_CHAIN_T_NAT, | 175 | .type = NFT_CHAIN_T_NAT, |
| 176 | .family = NFPROTO_IPV6, | ||
| 177 | .owner = THIS_MODULE, | ||
| 177 | .hook_mask = (1 << NF_INET_PRE_ROUTING) | | 178 | .hook_mask = (1 << NF_INET_PRE_ROUTING) | |
| 178 | (1 << NF_INET_POST_ROUTING) | | 179 | (1 << NF_INET_POST_ROUTING) | |
| 179 | (1 << NF_INET_LOCAL_OUT) | | 180 | (1 << NF_INET_LOCAL_OUT) | |
| 180 | (1 << NF_INET_LOCAL_IN), | 181 | (1 << NF_INET_LOCAL_IN), |
| 181 | .fn = { | 182 | .hooks = { |
| 182 | [NF_INET_PRE_ROUTING] = nf_nat_ipv6_prerouting, | 183 | [NF_INET_PRE_ROUTING] = nf_nat_ipv6_prerouting, |
| 183 | [NF_INET_POST_ROUTING] = nf_nat_ipv6_postrouting, | 184 | [NF_INET_POST_ROUTING] = nf_nat_ipv6_postrouting, |
| 184 | [NF_INET_LOCAL_OUT] = nf_nat_ipv6_output, | 185 | [NF_INET_LOCAL_OUT] = nf_nat_ipv6_output, |
| 185 | [NF_INET_LOCAL_IN] = nf_nat_ipv6_fn, | 186 | [NF_INET_LOCAL_IN] = nf_nat_ipv6_fn, |
| 186 | }, | 187 | }, |
| 187 | .me = THIS_MODULE, | ||
| 188 | }; | 188 | }; |
| 189 | 189 | ||
| 190 | static int __init nft_chain_nat_ipv6_init(void) | 190 | static int __init nft_chain_nat_ipv6_init(void) |
diff --git a/net/ipv6/netfilter/nft_chain_route_ipv6.c b/net/ipv6/netfilter/nft_chain_route_ipv6.c index 3fe40f0456ad..42031299585e 100644 --- a/net/ipv6/netfilter/nft_chain_route_ipv6.c +++ b/net/ipv6/netfilter/nft_chain_route_ipv6.c | |||
| @@ -47,7 +47,7 @@ static unsigned int nf_route_table_hook(const struct nf_hook_ops *ops, | |||
| 47 | /* flowlabel and prio (includes version, which shouldn't change either */ | 47 | /* flowlabel and prio (includes version, which shouldn't change either */ |
| 48 | flowlabel = *((u32 *)ipv6_hdr(skb)); | 48 | flowlabel = *((u32 *)ipv6_hdr(skb)); |
| 49 | 49 | ||
| 50 | ret = nft_do_chain_pktinfo(&pkt, ops); | 50 | ret = nft_do_chain(&pkt, ops); |
| 51 | if (ret != NF_DROP && ret != NF_QUEUE && | 51 | if (ret != NF_DROP && ret != NF_QUEUE && |
| 52 | (memcmp(&ipv6_hdr(skb)->saddr, &saddr, sizeof(saddr)) || | 52 | (memcmp(&ipv6_hdr(skb)->saddr, &saddr, sizeof(saddr)) || |
| 53 | memcmp(&ipv6_hdr(skb)->daddr, &daddr, sizeof(daddr)) || | 53 | memcmp(&ipv6_hdr(skb)->daddr, &daddr, sizeof(daddr)) || |
| @@ -59,15 +59,15 @@ static unsigned int nf_route_table_hook(const struct nf_hook_ops *ops, | |||
| 59 | return ret; | 59 | return ret; |
| 60 | } | 60 | } |
| 61 | 61 | ||
| 62 | static struct nf_chain_type nft_chain_route_ipv6 = { | 62 | static const struct nf_chain_type nft_chain_route_ipv6 = { |
| 63 | .family = NFPROTO_IPV6, | ||
| 64 | .name = "route", | 63 | .name = "route", |
| 65 | .type = NFT_CHAIN_T_ROUTE, | 64 | .type = NFT_CHAIN_T_ROUTE, |
| 65 | .family = NFPROTO_IPV6, | ||
| 66 | .owner = THIS_MODULE, | ||
| 66 | .hook_mask = (1 << NF_INET_LOCAL_OUT), | 67 | .hook_mask = (1 << NF_INET_LOCAL_OUT), |
| 67 | .fn = { | 68 | .hooks = { |
| 68 | [NF_INET_LOCAL_OUT] = nf_route_table_hook, | 69 | [NF_INET_LOCAL_OUT] = nf_route_table_hook, |
| 69 | }, | 70 | }, |
| 70 | .me = THIS_MODULE, | ||
| 71 | }; | 71 | }; |
| 72 | 72 | ||
| 73 | static int __init nft_chain_route_init(void) | 73 | static int __init nft_chain_route_init(void) |
diff --git a/net/ipv6/ping.c b/net/ipv6/ping.c index a83243c3d656..fb9beb78f00b 100644 --- a/net/ipv6/ping.c +++ b/net/ipv6/ping.c | |||
| @@ -31,7 +31,7 @@ struct proto pingv6_prot = { | |||
| 31 | .owner = THIS_MODULE, | 31 | .owner = THIS_MODULE, |
| 32 | .init = ping_init_sock, | 32 | .init = ping_init_sock, |
| 33 | .close = ping_close, | 33 | .close = ping_close, |
| 34 | .connect = ip6_datagram_connect, | 34 | .connect = ip6_datagram_connect_v6_only, |
| 35 | .disconnect = udp_disconnect, | 35 | .disconnect = udp_disconnect, |
| 36 | .setsockopt = ipv6_setsockopt, | 36 | .setsockopt = ipv6_setsockopt, |
| 37 | .getsockopt = ipv6_getsockopt, | 37 | .getsockopt = ipv6_getsockopt, |
| @@ -62,10 +62,9 @@ static int dummy_ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len, | |||
| 62 | { | 62 | { |
| 63 | return -EAFNOSUPPORT; | 63 | return -EAFNOSUPPORT; |
| 64 | } | 64 | } |
| 65 | static int dummy_ip6_datagram_recv_ctl(struct sock *sk, struct msghdr *msg, | 65 | static void dummy_ip6_datagram_recv_ctl(struct sock *sk, struct msghdr *msg, |
| 66 | struct sk_buff *skb) | 66 | struct sk_buff *skb) |
| 67 | { | 67 | { |
| 68 | return -EAFNOSUPPORT; | ||
| 69 | } | 68 | } |
| 70 | static int dummy_icmpv6_err_convert(u8 type, u8 code, int *err) | 69 | static int dummy_icmpv6_err_convert(u8 type, u8 code, int *err) |
| 71 | { | 70 | { |
| @@ -103,7 +102,7 @@ int ping_v6_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
| 103 | return err; | 102 | return err; |
| 104 | 103 | ||
| 105 | if (msg->msg_name) { | 104 | if (msg->msg_name) { |
| 106 | struct sockaddr_in6 *u = (struct sockaddr_in6 *) msg->msg_name; | 105 | DECLARE_SOCKADDR(struct sockaddr_in6 *, u, msg->msg_name); |
| 107 | if (msg->msg_namelen < sizeof(struct sockaddr_in6) || | 106 | if (msg->msg_namelen < sizeof(struct sockaddr_in6) || |
| 108 | u->sin6_family != AF_INET6) { | 107 | u->sin6_family != AF_INET6) { |
| 109 | return -EINVAL; | 108 | return -EINVAL; |
| @@ -145,7 +144,7 @@ int ping_v6_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
| 145 | else if (!fl6.flowi6_oif) | 144 | else if (!fl6.flowi6_oif) |
| 146 | fl6.flowi6_oif = np->ucast_oif; | 145 | fl6.flowi6_oif = np->ucast_oif; |
| 147 | 146 | ||
| 148 | dst = ip6_sk_dst_lookup_flow(sk, &fl6, daddr, 1); | 147 | dst = ip6_sk_dst_lookup_flow(sk, &fl6, daddr); |
| 149 | if (IS_ERR(dst)) | 148 | if (IS_ERR(dst)) |
| 150 | return PTR_ERR(dst); | 149 | return PTR_ERR(dst); |
| 151 | rt = (struct rt6_info *) dst; | 150 | rt = (struct rt6_info *) dst; |
| @@ -254,7 +253,9 @@ int __init pingv6_init(void) | |||
| 254 | return ret; | 253 | return ret; |
| 255 | #endif | 254 | #endif |
| 256 | pingv6_ops.ipv6_recv_error = ipv6_recv_error; | 255 | pingv6_ops.ipv6_recv_error = ipv6_recv_error; |
| 257 | pingv6_ops.ip6_datagram_recv_ctl = ip6_datagram_recv_ctl; | 256 | pingv6_ops.ip6_datagram_recv_common_ctl = ip6_datagram_recv_common_ctl; |
| 257 | pingv6_ops.ip6_datagram_recv_specific_ctl = | ||
| 258 | ip6_datagram_recv_specific_ctl; | ||
| 258 | pingv6_ops.icmpv6_err_convert = icmpv6_err_convert; | 259 | pingv6_ops.icmpv6_err_convert = icmpv6_err_convert; |
| 259 | pingv6_ops.ipv6_icmp_error = ipv6_icmp_error; | 260 | pingv6_ops.ipv6_icmp_error = ipv6_icmp_error; |
| 260 | pingv6_ops.ipv6_chk_addr = ipv6_chk_addr; | 261 | pingv6_ops.ipv6_chk_addr = ipv6_chk_addr; |
| @@ -267,7 +268,8 @@ int __init pingv6_init(void) | |||
| 267 | void pingv6_exit(void) | 268 | void pingv6_exit(void) |
| 268 | { | 269 | { |
| 269 | pingv6_ops.ipv6_recv_error = dummy_ipv6_recv_error; | 270 | pingv6_ops.ipv6_recv_error = dummy_ipv6_recv_error; |
| 270 | pingv6_ops.ip6_datagram_recv_ctl = dummy_ip6_datagram_recv_ctl; | 271 | pingv6_ops.ip6_datagram_recv_common_ctl = dummy_ip6_datagram_recv_ctl; |
| 272 | pingv6_ops.ip6_datagram_recv_specific_ctl = dummy_ip6_datagram_recv_ctl; | ||
| 271 | pingv6_ops.icmpv6_err_convert = dummy_icmpv6_err_convert; | 273 | pingv6_ops.icmpv6_err_convert = dummy_icmpv6_err_convert; |
| 272 | pingv6_ops.ipv6_icmp_error = dummy_ipv6_icmp_error; | 274 | pingv6_ops.ipv6_icmp_error = dummy_ipv6_icmp_error; |
| 273 | pingv6_ops.ipv6_chk_addr = dummy_ipv6_chk_addr; | 275 | pingv6_ops.ipv6_chk_addr = dummy_ipv6_chk_addr; |
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index b6bb87e55805..1f29996e368a 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c | |||
| @@ -250,6 +250,10 @@ static int rawv6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) | |||
| 250 | 250 | ||
| 251 | if (addr_len < SIN6_LEN_RFC2133) | 251 | if (addr_len < SIN6_LEN_RFC2133) |
| 252 | return -EINVAL; | 252 | return -EINVAL; |
| 253 | |||
| 254 | if (addr->sin6_family != AF_INET6) | ||
| 255 | return -EINVAL; | ||
| 256 | |||
| 253 | addr_type = ipv6_addr_type(&addr->sin6_addr); | 257 | addr_type = ipv6_addr_type(&addr->sin6_addr); |
| 254 | 258 | ||
| 255 | /* Raw sockets are IPv6 only */ | 259 | /* Raw sockets are IPv6 only */ |
| @@ -457,7 +461,7 @@ static int rawv6_recvmsg(struct kiocb *iocb, struct sock *sk, | |||
| 457 | int noblock, int flags, int *addr_len) | 461 | int noblock, int flags, int *addr_len) |
| 458 | { | 462 | { |
| 459 | struct ipv6_pinfo *np = inet6_sk(sk); | 463 | struct ipv6_pinfo *np = inet6_sk(sk); |
| 460 | struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)msg->msg_name; | 464 | DECLARE_SOCKADDR(struct sockaddr_in6 *, sin6, msg->msg_name); |
| 461 | struct sk_buff *skb; | 465 | struct sk_buff *skb; |
| 462 | size_t copied; | 466 | size_t copied; |
| 463 | int err; | 467 | int err; |
| @@ -734,7 +738,7 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
| 734 | struct msghdr *msg, size_t len) | 738 | struct msghdr *msg, size_t len) |
| 735 | { | 739 | { |
| 736 | struct ipv6_txoptions opt_space; | 740 | struct ipv6_txoptions opt_space; |
| 737 | struct sockaddr_in6 * sin6 = (struct sockaddr_in6 *) msg->msg_name; | 741 | DECLARE_SOCKADDR(struct sockaddr_in6 *, sin6, msg->msg_name); |
| 738 | struct in6_addr *daddr, *final_p, final; | 742 | struct in6_addr *daddr, *final_p, final; |
| 739 | struct inet_sock *inet = inet_sk(sk); | 743 | struct inet_sock *inet = inet_sk(sk); |
| 740 | struct ipv6_pinfo *np = inet6_sk(sk); | 744 | struct ipv6_pinfo *np = inet6_sk(sk); |
| @@ -864,7 +868,7 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
| 864 | fl6.flowi6_oif = np->ucast_oif; | 868 | fl6.flowi6_oif = np->ucast_oif; |
| 865 | security_sk_classify_flow(sk, flowi6_to_flowi(&fl6)); | 869 | security_sk_classify_flow(sk, flowi6_to_flowi(&fl6)); |
| 866 | 870 | ||
| 867 | dst = ip6_dst_lookup_flow(sk, &fl6, final_p, true); | 871 | dst = ip6_dst_lookup_flow(sk, &fl6, final_p); |
| 868 | if (IS_ERR(dst)) { | 872 | if (IS_ERR(dst)) { |
| 869 | err = PTR_ERR(dst); | 873 | err = PTR_ERR(dst); |
| 870 | goto out; | 874 | goto out; |
| @@ -1209,7 +1213,7 @@ struct proto rawv6_prot = { | |||
| 1209 | .owner = THIS_MODULE, | 1213 | .owner = THIS_MODULE, |
| 1210 | .close = rawv6_close, | 1214 | .close = rawv6_close, |
| 1211 | .destroy = raw6_destroy, | 1215 | .destroy = raw6_destroy, |
| 1212 | .connect = ip6_datagram_connect, | 1216 | .connect = ip6_datagram_connect_v6_only, |
| 1213 | .disconnect = udp_disconnect, | 1217 | .disconnect = udp_disconnect, |
| 1214 | .ioctl = rawv6_ioctl, | 1218 | .ioctl = rawv6_ioctl, |
| 1215 | .init = rawv6_init_sk, | 1219 | .init = rawv6_init_sk, |
diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 4b4944c3e4c4..11dac21e6586 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c | |||
| @@ -66,8 +66,9 @@ | |||
| 66 | #endif | 66 | #endif |
| 67 | 67 | ||
| 68 | enum rt6_nud_state { | 68 | enum rt6_nud_state { |
| 69 | RT6_NUD_FAIL_HARD = -2, | 69 | RT6_NUD_FAIL_HARD = -3, |
| 70 | RT6_NUD_FAIL_SOFT = -1, | 70 | RT6_NUD_FAIL_PROBE = -2, |
| 71 | RT6_NUD_FAIL_DO_RR = -1, | ||
| 71 | RT6_NUD_SUCCEED = 1 | 72 | RT6_NUD_SUCCEED = 1 |
| 72 | }; | 73 | }; |
| 73 | 74 | ||
| @@ -103,6 +104,36 @@ static struct rt6_info *rt6_get_route_info(struct net *net, | |||
| 103 | const struct in6_addr *gwaddr, int ifindex); | 104 | const struct in6_addr *gwaddr, int ifindex); |
| 104 | #endif | 105 | #endif |
| 105 | 106 | ||
| 107 | static void rt6_bind_peer(struct rt6_info *rt, int create) | ||
| 108 | { | ||
| 109 | struct inet_peer_base *base; | ||
| 110 | struct inet_peer *peer; | ||
| 111 | |||
| 112 | base = inetpeer_base_ptr(rt->_rt6i_peer); | ||
| 113 | if (!base) | ||
| 114 | return; | ||
| 115 | |||
| 116 | peer = inet_getpeer_v6(base, &rt->rt6i_dst.addr, create); | ||
| 117 | if (peer) { | ||
| 118 | if (!rt6_set_peer(rt, peer)) | ||
| 119 | inet_putpeer(peer); | ||
| 120 | } | ||
| 121 | } | ||
| 122 | |||
| 123 | static struct inet_peer *__rt6_get_peer(struct rt6_info *rt, int create) | ||
| 124 | { | ||
| 125 | if (rt6_has_peer(rt)) | ||
| 126 | return rt6_peer_ptr(rt); | ||
| 127 | |||
| 128 | rt6_bind_peer(rt, create); | ||
| 129 | return (rt6_has_peer(rt) ? rt6_peer_ptr(rt) : NULL); | ||
| 130 | } | ||
| 131 | |||
| 132 | static struct inet_peer *rt6_get_peer_create(struct rt6_info *rt) | ||
| 133 | { | ||
| 134 | return __rt6_get_peer(rt, 1); | ||
| 135 | } | ||
| 136 | |||
| 106 | static u32 *ipv6_cow_metrics(struct dst_entry *dst, unsigned long old) | 137 | static u32 *ipv6_cow_metrics(struct dst_entry *dst, unsigned long old) |
| 107 | { | 138 | { |
| 108 | struct rt6_info *rt = (struct rt6_info *) dst; | 139 | struct rt6_info *rt = (struct rt6_info *) dst; |
| @@ -311,22 +342,6 @@ static void ip6_dst_destroy(struct dst_entry *dst) | |||
| 311 | } | 342 | } |
| 312 | } | 343 | } |
| 313 | 344 | ||
| 314 | void rt6_bind_peer(struct rt6_info *rt, int create) | ||
| 315 | { | ||
| 316 | struct inet_peer_base *base; | ||
| 317 | struct inet_peer *peer; | ||
| 318 | |||
| 319 | base = inetpeer_base_ptr(rt->_rt6i_peer); | ||
| 320 | if (!base) | ||
| 321 | return; | ||
| 322 | |||
| 323 | peer = inet_getpeer_v6(base, &rt->rt6i_dst.addr, create); | ||
| 324 | if (peer) { | ||
| 325 | if (!rt6_set_peer(rt, peer)) | ||
| 326 | inet_putpeer(peer); | ||
| 327 | } | ||
| 328 | } | ||
| 329 | |||
| 330 | static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev, | 345 | static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev, |
| 331 | int how) | 346 | int how) |
| 332 | { | 347 | { |
| @@ -521,7 +536,7 @@ static void rt6_probe(struct rt6_info *rt) | |||
| 521 | work = kmalloc(sizeof(*work), GFP_ATOMIC); | 536 | work = kmalloc(sizeof(*work), GFP_ATOMIC); |
| 522 | 537 | ||
| 523 | if (neigh && work) | 538 | if (neigh && work) |
| 524 | neigh->updated = jiffies; | 539 | __neigh_set_probe_once(neigh); |
| 525 | 540 | ||
| 526 | if (neigh) | 541 | if (neigh) |
| 527 | write_unlock(&neigh->lock); | 542 | write_unlock(&neigh->lock); |
| @@ -577,11 +592,13 @@ static inline enum rt6_nud_state rt6_check_neigh(struct rt6_info *rt) | |||
| 577 | #ifdef CONFIG_IPV6_ROUTER_PREF | 592 | #ifdef CONFIG_IPV6_ROUTER_PREF |
| 578 | else if (!(neigh->nud_state & NUD_FAILED)) | 593 | else if (!(neigh->nud_state & NUD_FAILED)) |
| 579 | ret = RT6_NUD_SUCCEED; | 594 | ret = RT6_NUD_SUCCEED; |
| 595 | else | ||
| 596 | ret = RT6_NUD_FAIL_PROBE; | ||
| 580 | #endif | 597 | #endif |
| 581 | read_unlock(&neigh->lock); | 598 | read_unlock(&neigh->lock); |
| 582 | } else { | 599 | } else { |
| 583 | ret = IS_ENABLED(CONFIG_IPV6_ROUTER_PREF) ? | 600 | ret = IS_ENABLED(CONFIG_IPV6_ROUTER_PREF) ? |
| 584 | RT6_NUD_SUCCEED : RT6_NUD_FAIL_SOFT; | 601 | RT6_NUD_SUCCEED : RT6_NUD_FAIL_DO_RR; |
| 585 | } | 602 | } |
| 586 | rcu_read_unlock_bh(); | 603 | rcu_read_unlock_bh(); |
| 587 | 604 | ||
| @@ -618,16 +635,17 @@ static struct rt6_info *find_match(struct rt6_info *rt, int oif, int strict, | |||
| 618 | goto out; | 635 | goto out; |
| 619 | 636 | ||
| 620 | m = rt6_score_route(rt, oif, strict); | 637 | m = rt6_score_route(rt, oif, strict); |
| 621 | if (m == RT6_NUD_FAIL_SOFT) { | 638 | if (m == RT6_NUD_FAIL_DO_RR) { |
| 622 | match_do_rr = true; | 639 | match_do_rr = true; |
| 623 | m = 0; /* lowest valid score */ | 640 | m = 0; /* lowest valid score */ |
| 624 | } else if (m < 0) { | 641 | } else if (m == RT6_NUD_FAIL_HARD) { |
| 625 | goto out; | 642 | goto out; |
| 626 | } | 643 | } |
| 627 | 644 | ||
| 628 | if (strict & RT6_LOOKUP_F_REACHABLE) | 645 | if (strict & RT6_LOOKUP_F_REACHABLE) |
| 629 | rt6_probe(rt); | 646 | rt6_probe(rt); |
| 630 | 647 | ||
| 648 | /* note that m can be RT6_NUD_FAIL_PROBE at this point */ | ||
| 631 | if (m > *mpri) { | 649 | if (m > *mpri) { |
| 632 | *do_rr = match_do_rr; | 650 | *do_rr = match_do_rr; |
| 633 | *mpri = m; | 651 | *mpri = m; |
| @@ -2238,7 +2256,7 @@ void rt6_remove_prefsrc(struct inet6_ifaddr *ifp) | |||
| 2238 | .net = net, | 2256 | .net = net, |
| 2239 | .addr = &ifp->addr, | 2257 | .addr = &ifp->addr, |
| 2240 | }; | 2258 | }; |
| 2241 | fib6_clean_all(net, fib6_remove_prefsrc, 0, &adni); | 2259 | fib6_clean_all(net, fib6_remove_prefsrc, &adni); |
| 2242 | } | 2260 | } |
| 2243 | 2261 | ||
| 2244 | struct arg_dev_net { | 2262 | struct arg_dev_net { |
| @@ -2265,7 +2283,7 @@ void rt6_ifdown(struct net *net, struct net_device *dev) | |||
| 2265 | .net = net, | 2283 | .net = net, |
| 2266 | }; | 2284 | }; |
| 2267 | 2285 | ||
| 2268 | fib6_clean_all(net, fib6_ifdown, 0, &adn); | 2286 | fib6_clean_all(net, fib6_ifdown, &adn); |
| 2269 | icmp6_clean_all(fib6_ifdown, &adn); | 2287 | icmp6_clean_all(fib6_ifdown, &adn); |
| 2270 | } | 2288 | } |
| 2271 | 2289 | ||
| @@ -2320,7 +2338,7 @@ void rt6_mtu_change(struct net_device *dev, unsigned int mtu) | |||
| 2320 | .mtu = mtu, | 2338 | .mtu = mtu, |
| 2321 | }; | 2339 | }; |
| 2322 | 2340 | ||
| 2323 | fib6_clean_all(dev_net(dev), rt6_mtu_change_route, 0, &arg); | 2341 | fib6_clean_all(dev_net(dev), rt6_mtu_change_route, &arg); |
| 2324 | } | 2342 | } |
| 2325 | 2343 | ||
| 2326 | static const struct nla_policy rtm_ipv6_policy[RTA_MAX+1] = { | 2344 | static const struct nla_policy rtm_ipv6_policy[RTA_MAX+1] = { |
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index d3005b34476a..3dfbcf1dcb1c 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c | |||
| @@ -671,7 +671,7 @@ static int ipip6_rcv(struct sk_buff *skb) | |||
| 671 | tunnel = ipip6_tunnel_lookup(dev_net(skb->dev), skb->dev, | 671 | tunnel = ipip6_tunnel_lookup(dev_net(skb->dev), skb->dev, |
| 672 | iph->saddr, iph->daddr); | 672 | iph->saddr, iph->daddr); |
| 673 | if (tunnel != NULL) { | 673 | if (tunnel != NULL) { |
| 674 | struct pcpu_tstats *tstats; | 674 | struct pcpu_sw_netstats *tstats; |
| 675 | 675 | ||
| 676 | if (tunnel->parms.iph.protocol != IPPROTO_IPV6 && | 676 | if (tunnel->parms.iph.protocol != IPPROTO_IPV6 && |
| 677 | tunnel->parms.iph.protocol != 0) | 677 | tunnel->parms.iph.protocol != 0) |
| @@ -1365,12 +1365,12 @@ static int ipip6_tunnel_init(struct net_device *dev) | |||
| 1365 | memcpy(dev->broadcast, &tunnel->parms.iph.daddr, 4); | 1365 | memcpy(dev->broadcast, &tunnel->parms.iph.daddr, 4); |
| 1366 | 1366 | ||
| 1367 | ipip6_tunnel_bind_dev(dev); | 1367 | ipip6_tunnel_bind_dev(dev); |
| 1368 | dev->tstats = alloc_percpu(struct pcpu_tstats); | 1368 | dev->tstats = alloc_percpu(struct pcpu_sw_netstats); |
| 1369 | if (!dev->tstats) | 1369 | if (!dev->tstats) |
| 1370 | return -ENOMEM; | 1370 | return -ENOMEM; |
| 1371 | 1371 | ||
| 1372 | for_each_possible_cpu(i) { | 1372 | for_each_possible_cpu(i) { |
| 1373 | struct pcpu_tstats *ipip6_tunnel_stats; | 1373 | struct pcpu_sw_netstats *ipip6_tunnel_stats; |
| 1374 | ipip6_tunnel_stats = per_cpu_ptr(dev->tstats, i); | 1374 | ipip6_tunnel_stats = per_cpu_ptr(dev->tstats, i); |
| 1375 | u64_stats_init(&ipip6_tunnel_stats->syncp); | 1375 | u64_stats_init(&ipip6_tunnel_stats->syncp); |
| 1376 | } | 1376 | } |
| @@ -1395,12 +1395,12 @@ static int __net_init ipip6_fb_tunnel_init(struct net_device *dev) | |||
| 1395 | iph->ihl = 5; | 1395 | iph->ihl = 5; |
| 1396 | iph->ttl = 64; | 1396 | iph->ttl = 64; |
| 1397 | 1397 | ||
| 1398 | dev->tstats = alloc_percpu(struct pcpu_tstats); | 1398 | dev->tstats = alloc_percpu(struct pcpu_sw_netstats); |
| 1399 | if (!dev->tstats) | 1399 | if (!dev->tstats) |
| 1400 | return -ENOMEM; | 1400 | return -ENOMEM; |
| 1401 | 1401 | ||
| 1402 | for_each_possible_cpu(i) { | 1402 | for_each_possible_cpu(i) { |
| 1403 | struct pcpu_tstats *ipip6_fb_stats; | 1403 | struct pcpu_sw_netstats *ipip6_fb_stats; |
| 1404 | ipip6_fb_stats = per_cpu_ptr(dev->tstats, i); | 1404 | ipip6_fb_stats = per_cpu_ptr(dev->tstats, i); |
| 1405 | u64_stats_init(&ipip6_fb_stats->syncp); | 1405 | u64_stats_init(&ipip6_fb_stats->syncp); |
| 1406 | } | 1406 | } |
diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c index 535a3ad262f1..bb53a5e73c1a 100644 --- a/net/ipv6/syncookies.c +++ b/net/ipv6/syncookies.c | |||
| @@ -247,7 +247,7 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) | |||
| 247 | fl6.fl6_sport = inet_sk(sk)->inet_sport; | 247 | fl6.fl6_sport = inet_sk(sk)->inet_sport; |
| 248 | security_req_classify_flow(req, flowi6_to_flowi(&fl6)); | 248 | security_req_classify_flow(req, flowi6_to_flowi(&fl6)); |
| 249 | 249 | ||
| 250 | dst = ip6_dst_lookup_flow(sk, &fl6, final_p, false); | 250 | dst = ip6_dst_lookup_flow(sk, &fl6, final_p); |
| 251 | if (IS_ERR(dst)) | 251 | if (IS_ERR(dst)) |
| 252 | goto out_free; | 252 | goto out_free; |
| 253 | } | 253 | } |
diff --git a/net/ipv6/sysctl_net_ipv6.c b/net/ipv6/sysctl_net_ipv6.c index 107b2f1d90ae..7f405a168822 100644 --- a/net/ipv6/sysctl_net_ipv6.c +++ b/net/ipv6/sysctl_net_ipv6.c | |||
| @@ -24,6 +24,20 @@ static struct ctl_table ipv6_table_template[] = { | |||
| 24 | .mode = 0644, | 24 | .mode = 0644, |
| 25 | .proc_handler = proc_dointvec | 25 | .proc_handler = proc_dointvec |
| 26 | }, | 26 | }, |
| 27 | { | ||
| 28 | .procname = "anycast_src_echo_reply", | ||
| 29 | .data = &init_net.ipv6.sysctl.anycast_src_echo_reply, | ||
| 30 | .maxlen = sizeof(int), | ||
| 31 | .mode = 0644, | ||
| 32 | .proc_handler = proc_dointvec | ||
| 33 | }, | ||
| 34 | { | ||
| 35 | .procname = "flowlabel_consistency", | ||
| 36 | .data = &init_net.ipv6.sysctl.flowlabel_consistency, | ||
| 37 | .maxlen = sizeof(int), | ||
| 38 | .mode = 0644, | ||
| 39 | .proc_handler = proc_dointvec | ||
| 40 | }, | ||
| 27 | { } | 41 | { } |
| 28 | }; | 42 | }; |
| 29 | 43 | ||
| @@ -51,6 +65,8 @@ static int __net_init ipv6_sysctl_net_init(struct net *net) | |||
| 51 | if (!ipv6_table) | 65 | if (!ipv6_table) |
| 52 | goto out; | 66 | goto out; |
| 53 | ipv6_table[0].data = &net->ipv6.sysctl.bindv6only; | 67 | ipv6_table[0].data = &net->ipv6.sysctl.bindv6only; |
| 68 | ipv6_table[1].data = &net->ipv6.sysctl.anycast_src_echo_reply; | ||
| 69 | ipv6_table[2].data = &net->ipv6.sysctl.flowlabel_consistency; | ||
| 54 | 70 | ||
| 55 | ipv6_route_table = ipv6_route_sysctl_init(net); | 71 | ipv6_route_table = ipv6_route_sysctl_init(net); |
| 56 | if (!ipv6_route_table) | 72 | if (!ipv6_route_table) |
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index f67033b4bb66..889079b2ea85 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c | |||
| @@ -164,12 +164,12 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, | |||
| 164 | * connect() to INADDR_ANY means loopback (BSD'ism). | 164 | * connect() to INADDR_ANY means loopback (BSD'ism). |
| 165 | */ | 165 | */ |
| 166 | 166 | ||
| 167 | if(ipv6_addr_any(&usin->sin6_addr)) | 167 | if (ipv6_addr_any(&usin->sin6_addr)) |
| 168 | usin->sin6_addr.s6_addr[15] = 0x1; | 168 | usin->sin6_addr.s6_addr[15] = 0x1; |
| 169 | 169 | ||
| 170 | addr_type = ipv6_addr_type(&usin->sin6_addr); | 170 | addr_type = ipv6_addr_type(&usin->sin6_addr); |
| 171 | 171 | ||
| 172 | if(addr_type & IPV6_ADDR_MULTICAST) | 172 | if (addr_type & IPV6_ADDR_MULTICAST) |
| 173 | return -ENETUNREACH; | 173 | return -ENETUNREACH; |
| 174 | 174 | ||
| 175 | if (addr_type&IPV6_ADDR_LINKLOCAL) { | 175 | if (addr_type&IPV6_ADDR_LINKLOCAL) { |
| @@ -257,7 +257,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, | |||
| 257 | 257 | ||
| 258 | security_sk_classify_flow(sk, flowi6_to_flowi(&fl6)); | 258 | security_sk_classify_flow(sk, flowi6_to_flowi(&fl6)); |
| 259 | 259 | ||
| 260 | dst = ip6_dst_lookup_flow(sk, &fl6, final_p, true); | 260 | dst = ip6_dst_lookup_flow(sk, &fl6, final_p); |
| 261 | if (IS_ERR(dst)) { | 261 | if (IS_ERR(dst)) { |
| 262 | err = PTR_ERR(dst); | 262 | err = PTR_ERR(dst); |
| 263 | goto failure; | 263 | goto failure; |
| @@ -336,7 +336,7 @@ static void tcp_v6_mtu_reduced(struct sock *sk) | |||
| 336 | static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | 336 | static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, |
| 337 | u8 type, u8 code, int offset, __be32 info) | 337 | u8 type, u8 code, int offset, __be32 info) |
| 338 | { | 338 | { |
| 339 | const struct ipv6hdr *hdr = (const struct ipv6hdr*)skb->data; | 339 | const struct ipv6hdr *hdr = (const struct ipv6hdr *)skb->data; |
| 340 | const struct tcphdr *th = (struct tcphdr *)(skb->data+offset); | 340 | const struct tcphdr *th = (struct tcphdr *)(skb->data+offset); |
| 341 | struct ipv6_pinfo *np; | 341 | struct ipv6_pinfo *np; |
| 342 | struct sock *sk; | 342 | struct sock *sk; |
| @@ -397,6 +397,9 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
| 397 | if (sk->sk_state == TCP_LISTEN) | 397 | if (sk->sk_state == TCP_LISTEN) |
| 398 | goto out; | 398 | goto out; |
| 399 | 399 | ||
| 400 | if (!ip6_sk_accept_pmtu(sk)) | ||
| 401 | goto out; | ||
| 402 | |||
| 400 | tp->mtu_info = ntohl(info); | 403 | tp->mtu_info = ntohl(info); |
| 401 | if (!sock_owned_by_user(sk)) | 404 | if (!sock_owned_by_user(sk)) |
| 402 | tcp_v6_mtu_reduced(sk); | 405 | tcp_v6_mtu_reduced(sk); |
| @@ -466,7 +469,7 @@ static int tcp_v6_send_synack(struct sock *sk, struct dst_entry *dst, | |||
| 466 | { | 469 | { |
| 467 | struct inet_request_sock *ireq = inet_rsk(req); | 470 | struct inet_request_sock *ireq = inet_rsk(req); |
| 468 | struct ipv6_pinfo *np = inet6_sk(sk); | 471 | struct ipv6_pinfo *np = inet6_sk(sk); |
| 469 | struct sk_buff * skb; | 472 | struct sk_buff *skb; |
| 470 | int err = -ENOMEM; | 473 | int err = -ENOMEM; |
| 471 | 474 | ||
| 472 | /* First, grab a route. */ | 475 | /* First, grab a route. */ |
| @@ -480,6 +483,9 @@ static int tcp_v6_send_synack(struct sock *sk, struct dst_entry *dst, | |||
| 480 | &ireq->ir_v6_rmt_addr); | 483 | &ireq->ir_v6_rmt_addr); |
| 481 | 484 | ||
| 482 | fl6->daddr = ireq->ir_v6_rmt_addr; | 485 | fl6->daddr = ireq->ir_v6_rmt_addr; |
| 486 | if (np->repflow && (ireq->pktopts != NULL)) | ||
| 487 | fl6->flowlabel = ip6_flowlabel(ipv6_hdr(ireq->pktopts)); | ||
| 488 | |||
| 483 | skb_set_queue_mapping(skb, queue_mapping); | 489 | skb_set_queue_mapping(skb, queue_mapping); |
| 484 | err = ip6_xmit(sk, skb, fl6, np->opt, np->tclass); | 490 | err = ip6_xmit(sk, skb, fl6, np->opt, np->tclass); |
| 485 | err = net_xmit_eval(err); | 491 | err = net_xmit_eval(err); |
| @@ -721,7 +727,8 @@ static const struct tcp_request_sock_ops tcp_request_sock_ipv6_ops = { | |||
| 721 | 727 | ||
| 722 | static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win, | 728 | static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win, |
| 723 | u32 tsval, u32 tsecr, | 729 | u32 tsval, u32 tsecr, |
| 724 | struct tcp_md5sig_key *key, int rst, u8 tclass) | 730 | struct tcp_md5sig_key *key, int rst, u8 tclass, |
| 731 | u32 label) | ||
| 725 | { | 732 | { |
| 726 | const struct tcphdr *th = tcp_hdr(skb); | 733 | const struct tcphdr *th = tcp_hdr(skb); |
| 727 | struct tcphdr *t1; | 734 | struct tcphdr *t1; |
| @@ -783,6 +790,7 @@ static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win, | |||
| 783 | memset(&fl6, 0, sizeof(fl6)); | 790 | memset(&fl6, 0, sizeof(fl6)); |
| 784 | fl6.daddr = ipv6_hdr(skb)->saddr; | 791 | fl6.daddr = ipv6_hdr(skb)->saddr; |
| 785 | fl6.saddr = ipv6_hdr(skb)->daddr; | 792 | fl6.saddr = ipv6_hdr(skb)->daddr; |
| 793 | fl6.flowlabel = label; | ||
| 786 | 794 | ||
| 787 | buff->ip_summed = CHECKSUM_PARTIAL; | 795 | buff->ip_summed = CHECKSUM_PARTIAL; |
| 788 | buff->csum = 0; | 796 | buff->csum = 0; |
| @@ -800,7 +808,7 @@ static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win, | |||
| 800 | * Underlying function will use this to retrieve the network | 808 | * Underlying function will use this to retrieve the network |
| 801 | * namespace | 809 | * namespace |
| 802 | */ | 810 | */ |
| 803 | dst = ip6_dst_lookup_flow(ctl_sk, &fl6, NULL, false); | 811 | dst = ip6_dst_lookup_flow(ctl_sk, &fl6, NULL); |
| 804 | if (!IS_ERR(dst)) { | 812 | if (!IS_ERR(dst)) { |
| 805 | skb_dst_set(buff, dst); | 813 | skb_dst_set(buff, dst); |
| 806 | ip6_xmit(ctl_sk, buff, &fl6, NULL, tclass); | 814 | ip6_xmit(ctl_sk, buff, &fl6, NULL, tclass); |
| @@ -868,7 +876,7 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb) | |||
| 868 | ack_seq = ntohl(th->seq) + th->syn + th->fin + skb->len - | 876 | ack_seq = ntohl(th->seq) + th->syn + th->fin + skb->len - |
| 869 | (th->doff << 2); | 877 | (th->doff << 2); |
| 870 | 878 | ||
| 871 | tcp_v6_send_response(skb, seq, ack_seq, 0, 0, 0, key, 1, 0); | 879 | tcp_v6_send_response(skb, seq, ack_seq, 0, 0, 0, key, 1, 0, 0); |
| 872 | 880 | ||
| 873 | #ifdef CONFIG_TCP_MD5SIG | 881 | #ifdef CONFIG_TCP_MD5SIG |
| 874 | release_sk1: | 882 | release_sk1: |
| @@ -881,9 +889,11 @@ release_sk1: | |||
| 881 | 889 | ||
| 882 | static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack, | 890 | static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack, |
| 883 | u32 win, u32 tsval, u32 tsecr, | 891 | u32 win, u32 tsval, u32 tsecr, |
| 884 | struct tcp_md5sig_key *key, u8 tclass) | 892 | struct tcp_md5sig_key *key, u8 tclass, |
| 893 | u32 label) | ||
| 885 | { | 894 | { |
| 886 | tcp_v6_send_response(skb, seq, ack, win, tsval, tsecr, key, 0, tclass); | 895 | tcp_v6_send_response(skb, seq, ack, win, tsval, tsecr, key, 0, tclass, |
| 896 | label); | ||
| 887 | } | 897 | } |
| 888 | 898 | ||
| 889 | static void tcp_v6_timewait_ack(struct sock *sk, struct sk_buff *skb) | 899 | static void tcp_v6_timewait_ack(struct sock *sk, struct sk_buff *skb) |
| @@ -895,7 +905,7 @@ static void tcp_v6_timewait_ack(struct sock *sk, struct sk_buff *skb) | |||
| 895 | tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale, | 905 | tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale, |
| 896 | tcp_time_stamp + tcptw->tw_ts_offset, | 906 | tcp_time_stamp + tcptw->tw_ts_offset, |
| 897 | tcptw->tw_ts_recent, tcp_twsk_md5_key(tcptw), | 907 | tcptw->tw_ts_recent, tcp_twsk_md5_key(tcptw), |
| 898 | tw->tw_tclass); | 908 | tw->tw_tclass, (tw->tw_flowlabel << 12)); |
| 899 | 909 | ||
| 900 | inet_twsk_put(tw); | 910 | inet_twsk_put(tw); |
| 901 | } | 911 | } |
| @@ -905,11 +915,12 @@ static void tcp_v6_reqsk_send_ack(struct sock *sk, struct sk_buff *skb, | |||
| 905 | { | 915 | { |
| 906 | tcp_v6_send_ack(skb, tcp_rsk(req)->snt_isn + 1, tcp_rsk(req)->rcv_isn + 1, | 916 | tcp_v6_send_ack(skb, tcp_rsk(req)->snt_isn + 1, tcp_rsk(req)->rcv_isn + 1, |
| 907 | req->rcv_wnd, tcp_time_stamp, req->ts_recent, | 917 | req->rcv_wnd, tcp_time_stamp, req->ts_recent, |
| 908 | tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->daddr), 0); | 918 | tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->daddr), |
| 919 | 0, 0); | ||
| 909 | } | 920 | } |
| 910 | 921 | ||
| 911 | 922 | ||
| 912 | static struct sock *tcp_v6_hnd_req(struct sock *sk,struct sk_buff *skb) | 923 | static struct sock *tcp_v6_hnd_req(struct sock *sk, struct sk_buff *skb) |
| 913 | { | 924 | { |
| 914 | struct request_sock *req, **prev; | 925 | struct request_sock *req, **prev; |
| 915 | const struct tcphdr *th = tcp_hdr(skb); | 926 | const struct tcphdr *th = tcp_hdr(skb); |
| @@ -1010,7 +1021,8 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) | |||
| 1010 | if (!isn) { | 1021 | if (!isn) { |
| 1011 | if (ipv6_opt_accepted(sk, skb) || | 1022 | if (ipv6_opt_accepted(sk, skb) || |
| 1012 | np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo || | 1023 | np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo || |
| 1013 | np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) { | 1024 | np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim || |
| 1025 | np->repflow) { | ||
| 1014 | atomic_inc(&skb->users); | 1026 | atomic_inc(&skb->users); |
| 1015 | ireq->pktopts = skb; | 1027 | ireq->pktopts = skb; |
| 1016 | } | 1028 | } |
| @@ -1082,9 +1094,9 @@ drop: | |||
| 1082 | return 0; /* don't send reset */ | 1094 | return 0; /* don't send reset */ |
| 1083 | } | 1095 | } |
| 1084 | 1096 | ||
| 1085 | static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, | 1097 | static struct sock *tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, |
| 1086 | struct request_sock *req, | 1098 | struct request_sock *req, |
| 1087 | struct dst_entry *dst) | 1099 | struct dst_entry *dst) |
| 1088 | { | 1100 | { |
| 1089 | struct inet_request_sock *ireq; | 1101 | struct inet_request_sock *ireq; |
| 1090 | struct ipv6_pinfo *newnp, *np = inet6_sk(sk); | 1102 | struct ipv6_pinfo *newnp, *np = inet6_sk(sk); |
| @@ -1134,7 +1146,9 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, | |||
| 1134 | newnp->opt = NULL; | 1146 | newnp->opt = NULL; |
| 1135 | newnp->mcast_oif = inet6_iif(skb); | 1147 | newnp->mcast_oif = inet6_iif(skb); |
| 1136 | newnp->mcast_hops = ipv6_hdr(skb)->hop_limit; | 1148 | newnp->mcast_hops = ipv6_hdr(skb)->hop_limit; |
| 1137 | newnp->rcv_tclass = ipv6_get_dsfield(ipv6_hdr(skb)); | 1149 | newnp->rcv_flowinfo = ip6_flowinfo(ipv6_hdr(skb)); |
| 1150 | if (np->repflow) | ||
| 1151 | newnp->flow_label = ip6_flowlabel(ipv6_hdr(skb)); | ||
| 1138 | 1152 | ||
| 1139 | /* | 1153 | /* |
| 1140 | * No need to charge this sock to the relevant IPv6 refcnt debug socks count | 1154 | * No need to charge this sock to the relevant IPv6 refcnt debug socks count |
| @@ -1214,7 +1228,9 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, | |||
| 1214 | newnp->opt = NULL; | 1228 | newnp->opt = NULL; |
| 1215 | newnp->mcast_oif = inet6_iif(skb); | 1229 | newnp->mcast_oif = inet6_iif(skb); |
| 1216 | newnp->mcast_hops = ipv6_hdr(skb)->hop_limit; | 1230 | newnp->mcast_hops = ipv6_hdr(skb)->hop_limit; |
| 1217 | newnp->rcv_tclass = ipv6_get_dsfield(ipv6_hdr(skb)); | 1231 | newnp->rcv_flowinfo = ip6_flowinfo(ipv6_hdr(skb)); |
| 1232 | if (np->repflow) | ||
| 1233 | newnp->flow_label = ip6_flowlabel(ipv6_hdr(skb)); | ||
| 1218 | 1234 | ||
| 1219 | /* Clone native IPv6 options from listening socket (if any) | 1235 | /* Clone native IPv6 options from listening socket (if any) |
| 1220 | 1236 | ||
| @@ -1230,7 +1246,6 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, | |||
| 1230 | inet_csk(newsk)->icsk_ext_hdr_len = (newnp->opt->opt_nflen + | 1246 | inet_csk(newsk)->icsk_ext_hdr_len = (newnp->opt->opt_nflen + |
| 1231 | newnp->opt->opt_flen); | 1247 | newnp->opt->opt_flen); |
| 1232 | 1248 | ||
| 1233 | tcp_mtup_init(newsk); | ||
| 1234 | tcp_sync_mss(newsk, dst_mtu(dst)); | 1249 | tcp_sync_mss(newsk, dst_mtu(dst)); |
| 1235 | newtp->advmss = dst_metric_advmss(dst); | 1250 | newtp->advmss = dst_metric_advmss(dst); |
| 1236 | if (tcp_sk(sk)->rx_opt.user_mss && | 1251 | if (tcp_sk(sk)->rx_opt.user_mss && |
| @@ -1379,7 +1394,7 @@ static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb) | |||
| 1379 | * otherwise we just shortcircuit this and continue with | 1394 | * otherwise we just shortcircuit this and continue with |
| 1380 | * the new socket.. | 1395 | * the new socket.. |
| 1381 | */ | 1396 | */ |
| 1382 | if(nsk != sk) { | 1397 | if (nsk != sk) { |
| 1383 | sock_rps_save_rxhash(nsk, skb); | 1398 | sock_rps_save_rxhash(nsk, skb); |
| 1384 | if (tcp_child_process(sk, nsk, skb)) | 1399 | if (tcp_child_process(sk, nsk, skb)) |
| 1385 | goto reset; | 1400 | goto reset; |
| @@ -1424,8 +1439,10 @@ ipv6_pktoptions: | |||
| 1424 | np->mcast_oif = inet6_iif(opt_skb); | 1439 | np->mcast_oif = inet6_iif(opt_skb); |
| 1425 | if (np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) | 1440 | if (np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) |
| 1426 | np->mcast_hops = ipv6_hdr(opt_skb)->hop_limit; | 1441 | np->mcast_hops = ipv6_hdr(opt_skb)->hop_limit; |
| 1427 | if (np->rxopt.bits.rxtclass) | 1442 | if (np->rxopt.bits.rxflow || np->rxopt.bits.rxtclass) |
| 1428 | np->rcv_tclass = ipv6_get_dsfield(ipv6_hdr(opt_skb)); | 1443 | np->rcv_flowinfo = ip6_flowinfo(ipv6_hdr(opt_skb)); |
| 1444 | if (np->repflow) | ||
| 1445 | np->flow_label = ip6_flowlabel(ipv6_hdr(opt_skb)); | ||
| 1429 | if (ipv6_opt_accepted(sk, opt_skb)) { | 1446 | if (ipv6_opt_accepted(sk, opt_skb)) { |
| 1430 | skb_set_owner_r(opt_skb, sk); | 1447 | skb_set_owner_r(opt_skb, sk); |
| 1431 | opt_skb = xchg(&np->pktoptions, opt_skb); | 1448 | opt_skb = xchg(&np->pktoptions, opt_skb); |
| @@ -1739,7 +1756,7 @@ static void get_openreq6(struct seq_file *seq, | |||
| 1739 | dest->s6_addr32[2], dest->s6_addr32[3], | 1756 | dest->s6_addr32[2], dest->s6_addr32[3], |
| 1740 | ntohs(inet_rsk(req)->ir_rmt_port), | 1757 | ntohs(inet_rsk(req)->ir_rmt_port), |
| 1741 | TCP_SYN_RECV, | 1758 | TCP_SYN_RECV, |
| 1742 | 0,0, /* could print option size, but that is af dependent. */ | 1759 | 0, 0, /* could print option size, but that is af dependent. */ |
| 1743 | 1, /* timers active (only the expire timer) */ | 1760 | 1, /* timers active (only the expire timer) */ |
| 1744 | jiffies_to_clock_t(ttd), | 1761 | jiffies_to_clock_t(ttd), |
| 1745 | req->num_timeout, | 1762 | req->num_timeout, |
| @@ -1798,7 +1815,7 @@ static void get_tcp6_sock(struct seq_file *seq, struct sock *sp, int i) | |||
| 1798 | atomic_read(&sp->sk_refcnt), sp, | 1815 | atomic_read(&sp->sk_refcnt), sp, |
| 1799 | jiffies_to_clock_t(icsk->icsk_rto), | 1816 | jiffies_to_clock_t(icsk->icsk_rto), |
| 1800 | jiffies_to_clock_t(icsk->icsk_ack.ato), | 1817 | jiffies_to_clock_t(icsk->icsk_ack.ato), |
| 1801 | (icsk->icsk_ack.quick << 1 ) | icsk->icsk_ack.pingpong, | 1818 | (icsk->icsk_ack.quick << 1) | icsk->icsk_ack.pingpong, |
| 1802 | tp->snd_cwnd, | 1819 | tp->snd_cwnd, |
| 1803 | tcp_in_initial_slowstart(tp) ? -1 : tp->snd_ssthresh | 1820 | tcp_in_initial_slowstart(tp) ? -1 : tp->snd_ssthresh |
| 1804 | ); | 1821 | ); |
diff --git a/net/ipv6/tcpv6_offload.c b/net/ipv6/tcpv6_offload.c index 6d18157dc32c..0d78132ff18a 100644 --- a/net/ipv6/tcpv6_offload.c +++ b/net/ipv6/tcpv6_offload.c | |||
| @@ -66,13 +66,13 @@ skip_csum: | |||
| 66 | return tcp_gro_receive(head, skb); | 66 | return tcp_gro_receive(head, skb); |
| 67 | } | 67 | } |
| 68 | 68 | ||
| 69 | static int tcp6_gro_complete(struct sk_buff *skb) | 69 | static int tcp6_gro_complete(struct sk_buff *skb, int thoff) |
| 70 | { | 70 | { |
| 71 | const struct ipv6hdr *iph = ipv6_hdr(skb); | 71 | const struct ipv6hdr *iph = ipv6_hdr(skb); |
| 72 | struct tcphdr *th = tcp_hdr(skb); | 72 | struct tcphdr *th = tcp_hdr(skb); |
| 73 | 73 | ||
| 74 | th->check = ~tcp_v6_check(skb->len - skb_transport_offset(skb), | 74 | th->check = ~tcp_v6_check(skb->len - thoff, &iph->saddr, |
| 75 | &iph->saddr, &iph->daddr, 0); | 75 | &iph->daddr, 0); |
| 76 | skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6; | 76 | skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6; |
| 77 | 77 | ||
| 78 | return tcp_gro_complete(skb); | 78 | return tcp_gro_complete(skb); |
diff --git a/net/ipv6/tunnel6.c b/net/ipv6/tunnel6.c index 4b0f50d9a962..2c4e4c5c7614 100644 --- a/net/ipv6/tunnel6.c +++ b/net/ipv6/tunnel6.c | |||
| @@ -12,8 +12,7 @@ | |||
| 12 | * GNU General Public License for more details. | 12 | * GNU General Public License for more details. |
| 13 | * | 13 | * |
| 14 | * You should have received a copy of the GNU General Public License | 14 | * You should have received a copy of the GNU General Public License |
| 15 | * along with this program; if not, write to the Free Software | 15 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 17 | * | 16 | * |
| 18 | * Authors Mitsuru KANDA <mk@linux-ipv6.org> | 17 | * Authors Mitsuru KANDA <mk@linux-ipv6.org> |
| 19 | * YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> | 18 | * YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> |
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 089c741a3992..1e586d92260e 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c | |||
| @@ -460,9 +460,7 @@ try_again: | |||
| 460 | 460 | ||
| 461 | /* Copy the address. */ | 461 | /* Copy the address. */ |
| 462 | if (msg->msg_name) { | 462 | if (msg->msg_name) { |
| 463 | struct sockaddr_in6 *sin6; | 463 | DECLARE_SOCKADDR(struct sockaddr_in6 *, sin6, msg->msg_name); |
| 464 | |||
| 465 | sin6 = (struct sockaddr_in6 *) msg->msg_name; | ||
| 466 | sin6->sin6_family = AF_INET6; | 464 | sin6->sin6_family = AF_INET6; |
| 467 | sin6->sin6_port = udp_hdr(skb)->source; | 465 | sin6->sin6_port = udp_hdr(skb)->source; |
| 468 | sin6->sin6_flowinfo = 0; | 466 | sin6->sin6_flowinfo = 0; |
| @@ -479,12 +477,16 @@ try_again: | |||
| 479 | } | 477 | } |
| 480 | *addr_len = sizeof(*sin6); | 478 | *addr_len = sizeof(*sin6); |
| 481 | } | 479 | } |
| 480 | |||
| 481 | if (np->rxopt.all) | ||
| 482 | ip6_datagram_recv_common_ctl(sk, msg, skb); | ||
| 483 | |||
| 482 | if (is_udp4) { | 484 | if (is_udp4) { |
| 483 | if (inet->cmsg_flags) | 485 | if (inet->cmsg_flags) |
| 484 | ip_cmsg_recv(msg, skb); | 486 | ip_cmsg_recv(msg, skb); |
| 485 | } else { | 487 | } else { |
| 486 | if (np->rxopt.all) | 488 | if (np->rxopt.all) |
| 487 | ip6_datagram_recv_ctl(sk, msg, skb); | 489 | ip6_datagram_recv_specific_ctl(sk, msg, skb); |
| 488 | } | 490 | } |
| 489 | 491 | ||
| 490 | err = copied; | 492 | err = copied; |
| @@ -538,8 +540,11 @@ void __udp6_lib_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
| 538 | if (sk == NULL) | 540 | if (sk == NULL) |
| 539 | return; | 541 | return; |
| 540 | 542 | ||
| 541 | if (type == ICMPV6_PKT_TOOBIG) | 543 | if (type == ICMPV6_PKT_TOOBIG) { |
| 544 | if (!ip6_sk_accept_pmtu(sk)) | ||
| 545 | goto out; | ||
| 542 | ip6_sk_update_pmtu(skb, sk, info); | 546 | ip6_sk_update_pmtu(skb, sk, info); |
| 547 | } | ||
| 543 | if (type == NDISC_REDIRECT) { | 548 | if (type == NDISC_REDIRECT) { |
| 544 | ip6_sk_redirect(skb, sk); | 549 | ip6_sk_redirect(skb, sk); |
| 545 | goto out; | 550 | goto out; |
| @@ -1038,7 +1043,7 @@ int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
| 1038 | struct udp_sock *up = udp_sk(sk); | 1043 | struct udp_sock *up = udp_sk(sk); |
| 1039 | struct inet_sock *inet = inet_sk(sk); | 1044 | struct inet_sock *inet = inet_sk(sk); |
| 1040 | struct ipv6_pinfo *np = inet6_sk(sk); | 1045 | struct ipv6_pinfo *np = inet6_sk(sk); |
| 1041 | struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) msg->msg_name; | 1046 | DECLARE_SOCKADDR(struct sockaddr_in6 *, sin6, msg->msg_name); |
| 1042 | struct in6_addr *daddr, *final_p, final; | 1047 | struct in6_addr *daddr, *final_p, final; |
| 1043 | struct ipv6_txoptions *opt = NULL; | 1048 | struct ipv6_txoptions *opt = NULL; |
| 1044 | struct ip6_flowlabel *flowlabel = NULL; | 1049 | struct ip6_flowlabel *flowlabel = NULL; |
| @@ -1220,7 +1225,7 @@ do_udp_sendmsg: | |||
| 1220 | 1225 | ||
| 1221 | security_sk_classify_flow(sk, flowi6_to_flowi(&fl6)); | 1226 | security_sk_classify_flow(sk, flowi6_to_flowi(&fl6)); |
| 1222 | 1227 | ||
| 1223 | dst = ip6_sk_dst_lookup_flow(sk, &fl6, final_p, true); | 1228 | dst = ip6_sk_dst_lookup_flow(sk, &fl6, final_p); |
| 1224 | if (IS_ERR(dst)) { | 1229 | if (IS_ERR(dst)) { |
| 1225 | err = PTR_ERR(dst); | 1230 | err = PTR_ERR(dst); |
| 1226 | dst = NULL; | 1231 | dst = NULL; |
diff --git a/net/ipv6/xfrm6_mode_ro.c b/net/ipv6/xfrm6_mode_ro.c index 63d5d493098a..0e015906f9ca 100644 --- a/net/ipv6/xfrm6_mode_ro.c +++ b/net/ipv6/xfrm6_mode_ro.c | |||
| @@ -15,8 +15,7 @@ | |||
| 15 | * GNU General Public License for more details. | 15 | * GNU General Public License for more details. |
| 16 | * | 16 | * |
| 17 | * You should have received a copy of the GNU General Public License | 17 | * You should have received a copy of the GNU General Public License |
| 18 | * along with this program; if not, write to the Free Software | 18 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 20 | */ | 19 | */ |
| 21 | /* | 20 | /* |
| 22 | * Authors: | 21 | * Authors: |
diff --git a/net/ipv6/xfrm6_tunnel.c b/net/ipv6/xfrm6_tunnel.c index de2bcfaaf759..1c66465a42dd 100644 --- a/net/ipv6/xfrm6_tunnel.c +++ b/net/ipv6/xfrm6_tunnel.c | |||
| @@ -12,8 +12,7 @@ | |||
| 12 | * GNU General Public License for more details. | 12 | * GNU General Public License for more details. |
| 13 | * | 13 | * |
| 14 | * You should have received a copy of the GNU General Public License | 14 | * You should have received a copy of the GNU General Public License |
| 15 | * along with this program; if not, write to the Free Software | 15 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 17 | * | 16 | * |
| 18 | * Authors Mitsuru KANDA <mk@linux-ipv6.org> | 17 | * Authors Mitsuru KANDA <mk@linux-ipv6.org> |
| 19 | * YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> | 18 | * YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> |
diff --git a/net/ipx/af_ipx.c b/net/ipx/af_ipx.c index e096025b477f..994e28bfb32e 100644 --- a/net/ipx/af_ipx.c +++ b/net/ipx/af_ipx.c | |||
| @@ -1707,7 +1707,7 @@ static int ipx_sendmsg(struct kiocb *iocb, struct socket *sock, | |||
| 1707 | { | 1707 | { |
| 1708 | struct sock *sk = sock->sk; | 1708 | struct sock *sk = sock->sk; |
| 1709 | struct ipx_sock *ipxs = ipx_sk(sk); | 1709 | struct ipx_sock *ipxs = ipx_sk(sk); |
| 1710 | struct sockaddr_ipx *usipx = (struct sockaddr_ipx *)msg->msg_name; | 1710 | DECLARE_SOCKADDR(struct sockaddr_ipx *, usipx, msg->msg_name); |
| 1711 | struct sockaddr_ipx local_sipx; | 1711 | struct sockaddr_ipx local_sipx; |
| 1712 | int rc = -EINVAL; | 1712 | int rc = -EINVAL; |
| 1713 | int flags = msg->msg_flags; | 1713 | int flags = msg->msg_flags; |
| @@ -1774,7 +1774,7 @@ static int ipx_recvmsg(struct kiocb *iocb, struct socket *sock, | |||
| 1774 | { | 1774 | { |
| 1775 | struct sock *sk = sock->sk; | 1775 | struct sock *sk = sock->sk; |
| 1776 | struct ipx_sock *ipxs = ipx_sk(sk); | 1776 | struct ipx_sock *ipxs = ipx_sk(sk); |
| 1777 | struct sockaddr_ipx *sipx = (struct sockaddr_ipx *)msg->msg_name; | 1777 | DECLARE_SOCKADDR(struct sockaddr_ipx *, sipx, msg->msg_name); |
| 1778 | struct ipxhdr *ipx = NULL; | 1778 | struct ipxhdr *ipx = NULL; |
| 1779 | struct sk_buff *skb; | 1779 | struct sk_buff *skb; |
| 1780 | int copied, rc; | 1780 | int copied, rc; |
diff --git a/net/irda/af_irda.c b/net/irda/af_irda.c index de7db23049f1..54747c25c86c 100644 --- a/net/irda/af_irda.c +++ b/net/irda/af_irda.c | |||
| @@ -25,9 +25,7 @@ | |||
| 25 | * GNU General Public License for more details. | 25 | * GNU General Public License for more details. |
| 26 | * | 26 | * |
| 27 | * You should have received a copy of the GNU General Public License | 27 | * You should have received a copy of the GNU General Public License |
| 28 | * along with this program; if not, write to the Free Software | 28 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 29 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | ||
| 30 | * MA 02111-1307 USA | ||
| 31 | * | 29 | * |
| 32 | * Linux-IrDA now supports four different types of IrDA sockets: | 30 | * Linux-IrDA now supports four different types of IrDA sockets: |
| 33 | * | 31 | * |
| @@ -1654,7 +1652,7 @@ static int irda_sendmsg_ultra(struct kiocb *iocb, struct socket *sock, | |||
| 1654 | 1652 | ||
| 1655 | /* Check if an address was specified with sendto. Jean II */ | 1653 | /* Check if an address was specified with sendto. Jean II */ |
| 1656 | if (msg->msg_name) { | 1654 | if (msg->msg_name) { |
| 1657 | struct sockaddr_irda *addr = (struct sockaddr_irda *) msg->msg_name; | 1655 | DECLARE_SOCKADDR(struct sockaddr_irda *, addr, msg->msg_name); |
| 1658 | err = -EINVAL; | 1656 | err = -EINVAL; |
| 1659 | /* Check address, extract pid. Jean II */ | 1657 | /* Check address, extract pid. Jean II */ |
| 1660 | if (msg->msg_namelen < sizeof(*addr)) | 1658 | if (msg->msg_namelen < sizeof(*addr)) |
diff --git a/net/irda/discovery.c b/net/irda/discovery.c index b0b56a339a83..6786e7f193d2 100644 --- a/net/irda/discovery.c +++ b/net/irda/discovery.c | |||
| @@ -24,9 +24,7 @@ | |||
| 24 | * GNU General Public License for more details. | 24 | * GNU General Public License for more details. |
| 25 | * | 25 | * |
| 26 | * You should have received a copy of the GNU General Public License | 26 | * You should have received a copy of the GNU General Public License |
| 27 | * along with this program; if not, write to the Free Software | 27 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 28 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | ||
| 29 | * MA 02111-1307 USA | ||
| 30 | * | 28 | * |
| 31 | ********************************************************************/ | 29 | ********************************************************************/ |
| 32 | 30 | ||
diff --git a/net/irda/ircomm/ircomm_core.c b/net/irda/ircomm/ircomm_core.c index b797daac063c..4490a675b1bb 100644 --- a/net/irda/ircomm/ircomm_core.c +++ b/net/irda/ircomm/ircomm_core.c | |||
| @@ -23,9 +23,7 @@ | |||
| 23 | * GNU General Public License for more details. | 23 | * GNU General Public License for more details. |
| 24 | * | 24 | * |
| 25 | * You should have received a copy of the GNU General Public License | 25 | * You should have received a copy of the GNU General Public License |
| 26 | * along with this program; if not, write to the Free Software | 26 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 27 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | ||
| 28 | * MA 02111-1307 USA | ||
| 29 | * | 27 | * |
| 30 | ********************************************************************/ | 28 | ********************************************************************/ |
| 31 | 29 | ||
diff --git a/net/irda/ircomm/ircomm_event.c b/net/irda/ircomm/ircomm_event.c index d78554fedbac..b172c6522328 100644 --- a/net/irda/ircomm/ircomm_event.c +++ b/net/irda/ircomm/ircomm_event.c | |||
| @@ -22,9 +22,7 @@ | |||
| 22 | * GNU General Public License for more details. | 22 | * GNU General Public License for more details. |
| 23 | * | 23 | * |
| 24 | * You should have received a copy of the GNU General Public License | 24 | * You should have received a copy of the GNU General Public License |
| 25 | * along with this program; if not, write to the Free Software | 25 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 26 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | ||
| 27 | * MA 02111-1307 USA | ||
| 28 | * | 26 | * |
| 29 | ********************************************************************/ | 27 | ********************************************************************/ |
| 30 | 28 | ||
diff --git a/net/irda/ircomm/ircomm_lmp.c b/net/irda/ircomm/ircomm_lmp.c index 3b8095c771d4..6536114adf37 100644 --- a/net/irda/ircomm/ircomm_lmp.c +++ b/net/irda/ircomm/ircomm_lmp.c | |||
| @@ -24,9 +24,7 @@ | |||
| 24 | * GNU General Public License for more details. | 24 | * GNU General Public License for more details. |
| 25 | * | 25 | * |
| 26 | * You should have received a copy of the GNU General Public License | 26 | * You should have received a copy of the GNU General Public License |
| 27 | * along with this program; if not, write to the Free Software | 27 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 28 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | ||
| 29 | * MA 02111-1307 USA | ||
| 30 | * | 28 | * |
| 31 | ********************************************************************/ | 29 | ********************************************************************/ |
| 32 | 30 | ||
diff --git a/net/irda/ircomm/ircomm_param.c b/net/irda/ircomm/ircomm_param.c index 308939128359..f80b1a6a244b 100644 --- a/net/irda/ircomm/ircomm_param.c +++ b/net/irda/ircomm/ircomm_param.c | |||
| @@ -22,9 +22,7 @@ | |||
| 22 | * GNU General Public License for more details. | 22 | * GNU General Public License for more details. |
| 23 | * | 23 | * |
| 24 | * You should have received a copy of the GNU General Public License | 24 | * You should have received a copy of the GNU General Public License |
| 25 | * along with this program; if not, write to the Free Software | 25 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 26 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | ||
| 27 | * MA 02111-1307 USA | ||
| 28 | * | 26 | * |
| 29 | ********************************************************************/ | 27 | ********************************************************************/ |
| 30 | 28 | ||
diff --git a/net/irda/ircomm/ircomm_ttp.c b/net/irda/ircomm/ircomm_ttp.c index 6e6509f22f60..d362d711b79c 100644 --- a/net/irda/ircomm/ircomm_ttp.c +++ b/net/irda/ircomm/ircomm_ttp.c | |||
| @@ -23,9 +23,7 @@ | |||
| 23 | * GNU General Public License for more details. | 23 | * GNU General Public License for more details. |
| 24 | * | 24 | * |
| 25 | * You should have received a copy of the GNU General Public License | 25 | * You should have received a copy of the GNU General Public License |
| 26 | * along with this program; if not, write to the Free Software | 26 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 27 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | ||
| 28 | * MA 02111-1307 USA | ||
| 29 | * | 27 | * |
| 30 | ********************************************************************/ | 28 | ********************************************************************/ |
| 31 | 29 | ||
diff --git a/net/irda/ircomm/ircomm_tty.c b/net/irda/ircomm/ircomm_tty.c index 41ac7938268b..2ba8b9705bb7 100644 --- a/net/irda/ircomm/ircomm_tty.c +++ b/net/irda/ircomm/ircomm_tty.c | |||
| @@ -24,9 +24,7 @@ | |||
| 24 | * GNU General Public License for more details. | 24 | * GNU General Public License for more details. |
| 25 | * | 25 | * |
| 26 | * You should have received a copy of the GNU General Public License | 26 | * You should have received a copy of the GNU General Public License |
| 27 | * along with this program; if not, write to the Free Software | 27 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 28 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | ||
| 29 | * MA 02111-1307 USA | ||
| 30 | * | 28 | * |
| 31 | ********************************************************************/ | 29 | ********************************************************************/ |
| 32 | 30 | ||
diff --git a/net/irda/ircomm/ircomm_tty_attach.c b/net/irda/ircomm/ircomm_tty_attach.c index a2a508f5f268..2ee87bf387cc 100644 --- a/net/irda/ircomm/ircomm_tty_attach.c +++ b/net/irda/ircomm/ircomm_tty_attach.c | |||
| @@ -23,9 +23,7 @@ | |||
| 23 | * GNU General Public License for more details. | 23 | * GNU General Public License for more details. |
| 24 | * | 24 | * |
| 25 | * You should have received a copy of the GNU General Public License | 25 | * You should have received a copy of the GNU General Public License |
| 26 | * along with this program; if not, write to the Free Software | 26 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 27 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | ||
| 28 | * MA 02111-1307 USA | ||
| 29 | * | 27 | * |
| 30 | ********************************************************************/ | 28 | ********************************************************************/ |
| 31 | 29 | ||
diff --git a/net/irda/ircomm/ircomm_tty_ioctl.c b/net/irda/ircomm/ircomm_tty_ioctl.c index b343f50dc8d7..ce943853c38d 100644 --- a/net/irda/ircomm/ircomm_tty_ioctl.c +++ b/net/irda/ircomm/ircomm_tty_ioctl.c | |||
| @@ -22,9 +22,7 @@ | |||
| 22 | * GNU General Public License for more details. | 22 | * GNU General Public License for more details. |
| 23 | * | 23 | * |
| 24 | * You should have received a copy of the GNU General Public License | 24 | * You should have received a copy of the GNU General Public License |
| 25 | * along with this program; if not, write to the Free Software | 25 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 26 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | ||
| 27 | * MA 02111-1307 USA | ||
| 28 | * | 26 | * |
| 29 | ********************************************************************/ | 27 | ********************************************************************/ |
| 30 | 28 | ||
diff --git a/net/irda/irda_device.c b/net/irda/irda_device.c index 14653b8d664d..365b895da84b 100644 --- a/net/irda/irda_device.c +++ b/net/irda/irda_device.c | |||
| @@ -23,9 +23,7 @@ | |||
| 23 | * GNU General Public License for more details. | 23 | * GNU General Public License for more details. |
| 24 | * | 24 | * |
| 25 | * You should have received a copy of the GNU General Public License | 25 | * You should have received a copy of the GNU General Public License |
| 26 | * along with this program; if not, write to the Free Software | 26 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 27 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | ||
| 28 | * MA 02111-1307 USA | ||
| 29 | * | 27 | * |
| 30 | ********************************************************************/ | 28 | ********************************************************************/ |
| 31 | 29 | ||
diff --git a/net/irda/irlap.c b/net/irda/irlap.c index 005b424494a0..a778df55f5d6 100644 --- a/net/irda/irlap.c +++ b/net/irda/irlap.c | |||
| @@ -23,9 +23,7 @@ | |||
| 23 | * GNU General Public License for more details. | 23 | * GNU General Public License for more details. |
| 24 | * | 24 | * |
| 25 | * You should have received a copy of the GNU General Public License | 25 | * You should have received a copy of the GNU General Public License |
| 26 | * along with this program; if not, write to the Free Software | 26 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 27 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | ||
| 28 | * MA 02111-1307 USA | ||
| 29 | * | 27 | * |
| 30 | ********************************************************************/ | 28 | ********************************************************************/ |
| 31 | 29 | ||
diff --git a/net/irda/parameters.c b/net/irda/parameters.c index 71cd38c1a67f..6d0869716bf6 100644 --- a/net/irda/parameters.c +++ b/net/irda/parameters.c | |||
| @@ -22,9 +22,7 @@ | |||
| 22 | * GNU General Public License for more details. | 22 | * GNU General Public License for more details. |
| 23 | * | 23 | * |
| 24 | * You should have received a copy of the GNU General Public License | 24 | * You should have received a copy of the GNU General Public License |
| 25 | * along with this program; if not, write to the Free Software | 25 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 26 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | ||
| 27 | * MA 02111-1307 USA | ||
| 28 | * | 26 | * |
| 29 | ********************************************************************/ | 27 | ********************************************************************/ |
| 30 | 28 | ||
diff --git a/net/irda/qos.c b/net/irda/qos.c index 798ffd9a705e..11a7cc0cbc28 100644 --- a/net/irda/qos.c +++ b/net/irda/qos.c | |||
| @@ -24,9 +24,7 @@ | |||
| 24 | * GNU General Public License for more details. | 24 | * GNU General Public License for more details. |
| 25 | * | 25 | * |
| 26 | * You should have received a copy of the GNU General Public License | 26 | * You should have received a copy of the GNU General Public License |
| 27 | * along with this program; if not, write to the Free Software | 27 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 28 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | ||
| 29 | * MA 02111-1307 USA | ||
| 30 | * | 28 | * |
| 31 | ********************************************************************/ | 29 | ********************************************************************/ |
| 32 | 30 | ||
diff --git a/net/key/af_key.c b/net/key/af_key.c index 545f047868ad..1a04c1329362 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c | |||
| @@ -1340,6 +1340,12 @@ static int pfkey_getspi(struct sock *sk, struct sk_buff *skb, const struct sadb_ | |||
| 1340 | max_spi = range->sadb_spirange_max; | 1340 | max_spi = range->sadb_spirange_max; |
| 1341 | } | 1341 | } |
| 1342 | 1342 | ||
| 1343 | err = verify_spi_info(x->id.proto, min_spi, max_spi); | ||
| 1344 | if (err) { | ||
| 1345 | xfrm_state_put(x); | ||
| 1346 | return err; | ||
| 1347 | } | ||
| 1348 | |||
| 1343 | err = xfrm_alloc_spi(x, min_spi, max_spi); | 1349 | err = xfrm_alloc_spi(x, min_spi, max_spi); |
| 1344 | resp_skb = err ? ERR_PTR(err) : pfkey_xfrm_state2msg(x); | 1350 | resp_skb = err ? ERR_PTR(err) : pfkey_xfrm_state2msg(x); |
| 1345 | 1351 | ||
| @@ -1380,10 +1386,9 @@ static int pfkey_acquire(struct sock *sk, struct sk_buff *skb, const struct sadb | |||
| 1380 | return 0; | 1386 | return 0; |
| 1381 | 1387 | ||
| 1382 | spin_lock_bh(&x->lock); | 1388 | spin_lock_bh(&x->lock); |
| 1383 | if (x->km.state == XFRM_STATE_ACQ) { | 1389 | if (x->km.state == XFRM_STATE_ACQ) |
| 1384 | x->km.state = XFRM_STATE_ERROR; | 1390 | x->km.state = XFRM_STATE_ERROR; |
| 1385 | wake_up(&net->xfrm.km_waitq); | 1391 | |
| 1386 | } | ||
| 1387 | spin_unlock_bh(&x->lock); | 1392 | spin_unlock_bh(&x->lock); |
| 1388 | xfrm_state_put(x); | 1393 | xfrm_state_put(x); |
| 1389 | return 0; | 1394 | return 0; |
| @@ -1785,7 +1790,9 @@ static int pfkey_dump_sa(struct pfkey_sock *pfk) | |||
| 1785 | 1790 | ||
| 1786 | static void pfkey_dump_sa_done(struct pfkey_sock *pfk) | 1791 | static void pfkey_dump_sa_done(struct pfkey_sock *pfk) |
| 1787 | { | 1792 | { |
| 1788 | xfrm_state_walk_done(&pfk->dump.u.state); | 1793 | struct net *net = sock_net(&pfk->sk); |
| 1794 | |||
| 1795 | xfrm_state_walk_done(&pfk->dump.u.state, net); | ||
| 1789 | } | 1796 | } |
| 1790 | 1797 | ||
| 1791 | static int pfkey_dump(struct sock *sk, struct sk_buff *skb, const struct sadb_msg *hdr, void * const *ext_hdrs) | 1798 | static int pfkey_dump(struct sock *sk, struct sk_buff *skb, const struct sadb_msg *hdr, void * const *ext_hdrs) |
| @@ -1861,7 +1868,7 @@ static u32 gen_reqid(struct net *net) | |||
| 1861 | reqid = IPSEC_MANUAL_REQID_MAX+1; | 1868 | reqid = IPSEC_MANUAL_REQID_MAX+1; |
| 1862 | xfrm_policy_walk_init(&walk, XFRM_POLICY_TYPE_MAIN); | 1869 | xfrm_policy_walk_init(&walk, XFRM_POLICY_TYPE_MAIN); |
| 1863 | rc = xfrm_policy_walk(net, &walk, check_reqid, (void*)&reqid); | 1870 | rc = xfrm_policy_walk(net, &walk, check_reqid, (void*)&reqid); |
| 1864 | xfrm_policy_walk_done(&walk); | 1871 | xfrm_policy_walk_done(&walk, net); |
| 1865 | if (rc != -EEXIST) | 1872 | if (rc != -EEXIST) |
| 1866 | return reqid; | 1873 | return reqid; |
| 1867 | } while (reqid != start); | 1874 | } while (reqid != start); |
| @@ -2485,6 +2492,7 @@ static int pfkey_migrate(struct sock *sk, struct sk_buff *skb, | |||
| 2485 | struct xfrm_selector sel; | 2492 | struct xfrm_selector sel; |
| 2486 | struct xfrm_migrate m[XFRM_MAX_DEPTH]; | 2493 | struct xfrm_migrate m[XFRM_MAX_DEPTH]; |
| 2487 | struct xfrm_kmaddress k; | 2494 | struct xfrm_kmaddress k; |
| 2495 | struct net *net = sock_net(sk); | ||
| 2488 | 2496 | ||
| 2489 | if (!present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC - 1], | 2497 | if (!present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC - 1], |
| 2490 | ext_hdrs[SADB_EXT_ADDRESS_DST - 1]) || | 2498 | ext_hdrs[SADB_EXT_ADDRESS_DST - 1]) || |
| @@ -2558,7 +2566,7 @@ static int pfkey_migrate(struct sock *sk, struct sk_buff *skb, | |||
| 2558 | } | 2566 | } |
| 2559 | 2567 | ||
| 2560 | return xfrm_migrate(&sel, dir, XFRM_POLICY_TYPE_MAIN, m, i, | 2568 | return xfrm_migrate(&sel, dir, XFRM_POLICY_TYPE_MAIN, m, i, |
| 2561 | kma ? &k : NULL); | 2569 | kma ? &k : NULL, net); |
| 2562 | 2570 | ||
| 2563 | out: | 2571 | out: |
| 2564 | return err; | 2572 | return err; |
| @@ -2659,7 +2667,9 @@ static int pfkey_dump_sp(struct pfkey_sock *pfk) | |||
| 2659 | 2667 | ||
| 2660 | static void pfkey_dump_sp_done(struct pfkey_sock *pfk) | 2668 | static void pfkey_dump_sp_done(struct pfkey_sock *pfk) |
| 2661 | { | 2669 | { |
| 2662 | xfrm_policy_walk_done(&pfk->dump.u.policy); | 2670 | struct net *net = sock_net((struct sock *)pfk); |
| 2671 | |||
| 2672 | xfrm_policy_walk_done(&pfk->dump.u.policy, net); | ||
| 2663 | } | 2673 | } |
| 2664 | 2674 | ||
| 2665 | static int pfkey_spddump(struct sock *sk, struct sk_buff *skb, const struct sadb_msg *hdr, void * const *ext_hdrs) | 2675 | static int pfkey_spddump(struct sock *sk, struct sk_buff *skb, const struct sadb_msg *hdr, void * const *ext_hdrs) |
| @@ -3569,6 +3579,7 @@ static int pfkey_sendmsg(struct kiocb *kiocb, | |||
| 3569 | struct sk_buff *skb = NULL; | 3579 | struct sk_buff *skb = NULL; |
| 3570 | struct sadb_msg *hdr = NULL; | 3580 | struct sadb_msg *hdr = NULL; |
| 3571 | int err; | 3581 | int err; |
| 3582 | struct net *net = sock_net(sk); | ||
| 3572 | 3583 | ||
| 3573 | err = -EOPNOTSUPP; | 3584 | err = -EOPNOTSUPP; |
| 3574 | if (msg->msg_flags & MSG_OOB) | 3585 | if (msg->msg_flags & MSG_OOB) |
| @@ -3591,9 +3602,9 @@ static int pfkey_sendmsg(struct kiocb *kiocb, | |||
| 3591 | if (!hdr) | 3602 | if (!hdr) |
| 3592 | goto out; | 3603 | goto out; |
| 3593 | 3604 | ||
| 3594 | mutex_lock(&xfrm_cfg_mutex); | 3605 | mutex_lock(&net->xfrm.xfrm_cfg_mutex); |
| 3595 | err = pfkey_process(sk, skb, hdr); | 3606 | err = pfkey_process(sk, skb, hdr); |
| 3596 | mutex_unlock(&xfrm_cfg_mutex); | 3607 | mutex_unlock(&net->xfrm.xfrm_cfg_mutex); |
| 3597 | 3608 | ||
| 3598 | out: | 3609 | out: |
| 3599 | if (err && hdr && pfkey_error(hdr, err, sk) == 0) | 3610 | if (err && hdr && pfkey_error(hdr, err, sk) == 0) |
diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c index 9af77d9c0ec9..735d0f60c83a 100644 --- a/net/l2tp/l2tp_core.c +++ b/net/l2tp/l2tp_core.c | |||
| @@ -176,7 +176,7 @@ l2tp_session_id_hash_2(struct l2tp_net *pn, u32 session_id) | |||
| 176 | * owned by userspace. A struct sock returned from this function must be | 176 | * owned by userspace. A struct sock returned from this function must be |
| 177 | * released using l2tp_tunnel_sock_put once you're done with it. | 177 | * released using l2tp_tunnel_sock_put once you're done with it. |
| 178 | */ | 178 | */ |
| 179 | struct sock *l2tp_tunnel_sock_lookup(struct l2tp_tunnel *tunnel) | 179 | static struct sock *l2tp_tunnel_sock_lookup(struct l2tp_tunnel *tunnel) |
| 180 | { | 180 | { |
| 181 | int err = 0; | 181 | int err = 0; |
| 182 | struct socket *sock = NULL; | 182 | struct socket *sock = NULL; |
| @@ -202,10 +202,9 @@ struct sock *l2tp_tunnel_sock_lookup(struct l2tp_tunnel *tunnel) | |||
| 202 | out: | 202 | out: |
| 203 | return sk; | 203 | return sk; |
| 204 | } | 204 | } |
| 205 | EXPORT_SYMBOL_GPL(l2tp_tunnel_sock_lookup); | ||
| 206 | 205 | ||
| 207 | /* Drop a reference to a tunnel socket obtained via. l2tp_tunnel_sock_put */ | 206 | /* Drop a reference to a tunnel socket obtained via. l2tp_tunnel_sock_put */ |
| 208 | void l2tp_tunnel_sock_put(struct sock *sk) | 207 | static void l2tp_tunnel_sock_put(struct sock *sk) |
| 209 | { | 208 | { |
| 210 | struct l2tp_tunnel *tunnel = l2tp_sock_to_tunnel(sk); | 209 | struct l2tp_tunnel *tunnel = l2tp_sock_to_tunnel(sk); |
| 211 | if (tunnel) { | 210 | if (tunnel) { |
| @@ -217,7 +216,6 @@ void l2tp_tunnel_sock_put(struct sock *sk) | |||
| 217 | } | 216 | } |
| 218 | sock_put(sk); | 217 | sock_put(sk); |
| 219 | } | 218 | } |
| 220 | EXPORT_SYMBOL_GPL(l2tp_tunnel_sock_put); | ||
| 221 | 219 | ||
| 222 | /* Lookup a session by id in the global session list | 220 | /* Lookup a session by id in the global session list |
| 223 | */ | 221 | */ |
diff --git a/net/l2tp/l2tp_core.h b/net/l2tp/l2tp_core.h index 1ee9f6965d68..1f01ba3435bc 100644 --- a/net/l2tp/l2tp_core.h +++ b/net/l2tp/l2tp_core.h | |||
| @@ -238,8 +238,6 @@ out: | |||
| 238 | return tunnel; | 238 | return tunnel; |
| 239 | } | 239 | } |
| 240 | 240 | ||
| 241 | struct sock *l2tp_tunnel_sock_lookup(struct l2tp_tunnel *tunnel); | ||
| 242 | void l2tp_tunnel_sock_put(struct sock *sk); | ||
| 243 | struct l2tp_session *l2tp_session_find(struct net *net, | 241 | struct l2tp_session *l2tp_session_find(struct net *net, |
| 244 | struct l2tp_tunnel *tunnel, | 242 | struct l2tp_tunnel *tunnel, |
| 245 | u32 session_id); | 243 | u32 session_id); |
diff --git a/net/l2tp/l2tp_ip.c b/net/l2tp/l2tp_ip.c index da1a1cee1a08..0b44d855269c 100644 --- a/net/l2tp/l2tp_ip.c +++ b/net/l2tp/l2tp_ip.c | |||
| @@ -403,7 +403,7 @@ static int l2tp_ip_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *m | |||
| 403 | 403 | ||
| 404 | /* Get and verify the address. */ | 404 | /* Get and verify the address. */ |
| 405 | if (msg->msg_name) { | 405 | if (msg->msg_name) { |
| 406 | struct sockaddr_l2tpip *lip = (struct sockaddr_l2tpip *) msg->msg_name; | 406 | DECLARE_SOCKADDR(struct sockaddr_l2tpip *, lip, msg->msg_name); |
| 407 | rc = -EINVAL; | 407 | rc = -EINVAL; |
| 408 | if (msg->msg_namelen < sizeof(*lip)) | 408 | if (msg->msg_namelen < sizeof(*lip)) |
| 409 | goto out; | 409 | goto out; |
| @@ -512,7 +512,7 @@ static int l2tp_ip_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *m | |||
| 512 | struct inet_sock *inet = inet_sk(sk); | 512 | struct inet_sock *inet = inet_sk(sk); |
| 513 | size_t copied = 0; | 513 | size_t copied = 0; |
| 514 | int err = -EOPNOTSUPP; | 514 | int err = -EOPNOTSUPP; |
| 515 | struct sockaddr_in *sin = (struct sockaddr_in *)msg->msg_name; | 515 | DECLARE_SOCKADDR(struct sockaddr_in *, sin, msg->msg_name); |
| 516 | struct sk_buff *skb; | 516 | struct sk_buff *skb; |
| 517 | 517 | ||
| 518 | if (flags & MSG_OOB) | 518 | if (flags & MSG_OOB) |
diff --git a/net/l2tp/l2tp_ip6.c b/net/l2tp/l2tp_ip6.c index bb6e206ea70b..7704ea9502fd 100644 --- a/net/l2tp/l2tp_ip6.c +++ b/net/l2tp/l2tp_ip6.c | |||
| @@ -371,6 +371,9 @@ static int l2tp_ip6_connect(struct sock *sk, struct sockaddr *uaddr, | |||
| 371 | if (addr_len < sizeof(*lsa)) | 371 | if (addr_len < sizeof(*lsa)) |
| 372 | return -EINVAL; | 372 | return -EINVAL; |
| 373 | 373 | ||
| 374 | if (usin->sin6_family != AF_INET6) | ||
| 375 | return -EINVAL; | ||
| 376 | |||
| 374 | addr_type = ipv6_addr_type(&usin->sin6_addr); | 377 | addr_type = ipv6_addr_type(&usin->sin6_addr); |
| 375 | if (addr_type & IPV6_ADDR_MULTICAST) | 378 | if (addr_type & IPV6_ADDR_MULTICAST) |
| 376 | return -EINVAL; | 379 | return -EINVAL; |
| @@ -481,8 +484,7 @@ static int l2tp_ip6_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
| 481 | struct msghdr *msg, size_t len) | 484 | struct msghdr *msg, size_t len) |
| 482 | { | 485 | { |
| 483 | struct ipv6_txoptions opt_space; | 486 | struct ipv6_txoptions opt_space; |
| 484 | struct sockaddr_l2tpip6 *lsa = | 487 | DECLARE_SOCKADDR(struct sockaddr_l2tpip6 *, lsa, msg->msg_name); |
| 485 | (struct sockaddr_l2tpip6 *) msg->msg_name; | ||
| 486 | struct in6_addr *daddr, *final_p, final; | 488 | struct in6_addr *daddr, *final_p, final; |
| 487 | struct ipv6_pinfo *np = inet6_sk(sk); | 489 | struct ipv6_pinfo *np = inet6_sk(sk); |
| 488 | struct ipv6_txoptions *opt = NULL; | 490 | struct ipv6_txoptions *opt = NULL; |
| @@ -597,7 +599,7 @@ static int l2tp_ip6_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
| 597 | 599 | ||
| 598 | security_sk_classify_flow(sk, flowi6_to_flowi(&fl6)); | 600 | security_sk_classify_flow(sk, flowi6_to_flowi(&fl6)); |
| 599 | 601 | ||
| 600 | dst = ip6_dst_lookup_flow(sk, &fl6, final_p, true); | 602 | dst = ip6_dst_lookup_flow(sk, &fl6, final_p); |
| 601 | if (IS_ERR(dst)) { | 603 | if (IS_ERR(dst)) { |
| 602 | err = PTR_ERR(dst); | 604 | err = PTR_ERR(dst); |
| 603 | goto out; | 605 | goto out; |
| @@ -652,7 +654,7 @@ static int l2tp_ip6_recvmsg(struct kiocb *iocb, struct sock *sk, | |||
| 652 | int flags, int *addr_len) | 654 | int flags, int *addr_len) |
| 653 | { | 655 | { |
| 654 | struct ipv6_pinfo *np = inet6_sk(sk); | 656 | struct ipv6_pinfo *np = inet6_sk(sk); |
| 655 | struct sockaddr_l2tpip6 *lsa = (struct sockaddr_l2tpip6 *)msg->msg_name; | 657 | DECLARE_SOCKADDR(struct sockaddr_l2tpip6 *, lsa, msg->msg_name); |
| 656 | size_t copied = 0; | 658 | size_t copied = 0; |
| 657 | int err = -EOPNOTSUPP; | 659 | int err = -EOPNOTSUPP; |
| 658 | struct sk_buff *skb; | 660 | struct sk_buff *skb; |
diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c index c71b699eb555..0080d2b0a8ae 100644 --- a/net/llc/af_llc.c +++ b/net/llc/af_llc.c | |||
| @@ -707,7 +707,7 @@ out: | |||
| 707 | static int llc_ui_recvmsg(struct kiocb *iocb, struct socket *sock, | 707 | static int llc_ui_recvmsg(struct kiocb *iocb, struct socket *sock, |
| 708 | struct msghdr *msg, size_t len, int flags) | 708 | struct msghdr *msg, size_t len, int flags) |
| 709 | { | 709 | { |
| 710 | struct sockaddr_llc *uaddr = (struct sockaddr_llc *)msg->msg_name; | 710 | DECLARE_SOCKADDR(struct sockaddr_llc *, uaddr, msg->msg_name); |
| 711 | const int nonblock = flags & MSG_DONTWAIT; | 711 | const int nonblock = flags & MSG_DONTWAIT; |
| 712 | struct sk_buff *skb = NULL; | 712 | struct sk_buff *skb = NULL; |
| 713 | struct sock *sk = sock->sk; | 713 | struct sock *sk = sock->sk; |
| @@ -884,7 +884,7 @@ static int llc_ui_sendmsg(struct kiocb *iocb, struct socket *sock, | |||
| 884 | { | 884 | { |
| 885 | struct sock *sk = sock->sk; | 885 | struct sock *sk = sock->sk; |
| 886 | struct llc_sock *llc = llc_sk(sk); | 886 | struct llc_sock *llc = llc_sk(sk); |
| 887 | struct sockaddr_llc *addr = (struct sockaddr_llc *)msg->msg_name; | 887 | DECLARE_SOCKADDR(struct sockaddr_llc *, addr, msg->msg_name); |
| 888 | int flags = msg->msg_flags; | 888 | int flags = msg->msg_flags; |
| 889 | int noblock = flags & MSG_DONTWAIT; | 889 | int noblock = flags & MSG_DONTWAIT; |
| 890 | struct sk_buff *skb; | 890 | struct sk_buff *skb; |
diff --git a/net/llc/llc_conn.c b/net/llc/llc_conn.c index cd8724177965..42dc2e45c921 100644 --- a/net/llc/llc_conn.c +++ b/net/llc/llc_conn.c | |||
| @@ -753,7 +753,7 @@ void llc_sap_remove_socket(struct llc_sap *sap, struct sock *sk) | |||
| 753 | * | 753 | * |
| 754 | * Sends received pdus to the connection state machine. | 754 | * Sends received pdus to the connection state machine. |
| 755 | */ | 755 | */ |
| 756 | static int llc_conn_rcv(struct sock* sk, struct sk_buff *skb) | 756 | static int llc_conn_rcv(struct sock *sk, struct sk_buff *skb) |
| 757 | { | 757 | { |
| 758 | struct llc_conn_state_ev *ev = llc_conn_ev(skb); | 758 | struct llc_conn_state_ev *ev = llc_conn_ev(skb); |
| 759 | 759 | ||
| @@ -891,7 +891,7 @@ out_kfree_skb: | |||
| 891 | * | 891 | * |
| 892 | * Initializes a socket with default llc values. | 892 | * Initializes a socket with default llc values. |
| 893 | */ | 893 | */ |
| 894 | static void llc_sk_init(struct sock* sk) | 894 | static void llc_sk_init(struct sock *sk) |
| 895 | { | 895 | { |
| 896 | struct llc_sock *llc = llc_sk(sk); | 896 | struct llc_sock *llc = llc_sk(sk); |
| 897 | 897 | ||
diff --git a/net/llc/llc_core.c b/net/llc/llc_core.c index 2bb0ddff8c0f..842851cef698 100644 --- a/net/llc/llc_core.c +++ b/net/llc/llc_core.c | |||
| @@ -23,7 +23,7 @@ | |||
| 23 | #include <net/llc.h> | 23 | #include <net/llc.h> |
| 24 | 24 | ||
| 25 | LIST_HEAD(llc_sap_list); | 25 | LIST_HEAD(llc_sap_list); |
| 26 | DEFINE_SPINLOCK(llc_sap_list_lock); | 26 | static DEFINE_SPINLOCK(llc_sap_list_lock); |
| 27 | 27 | ||
| 28 | /** | 28 | /** |
| 29 | * llc_sap_alloc - allocates and initializes sap. | 29 | * llc_sap_alloc - allocates and initializes sap. |
| @@ -48,7 +48,7 @@ static struct llc_sap *llc_sap_alloc(void) | |||
| 48 | 48 | ||
| 49 | static struct llc_sap *__llc_sap_find(unsigned char sap_value) | 49 | static struct llc_sap *__llc_sap_find(unsigned char sap_value) |
| 50 | { | 50 | { |
| 51 | struct llc_sap* sap; | 51 | struct llc_sap *sap; |
| 52 | 52 | ||
| 53 | list_for_each_entry(sap, &llc_sap_list, node) | 53 | list_for_each_entry(sap, &llc_sap_list, node) |
| 54 | if (sap->laddr.lsap == sap_value) | 54 | if (sap->laddr.lsap == sap_value) |
| @@ -159,7 +159,6 @@ module_init(llc_init); | |||
| 159 | module_exit(llc_exit); | 159 | module_exit(llc_exit); |
| 160 | 160 | ||
| 161 | EXPORT_SYMBOL(llc_sap_list); | 161 | EXPORT_SYMBOL(llc_sap_list); |
| 162 | EXPORT_SYMBOL(llc_sap_list_lock); | ||
| 163 | EXPORT_SYMBOL(llc_sap_find); | 162 | EXPORT_SYMBOL(llc_sap_find); |
| 164 | EXPORT_SYMBOL(llc_sap_open); | 163 | EXPORT_SYMBOL(llc_sap_open); |
| 165 | EXPORT_SYMBOL(llc_sap_close); | 164 | EXPORT_SYMBOL(llc_sap_close); |
diff --git a/net/llc/llc_output.c b/net/llc/llc_output.c index 2dae8a5df23f..94425e421213 100644 --- a/net/llc/llc_output.c +++ b/net/llc/llc_output.c | |||
| @@ -43,7 +43,7 @@ int llc_mac_hdr_init(struct sk_buff *skb, | |||
| 43 | rc = 0; | 43 | rc = 0; |
| 44 | break; | 44 | break; |
| 45 | default: | 45 | default: |
| 46 | WARN(1, "device type not supported: %d\n", skb->dev->type); | 46 | break; |
| 47 | } | 47 | } |
| 48 | return rc; | 48 | return rc; |
| 49 | } | 49 | } |
diff --git a/net/llc/llc_sap.c b/net/llc/llc_sap.c index e5850699098e..06033f6c845f 100644 --- a/net/llc/llc_sap.c +++ b/net/llc/llc_sap.c | |||
| @@ -66,7 +66,7 @@ struct sk_buff *llc_alloc_frame(struct sock *sk, struct net_device *dev, | |||
| 66 | return skb; | 66 | return skb; |
| 67 | } | 67 | } |
| 68 | 68 | ||
| 69 | void llc_save_primitive(struct sock *sk, struct sk_buff* skb, u8 prim) | 69 | void llc_save_primitive(struct sock *sk, struct sk_buff *skb, u8 prim) |
| 70 | { | 70 | { |
| 71 | struct sockaddr_llc *addr; | 71 | struct sockaddr_llc *addr; |
| 72 | 72 | ||
| @@ -114,7 +114,7 @@ void llc_sap_rtn_pdu(struct llc_sap *sap, struct sk_buff *skb) | |||
| 114 | * failure. | 114 | * failure. |
| 115 | */ | 115 | */ |
| 116 | static struct llc_sap_state_trans *llc_find_sap_trans(struct llc_sap *sap, | 116 | static struct llc_sap_state_trans *llc_find_sap_trans(struct llc_sap *sap, |
| 117 | struct sk_buff* skb) | 117 | struct sk_buff *skb) |
| 118 | { | 118 | { |
| 119 | int i = 0; | 119 | int i = 0; |
| 120 | struct llc_sap_state_trans *rc = NULL; | 120 | struct llc_sap_state_trans *rc = NULL; |
diff --git a/net/mac80211/aes_cmac.c b/net/mac80211/aes_cmac.c index 537488cbf941..9b9009f99551 100644 --- a/net/mac80211/aes_cmac.c +++ b/net/mac80211/aes_cmac.c | |||
| @@ -111,7 +111,7 @@ void ieee80211_aes_cmac(struct crypto_cipher *tfm, const u8 *aad, | |||
| 111 | } | 111 | } |
| 112 | 112 | ||
| 113 | 113 | ||
| 114 | struct crypto_cipher * ieee80211_aes_cmac_key_setup(const u8 key[]) | 114 | struct crypto_cipher *ieee80211_aes_cmac_key_setup(const u8 key[]) |
| 115 | { | 115 | { |
| 116 | struct crypto_cipher *tfm; | 116 | struct crypto_cipher *tfm; |
| 117 | 117 | ||
diff --git a/net/mac80211/aes_cmac.h b/net/mac80211/aes_cmac.h index 20785a647254..0ce6487af795 100644 --- a/net/mac80211/aes_cmac.h +++ b/net/mac80211/aes_cmac.h | |||
| @@ -11,7 +11,7 @@ | |||
| 11 | 11 | ||
| 12 | #include <linux/crypto.h> | 12 | #include <linux/crypto.h> |
| 13 | 13 | ||
| 14 | struct crypto_cipher * ieee80211_aes_cmac_key_setup(const u8 key[]); | 14 | struct crypto_cipher *ieee80211_aes_cmac_key_setup(const u8 key[]); |
| 15 | void ieee80211_aes_cmac(struct crypto_cipher *tfm, const u8 *aad, | 15 | void ieee80211_aes_cmac(struct crypto_cipher *tfm, const u8 *aad, |
| 16 | const u8 *data, size_t data_len, u8 *mic); | 16 | const u8 *data, size_t data_len, u8 *mic); |
| 17 | void ieee80211_aes_cmac_key_free(struct crypto_cipher *tfm); | 17 | void ieee80211_aes_cmac_key_free(struct crypto_cipher *tfm); |
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 364ce0c5962f..f9ae9b85d4c1 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
| @@ -133,7 +133,9 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, | |||
| 133 | struct key_params *params) | 133 | struct key_params *params) |
| 134 | { | 134 | { |
| 135 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 135 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
| 136 | struct ieee80211_local *local = sdata->local; | ||
| 136 | struct sta_info *sta = NULL; | 137 | struct sta_info *sta = NULL; |
| 138 | const struct ieee80211_cipher_scheme *cs = NULL; | ||
| 137 | struct ieee80211_key *key; | 139 | struct ieee80211_key *key; |
| 138 | int err; | 140 | int err; |
| 139 | 141 | ||
| @@ -145,22 +147,28 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, | |||
| 145 | case WLAN_CIPHER_SUITE_WEP40: | 147 | case WLAN_CIPHER_SUITE_WEP40: |
| 146 | case WLAN_CIPHER_SUITE_TKIP: | 148 | case WLAN_CIPHER_SUITE_TKIP: |
| 147 | case WLAN_CIPHER_SUITE_WEP104: | 149 | case WLAN_CIPHER_SUITE_WEP104: |
| 148 | if (IS_ERR(sdata->local->wep_tx_tfm)) | 150 | if (IS_ERR(local->wep_tx_tfm)) |
| 149 | return -EINVAL; | 151 | return -EINVAL; |
| 150 | break; | 152 | break; |
| 153 | case WLAN_CIPHER_SUITE_CCMP: | ||
| 154 | case WLAN_CIPHER_SUITE_AES_CMAC: | ||
| 155 | case WLAN_CIPHER_SUITE_GCMP: | ||
| 156 | break; | ||
| 151 | default: | 157 | default: |
| 158 | cs = ieee80211_cs_get(local, params->cipher, sdata->vif.type); | ||
| 152 | break; | 159 | break; |
| 153 | } | 160 | } |
| 154 | 161 | ||
| 155 | key = ieee80211_key_alloc(params->cipher, key_idx, params->key_len, | 162 | key = ieee80211_key_alloc(params->cipher, key_idx, params->key_len, |
| 156 | params->key, params->seq_len, params->seq); | 163 | params->key, params->seq_len, params->seq, |
| 164 | cs); | ||
| 157 | if (IS_ERR(key)) | 165 | if (IS_ERR(key)) |
| 158 | return PTR_ERR(key); | 166 | return PTR_ERR(key); |
| 159 | 167 | ||
| 160 | if (pairwise) | 168 | if (pairwise) |
| 161 | key->conf.flags |= IEEE80211_KEY_FLAG_PAIRWISE; | 169 | key->conf.flags |= IEEE80211_KEY_FLAG_PAIRWISE; |
| 162 | 170 | ||
| 163 | mutex_lock(&sdata->local->sta_mtx); | 171 | mutex_lock(&local->sta_mtx); |
| 164 | 172 | ||
| 165 | if (mac_addr) { | 173 | if (mac_addr) { |
| 166 | if (ieee80211_vif_is_mesh(&sdata->vif)) | 174 | if (ieee80211_vif_is_mesh(&sdata->vif)) |
| @@ -216,10 +224,13 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, | |||
| 216 | break; | 224 | break; |
| 217 | } | 225 | } |
| 218 | 226 | ||
| 227 | if (sta) | ||
| 228 | sta->cipher_scheme = cs; | ||
| 229 | |||
| 219 | err = ieee80211_key_link(key, sdata, sta); | 230 | err = ieee80211_key_link(key, sdata, sta); |
| 220 | 231 | ||
| 221 | out_unlock: | 232 | out_unlock: |
| 222 | mutex_unlock(&sdata->local->sta_mtx); | 233 | mutex_unlock(&local->sta_mtx); |
| 223 | 234 | ||
| 224 | return err; | 235 | return err; |
| 225 | } | 236 | } |
| @@ -244,7 +255,7 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, | |||
| 244 | goto out_unlock; | 255 | goto out_unlock; |
| 245 | 256 | ||
| 246 | if (pairwise) | 257 | if (pairwise) |
| 247 | key = key_mtx_dereference(local, sta->ptk); | 258 | key = key_mtx_dereference(local, sta->ptk[key_idx]); |
| 248 | else | 259 | else |
| 249 | key = key_mtx_dereference(local, sta->gtk[key_idx]); | 260 | key = key_mtx_dereference(local, sta->gtk[key_idx]); |
| 250 | } else | 261 | } else |
| @@ -290,9 +301,10 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, | |||
| 290 | if (!sta) | 301 | if (!sta) |
| 291 | goto out; | 302 | goto out; |
| 292 | 303 | ||
| 293 | if (pairwise) | 304 | if (pairwise && key_idx < NUM_DEFAULT_KEYS) |
| 294 | key = rcu_dereference(sta->ptk); | 305 | key = rcu_dereference(sta->ptk[key_idx]); |
| 295 | else if (key_idx < NUM_DEFAULT_KEYS) | 306 | else if (!pairwise && |
| 307 | key_idx < NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS) | ||
| 296 | key = rcu_dereference(sta->gtk[key_idx]); | 308 | key = rcu_dereference(sta->gtk[key_idx]); |
| 297 | } else | 309 | } else |
| 298 | key = rcu_dereference(sdata->keys[key_idx]); | 310 | key = rcu_dereference(sdata->keys[key_idx]); |
| @@ -521,8 +533,8 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) | |||
| 521 | STATION_INFO_PEER_PM | | 533 | STATION_INFO_PEER_PM | |
| 522 | STATION_INFO_NONPEER_PM; | 534 | STATION_INFO_NONPEER_PM; |
| 523 | 535 | ||
| 524 | sinfo->llid = le16_to_cpu(sta->llid); | 536 | sinfo->llid = sta->llid; |
| 525 | sinfo->plid = le16_to_cpu(sta->plid); | 537 | sinfo->plid = sta->plid; |
| 526 | sinfo->plink_state = sta->plink_state; | 538 | sinfo->plink_state = sta->plink_state; |
| 527 | if (test_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN)) { | 539 | if (test_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN)) { |
| 528 | sinfo->filled |= STATION_INFO_T_OFFSET; | 540 | sinfo->filled |= STATION_INFO_T_OFFSET; |
| @@ -816,6 +828,7 @@ static int ieee80211_set_monitor_channel(struct wiphy *wiphy, | |||
| 816 | if (cfg80211_chandef_identical(&local->monitor_chandef, chandef)) | 828 | if (cfg80211_chandef_identical(&local->monitor_chandef, chandef)) |
| 817 | return 0; | 829 | return 0; |
| 818 | 830 | ||
| 831 | mutex_lock(&local->mtx); | ||
| 819 | mutex_lock(&local->iflist_mtx); | 832 | mutex_lock(&local->iflist_mtx); |
| 820 | if (local->use_chanctx) { | 833 | if (local->use_chanctx) { |
| 821 | sdata = rcu_dereference_protected( | 834 | sdata = rcu_dereference_protected( |
| @@ -834,6 +847,7 @@ static int ieee80211_set_monitor_channel(struct wiphy *wiphy, | |||
| 834 | if (ret == 0) | 847 | if (ret == 0) |
| 835 | local->monitor_chandef = *chandef; | 848 | local->monitor_chandef = *chandef; |
| 836 | mutex_unlock(&local->iflist_mtx); | 849 | mutex_unlock(&local->iflist_mtx); |
| 850 | mutex_unlock(&local->mtx); | ||
| 837 | 851 | ||
| 838 | return ret; | 852 | return ret; |
| 839 | } | 853 | } |
| @@ -846,7 +860,7 @@ static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata, | |||
| 846 | if (!resp || !resp_len) | 860 | if (!resp || !resp_len) |
| 847 | return 1; | 861 | return 1; |
| 848 | 862 | ||
| 849 | old = rtnl_dereference(sdata->u.ap.probe_resp); | 863 | old = sdata_dereference(sdata->u.ap.probe_resp, sdata); |
| 850 | 864 | ||
| 851 | new = kzalloc(sizeof(struct probe_resp) + resp_len, GFP_KERNEL); | 865 | new = kzalloc(sizeof(struct probe_resp) + resp_len, GFP_KERNEL); |
| 852 | if (!new) | 866 | if (!new) |
| @@ -862,15 +876,16 @@ static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata, | |||
| 862 | return 0; | 876 | return 0; |
| 863 | } | 877 | } |
| 864 | 878 | ||
| 865 | int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata, | 879 | static int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata, |
| 866 | struct cfg80211_beacon_data *params) | 880 | struct cfg80211_beacon_data *params) |
| 867 | { | 881 | { |
| 868 | struct beacon_data *new, *old; | 882 | struct beacon_data *new, *old; |
| 869 | int new_head_len, new_tail_len; | 883 | int new_head_len, new_tail_len; |
| 870 | int size, err; | 884 | int size, err; |
| 871 | u32 changed = BSS_CHANGED_BEACON; | 885 | u32 changed = BSS_CHANGED_BEACON; |
| 872 | 886 | ||
| 873 | old = rtnl_dereference(sdata->u.ap.beacon); | 887 | old = sdata_dereference(sdata->u.ap.beacon, sdata); |
| 888 | |||
| 874 | 889 | ||
| 875 | /* Need to have a beacon head if we don't have one yet */ | 890 | /* Need to have a beacon head if we don't have one yet */ |
| 876 | if (!params->head && !old) | 891 | if (!params->head && !old) |
| @@ -938,6 +953,7 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, | |||
| 938 | struct cfg80211_ap_settings *params) | 953 | struct cfg80211_ap_settings *params) |
| 939 | { | 954 | { |
| 940 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 955 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
| 956 | struct ieee80211_local *local = sdata->local; | ||
| 941 | struct beacon_data *old; | 957 | struct beacon_data *old; |
| 942 | struct ieee80211_sub_if_data *vlan; | 958 | struct ieee80211_sub_if_data *vlan; |
| 943 | u32 changed = BSS_CHANGED_BEACON_INT | | 959 | u32 changed = BSS_CHANGED_BEACON_INT | |
| @@ -947,7 +963,7 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, | |||
| 947 | BSS_CHANGED_P2P_PS; | 963 | BSS_CHANGED_P2P_PS; |
| 948 | int err; | 964 | int err; |
| 949 | 965 | ||
| 950 | old = rtnl_dereference(sdata->u.ap.beacon); | 966 | old = sdata_dereference(sdata->u.ap.beacon, sdata); |
| 951 | if (old) | 967 | if (old) |
| 952 | return -EALREADY; | 968 | return -EALREADY; |
| 953 | 969 | ||
| @@ -956,8 +972,10 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, | |||
| 956 | sdata->needed_rx_chains = sdata->local->rx_chains; | 972 | sdata->needed_rx_chains = sdata->local->rx_chains; |
| 957 | sdata->radar_required = params->radar_required; | 973 | sdata->radar_required = params->radar_required; |
| 958 | 974 | ||
| 975 | mutex_lock(&local->mtx); | ||
| 959 | err = ieee80211_vif_use_channel(sdata, ¶ms->chandef, | 976 | err = ieee80211_vif_use_channel(sdata, ¶ms->chandef, |
| 960 | IEEE80211_CHANCTX_SHARED); | 977 | IEEE80211_CHANCTX_SHARED); |
| 978 | mutex_unlock(&local->mtx); | ||
| 961 | if (err) | 979 | if (err) |
| 962 | return err; | 980 | return err; |
| 963 | ieee80211_vif_copy_chanctx_to_vlans(sdata, false); | 981 | ieee80211_vif_copy_chanctx_to_vlans(sdata, false); |
| @@ -968,11 +986,19 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, | |||
| 968 | */ | 986 | */ |
| 969 | sdata->control_port_protocol = params->crypto.control_port_ethertype; | 987 | sdata->control_port_protocol = params->crypto.control_port_ethertype; |
| 970 | sdata->control_port_no_encrypt = params->crypto.control_port_no_encrypt; | 988 | sdata->control_port_no_encrypt = params->crypto.control_port_no_encrypt; |
| 989 | sdata->encrypt_headroom = ieee80211_cs_headroom(sdata->local, | ||
| 990 | ¶ms->crypto, | ||
| 991 | sdata->vif.type); | ||
| 992 | |||
| 971 | list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) { | 993 | list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) { |
| 972 | vlan->control_port_protocol = | 994 | vlan->control_port_protocol = |
| 973 | params->crypto.control_port_ethertype; | 995 | params->crypto.control_port_ethertype; |
| 974 | vlan->control_port_no_encrypt = | 996 | vlan->control_port_no_encrypt = |
| 975 | params->crypto.control_port_no_encrypt; | 997 | params->crypto.control_port_no_encrypt; |
| 998 | vlan->encrypt_headroom = | ||
| 999 | ieee80211_cs_headroom(sdata->local, | ||
| 1000 | ¶ms->crypto, | ||
| 1001 | vlan->vif.type); | ||
| 976 | } | 1002 | } |
| 977 | 1003 | ||
| 978 | sdata->vif.bss_conf.beacon_int = params->beacon_interval; | 1004 | sdata->vif.bss_conf.beacon_int = params->beacon_interval; |
| @@ -1001,13 +1027,15 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, | |||
| 1001 | 1027 | ||
| 1002 | err = drv_start_ap(sdata->local, sdata); | 1028 | err = drv_start_ap(sdata->local, sdata); |
| 1003 | if (err) { | 1029 | if (err) { |
| 1004 | old = rtnl_dereference(sdata->u.ap.beacon); | 1030 | old = sdata_dereference(sdata->u.ap.beacon, sdata); |
| 1031 | |||
| 1005 | if (old) | 1032 | if (old) |
| 1006 | kfree_rcu(old, rcu_head); | 1033 | kfree_rcu(old, rcu_head); |
| 1007 | RCU_INIT_POINTER(sdata->u.ap.beacon, NULL); | 1034 | RCU_INIT_POINTER(sdata->u.ap.beacon, NULL); |
| 1008 | return err; | 1035 | return err; |
| 1009 | } | 1036 | } |
| 1010 | 1037 | ||
| 1038 | ieee80211_recalc_dtim(local, sdata); | ||
| 1011 | ieee80211_bss_info_change_notify(sdata, changed); | 1039 | ieee80211_bss_info_change_notify(sdata, changed); |
| 1012 | 1040 | ||
| 1013 | netif_carrier_on(dev); | 1041 | netif_carrier_on(dev); |
| @@ -1032,7 +1060,7 @@ static int ieee80211_change_beacon(struct wiphy *wiphy, struct net_device *dev, | |||
| 1032 | if (sdata->vif.csa_active) | 1060 | if (sdata->vif.csa_active) |
| 1033 | return -EBUSY; | 1061 | return -EBUSY; |
| 1034 | 1062 | ||
| 1035 | old = rtnl_dereference(sdata->u.ap.beacon); | 1063 | old = sdata_dereference(sdata->u.ap.beacon, sdata); |
| 1036 | if (!old) | 1064 | if (!old) |
| 1037 | return -ENOENT; | 1065 | return -ENOENT; |
| 1038 | 1066 | ||
| @@ -1050,15 +1078,18 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) | |||
| 1050 | struct ieee80211_local *local = sdata->local; | 1078 | struct ieee80211_local *local = sdata->local; |
| 1051 | struct beacon_data *old_beacon; | 1079 | struct beacon_data *old_beacon; |
| 1052 | struct probe_resp *old_probe_resp; | 1080 | struct probe_resp *old_probe_resp; |
| 1081 | struct cfg80211_chan_def chandef; | ||
| 1053 | 1082 | ||
| 1054 | old_beacon = rtnl_dereference(sdata->u.ap.beacon); | 1083 | old_beacon = sdata_dereference(sdata->u.ap.beacon, sdata); |
| 1055 | if (!old_beacon) | 1084 | if (!old_beacon) |
| 1056 | return -ENOENT; | 1085 | return -ENOENT; |
| 1057 | old_probe_resp = rtnl_dereference(sdata->u.ap.probe_resp); | 1086 | old_probe_resp = sdata_dereference(sdata->u.ap.probe_resp, sdata); |
| 1058 | 1087 | ||
| 1059 | /* abort any running channel switch */ | 1088 | /* abort any running channel switch */ |
| 1060 | sdata->vif.csa_active = false; | 1089 | sdata->vif.csa_active = false; |
| 1061 | cancel_work_sync(&sdata->csa_finalize_work); | 1090 | kfree(sdata->u.ap.next_beacon); |
| 1091 | sdata->u.ap.next_beacon = NULL; | ||
| 1092 | |||
| 1062 | cancel_work_sync(&sdata->u.ap.request_smps_work); | 1093 | cancel_work_sync(&sdata->u.ap.request_smps_work); |
| 1063 | 1094 | ||
| 1064 | /* turn off carrier for this interface and dependent VLANs */ | 1095 | /* turn off carrier for this interface and dependent VLANs */ |
| @@ -1073,17 +1104,8 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) | |||
| 1073 | if (old_probe_resp) | 1104 | if (old_probe_resp) |
| 1074 | kfree_rcu(old_probe_resp, rcu_head); | 1105 | kfree_rcu(old_probe_resp, rcu_head); |
| 1075 | 1106 | ||
| 1076 | list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) | 1107 | __sta_info_flush(sdata, true); |
| 1077 | sta_info_flush_defer(vlan); | 1108 | ieee80211_free_keys(sdata, true); |
| 1078 | sta_info_flush_defer(sdata); | ||
| 1079 | synchronize_net(); | ||
| 1080 | rcu_barrier(); | ||
| 1081 | list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) { | ||
| 1082 | sta_info_flush_cleanup(vlan); | ||
| 1083 | ieee80211_free_keys(vlan); | ||
| 1084 | } | ||
| 1085 | sta_info_flush_cleanup(sdata); | ||
| 1086 | ieee80211_free_keys(sdata); | ||
| 1087 | 1109 | ||
| 1088 | sdata->vif.bss_conf.enable_beacon = false; | 1110 | sdata->vif.bss_conf.enable_beacon = false; |
| 1089 | sdata->vif.bss_conf.ssid_len = 0; | 1111 | sdata->vif.bss_conf.ssid_len = 0; |
| @@ -1091,8 +1113,10 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) | |||
| 1091 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED); | 1113 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED); |
| 1092 | 1114 | ||
| 1093 | if (sdata->wdev.cac_started) { | 1115 | if (sdata->wdev.cac_started) { |
| 1116 | chandef = sdata->vif.bss_conf.chandef; | ||
| 1094 | cancel_delayed_work_sync(&sdata->dfs_cac_timer_work); | 1117 | cancel_delayed_work_sync(&sdata->dfs_cac_timer_work); |
| 1095 | cfg80211_cac_event(sdata->dev, NL80211_RADAR_CAC_ABORTED, | 1118 | cfg80211_cac_event(sdata->dev, &chandef, |
| 1119 | NL80211_RADAR_CAC_ABORTED, | ||
| 1096 | GFP_KERNEL); | 1120 | GFP_KERNEL); |
| 1097 | } | 1121 | } |
| 1098 | 1122 | ||
| @@ -1103,7 +1127,9 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) | |||
| 1103 | skb_queue_purge(&sdata->u.ap.ps.bc_buf); | 1127 | skb_queue_purge(&sdata->u.ap.ps.bc_buf); |
| 1104 | 1128 | ||
| 1105 | ieee80211_vif_copy_chanctx_to_vlans(sdata, true); | 1129 | ieee80211_vif_copy_chanctx_to_vlans(sdata, true); |
| 1130 | mutex_lock(&local->mtx); | ||
| 1106 | ieee80211_vif_release_channel(sdata); | 1131 | ieee80211_vif_release_channel(sdata); |
| 1132 | mutex_unlock(&local->mtx); | ||
| 1107 | 1133 | ||
| 1108 | return 0; | 1134 | return 0; |
| 1109 | } | 1135 | } |
| @@ -1926,8 +1952,10 @@ static int ieee80211_join_mesh(struct wiphy *wiphy, struct net_device *dev, | |||
| 1926 | sdata->smps_mode = IEEE80211_SMPS_OFF; | 1952 | sdata->smps_mode = IEEE80211_SMPS_OFF; |
| 1927 | sdata->needed_rx_chains = sdata->local->rx_chains; | 1953 | sdata->needed_rx_chains = sdata->local->rx_chains; |
| 1928 | 1954 | ||
| 1955 | mutex_lock(&sdata->local->mtx); | ||
| 1929 | err = ieee80211_vif_use_channel(sdata, &setup->chandef, | 1956 | err = ieee80211_vif_use_channel(sdata, &setup->chandef, |
| 1930 | IEEE80211_CHANCTX_SHARED); | 1957 | IEEE80211_CHANCTX_SHARED); |
| 1958 | mutex_unlock(&sdata->local->mtx); | ||
| 1931 | if (err) | 1959 | if (err) |
| 1932 | return err; | 1960 | return err; |
| 1933 | 1961 | ||
| @@ -1939,7 +1967,9 @@ static int ieee80211_leave_mesh(struct wiphy *wiphy, struct net_device *dev) | |||
| 1939 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 1967 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
| 1940 | 1968 | ||
| 1941 | ieee80211_stop_mesh(sdata); | 1969 | ieee80211_stop_mesh(sdata); |
| 1970 | mutex_lock(&sdata->local->mtx); | ||
| 1942 | ieee80211_vif_release_channel(sdata); | 1971 | ieee80211_vif_release_channel(sdata); |
| 1972 | mutex_unlock(&sdata->local->mtx); | ||
| 1943 | 1973 | ||
| 1944 | return 0; | 1974 | return 0; |
| 1945 | } | 1975 | } |
| @@ -1953,7 +1983,7 @@ static int ieee80211_change_bss(struct wiphy *wiphy, | |||
| 1953 | enum ieee80211_band band; | 1983 | enum ieee80211_band band; |
| 1954 | u32 changed = 0; | 1984 | u32 changed = 0; |
| 1955 | 1985 | ||
| 1956 | if (!rtnl_dereference(sdata->u.ap.beacon)) | 1986 | if (!sdata_dereference(sdata->u.ap.beacon, sdata)) |
| 1957 | return -ENOENT; | 1987 | return -ENOENT; |
| 1958 | 1988 | ||
| 1959 | band = ieee80211_get_sdata_band(sdata); | 1989 | band = ieee80211_get_sdata_band(sdata); |
| @@ -2561,8 +2591,8 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy, | |||
| 2561 | int j; | 2591 | int j; |
| 2562 | 2592 | ||
| 2563 | sdata->rc_rateidx_mask[i] = mask->control[i].legacy; | 2593 | sdata->rc_rateidx_mask[i] = mask->control[i].legacy; |
| 2564 | memcpy(sdata->rc_rateidx_mcs_mask[i], mask->control[i].mcs, | 2594 | memcpy(sdata->rc_rateidx_mcs_mask[i], mask->control[i].ht_mcs, |
| 2565 | sizeof(mask->control[i].mcs)); | 2595 | sizeof(mask->control[i].ht_mcs)); |
| 2566 | 2596 | ||
| 2567 | sdata->rc_has_mcs_mask[i] = false; | 2597 | sdata->rc_has_mcs_mask[i] = false; |
| 2568 | if (!sband) | 2598 | if (!sband) |
| @@ -2877,26 +2907,29 @@ static int ieee80211_start_radar_detection(struct wiphy *wiphy, | |||
| 2877 | unsigned long timeout; | 2907 | unsigned long timeout; |
| 2878 | int err; | 2908 | int err; |
| 2879 | 2909 | ||
| 2880 | if (!list_empty(&local->roc_list) || local->scanning) | 2910 | mutex_lock(&local->mtx); |
| 2881 | return -EBUSY; | 2911 | if (!list_empty(&local->roc_list) || local->scanning) { |
| 2912 | err = -EBUSY; | ||
| 2913 | goto out_unlock; | ||
| 2914 | } | ||
| 2882 | 2915 | ||
| 2883 | /* whatever, but channel contexts should not complain about that one */ | 2916 | /* whatever, but channel contexts should not complain about that one */ |
| 2884 | sdata->smps_mode = IEEE80211_SMPS_OFF; | 2917 | sdata->smps_mode = IEEE80211_SMPS_OFF; |
| 2885 | sdata->needed_rx_chains = local->rx_chains; | 2918 | sdata->needed_rx_chains = local->rx_chains; |
| 2886 | sdata->radar_required = true; | 2919 | sdata->radar_required = true; |
| 2887 | 2920 | ||
| 2888 | mutex_lock(&local->iflist_mtx); | ||
| 2889 | err = ieee80211_vif_use_channel(sdata, chandef, | 2921 | err = ieee80211_vif_use_channel(sdata, chandef, |
| 2890 | IEEE80211_CHANCTX_SHARED); | 2922 | IEEE80211_CHANCTX_SHARED); |
| 2891 | mutex_unlock(&local->iflist_mtx); | ||
| 2892 | if (err) | 2923 | if (err) |
| 2893 | return err; | 2924 | goto out_unlock; |
| 2894 | 2925 | ||
| 2895 | timeout = msecs_to_jiffies(IEEE80211_DFS_MIN_CAC_TIME_MS); | 2926 | timeout = msecs_to_jiffies(IEEE80211_DFS_MIN_CAC_TIME_MS); |
| 2896 | ieee80211_queue_delayed_work(&sdata->local->hw, | 2927 | ieee80211_queue_delayed_work(&sdata->local->hw, |
| 2897 | &sdata->dfs_cac_timer_work, timeout); | 2928 | &sdata->dfs_cac_timer_work, timeout); |
| 2898 | 2929 | ||
| 2899 | return 0; | 2930 | out_unlock: |
| 2931 | mutex_unlock(&local->mtx); | ||
| 2932 | return err; | ||
| 2900 | } | 2933 | } |
| 2901 | 2934 | ||
| 2902 | static struct cfg80211_beacon_data * | 2935 | static struct cfg80211_beacon_data * |
| @@ -2963,27 +2996,35 @@ void ieee80211_csa_finalize_work(struct work_struct *work) | |||
| 2963 | struct ieee80211_local *local = sdata->local; | 2996 | struct ieee80211_local *local = sdata->local; |
| 2964 | int err, changed = 0; | 2997 | int err, changed = 0; |
| 2965 | 2998 | ||
| 2999 | sdata_lock(sdata); | ||
| 3000 | /* AP might have been stopped while waiting for the lock. */ | ||
| 3001 | if (!sdata->vif.csa_active) | ||
| 3002 | goto unlock; | ||
| 3003 | |||
| 2966 | if (!ieee80211_sdata_running(sdata)) | 3004 | if (!ieee80211_sdata_running(sdata)) |
| 2967 | return; | 3005 | goto unlock; |
| 2968 | 3006 | ||
| 2969 | sdata->radar_required = sdata->csa_radar_required; | 3007 | sdata->radar_required = sdata->csa_radar_required; |
| 2970 | err = ieee80211_vif_change_channel(sdata, &local->csa_chandef, | 3008 | mutex_lock(&local->mtx); |
| 2971 | &changed); | 3009 | err = ieee80211_vif_change_channel(sdata, &changed); |
| 3010 | mutex_unlock(&local->mtx); | ||
| 2972 | if (WARN_ON(err < 0)) | 3011 | if (WARN_ON(err < 0)) |
| 2973 | return; | 3012 | goto unlock; |
| 2974 | 3013 | ||
| 2975 | if (!local->use_chanctx) { | 3014 | if (!local->use_chanctx) { |
| 2976 | local->_oper_chandef = local->csa_chandef; | 3015 | local->_oper_chandef = sdata->csa_chandef; |
| 2977 | ieee80211_hw_config(local, 0); | 3016 | ieee80211_hw_config(local, 0); |
| 2978 | } | 3017 | } |
| 2979 | 3018 | ||
| 2980 | ieee80211_bss_info_change_notify(sdata, changed); | 3019 | ieee80211_bss_info_change_notify(sdata, changed); |
| 2981 | 3020 | ||
| 3021 | sdata->vif.csa_active = false; | ||
| 2982 | switch (sdata->vif.type) { | 3022 | switch (sdata->vif.type) { |
| 2983 | case NL80211_IFTYPE_AP: | 3023 | case NL80211_IFTYPE_AP: |
| 2984 | err = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon); | 3024 | err = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon); |
| 2985 | if (err < 0) | 3025 | if (err < 0) |
| 2986 | return; | 3026 | goto unlock; |
| 3027 | |||
| 2987 | changed |= err; | 3028 | changed |= err; |
| 2988 | kfree(sdata->u.ap.next_beacon); | 3029 | kfree(sdata->u.ap.next_beacon); |
| 2989 | sdata->u.ap.next_beacon = NULL; | 3030 | sdata->u.ap.next_beacon = NULL; |
| @@ -2997,24 +3038,26 @@ void ieee80211_csa_finalize_work(struct work_struct *work) | |||
| 2997 | case NL80211_IFTYPE_MESH_POINT: | 3038 | case NL80211_IFTYPE_MESH_POINT: |
| 2998 | err = ieee80211_mesh_finish_csa(sdata); | 3039 | err = ieee80211_mesh_finish_csa(sdata); |
| 2999 | if (err < 0) | 3040 | if (err < 0) |
| 3000 | return; | 3041 | goto unlock; |
| 3001 | break; | 3042 | break; |
| 3002 | #endif | 3043 | #endif |
| 3003 | default: | 3044 | default: |
| 3004 | WARN_ON(1); | 3045 | WARN_ON(1); |
| 3005 | return; | 3046 | goto unlock; |
| 3006 | } | 3047 | } |
| 3007 | sdata->vif.csa_active = false; | ||
| 3008 | 3048 | ||
| 3009 | ieee80211_wake_queues_by_reason(&sdata->local->hw, | 3049 | ieee80211_wake_queues_by_reason(&sdata->local->hw, |
| 3010 | IEEE80211_MAX_QUEUE_MAP, | 3050 | IEEE80211_MAX_QUEUE_MAP, |
| 3011 | IEEE80211_QUEUE_STOP_REASON_CSA); | 3051 | IEEE80211_QUEUE_STOP_REASON_CSA); |
| 3012 | 3052 | ||
| 3013 | cfg80211_ch_switch_notify(sdata->dev, &local->csa_chandef); | 3053 | cfg80211_ch_switch_notify(sdata->dev, &sdata->csa_chandef); |
| 3054 | |||
| 3055 | unlock: | ||
| 3056 | sdata_unlock(sdata); | ||
| 3014 | } | 3057 | } |
| 3015 | 3058 | ||
| 3016 | static int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, | 3059 | int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, |
| 3017 | struct cfg80211_csa_settings *params) | 3060 | struct cfg80211_csa_settings *params) |
| 3018 | { | 3061 | { |
| 3019 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 3062 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
| 3020 | struct ieee80211_local *local = sdata->local; | 3063 | struct ieee80211_local *local = sdata->local; |
| @@ -3023,6 +3066,8 @@ static int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, | |||
| 3023 | struct ieee80211_if_mesh __maybe_unused *ifmsh; | 3066 | struct ieee80211_if_mesh __maybe_unused *ifmsh; |
| 3024 | int err, num_chanctx; | 3067 | int err, num_chanctx; |
| 3025 | 3068 | ||
| 3069 | lockdep_assert_held(&sdata->wdev.mtx); | ||
| 3070 | |||
| 3026 | if (!list_empty(&local->roc_list) || local->scanning) | 3071 | if (!list_empty(&local->roc_list) || local->scanning) |
| 3027 | return -EBUSY; | 3072 | return -EBUSY; |
| 3028 | 3073 | ||
| @@ -3143,7 +3188,7 @@ static int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, | |||
| 3143 | IEEE80211_MAX_QUEUE_MAP, | 3188 | IEEE80211_MAX_QUEUE_MAP, |
| 3144 | IEEE80211_QUEUE_STOP_REASON_CSA); | 3189 | IEEE80211_QUEUE_STOP_REASON_CSA); |
| 3145 | 3190 | ||
| 3146 | local->csa_chandef = params->chandef; | 3191 | sdata->csa_chandef = params->chandef; |
| 3147 | sdata->vif.csa_active = true; | 3192 | sdata->vif.csa_active = true; |
| 3148 | 3193 | ||
| 3149 | ieee80211_bss_info_change_notify(sdata, err); | 3194 | ieee80211_bss_info_change_notify(sdata, err); |
| @@ -3153,26 +3198,25 @@ static int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, | |||
| 3153 | } | 3198 | } |
| 3154 | 3199 | ||
| 3155 | static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, | 3200 | static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, |
| 3156 | struct ieee80211_channel *chan, bool offchan, | 3201 | struct cfg80211_mgmt_tx_params *params, |
| 3157 | unsigned int wait, const u8 *buf, size_t len, | 3202 | u64 *cookie) |
| 3158 | bool no_cck, bool dont_wait_for_ack, u64 *cookie) | ||
| 3159 | { | 3203 | { |
| 3160 | struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); | 3204 | struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); |
| 3161 | struct ieee80211_local *local = sdata->local; | 3205 | struct ieee80211_local *local = sdata->local; |
| 3162 | struct sk_buff *skb; | 3206 | struct sk_buff *skb; |
| 3163 | struct sta_info *sta; | 3207 | struct sta_info *sta; |
| 3164 | const struct ieee80211_mgmt *mgmt = (void *)buf; | 3208 | const struct ieee80211_mgmt *mgmt = (void *)params->buf; |
| 3165 | bool need_offchan = false; | 3209 | bool need_offchan = false; |
| 3166 | u32 flags; | 3210 | u32 flags; |
| 3167 | int ret; | 3211 | int ret; |
| 3168 | 3212 | ||
| 3169 | if (dont_wait_for_ack) | 3213 | if (params->dont_wait_for_ack) |
| 3170 | flags = IEEE80211_TX_CTL_NO_ACK; | 3214 | flags = IEEE80211_TX_CTL_NO_ACK; |
| 3171 | else | 3215 | else |
| 3172 | flags = IEEE80211_TX_INTFL_NL80211_FRAME_TX | | 3216 | flags = IEEE80211_TX_INTFL_NL80211_FRAME_TX | |
| 3173 | IEEE80211_TX_CTL_REQ_TX_STATUS; | 3217 | IEEE80211_TX_CTL_REQ_TX_STATUS; |
| 3174 | 3218 | ||
| 3175 | if (no_cck) | 3219 | if (params->no_cck) |
| 3176 | flags |= IEEE80211_TX_CTL_NO_CCK_RATE; | 3220 | flags |= IEEE80211_TX_CTL_NO_CCK_RATE; |
| 3177 | 3221 | ||
| 3178 | switch (sdata->vif.type) { | 3222 | switch (sdata->vif.type) { |
| @@ -3220,7 +3264,7 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, | |||
| 3220 | /* configurations requiring offchan cannot work if no channel has been | 3264 | /* configurations requiring offchan cannot work if no channel has been |
| 3221 | * specified | 3265 | * specified |
| 3222 | */ | 3266 | */ |
| 3223 | if (need_offchan && !chan) | 3267 | if (need_offchan && !params->chan) |
| 3224 | return -EINVAL; | 3268 | return -EINVAL; |
| 3225 | 3269 | ||
| 3226 | mutex_lock(&local->mtx); | 3270 | mutex_lock(&local->mtx); |
| @@ -3233,8 +3277,10 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, | |||
| 3233 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | 3277 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); |
| 3234 | 3278 | ||
| 3235 | if (chanctx_conf) { | 3279 | if (chanctx_conf) { |
| 3236 | need_offchan = chan && (chan != chanctx_conf->def.chan); | 3280 | need_offchan = params->chan && |
| 3237 | } else if (!chan) { | 3281 | (params->chan != |
| 3282 | chanctx_conf->def.chan); | ||
| 3283 | } else if (!params->chan) { | ||
| 3238 | ret = -EINVAL; | 3284 | ret = -EINVAL; |
| 3239 | rcu_read_unlock(); | 3285 | rcu_read_unlock(); |
| 3240 | goto out_unlock; | 3286 | goto out_unlock; |
| @@ -3244,19 +3290,19 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, | |||
| 3244 | rcu_read_unlock(); | 3290 | rcu_read_unlock(); |
| 3245 | } | 3291 | } |
| 3246 | 3292 | ||
| 3247 | if (need_offchan && !offchan) { | 3293 | if (need_offchan && !params->offchan) { |
| 3248 | ret = -EBUSY; | 3294 | ret = -EBUSY; |
| 3249 | goto out_unlock; | 3295 | goto out_unlock; |
| 3250 | } | 3296 | } |
| 3251 | 3297 | ||
| 3252 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + len); | 3298 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + params->len); |
| 3253 | if (!skb) { | 3299 | if (!skb) { |
| 3254 | ret = -ENOMEM; | 3300 | ret = -ENOMEM; |
| 3255 | goto out_unlock; | 3301 | goto out_unlock; |
| 3256 | } | 3302 | } |
| 3257 | skb_reserve(skb, local->hw.extra_tx_headroom); | 3303 | skb_reserve(skb, local->hw.extra_tx_headroom); |
| 3258 | 3304 | ||
| 3259 | memcpy(skb_put(skb, len), buf, len); | 3305 | memcpy(skb_put(skb, params->len), params->buf, params->len); |
| 3260 | 3306 | ||
| 3261 | IEEE80211_SKB_CB(skb)->flags = flags; | 3307 | IEEE80211_SKB_CB(skb)->flags = flags; |
| 3262 | 3308 | ||
| @@ -3276,8 +3322,8 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, | |||
| 3276 | local->hw.offchannel_tx_hw_queue; | 3322 | local->hw.offchannel_tx_hw_queue; |
| 3277 | 3323 | ||
| 3278 | /* This will handle all kinds of coalescing and immediate TX */ | 3324 | /* This will handle all kinds of coalescing and immediate TX */ |
| 3279 | ret = ieee80211_start_roc_work(local, sdata, chan, | 3325 | ret = ieee80211_start_roc_work(local, sdata, params->chan, |
| 3280 | wait, cookie, skb, | 3326 | params->wait, cookie, skb, |
| 3281 | IEEE80211_ROC_TYPE_MGMT_TX); | 3327 | IEEE80211_ROC_TYPE_MGMT_TX); |
| 3282 | if (ret) | 3328 | if (ret) |
| 3283 | kfree_skb(skb); | 3329 | kfree_skb(skb); |
| @@ -3792,6 +3838,31 @@ static void ieee80211_set_wakeup(struct wiphy *wiphy, bool enabled) | |||
| 3792 | } | 3838 | } |
| 3793 | #endif | 3839 | #endif |
| 3794 | 3840 | ||
| 3841 | static int ieee80211_set_qos_map(struct wiphy *wiphy, | ||
| 3842 | struct net_device *dev, | ||
| 3843 | struct cfg80211_qos_map *qos_map) | ||
| 3844 | { | ||
| 3845 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
| 3846 | struct mac80211_qos_map *new_qos_map, *old_qos_map; | ||
| 3847 | |||
| 3848 | if (qos_map) { | ||
| 3849 | new_qos_map = kzalloc(sizeof(*new_qos_map), GFP_KERNEL); | ||
| 3850 | if (!new_qos_map) | ||
| 3851 | return -ENOMEM; | ||
| 3852 | memcpy(&new_qos_map->qos_map, qos_map, sizeof(*qos_map)); | ||
| 3853 | } else { | ||
| 3854 | /* A NULL qos_map was passed to disable QoS mapping */ | ||
| 3855 | new_qos_map = NULL; | ||
| 3856 | } | ||
| 3857 | |||
| 3858 | old_qos_map = sdata_dereference(sdata->qos_map, sdata); | ||
| 3859 | rcu_assign_pointer(sdata->qos_map, new_qos_map); | ||
| 3860 | if (old_qos_map) | ||
| 3861 | kfree_rcu(old_qos_map, rcu_head); | ||
| 3862 | |||
| 3863 | return 0; | ||
| 3864 | } | ||
| 3865 | |||
| 3795 | struct cfg80211_ops mac80211_config_ops = { | 3866 | struct cfg80211_ops mac80211_config_ops = { |
| 3796 | .add_virtual_intf = ieee80211_add_iface, | 3867 | .add_virtual_intf = ieee80211_add_iface, |
| 3797 | .del_virtual_intf = ieee80211_del_iface, | 3868 | .del_virtual_intf = ieee80211_del_iface, |
| @@ -3871,4 +3942,5 @@ struct cfg80211_ops mac80211_config_ops = { | |||
| 3871 | .get_channel = ieee80211_cfg_get_channel, | 3942 | .get_channel = ieee80211_cfg_get_channel, |
| 3872 | .start_radar_detection = ieee80211_start_radar_detection, | 3943 | .start_radar_detection = ieee80211_start_radar_detection, |
| 3873 | .channel_switch = ieee80211_channel_switch, | 3944 | .channel_switch = ieee80211_channel_switch, |
| 3945 | .set_qos_map = ieee80211_set_qos_map, | ||
| 3874 | }; | 3946 | }; |
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index 03ba6b5c5373..f43613a97dd6 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c | |||
| @@ -9,6 +9,140 @@ | |||
| 9 | #include "ieee80211_i.h" | 9 | #include "ieee80211_i.h" |
| 10 | #include "driver-ops.h" | 10 | #include "driver-ops.h" |
| 11 | 11 | ||
| 12 | static enum nl80211_chan_width ieee80211_get_sta_bw(struct ieee80211_sta *sta) | ||
| 13 | { | ||
| 14 | switch (sta->bandwidth) { | ||
| 15 | case IEEE80211_STA_RX_BW_20: | ||
| 16 | if (sta->ht_cap.ht_supported) | ||
| 17 | return NL80211_CHAN_WIDTH_20; | ||
| 18 | else | ||
| 19 | return NL80211_CHAN_WIDTH_20_NOHT; | ||
| 20 | case IEEE80211_STA_RX_BW_40: | ||
| 21 | return NL80211_CHAN_WIDTH_40; | ||
| 22 | case IEEE80211_STA_RX_BW_80: | ||
| 23 | return NL80211_CHAN_WIDTH_80; | ||
| 24 | case IEEE80211_STA_RX_BW_160: | ||
| 25 | /* | ||
| 26 | * This applied for both 160 and 80+80. since we use | ||
| 27 | * the returned value to consider degradation of | ||
| 28 | * ctx->conf.min_def, we have to make sure to take | ||
| 29 | * the bigger one (NL80211_CHAN_WIDTH_160). | ||
| 30 | * Otherwise we might try degrading even when not | ||
| 31 | * needed, as the max required sta_bw returned (80+80) | ||
| 32 | * might be smaller than the configured bw (160). | ||
| 33 | */ | ||
| 34 | return NL80211_CHAN_WIDTH_160; | ||
| 35 | default: | ||
| 36 | WARN_ON(1); | ||
| 37 | return NL80211_CHAN_WIDTH_20; | ||
| 38 | } | ||
| 39 | } | ||
| 40 | |||
| 41 | static enum nl80211_chan_width | ||
| 42 | ieee80211_get_max_required_bw(struct ieee80211_sub_if_data *sdata) | ||
| 43 | { | ||
| 44 | enum nl80211_chan_width max_bw = NL80211_CHAN_WIDTH_20_NOHT; | ||
| 45 | struct sta_info *sta; | ||
| 46 | |||
| 47 | rcu_read_lock(); | ||
| 48 | list_for_each_entry_rcu(sta, &sdata->local->sta_list, list) { | ||
| 49 | if (sdata != sta->sdata && | ||
| 50 | !(sta->sdata->bss && sta->sdata->bss == sdata->bss)) | ||
| 51 | continue; | ||
| 52 | |||
| 53 | if (!sta->uploaded) | ||
| 54 | continue; | ||
| 55 | |||
| 56 | max_bw = max(max_bw, ieee80211_get_sta_bw(&sta->sta)); | ||
| 57 | } | ||
| 58 | rcu_read_unlock(); | ||
| 59 | |||
| 60 | return max_bw; | ||
| 61 | } | ||
| 62 | |||
| 63 | static enum nl80211_chan_width | ||
| 64 | ieee80211_get_chanctx_max_required_bw(struct ieee80211_local *local, | ||
| 65 | struct ieee80211_chanctx_conf *conf) | ||
| 66 | { | ||
| 67 | struct ieee80211_sub_if_data *sdata; | ||
| 68 | enum nl80211_chan_width max_bw = NL80211_CHAN_WIDTH_20_NOHT; | ||
| 69 | |||
| 70 | rcu_read_lock(); | ||
| 71 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { | ||
| 72 | struct ieee80211_vif *vif = &sdata->vif; | ||
| 73 | enum nl80211_chan_width width = NL80211_CHAN_WIDTH_20_NOHT; | ||
| 74 | |||
| 75 | if (!ieee80211_sdata_running(sdata)) | ||
| 76 | continue; | ||
| 77 | |||
| 78 | if (rcu_access_pointer(sdata->vif.chanctx_conf) != conf) | ||
| 79 | continue; | ||
| 80 | |||
| 81 | switch (vif->type) { | ||
| 82 | case NL80211_IFTYPE_AP: | ||
| 83 | case NL80211_IFTYPE_AP_VLAN: | ||
| 84 | width = ieee80211_get_max_required_bw(sdata); | ||
| 85 | break; | ||
| 86 | case NL80211_IFTYPE_P2P_DEVICE: | ||
| 87 | continue; | ||
| 88 | case NL80211_IFTYPE_STATION: | ||
| 89 | case NL80211_IFTYPE_ADHOC: | ||
| 90 | case NL80211_IFTYPE_WDS: | ||
| 91 | case NL80211_IFTYPE_MESH_POINT: | ||
| 92 | width = vif->bss_conf.chandef.width; | ||
| 93 | break; | ||
| 94 | case NL80211_IFTYPE_UNSPECIFIED: | ||
| 95 | case NUM_NL80211_IFTYPES: | ||
| 96 | case NL80211_IFTYPE_MONITOR: | ||
| 97 | case NL80211_IFTYPE_P2P_CLIENT: | ||
| 98 | case NL80211_IFTYPE_P2P_GO: | ||
| 99 | WARN_ON_ONCE(1); | ||
| 100 | } | ||
| 101 | max_bw = max(max_bw, width); | ||
| 102 | } | ||
| 103 | rcu_read_unlock(); | ||
| 104 | |||
| 105 | return max_bw; | ||
| 106 | } | ||
| 107 | |||
| 108 | /* | ||
| 109 | * recalc the min required chan width of the channel context, which is | ||
| 110 | * the max of min required widths of all the interfaces bound to this | ||
| 111 | * channel context. | ||
| 112 | */ | ||
| 113 | void ieee80211_recalc_chanctx_min_def(struct ieee80211_local *local, | ||
| 114 | struct ieee80211_chanctx *ctx) | ||
| 115 | { | ||
| 116 | enum nl80211_chan_width max_bw; | ||
| 117 | struct cfg80211_chan_def min_def; | ||
| 118 | |||
| 119 | lockdep_assert_held(&local->chanctx_mtx); | ||
| 120 | |||
| 121 | /* don't optimize 5MHz, 10MHz, and radar_enabled confs */ | ||
| 122 | if (ctx->conf.def.width == NL80211_CHAN_WIDTH_5 || | ||
| 123 | ctx->conf.def.width == NL80211_CHAN_WIDTH_10 || | ||
| 124 | ctx->conf.radar_enabled) { | ||
| 125 | ctx->conf.min_def = ctx->conf.def; | ||
| 126 | return; | ||
| 127 | } | ||
| 128 | |||
| 129 | max_bw = ieee80211_get_chanctx_max_required_bw(local, &ctx->conf); | ||
| 130 | |||
| 131 | /* downgrade chandef up to max_bw */ | ||
| 132 | min_def = ctx->conf.def; | ||
| 133 | while (min_def.width > max_bw) | ||
| 134 | ieee80211_chandef_downgrade(&min_def); | ||
| 135 | |||
| 136 | if (cfg80211_chandef_identical(&ctx->conf.min_def, &min_def)) | ||
| 137 | return; | ||
| 138 | |||
| 139 | ctx->conf.min_def = min_def; | ||
| 140 | if (!ctx->driver_present) | ||
| 141 | return; | ||
| 142 | |||
| 143 | drv_change_chanctx(local, ctx, IEEE80211_CHANCTX_CHANGE_MIN_WIDTH); | ||
| 144 | } | ||
| 145 | |||
| 12 | static void ieee80211_change_chanctx(struct ieee80211_local *local, | 146 | static void ieee80211_change_chanctx(struct ieee80211_local *local, |
| 13 | struct ieee80211_chanctx *ctx, | 147 | struct ieee80211_chanctx *ctx, |
| 14 | const struct cfg80211_chan_def *chandef) | 148 | const struct cfg80211_chan_def *chandef) |
| @@ -20,6 +154,7 @@ static void ieee80211_change_chanctx(struct ieee80211_local *local, | |||
| 20 | 154 | ||
| 21 | ctx->conf.def = *chandef; | 155 | ctx->conf.def = *chandef; |
| 22 | drv_change_chanctx(local, ctx, IEEE80211_CHANCTX_CHANGE_WIDTH); | 156 | drv_change_chanctx(local, ctx, IEEE80211_CHANCTX_CHANGE_WIDTH); |
| 157 | ieee80211_recalc_chanctx_min_def(local, ctx); | ||
| 23 | 158 | ||
| 24 | if (!local->use_chanctx) { | 159 | if (!local->use_chanctx) { |
| 25 | local->_oper_chandef = *chandef; | 160 | local->_oper_chandef = *chandef; |
| @@ -93,11 +228,12 @@ ieee80211_new_chanctx(struct ieee80211_local *local, | |||
| 93 | ctx->conf.rx_chains_dynamic = 1; | 228 | ctx->conf.rx_chains_dynamic = 1; |
| 94 | ctx->mode = mode; | 229 | ctx->mode = mode; |
| 95 | ctx->conf.radar_enabled = ieee80211_is_radar_required(local); | 230 | ctx->conf.radar_enabled = ieee80211_is_radar_required(local); |
| 231 | ieee80211_recalc_chanctx_min_def(local, ctx); | ||
| 96 | if (!local->use_chanctx) | 232 | if (!local->use_chanctx) |
| 97 | local->hw.conf.radar_enabled = ctx->conf.radar_enabled; | 233 | local->hw.conf.radar_enabled = ctx->conf.radar_enabled; |
| 98 | 234 | ||
| 99 | /* acquire mutex to prevent idle from changing */ | 235 | /* we hold the mutex to prevent idle from changing */ |
| 100 | mutex_lock(&local->mtx); | 236 | lockdep_assert_held(&local->mtx); |
| 101 | /* turn idle off *before* setting channel -- some drivers need that */ | 237 | /* turn idle off *before* setting channel -- some drivers need that */ |
| 102 | changed = ieee80211_idle_off(local); | 238 | changed = ieee80211_idle_off(local); |
| 103 | if (changed) | 239 | if (changed) |
| @@ -110,19 +246,14 @@ ieee80211_new_chanctx(struct ieee80211_local *local, | |||
| 110 | err = drv_add_chanctx(local, ctx); | 246 | err = drv_add_chanctx(local, ctx); |
| 111 | if (err) { | 247 | if (err) { |
| 112 | kfree(ctx); | 248 | kfree(ctx); |
| 113 | ctx = ERR_PTR(err); | ||
| 114 | |||
| 115 | ieee80211_recalc_idle(local); | 249 | ieee80211_recalc_idle(local); |
| 116 | goto out; | 250 | return ERR_PTR(err); |
| 117 | } | 251 | } |
| 118 | } | 252 | } |
| 119 | 253 | ||
| 120 | /* and keep the mutex held until the new chanctx is on the list */ | 254 | /* and keep the mutex held until the new chanctx is on the list */ |
| 121 | list_add_rcu(&ctx->list, &local->chanctx_list); | 255 | list_add_rcu(&ctx->list, &local->chanctx_list); |
| 122 | 256 | ||
| 123 | out: | ||
| 124 | mutex_unlock(&local->mtx); | ||
| 125 | |||
| 126 | return ctx; | 257 | return ctx; |
| 127 | } | 258 | } |
| 128 | 259 | ||
| @@ -158,9 +289,7 @@ static void ieee80211_free_chanctx(struct ieee80211_local *local, | |||
| 158 | /* throw a warning if this wasn't the only channel context. */ | 289 | /* throw a warning if this wasn't the only channel context. */ |
| 159 | WARN_ON(check_single_channel && !list_empty(&local->chanctx_list)); | 290 | WARN_ON(check_single_channel && !list_empty(&local->chanctx_list)); |
| 160 | 291 | ||
| 161 | mutex_lock(&local->mtx); | ||
| 162 | ieee80211_recalc_idle(local); | 292 | ieee80211_recalc_idle(local); |
| 163 | mutex_unlock(&local->mtx); | ||
| 164 | } | 293 | } |
| 165 | 294 | ||
| 166 | static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata, | 295 | static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata, |
| @@ -179,6 +308,7 @@ static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata, | |||
| 179 | ctx->refcount++; | 308 | ctx->refcount++; |
| 180 | 309 | ||
| 181 | ieee80211_recalc_txpower(sdata); | 310 | ieee80211_recalc_txpower(sdata); |
| 311 | ieee80211_recalc_chanctx_min_def(local, ctx); | ||
| 182 | sdata->vif.bss_conf.idle = false; | 312 | sdata->vif.bss_conf.idle = false; |
| 183 | 313 | ||
| 184 | if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE && | 314 | if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE && |
| @@ -221,6 +351,31 @@ static void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local, | |||
| 221 | ieee80211_change_chanctx(local, ctx, compat); | 351 | ieee80211_change_chanctx(local, ctx, compat); |
| 222 | } | 352 | } |
| 223 | 353 | ||
| 354 | static void ieee80211_recalc_radar_chanctx(struct ieee80211_local *local, | ||
| 355 | struct ieee80211_chanctx *chanctx) | ||
| 356 | { | ||
| 357 | bool radar_enabled; | ||
| 358 | |||
| 359 | lockdep_assert_held(&local->chanctx_mtx); | ||
| 360 | /* for setting local->radar_detect_enabled */ | ||
| 361 | lockdep_assert_held(&local->mtx); | ||
| 362 | |||
| 363 | radar_enabled = ieee80211_is_radar_required(local); | ||
| 364 | |||
| 365 | if (radar_enabled == chanctx->conf.radar_enabled) | ||
| 366 | return; | ||
| 367 | |||
| 368 | chanctx->conf.radar_enabled = radar_enabled; | ||
| 369 | local->radar_detect_enabled = chanctx->conf.radar_enabled; | ||
| 370 | |||
| 371 | if (!local->use_chanctx) { | ||
| 372 | local->hw.conf.radar_enabled = chanctx->conf.radar_enabled; | ||
| 373 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); | ||
| 374 | } | ||
| 375 | |||
| 376 | drv_change_chanctx(local, chanctx, IEEE80211_CHANCTX_CHANGE_RADAR); | ||
| 377 | } | ||
| 378 | |||
| 224 | static void ieee80211_unassign_vif_chanctx(struct ieee80211_sub_if_data *sdata, | 379 | static void ieee80211_unassign_vif_chanctx(struct ieee80211_sub_if_data *sdata, |
| 225 | struct ieee80211_chanctx *ctx) | 380 | struct ieee80211_chanctx *ctx) |
| 226 | { | 381 | { |
| @@ -243,6 +398,7 @@ static void ieee80211_unassign_vif_chanctx(struct ieee80211_sub_if_data *sdata, | |||
| 243 | ieee80211_recalc_chanctx_chantype(sdata->local, ctx); | 398 | ieee80211_recalc_chanctx_chantype(sdata->local, ctx); |
| 244 | ieee80211_recalc_smps_chanctx(local, ctx); | 399 | ieee80211_recalc_smps_chanctx(local, ctx); |
| 245 | ieee80211_recalc_radar_chanctx(local, ctx); | 400 | ieee80211_recalc_radar_chanctx(local, ctx); |
| 401 | ieee80211_recalc_chanctx_min_def(local, ctx); | ||
| 246 | } | 402 | } |
| 247 | } | 403 | } |
| 248 | 404 | ||
| @@ -266,29 +422,6 @@ static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata) | |||
| 266 | ieee80211_free_chanctx(local, ctx); | 422 | ieee80211_free_chanctx(local, ctx); |
| 267 | } | 423 | } |
| 268 | 424 | ||
| 269 | void ieee80211_recalc_radar_chanctx(struct ieee80211_local *local, | ||
| 270 | struct ieee80211_chanctx *chanctx) | ||
| 271 | { | ||
| 272 | bool radar_enabled; | ||
| 273 | |||
| 274 | lockdep_assert_held(&local->chanctx_mtx); | ||
| 275 | |||
| 276 | radar_enabled = ieee80211_is_radar_required(local); | ||
| 277 | |||
| 278 | if (radar_enabled == chanctx->conf.radar_enabled) | ||
| 279 | return; | ||
| 280 | |||
| 281 | chanctx->conf.radar_enabled = radar_enabled; | ||
| 282 | local->radar_detect_enabled = chanctx->conf.radar_enabled; | ||
| 283 | |||
| 284 | if (!local->use_chanctx) { | ||
| 285 | local->hw.conf.radar_enabled = chanctx->conf.radar_enabled; | ||
| 286 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); | ||
| 287 | } | ||
| 288 | |||
| 289 | drv_change_chanctx(local, chanctx, IEEE80211_CHANCTX_CHANGE_RADAR); | ||
| 290 | } | ||
| 291 | |||
| 292 | void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local, | 425 | void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local, |
| 293 | struct ieee80211_chanctx *chanctx) | 426 | struct ieee80211_chanctx *chanctx) |
| 294 | { | 427 | { |
| @@ -380,6 +513,8 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata, | |||
| 380 | struct ieee80211_chanctx *ctx; | 513 | struct ieee80211_chanctx *ctx; |
| 381 | int ret; | 514 | int ret; |
| 382 | 515 | ||
| 516 | lockdep_assert_held(&local->mtx); | ||
| 517 | |||
| 383 | WARN_ON(sdata->dev && netif_carrier_ok(sdata->dev)); | 518 | WARN_ON(sdata->dev && netif_carrier_ok(sdata->dev)); |
| 384 | 519 | ||
| 385 | mutex_lock(&local->chanctx_mtx); | 520 | mutex_lock(&local->chanctx_mtx); |
| @@ -411,15 +546,17 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata, | |||
| 411 | } | 546 | } |
| 412 | 547 | ||
| 413 | int ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata, | 548 | int ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata, |
| 414 | const struct cfg80211_chan_def *chandef, | ||
| 415 | u32 *changed) | 549 | u32 *changed) |
| 416 | { | 550 | { |
| 417 | struct ieee80211_local *local = sdata->local; | 551 | struct ieee80211_local *local = sdata->local; |
| 418 | struct ieee80211_chanctx_conf *conf; | 552 | struct ieee80211_chanctx_conf *conf; |
| 419 | struct ieee80211_chanctx *ctx; | 553 | struct ieee80211_chanctx *ctx; |
| 554 | const struct cfg80211_chan_def *chandef = &sdata->csa_chandef; | ||
| 420 | int ret; | 555 | int ret; |
| 421 | u32 chanctx_changed = 0; | 556 | u32 chanctx_changed = 0; |
| 422 | 557 | ||
| 558 | lockdep_assert_held(&local->mtx); | ||
| 559 | |||
| 423 | /* should never be called if not performing a channel switch. */ | 560 | /* should never be called if not performing a channel switch. */ |
| 424 | if (WARN_ON(!sdata->vif.csa_active)) | 561 | if (WARN_ON(!sdata->vif.csa_active)) |
| 425 | return -EINVAL; | 562 | return -EINVAL; |
| @@ -456,6 +593,7 @@ int ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata, | |||
| 456 | ieee80211_recalc_chanctx_chantype(local, ctx); | 593 | ieee80211_recalc_chanctx_chantype(local, ctx); |
| 457 | ieee80211_recalc_smps_chanctx(local, ctx); | 594 | ieee80211_recalc_smps_chanctx(local, ctx); |
| 458 | ieee80211_recalc_radar_chanctx(local, ctx); | 595 | ieee80211_recalc_radar_chanctx(local, ctx); |
| 596 | ieee80211_recalc_chanctx_min_def(local, ctx); | ||
| 459 | 597 | ||
| 460 | ret = 0; | 598 | ret = 0; |
| 461 | out: | 599 | out: |
| @@ -516,6 +654,8 @@ void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata) | |||
| 516 | { | 654 | { |
| 517 | WARN_ON(sdata->dev && netif_carrier_ok(sdata->dev)); | 655 | WARN_ON(sdata->dev && netif_carrier_ok(sdata->dev)); |
| 518 | 656 | ||
| 657 | lockdep_assert_held(&sdata->local->mtx); | ||
| 658 | |||
| 519 | mutex_lock(&sdata->local->chanctx_mtx); | 659 | mutex_lock(&sdata->local->chanctx_mtx); |
| 520 | __ieee80211_vif_release_channel(sdata); | 660 | __ieee80211_vif_release_channel(sdata); |
| 521 | mutex_unlock(&sdata->local->chanctx_mtx); | 661 | mutex_unlock(&sdata->local->chanctx_mtx); |
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index 5c090e41d9bb..fa16e54980a1 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c | |||
| @@ -17,6 +17,172 @@ | |||
| 17 | 17 | ||
| 18 | #define DEBUGFS_FORMAT_BUFFER_SIZE 100 | 18 | #define DEBUGFS_FORMAT_BUFFER_SIZE 100 |
| 19 | 19 | ||
| 20 | #define TX_LATENCY_BIN_DELIMTER_C ',' | ||
| 21 | #define TX_LATENCY_BIN_DELIMTER_S "," | ||
| 22 | #define TX_LATENCY_BINS_DISABLED "enable(bins disabled)\n" | ||
| 23 | #define TX_LATENCY_DISABLED "disable\n" | ||
| 24 | |||
| 25 | |||
| 26 | /* | ||
| 27 | * Display if Tx latency statistics & bins are enabled/disabled | ||
| 28 | */ | ||
| 29 | static ssize_t sta_tx_latency_stat_read(struct file *file, | ||
| 30 | char __user *userbuf, | ||
| 31 | size_t count, loff_t *ppos) | ||
| 32 | { | ||
| 33 | struct ieee80211_local *local = file->private_data; | ||
| 34 | struct ieee80211_tx_latency_bin_ranges *tx_latency; | ||
| 35 | char *buf; | ||
| 36 | int bufsz, i, ret; | ||
| 37 | int pos = 0; | ||
| 38 | |||
| 39 | rcu_read_lock(); | ||
| 40 | |||
| 41 | tx_latency = rcu_dereference(local->tx_latency); | ||
| 42 | |||
| 43 | if (tx_latency && tx_latency->n_ranges) { | ||
| 44 | bufsz = tx_latency->n_ranges * 15; | ||
| 45 | buf = kzalloc(bufsz, GFP_ATOMIC); | ||
| 46 | if (!buf) | ||
| 47 | goto err; | ||
| 48 | |||
| 49 | for (i = 0; i < tx_latency->n_ranges; i++) | ||
| 50 | pos += scnprintf(buf + pos, bufsz - pos, "%d,", | ||
| 51 | tx_latency->ranges[i]); | ||
| 52 | pos += scnprintf(buf + pos, bufsz - pos, "\n"); | ||
| 53 | } else if (tx_latency) { | ||
| 54 | bufsz = sizeof(TX_LATENCY_BINS_DISABLED) + 1; | ||
| 55 | buf = kzalloc(bufsz, GFP_ATOMIC); | ||
| 56 | if (!buf) | ||
| 57 | goto err; | ||
| 58 | |||
| 59 | pos += scnprintf(buf + pos, bufsz - pos, "%s\n", | ||
| 60 | TX_LATENCY_BINS_DISABLED); | ||
| 61 | } else { | ||
| 62 | bufsz = sizeof(TX_LATENCY_DISABLED) + 1; | ||
| 63 | buf = kzalloc(bufsz, GFP_ATOMIC); | ||
| 64 | if (!buf) | ||
| 65 | goto err; | ||
| 66 | |||
| 67 | pos += scnprintf(buf + pos, bufsz - pos, "%s\n", | ||
| 68 | TX_LATENCY_DISABLED); | ||
| 69 | } | ||
| 70 | |||
| 71 | rcu_read_unlock(); | ||
| 72 | |||
| 73 | ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos); | ||
| 74 | kfree(buf); | ||
| 75 | |||
| 76 | return ret; | ||
| 77 | err: | ||
| 78 | rcu_read_unlock(); | ||
| 79 | return -ENOMEM; | ||
| 80 | } | ||
| 81 | |||
| 82 | /* | ||
| 83 | * Receive input from user regarding Tx latency statistics | ||
| 84 | * The input should indicate if Tx latency statistics and bins are | ||
| 85 | * enabled/disabled. | ||
| 86 | * If bins are enabled input should indicate the amount of different bins and | ||
| 87 | * their ranges. Each bin will count how many Tx frames transmitted within the | ||
| 88 | * appropriate latency. | ||
| 89 | * Legal input is: | ||
| 90 | * a) "enable(bins disabled)" - to enable only general statistics | ||
| 91 | * b) "a,b,c,d,...z" - to enable general statistics and bins, where all are | ||
| 92 | * numbers and a < b < c < d.. < z | ||
| 93 | * c) "disable" - disable all statistics | ||
| 94 | * NOTE: must configure Tx latency statistics bins before stations connected. | ||
| 95 | */ | ||
| 96 | |||
| 97 | static ssize_t sta_tx_latency_stat_write(struct file *file, | ||
| 98 | const char __user *userbuf, | ||
| 99 | size_t count, loff_t *ppos) | ||
| 100 | { | ||
| 101 | struct ieee80211_local *local = file->private_data; | ||
| 102 | char buf[128] = {}; | ||
| 103 | char *bins = buf; | ||
| 104 | char *token; | ||
| 105 | int buf_size, i, alloc_size; | ||
| 106 | int prev_bin = 0; | ||
| 107 | int n_ranges = 0; | ||
| 108 | int ret = count; | ||
| 109 | struct ieee80211_tx_latency_bin_ranges *tx_latency; | ||
| 110 | |||
| 111 | if (sizeof(buf) <= count) | ||
| 112 | return -EINVAL; | ||
| 113 | buf_size = count; | ||
| 114 | if (copy_from_user(buf, userbuf, buf_size)) | ||
| 115 | return -EFAULT; | ||
| 116 | |||
| 117 | mutex_lock(&local->sta_mtx); | ||
| 118 | |||
| 119 | /* cannot change config once we have stations */ | ||
| 120 | if (local->num_sta) | ||
| 121 | goto unlock; | ||
| 122 | |||
| 123 | tx_latency = | ||
| 124 | rcu_dereference_protected(local->tx_latency, | ||
| 125 | lockdep_is_held(&local->sta_mtx)); | ||
| 126 | |||
| 127 | /* disable Tx statistics */ | ||
| 128 | if (!strcmp(buf, TX_LATENCY_DISABLED)) { | ||
| 129 | if (!tx_latency) | ||
| 130 | goto unlock; | ||
| 131 | rcu_assign_pointer(local->tx_latency, NULL); | ||
| 132 | synchronize_rcu(); | ||
| 133 | kfree(tx_latency); | ||
| 134 | goto unlock; | ||
| 135 | } | ||
| 136 | |||
| 137 | /* Tx latency already enabled */ | ||
| 138 | if (tx_latency) | ||
| 139 | goto unlock; | ||
| 140 | |||
| 141 | if (strcmp(TX_LATENCY_BINS_DISABLED, buf)) { | ||
| 142 | /* check how many bins and between what ranges user requested */ | ||
| 143 | token = buf; | ||
| 144 | while (*token != '\0') { | ||
| 145 | if (*token == TX_LATENCY_BIN_DELIMTER_C) | ||
| 146 | n_ranges++; | ||
| 147 | token++; | ||
| 148 | } | ||
| 149 | n_ranges++; | ||
| 150 | } | ||
| 151 | |||
| 152 | alloc_size = sizeof(struct ieee80211_tx_latency_bin_ranges) + | ||
| 153 | n_ranges * sizeof(u32); | ||
| 154 | tx_latency = kzalloc(alloc_size, GFP_ATOMIC); | ||
| 155 | if (!tx_latency) { | ||
| 156 | ret = -ENOMEM; | ||
| 157 | goto unlock; | ||
| 158 | } | ||
| 159 | tx_latency->n_ranges = n_ranges; | ||
| 160 | for (i = 0; i < n_ranges; i++) { /* setting bin ranges */ | ||
| 161 | token = strsep(&bins, TX_LATENCY_BIN_DELIMTER_S); | ||
| 162 | sscanf(token, "%d", &tx_latency->ranges[i]); | ||
| 163 | /* bins values should be in ascending order */ | ||
| 164 | if (prev_bin >= tx_latency->ranges[i]) { | ||
| 165 | ret = -EINVAL; | ||
| 166 | kfree(tx_latency); | ||
| 167 | goto unlock; | ||
| 168 | } | ||
| 169 | prev_bin = tx_latency->ranges[i]; | ||
| 170 | } | ||
| 171 | rcu_assign_pointer(local->tx_latency, tx_latency); | ||
| 172 | |||
| 173 | unlock: | ||
| 174 | mutex_unlock(&local->sta_mtx); | ||
| 175 | |||
| 176 | return ret; | ||
| 177 | } | ||
| 178 | |||
| 179 | static const struct file_operations stats_tx_latency_ops = { | ||
| 180 | .write = sta_tx_latency_stat_write, | ||
| 181 | .read = sta_tx_latency_stat_read, | ||
| 182 | .open = simple_open, | ||
| 183 | .llseek = generic_file_llseek, | ||
| 184 | }; | ||
| 185 | |||
| 20 | int mac80211_format_buffer(char __user *userbuf, size_t count, | 186 | int mac80211_format_buffer(char __user *userbuf, size_t count, |
| 21 | loff_t *ppos, char *fmt, ...) | 187 | loff_t *ppos, char *fmt, ...) |
| 22 | { | 188 | { |
| @@ -315,4 +481,6 @@ void debugfs_hw_add(struct ieee80211_local *local) | |||
| 315 | DEBUGFS_DEVSTATS_ADD(dot11RTSFailureCount); | 481 | DEBUGFS_DEVSTATS_ADD(dot11RTSFailureCount); |
| 316 | DEBUGFS_DEVSTATS_ADD(dot11FCSErrorCount); | 482 | DEBUGFS_DEVSTATS_ADD(dot11FCSErrorCount); |
| 317 | DEBUGFS_DEVSTATS_ADD(dot11RTSSuccessCount); | 483 | DEBUGFS_DEVSTATS_ADD(dot11RTSSuccessCount); |
| 484 | |||
| 485 | DEBUGFS_DEVSTATS_ADD(tx_latency); | ||
| 318 | } | 486 | } |
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index 04b5a14c8a05..ebf80f3abd83 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c | |||
| @@ -133,7 +133,15 @@ static ssize_t ieee80211_if_fmt_##name( \ | |||
| 133 | jiffies_to_msecs(sdata->field)); \ | 133 | jiffies_to_msecs(sdata->field)); \ |
| 134 | } | 134 | } |
| 135 | 135 | ||
| 136 | #define __IEEE80211_IF_FILE(name, _write) \ | 136 | #define _IEEE80211_IF_FILE_OPS(name, _read, _write) \ |
| 137 | static const struct file_operations name##_ops = { \ | ||
| 138 | .read = (_read), \ | ||
| 139 | .write = (_write), \ | ||
| 140 | .open = simple_open, \ | ||
| 141 | .llseek = generic_file_llseek, \ | ||
| 142 | } | ||
| 143 | |||
| 144 | #define _IEEE80211_IF_FILE_R_FN(name) \ | ||
| 137 | static ssize_t ieee80211_if_read_##name(struct file *file, \ | 145 | static ssize_t ieee80211_if_read_##name(struct file *file, \ |
| 138 | char __user *userbuf, \ | 146 | char __user *userbuf, \ |
| 139 | size_t count, loff_t *ppos) \ | 147 | size_t count, loff_t *ppos) \ |
| @@ -141,28 +149,34 @@ static ssize_t ieee80211_if_read_##name(struct file *file, \ | |||
| 141 | return ieee80211_if_read(file->private_data, \ | 149 | return ieee80211_if_read(file->private_data, \ |
| 142 | userbuf, count, ppos, \ | 150 | userbuf, count, ppos, \ |
| 143 | ieee80211_if_fmt_##name); \ | 151 | ieee80211_if_fmt_##name); \ |
| 144 | } \ | ||
| 145 | static const struct file_operations name##_ops = { \ | ||
| 146 | .read = ieee80211_if_read_##name, \ | ||
| 147 | .write = (_write), \ | ||
| 148 | .open = simple_open, \ | ||
| 149 | .llseek = generic_file_llseek, \ | ||
| 150 | } | 152 | } |
| 151 | 153 | ||
| 152 | #define __IEEE80211_IF_FILE_W(name) \ | 154 | #define _IEEE80211_IF_FILE_W_FN(name) \ |
| 153 | static ssize_t ieee80211_if_write_##name(struct file *file, \ | 155 | static ssize_t ieee80211_if_write_##name(struct file *file, \ |
| 154 | const char __user *userbuf, \ | 156 | const char __user *userbuf, \ |
| 155 | size_t count, loff_t *ppos) \ | 157 | size_t count, loff_t *ppos) \ |
| 156 | { \ | 158 | { \ |
| 157 | return ieee80211_if_write(file->private_data, userbuf, count, \ | 159 | return ieee80211_if_write(file->private_data, userbuf, count, \ |
| 158 | ppos, ieee80211_if_parse_##name); \ | 160 | ppos, ieee80211_if_parse_##name); \ |
| 159 | } \ | 161 | } |
| 160 | __IEEE80211_IF_FILE(name, ieee80211_if_write_##name) | 162 | |
| 163 | #define IEEE80211_IF_FILE_R(name) \ | ||
| 164 | _IEEE80211_IF_FILE_R_FN(name) \ | ||
| 165 | _IEEE80211_IF_FILE_OPS(name, ieee80211_if_read_##name, NULL) | ||
| 166 | |||
| 167 | #define IEEE80211_IF_FILE_W(name) \ | ||
| 168 | _IEEE80211_IF_FILE_W_FN(name) \ | ||
| 169 | _IEEE80211_IF_FILE_OPS(name, NULL, ieee80211_if_write_##name) | ||
| 161 | 170 | ||
| 171 | #define IEEE80211_IF_FILE_RW(name) \ | ||
| 172 | _IEEE80211_IF_FILE_R_FN(name) \ | ||
| 173 | _IEEE80211_IF_FILE_W_FN(name) \ | ||
| 174 | _IEEE80211_IF_FILE_OPS(name, ieee80211_if_read_##name, \ | ||
| 175 | ieee80211_if_write_##name) | ||
| 162 | 176 | ||
| 163 | #define IEEE80211_IF_FILE(name, field, format) \ | 177 | #define IEEE80211_IF_FILE(name, field, format) \ |
| 164 | IEEE80211_IF_FMT_##format(name, field) \ | 178 | IEEE80211_IF_FMT_##format(name, field) \ |
| 165 | __IEEE80211_IF_FILE(name, NULL) | 179 | IEEE80211_IF_FILE_R(name) |
| 166 | 180 | ||
| 167 | /* common attributes */ | 181 | /* common attributes */ |
| 168 | IEEE80211_IF_FILE(drop_unencrypted, drop_unencrypted, DEC); | 182 | IEEE80211_IF_FILE(drop_unencrypted, drop_unencrypted, DEC); |
| @@ -199,7 +213,7 @@ ieee80211_if_fmt_hw_queues(const struct ieee80211_sub_if_data *sdata, | |||
| 199 | 213 | ||
| 200 | return len; | 214 | return len; |
| 201 | } | 215 | } |
| 202 | __IEEE80211_IF_FILE(hw_queues, NULL); | 216 | IEEE80211_IF_FILE_R(hw_queues); |
| 203 | 217 | ||
| 204 | /* STA attributes */ | 218 | /* STA attributes */ |
| 205 | IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC); | 219 | IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC); |
| @@ -275,14 +289,7 @@ static ssize_t ieee80211_if_parse_smps(struct ieee80211_sub_if_data *sdata, | |||
| 275 | 289 | ||
| 276 | return -EINVAL; | 290 | return -EINVAL; |
| 277 | } | 291 | } |
| 278 | 292 | IEEE80211_IF_FILE_RW(smps); | |
| 279 | __IEEE80211_IF_FILE_W(smps); | ||
| 280 | |||
| 281 | static ssize_t ieee80211_if_fmt_tkip_mic_test( | ||
| 282 | const struct ieee80211_sub_if_data *sdata, char *buf, int buflen) | ||
| 283 | { | ||
| 284 | return -EOPNOTSUPP; | ||
| 285 | } | ||
| 286 | 293 | ||
| 287 | static ssize_t ieee80211_if_parse_tkip_mic_test( | 294 | static ssize_t ieee80211_if_parse_tkip_mic_test( |
| 288 | struct ieee80211_sub_if_data *sdata, const char *buf, int buflen) | 295 | struct ieee80211_sub_if_data *sdata, const char *buf, int buflen) |
| @@ -349,8 +356,7 @@ static ssize_t ieee80211_if_parse_tkip_mic_test( | |||
| 349 | 356 | ||
| 350 | return buflen; | 357 | return buflen; |
| 351 | } | 358 | } |
| 352 | 359 | IEEE80211_IF_FILE_W(tkip_mic_test); | |
| 353 | __IEEE80211_IF_FILE_W(tkip_mic_test); | ||
| 354 | 360 | ||
| 355 | static ssize_t ieee80211_if_fmt_uapsd_queues( | 361 | static ssize_t ieee80211_if_fmt_uapsd_queues( |
| 356 | const struct ieee80211_sub_if_data *sdata, char *buf, int buflen) | 362 | const struct ieee80211_sub_if_data *sdata, char *buf, int buflen) |
| @@ -378,7 +384,7 @@ static ssize_t ieee80211_if_parse_uapsd_queues( | |||
| 378 | 384 | ||
| 379 | return buflen; | 385 | return buflen; |
| 380 | } | 386 | } |
| 381 | __IEEE80211_IF_FILE_W(uapsd_queues); | 387 | IEEE80211_IF_FILE_RW(uapsd_queues); |
| 382 | 388 | ||
| 383 | static ssize_t ieee80211_if_fmt_uapsd_max_sp_len( | 389 | static ssize_t ieee80211_if_fmt_uapsd_max_sp_len( |
| 384 | const struct ieee80211_sub_if_data *sdata, char *buf, int buflen) | 390 | const struct ieee80211_sub_if_data *sdata, char *buf, int buflen) |
| @@ -406,7 +412,7 @@ static ssize_t ieee80211_if_parse_uapsd_max_sp_len( | |||
| 406 | 412 | ||
| 407 | return buflen; | 413 | return buflen; |
| 408 | } | 414 | } |
| 409 | __IEEE80211_IF_FILE_W(uapsd_max_sp_len); | 415 | IEEE80211_IF_FILE_RW(uapsd_max_sp_len); |
| 410 | 416 | ||
| 411 | /* AP attributes */ | 417 | /* AP attributes */ |
| 412 | IEEE80211_IF_FILE(num_mcast_sta, u.ap.num_mcast_sta, ATOMIC); | 418 | IEEE80211_IF_FILE(num_mcast_sta, u.ap.num_mcast_sta, ATOMIC); |
| @@ -419,7 +425,7 @@ static ssize_t ieee80211_if_fmt_num_buffered_multicast( | |||
| 419 | return scnprintf(buf, buflen, "%u\n", | 425 | return scnprintf(buf, buflen, "%u\n", |
| 420 | skb_queue_len(&sdata->u.ap.ps.bc_buf)); | 426 | skb_queue_len(&sdata->u.ap.ps.bc_buf)); |
| 421 | } | 427 | } |
| 422 | __IEEE80211_IF_FILE(num_buffered_multicast, NULL); | 428 | IEEE80211_IF_FILE_R(num_buffered_multicast); |
| 423 | 429 | ||
| 424 | /* IBSS attributes */ | 430 | /* IBSS attributes */ |
| 425 | static ssize_t ieee80211_if_fmt_tsf( | 431 | static ssize_t ieee80211_if_fmt_tsf( |
| @@ -468,9 +474,10 @@ static ssize_t ieee80211_if_parse_tsf( | |||
| 468 | } | 474 | } |
| 469 | } | 475 | } |
| 470 | 476 | ||
| 477 | ieee80211_recalc_dtim(local, sdata); | ||
| 471 | return buflen; | 478 | return buflen; |
| 472 | } | 479 | } |
| 473 | __IEEE80211_IF_FILE_W(tsf); | 480 | IEEE80211_IF_FILE_RW(tsf); |
| 474 | 481 | ||
| 475 | 482 | ||
| 476 | /* WDS attributes */ | 483 | /* WDS attributes */ |
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index 19c54a44ed47..80194b557a0c 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c | |||
| @@ -38,6 +38,13 @@ static const struct file_operations sta_ ##name## _ops = { \ | |||
| 38 | .llseek = generic_file_llseek, \ | 38 | .llseek = generic_file_llseek, \ |
| 39 | } | 39 | } |
| 40 | 40 | ||
| 41 | #define STA_OPS_W(name) \ | ||
| 42 | static const struct file_operations sta_ ##name## _ops = { \ | ||
| 43 | .write = sta_##name##_write, \ | ||
| 44 | .open = simple_open, \ | ||
| 45 | .llseek = generic_file_llseek, \ | ||
| 46 | } | ||
| 47 | |||
| 41 | #define STA_OPS_RW(name) \ | 48 | #define STA_OPS_RW(name) \ |
| 42 | static const struct file_operations sta_ ##name## _ops = { \ | 49 | static const struct file_operations sta_ ##name## _ops = { \ |
| 43 | .read = sta_##name##_read, \ | 50 | .read = sta_##name##_read, \ |
| @@ -388,6 +395,131 @@ static ssize_t sta_last_rx_rate_read(struct file *file, char __user *userbuf, | |||
| 388 | } | 395 | } |
| 389 | STA_OPS(last_rx_rate); | 396 | STA_OPS(last_rx_rate); |
| 390 | 397 | ||
| 398 | static int | ||
| 399 | sta_tx_latency_stat_header(struct ieee80211_tx_latency_bin_ranges *tx_latency, | ||
| 400 | char *buf, int pos, int bufsz) | ||
| 401 | { | ||
| 402 | int i; | ||
| 403 | int range_count = tx_latency->n_ranges; | ||
| 404 | u32 *bin_ranges = tx_latency->ranges; | ||
| 405 | |||
| 406 | pos += scnprintf(buf + pos, bufsz - pos, | ||
| 407 | "Station\t\t\tTID\tMax\tAvg"); | ||
| 408 | if (range_count) { | ||
| 409 | pos += scnprintf(buf + pos, bufsz - pos, | ||
| 410 | "\t<=%d", bin_ranges[0]); | ||
| 411 | for (i = 0; i < range_count - 1; i++) | ||
| 412 | pos += scnprintf(buf + pos, bufsz - pos, "\t%d-%d", | ||
| 413 | bin_ranges[i], bin_ranges[i+1]); | ||
| 414 | pos += scnprintf(buf + pos, bufsz - pos, | ||
| 415 | "\t%d<", bin_ranges[range_count - 1]); | ||
| 416 | } | ||
| 417 | |||
| 418 | pos += scnprintf(buf + pos, bufsz - pos, "\n"); | ||
| 419 | |||
| 420 | return pos; | ||
| 421 | } | ||
| 422 | |||
| 423 | static int | ||
| 424 | sta_tx_latency_stat_table(struct ieee80211_tx_latency_bin_ranges *tx_lat_range, | ||
| 425 | struct ieee80211_tx_latency_stat *tx_lat, | ||
| 426 | char *buf, int pos, int bufsz, int tid) | ||
| 427 | { | ||
| 428 | u32 avg = 0; | ||
| 429 | int j; | ||
| 430 | int bin_count = tx_lat->bin_count; | ||
| 431 | |||
| 432 | pos += scnprintf(buf + pos, bufsz - pos, "\t\t\t%d", tid); | ||
| 433 | /* make sure you don't divide in 0 */ | ||
| 434 | if (tx_lat->counter) | ||
| 435 | avg = tx_lat->sum / tx_lat->counter; | ||
| 436 | |||
| 437 | pos += scnprintf(buf + pos, bufsz - pos, "\t%d\t%d", | ||
| 438 | tx_lat->max, avg); | ||
| 439 | |||
| 440 | if (tx_lat_range->n_ranges && tx_lat->bins) | ||
| 441 | for (j = 0; j < bin_count; j++) | ||
| 442 | pos += scnprintf(buf + pos, bufsz - pos, | ||
| 443 | "\t%d", tx_lat->bins[j]); | ||
| 444 | pos += scnprintf(buf + pos, bufsz - pos, "\n"); | ||
| 445 | |||
| 446 | return pos; | ||
| 447 | } | ||
| 448 | |||
| 449 | /* | ||
| 450 | * Output Tx latency statistics station && restart all statistics information | ||
| 451 | */ | ||
| 452 | static ssize_t sta_tx_latency_stat_read(struct file *file, | ||
| 453 | char __user *userbuf, | ||
| 454 | size_t count, loff_t *ppos) | ||
| 455 | { | ||
| 456 | struct sta_info *sta = file->private_data; | ||
| 457 | struct ieee80211_local *local = sta->local; | ||
| 458 | struct ieee80211_tx_latency_bin_ranges *tx_latency; | ||
| 459 | char *buf; | ||
| 460 | int bufsz, ret, i; | ||
| 461 | int pos = 0; | ||
| 462 | |||
| 463 | bufsz = 20 * IEEE80211_NUM_TIDS * | ||
| 464 | sizeof(struct ieee80211_tx_latency_stat); | ||
| 465 | buf = kzalloc(bufsz, GFP_KERNEL); | ||
| 466 | if (!buf) | ||
| 467 | return -ENOMEM; | ||
| 468 | |||
| 469 | rcu_read_lock(); | ||
| 470 | |||
| 471 | tx_latency = rcu_dereference(local->tx_latency); | ||
| 472 | |||
| 473 | if (!sta->tx_lat) { | ||
| 474 | pos += scnprintf(buf + pos, bufsz - pos, | ||
| 475 | "Tx latency statistics are not enabled\n"); | ||
| 476 | goto unlock; | ||
| 477 | } | ||
| 478 | |||
| 479 | pos = sta_tx_latency_stat_header(tx_latency, buf, pos, bufsz); | ||
| 480 | |||
| 481 | pos += scnprintf(buf + pos, bufsz - pos, "%pM\n", sta->sta.addr); | ||
| 482 | for (i = 0; i < IEEE80211_NUM_TIDS; i++) | ||
| 483 | pos = sta_tx_latency_stat_table(tx_latency, &sta->tx_lat[i], | ||
| 484 | buf, pos, bufsz, i); | ||
| 485 | unlock: | ||
| 486 | rcu_read_unlock(); | ||
| 487 | |||
| 488 | ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos); | ||
| 489 | kfree(buf); | ||
| 490 | |||
| 491 | return ret; | ||
| 492 | } | ||
| 493 | STA_OPS(tx_latency_stat); | ||
| 494 | |||
| 495 | static ssize_t sta_tx_latency_stat_reset_write(struct file *file, | ||
| 496 | const char __user *userbuf, | ||
| 497 | size_t count, loff_t *ppos) | ||
| 498 | { | ||
| 499 | u32 *bins; | ||
| 500 | int bin_count; | ||
| 501 | struct sta_info *sta = file->private_data; | ||
| 502 | int i; | ||
| 503 | |||
| 504 | if (!sta->tx_lat) | ||
| 505 | return -EINVAL; | ||
| 506 | |||
| 507 | for (i = 0; i < IEEE80211_NUM_TIDS; i++) { | ||
| 508 | bins = sta->tx_lat[i].bins; | ||
| 509 | bin_count = sta->tx_lat[i].bin_count; | ||
| 510 | |||
| 511 | sta->tx_lat[i].max = 0; | ||
| 512 | sta->tx_lat[i].sum = 0; | ||
| 513 | sta->tx_lat[i].counter = 0; | ||
| 514 | |||
| 515 | if (bin_count) | ||
| 516 | memset(bins, 0, bin_count * sizeof(u32)); | ||
| 517 | } | ||
| 518 | |||
| 519 | return count; | ||
| 520 | } | ||
| 521 | STA_OPS_W(tx_latency_stat_reset); | ||
| 522 | |||
| 391 | #define DEBUGFS_ADD(name) \ | 523 | #define DEBUGFS_ADD(name) \ |
| 392 | debugfs_create_file(#name, 0400, \ | 524 | debugfs_create_file(#name, 0400, \ |
| 393 | sta->debugfs.dir, sta, &sta_ ##name## _ops); | 525 | sta->debugfs.dir, sta, &sta_ ##name## _ops); |
| @@ -441,6 +573,8 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta) | |||
| 441 | DEBUGFS_ADD(last_ack_signal); | 573 | DEBUGFS_ADD(last_ack_signal); |
| 442 | DEBUGFS_ADD(current_tx_rate); | 574 | DEBUGFS_ADD(current_tx_rate); |
| 443 | DEBUGFS_ADD(last_rx_rate); | 575 | DEBUGFS_ADD(last_rx_rate); |
| 576 | DEBUGFS_ADD(tx_latency_stat); | ||
| 577 | DEBUGFS_ADD(tx_latency_stat_reset); | ||
| 444 | 578 | ||
| 445 | DEBUGFS_ADD_COUNTER(rx_packets, rx_packets); | 579 | DEBUGFS_ADD_COUNTER(rx_packets, rx_packets); |
| 446 | DEBUGFS_ADD_COUNTER(tx_packets, tx_packets); | 580 | DEBUGFS_ADD_COUNTER(tx_packets, tx_packets); |
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 5d03c47c0a4c..ef8b385eff04 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h | |||
| @@ -242,22 +242,6 @@ static inline u64 drv_prepare_multicast(struct ieee80211_local *local, | |||
| 242 | return ret; | 242 | return ret; |
| 243 | } | 243 | } |
| 244 | 244 | ||
| 245 | static inline void drv_set_multicast_list(struct ieee80211_local *local, | ||
| 246 | struct ieee80211_sub_if_data *sdata, | ||
| 247 | struct netdev_hw_addr_list *mc_list) | ||
| 248 | { | ||
| 249 | bool allmulti = sdata->flags & IEEE80211_SDATA_ALLMULTI; | ||
| 250 | |||
| 251 | trace_drv_set_multicast_list(local, sdata, mc_list->count); | ||
| 252 | |||
| 253 | check_sdata_in_driver(sdata); | ||
| 254 | |||
| 255 | if (local->ops->set_multicast_list) | ||
| 256 | local->ops->set_multicast_list(&local->hw, &sdata->vif, | ||
| 257 | allmulti, mc_list); | ||
| 258 | trace_drv_return_void(local); | ||
| 259 | } | ||
| 260 | |||
| 261 | static inline void drv_configure_filter(struct ieee80211_local *local, | 245 | static inline void drv_configure_filter(struct ieee80211_local *local, |
| 262 | unsigned int changed_flags, | 246 | unsigned int changed_flags, |
| 263 | unsigned int *total_flags, | 247 | unsigned int *total_flags, |
| @@ -550,6 +534,22 @@ static inline void drv_sta_remove_debugfs(struct ieee80211_local *local, | |||
| 550 | } | 534 | } |
| 551 | #endif | 535 | #endif |
| 552 | 536 | ||
| 537 | static inline void drv_sta_pre_rcu_remove(struct ieee80211_local *local, | ||
| 538 | struct ieee80211_sub_if_data *sdata, | ||
| 539 | struct sta_info *sta) | ||
| 540 | { | ||
| 541 | might_sleep(); | ||
| 542 | |||
| 543 | sdata = get_bss_sdata(sdata); | ||
| 544 | check_sdata_in_driver(sdata); | ||
| 545 | |||
| 546 | trace_drv_sta_pre_rcu_remove(local, sdata, &sta->sta); | ||
| 547 | if (local->ops->sta_pre_rcu_remove) | ||
| 548 | local->ops->sta_pre_rcu_remove(&local->hw, &sdata->vif, | ||
| 549 | &sta->sta); | ||
| 550 | trace_drv_return_void(local); | ||
| 551 | } | ||
| 552 | |||
| 553 | static inline __must_check | 553 | static inline __must_check |
| 554 | int drv_sta_state(struct ieee80211_local *local, | 554 | int drv_sta_state(struct ieee80211_local *local, |
| 555 | struct ieee80211_sub_if_data *sdata, | 555 | struct ieee80211_sub_if_data *sdata, |
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index 9a8be8f69224..fab7b91923e0 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c | |||
| @@ -479,10 +479,9 @@ void ieee80211_request_smps(struct ieee80211_vif *vif, | |||
| 479 | vif->type != NL80211_IFTYPE_AP)) | 479 | vif->type != NL80211_IFTYPE_AP)) |
| 480 | return; | 480 | return; |
| 481 | 481 | ||
| 482 | if (WARN_ON(smps_mode == IEEE80211_SMPS_OFF)) | ||
| 483 | smps_mode = IEEE80211_SMPS_AUTOMATIC; | ||
| 484 | |||
| 485 | if (vif->type == NL80211_IFTYPE_STATION) { | 482 | if (vif->type == NL80211_IFTYPE_STATION) { |
| 483 | if (WARN_ON(smps_mode == IEEE80211_SMPS_OFF)) | ||
| 484 | smps_mode = IEEE80211_SMPS_AUTOMATIC; | ||
| 486 | if (sdata->u.mgd.driver_smps_mode == smps_mode) | 485 | if (sdata->u.mgd.driver_smps_mode == smps_mode) |
| 487 | return; | 486 | return; |
| 488 | sdata->u.mgd.driver_smps_mode = smps_mode; | 487 | sdata->u.mgd.driver_smps_mode = smps_mode; |
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 27a39de89679..771080ec7212 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c | |||
| @@ -293,14 +293,17 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
| 293 | radar_required = true; | 293 | radar_required = true; |
| 294 | } | 294 | } |
| 295 | 295 | ||
| 296 | mutex_lock(&local->mtx); | ||
| 296 | ieee80211_vif_release_channel(sdata); | 297 | ieee80211_vif_release_channel(sdata); |
| 297 | if (ieee80211_vif_use_channel(sdata, &chandef, | 298 | if (ieee80211_vif_use_channel(sdata, &chandef, |
| 298 | ifibss->fixed_channel ? | 299 | ifibss->fixed_channel ? |
| 299 | IEEE80211_CHANCTX_SHARED : | 300 | IEEE80211_CHANCTX_SHARED : |
| 300 | IEEE80211_CHANCTX_EXCLUSIVE)) { | 301 | IEEE80211_CHANCTX_EXCLUSIVE)) { |
| 301 | sdata_info(sdata, "Failed to join IBSS, no channel context\n"); | 302 | sdata_info(sdata, "Failed to join IBSS, no channel context\n"); |
| 303 | mutex_unlock(&local->mtx); | ||
| 302 | return; | 304 | return; |
| 303 | } | 305 | } |
| 306 | mutex_unlock(&local->mtx); | ||
| 304 | 307 | ||
| 305 | memcpy(ifibss->bssid, bssid, ETH_ALEN); | 308 | memcpy(ifibss->bssid, bssid, ETH_ALEN); |
| 306 | 309 | ||
| @@ -363,7 +366,9 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
| 363 | sdata->vif.bss_conf.ssid_len = 0; | 366 | sdata->vif.bss_conf.ssid_len = 0; |
| 364 | RCU_INIT_POINTER(ifibss->presp, NULL); | 367 | RCU_INIT_POINTER(ifibss->presp, NULL); |
| 365 | kfree_rcu(presp, rcu_head); | 368 | kfree_rcu(presp, rcu_head); |
| 369 | mutex_lock(&local->mtx); | ||
| 366 | ieee80211_vif_release_channel(sdata); | 370 | ieee80211_vif_release_channel(sdata); |
| 371 | mutex_unlock(&local->mtx); | ||
| 367 | sdata_info(sdata, "Failed to join IBSS, driver failure: %d\n", | 372 | sdata_info(sdata, "Failed to join IBSS, driver failure: %d\n", |
| 368 | err); | 373 | err); |
| 369 | return; | 374 | return; |
| @@ -522,7 +527,7 @@ int ieee80211_ibss_csa_beacon(struct ieee80211_sub_if_data *sdata, | |||
| 522 | if (csa_settings) | 527 | if (csa_settings) |
| 523 | ieee80211_send_action_csa(sdata, csa_settings); | 528 | ieee80211_send_action_csa(sdata, csa_settings); |
| 524 | 529 | ||
| 525 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON); | 530 | return BSS_CHANGED_BEACON; |
| 526 | out: | 531 | out: |
| 527 | return ret; | 532 | return ret; |
| 528 | } | 533 | } |
| @@ -534,7 +539,8 @@ int ieee80211_ibss_finish_csa(struct ieee80211_sub_if_data *sdata) | |||
| 534 | int err; | 539 | int err; |
| 535 | u16 capability; | 540 | u16 capability; |
| 536 | 541 | ||
| 537 | sdata_lock(sdata); | 542 | sdata_assert_lock(sdata); |
| 543 | |||
| 538 | /* update cfg80211 bss information with the new channel */ | 544 | /* update cfg80211 bss information with the new channel */ |
| 539 | if (!is_zero_ether_addr(ifibss->bssid)) { | 545 | if (!is_zero_ether_addr(ifibss->bssid)) { |
| 540 | capability = WLAN_CAPABILITY_IBSS; | 546 | capability = WLAN_CAPABILITY_IBSS; |
| @@ -550,19 +556,21 @@ int ieee80211_ibss_finish_csa(struct ieee80211_sub_if_data *sdata) | |||
| 550 | capability); | 556 | capability); |
| 551 | /* XXX: should not really modify cfg80211 data */ | 557 | /* XXX: should not really modify cfg80211 data */ |
| 552 | if (cbss) { | 558 | if (cbss) { |
| 553 | cbss->channel = sdata->local->csa_chandef.chan; | 559 | cbss->channel = sdata->csa_chandef.chan; |
| 554 | cfg80211_put_bss(sdata->local->hw.wiphy, cbss); | 560 | cfg80211_put_bss(sdata->local->hw.wiphy, cbss); |
| 555 | } | 561 | } |
| 556 | } | 562 | } |
| 557 | 563 | ||
| 558 | ifibss->chandef = sdata->local->csa_chandef; | 564 | ifibss->chandef = sdata->csa_chandef; |
| 559 | 565 | ||
| 560 | /* generate the beacon */ | 566 | /* generate the beacon */ |
| 561 | err = ieee80211_ibss_csa_beacon(sdata, NULL); | 567 | err = ieee80211_ibss_csa_beacon(sdata, NULL); |
| 562 | sdata_unlock(sdata); | ||
| 563 | if (err < 0) | 568 | if (err < 0) |
| 564 | return err; | 569 | return err; |
| 565 | 570 | ||
| 571 | if (err) | ||
| 572 | ieee80211_bss_info_change_notify(sdata, err); | ||
| 573 | |||
| 566 | return 0; | 574 | return 0; |
| 567 | } | 575 | } |
| 568 | 576 | ||
| @@ -744,7 +752,9 @@ static void ieee80211_ibss_disconnect(struct ieee80211_sub_if_data *sdata) | |||
| 744 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED | | 752 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED | |
| 745 | BSS_CHANGED_IBSS); | 753 | BSS_CHANGED_IBSS); |
| 746 | drv_leave_ibss(local, sdata); | 754 | drv_leave_ibss(local, sdata); |
| 755 | mutex_lock(&local->mtx); | ||
| 747 | ieee80211_vif_release_channel(sdata); | 756 | ieee80211_vif_release_channel(sdata); |
| 757 | mutex_unlock(&local->mtx); | ||
| 748 | } | 758 | } |
| 749 | 759 | ||
| 750 | static void ieee80211_csa_connection_drop_work(struct work_struct *work) | 760 | static void ieee80211_csa_connection_drop_work(struct work_struct *work) |
| @@ -753,12 +763,16 @@ static void ieee80211_csa_connection_drop_work(struct work_struct *work) | |||
| 753 | container_of(work, struct ieee80211_sub_if_data, | 763 | container_of(work, struct ieee80211_sub_if_data, |
| 754 | u.ibss.csa_connection_drop_work); | 764 | u.ibss.csa_connection_drop_work); |
| 755 | 765 | ||
| 766 | sdata_lock(sdata); | ||
| 767 | |||
| 756 | ieee80211_ibss_disconnect(sdata); | 768 | ieee80211_ibss_disconnect(sdata); |
| 757 | synchronize_rcu(); | 769 | synchronize_rcu(); |
| 758 | skb_queue_purge(&sdata->skb_queue); | 770 | skb_queue_purge(&sdata->skb_queue); |
| 759 | 771 | ||
| 760 | /* trigger a scan to find another IBSS network to join */ | 772 | /* trigger a scan to find another IBSS network to join */ |
| 761 | ieee80211_queue_work(&sdata->local->hw, &sdata->work); | 773 | ieee80211_queue_work(&sdata->local->hw, &sdata->work); |
| 774 | |||
| 775 | sdata_unlock(sdata); | ||
| 762 | } | 776 | } |
| 763 | 777 | ||
| 764 | static void ieee80211_ibss_csa_mark_radar(struct ieee80211_sub_if_data *sdata) | 778 | static void ieee80211_ibss_csa_mark_radar(struct ieee80211_sub_if_data *sdata) |
| @@ -784,18 +798,10 @@ ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
| 784 | struct cfg80211_csa_settings params; | 798 | struct cfg80211_csa_settings params; |
| 785 | struct ieee80211_csa_ie csa_ie; | 799 | struct ieee80211_csa_ie csa_ie; |
| 786 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | 800 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; |
| 787 | struct ieee80211_chanctx_conf *chanctx_conf; | ||
| 788 | struct ieee80211_chanctx *chanctx; | ||
| 789 | enum nl80211_channel_type ch_type; | 801 | enum nl80211_channel_type ch_type; |
| 790 | int err, num_chanctx; | 802 | int err; |
| 791 | u32 sta_flags; | 803 | u32 sta_flags; |
| 792 | 804 | ||
| 793 | if (sdata->vif.csa_active) | ||
| 794 | return true; | ||
| 795 | |||
| 796 | if (!sdata->vif.bss_conf.ibss_joined) | ||
| 797 | return false; | ||
| 798 | |||
| 799 | sta_flags = IEEE80211_STA_DISABLE_VHT; | 805 | sta_flags = IEEE80211_STA_DISABLE_VHT; |
| 800 | switch (ifibss->chandef.width) { | 806 | switch (ifibss->chandef.width) { |
| 801 | case NL80211_CHAN_WIDTH_5: | 807 | case NL80211_CHAN_WIDTH_5: |
| @@ -830,9 +836,6 @@ ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
| 830 | params.count = csa_ie.count; | 836 | params.count = csa_ie.count; |
| 831 | params.chandef = csa_ie.chandef; | 837 | params.chandef = csa_ie.chandef; |
| 832 | 838 | ||
| 833 | if (ifibss->chandef.chan->band != params.chandef.chan->band) | ||
| 834 | goto disconnect; | ||
| 835 | |||
| 836 | switch (ifibss->chandef.width) { | 839 | switch (ifibss->chandef.width) { |
| 837 | case NL80211_CHAN_WIDTH_20_NOHT: | 840 | case NL80211_CHAN_WIDTH_20_NOHT: |
| 838 | case NL80211_CHAN_WIDTH_20: | 841 | case NL80211_CHAN_WIDTH_20: |
| @@ -888,28 +891,12 @@ ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
| 888 | params.radar_required = true; | 891 | params.radar_required = true; |
| 889 | } | 892 | } |
| 890 | 893 | ||
| 891 | rcu_read_lock(); | 894 | if (cfg80211_chandef_identical(¶ms.chandef, |
| 892 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | 895 | &sdata->vif.bss_conf.chandef)) { |
| 893 | if (!chanctx_conf) { | 896 | ibss_dbg(sdata, |
| 894 | rcu_read_unlock(); | 897 | "received csa with an identical chandef, ignoring\n"); |
| 895 | goto disconnect; | 898 | return true; |
| 896 | } | ||
| 897 | |||
| 898 | /* don't handle for multi-VIF cases */ | ||
| 899 | chanctx = container_of(chanctx_conf, struct ieee80211_chanctx, conf); | ||
| 900 | if (chanctx->refcount > 1) { | ||
| 901 | rcu_read_unlock(); | ||
| 902 | goto disconnect; | ||
| 903 | } | ||
| 904 | num_chanctx = 0; | ||
| 905 | list_for_each_entry_rcu(chanctx, &sdata->local->chanctx_list, list) | ||
| 906 | num_chanctx++; | ||
| 907 | |||
| 908 | if (num_chanctx > 1) { | ||
| 909 | rcu_read_unlock(); | ||
| 910 | goto disconnect; | ||
| 911 | } | 899 | } |
| 912 | rcu_read_unlock(); | ||
| 913 | 900 | ||
| 914 | /* all checks done, now perform the channel switch. */ | 901 | /* all checks done, now perform the channel switch. */ |
| 915 | ibss_dbg(sdata, | 902 | ibss_dbg(sdata, |
| @@ -918,19 +905,9 @@ ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
| 918 | 905 | ||
| 919 | params.block_tx = !!csa_ie.mode; | 906 | params.block_tx = !!csa_ie.mode; |
| 920 | 907 | ||
| 921 | ieee80211_ibss_csa_beacon(sdata, ¶ms); | 908 | if (ieee80211_channel_switch(sdata->local->hw.wiphy, sdata->dev, |
| 922 | sdata->csa_radar_required = params.radar_required; | 909 | ¶ms)) |
| 923 | 910 | goto disconnect; | |
| 924 | if (params.block_tx) | ||
| 925 | ieee80211_stop_queues_by_reason(&sdata->local->hw, | ||
| 926 | IEEE80211_MAX_QUEUE_MAP, | ||
| 927 | IEEE80211_QUEUE_STOP_REASON_CSA); | ||
| 928 | |||
| 929 | sdata->local->csa_chandef = params.chandef; | ||
| 930 | sdata->vif.csa_active = true; | ||
| 931 | |||
| 932 | ieee80211_bss_info_change_notify(sdata, err); | ||
| 933 | drv_channel_switch_beacon(sdata, ¶ms.chandef); | ||
| 934 | 911 | ||
| 935 | ieee80211_ibss_csa_mark_radar(sdata); | 912 | ieee80211_ibss_csa_mark_radar(sdata); |
| 936 | 913 | ||
| @@ -966,7 +943,8 @@ ieee80211_rx_mgmt_spectrum_mgmt(struct ieee80211_sub_if_data *sdata, | |||
| 966 | if (len < required_len) | 943 | if (len < required_len) |
| 967 | return; | 944 | return; |
| 968 | 945 | ||
| 969 | ieee80211_ibss_process_chanswitch(sdata, elems, false); | 946 | if (!sdata->vif.csa_active) |
| 947 | ieee80211_ibss_process_chanswitch(sdata, elems, false); | ||
| 970 | } | 948 | } |
| 971 | 949 | ||
| 972 | static void ieee80211_rx_mgmt_deauth_ibss(struct ieee80211_sub_if_data *sdata, | 950 | static void ieee80211_rx_mgmt_deauth_ibss(struct ieee80211_sub_if_data *sdata, |
| @@ -1147,7 +1125,8 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
| 1147 | goto put_bss; | 1125 | goto put_bss; |
| 1148 | 1126 | ||
| 1149 | /* process channel switch */ | 1127 | /* process channel switch */ |
| 1150 | if (ieee80211_ibss_process_chanswitch(sdata, elems, true)) | 1128 | if (sdata->vif.csa_active || |
| 1129 | ieee80211_ibss_process_chanswitch(sdata, elems, true)) | ||
| 1151 | goto put_bss; | 1130 | goto put_bss; |
| 1152 | 1131 | ||
| 1153 | /* same BSSID */ | 1132 | /* same BSSID */ |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 4aea4e791113..3701930c6649 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
| @@ -232,6 +232,7 @@ struct ieee80211_rx_data { | |||
| 232 | struct beacon_data { | 232 | struct beacon_data { |
| 233 | u8 *head, *tail; | 233 | u8 *head, *tail; |
| 234 | int head_len, tail_len; | 234 | int head_len, tail_len; |
| 235 | struct ieee80211_meshconf_ie *meshconf; | ||
| 235 | struct rcu_head rcu_head; | 236 | struct rcu_head rcu_head; |
| 236 | }; | 237 | }; |
| 237 | 238 | ||
| @@ -245,7 +246,8 @@ struct ps_data { | |||
| 245 | /* yes, this looks ugly, but guarantees that we can later use | 246 | /* yes, this looks ugly, but guarantees that we can later use |
| 246 | * bitmap_empty :) | 247 | * bitmap_empty :) |
| 247 | * NB: don't touch this bitmap, use sta_info_{set,clear}_tim_bit */ | 248 | * NB: don't touch this bitmap, use sta_info_{set,clear}_tim_bit */ |
| 248 | u8 tim[sizeof(unsigned long) * BITS_TO_LONGS(IEEE80211_MAX_AID + 1)]; | 249 | u8 tim[sizeof(unsigned long) * BITS_TO_LONGS(IEEE80211_MAX_AID + 1)] |
| 250 | __aligned(__alignof__(unsigned long)); | ||
| 249 | struct sk_buff_head bc_buf; | 251 | struct sk_buff_head bc_buf; |
| 250 | atomic_t num_sta_ps; /* number of stations in PS mode */ | 252 | atomic_t num_sta_ps; /* number of stations in PS mode */ |
| 251 | int dtim_count; | 253 | int dtim_count; |
| @@ -540,7 +542,10 @@ struct ieee80211_mesh_sync_ops { | |||
| 540 | struct ieee80211_mgmt *mgmt, | 542 | struct ieee80211_mgmt *mgmt, |
| 541 | struct ieee802_11_elems *elems, | 543 | struct ieee802_11_elems *elems, |
| 542 | struct ieee80211_rx_status *rx_status); | 544 | struct ieee80211_rx_status *rx_status); |
| 543 | void (*adjust_tbtt)(struct ieee80211_sub_if_data *sdata); | 545 | |
| 546 | /* should be called with beacon_data under RCU read lock */ | ||
| 547 | void (*adjust_tbtt)(struct ieee80211_sub_if_data *sdata, | ||
| 548 | struct beacon_data *beacon); | ||
| 544 | /* add other framework functions here */ | 549 | /* add other framework functions here */ |
| 545 | }; | 550 | }; |
| 546 | 551 | ||
| @@ -614,6 +619,9 @@ struct ieee80211_if_mesh { | |||
| 614 | bool chsw_init; | 619 | bool chsw_init; |
| 615 | u8 chsw_ttl; | 620 | u8 chsw_ttl; |
| 616 | u16 pre_value; | 621 | u16 pre_value; |
| 622 | |||
| 623 | /* offset from skb->data while building IE */ | ||
| 624 | int meshconf_offset; | ||
| 617 | }; | 625 | }; |
| 618 | 626 | ||
| 619 | #ifdef CONFIG_MAC80211_MESH | 627 | #ifdef CONFIG_MAC80211_MESH |
| @@ -686,6 +694,11 @@ struct ieee80211_chanctx { | |||
| 686 | struct ieee80211_chanctx_conf conf; | 694 | struct ieee80211_chanctx_conf conf; |
| 687 | }; | 695 | }; |
| 688 | 696 | ||
| 697 | struct mac80211_qos_map { | ||
| 698 | struct cfg80211_qos_map qos_map; | ||
| 699 | struct rcu_head rcu_head; | ||
| 700 | }; | ||
| 701 | |||
| 689 | struct ieee80211_sub_if_data { | 702 | struct ieee80211_sub_if_data { |
| 690 | struct list_head list; | 703 | struct list_head list; |
| 691 | 704 | ||
| @@ -728,13 +741,16 @@ struct ieee80211_sub_if_data { | |||
| 728 | u16 sequence_number; | 741 | u16 sequence_number; |
| 729 | __be16 control_port_protocol; | 742 | __be16 control_port_protocol; |
| 730 | bool control_port_no_encrypt; | 743 | bool control_port_no_encrypt; |
| 744 | int encrypt_headroom; | ||
| 731 | 745 | ||
| 732 | struct ieee80211_tx_queue_params tx_conf[IEEE80211_NUM_ACS]; | 746 | struct ieee80211_tx_queue_params tx_conf[IEEE80211_NUM_ACS]; |
| 747 | struct mac80211_qos_map __rcu *qos_map; | ||
| 733 | 748 | ||
| 734 | struct work_struct csa_finalize_work; | 749 | struct work_struct csa_finalize_work; |
| 735 | int csa_counter_offset_beacon; | 750 | int csa_counter_offset_beacon; |
| 736 | int csa_counter_offset_presp; | 751 | int csa_counter_offset_presp; |
| 737 | bool csa_radar_required; | 752 | bool csa_radar_required; |
| 753 | struct cfg80211_chan_def csa_chandef; | ||
| 738 | 754 | ||
| 739 | /* used to reconfigure hardware SM PS */ | 755 | /* used to reconfigure hardware SM PS */ |
| 740 | struct work_struct recalc_smps; | 756 | struct work_struct recalc_smps; |
| @@ -774,10 +790,6 @@ struct ieee80211_sub_if_data { | |||
| 774 | u32 mntr_flags; | 790 | u32 mntr_flags; |
| 775 | } u; | 791 | } u; |
| 776 | 792 | ||
| 777 | spinlock_t cleanup_stations_lock; | ||
| 778 | struct list_head cleanup_stations; | ||
| 779 | struct work_struct cleanup_stations_wk; | ||
| 780 | |||
| 781 | #ifdef CONFIG_MAC80211_DEBUGFS | 793 | #ifdef CONFIG_MAC80211_DEBUGFS |
| 782 | struct { | 794 | struct { |
| 783 | struct dentry *subdir_stations; | 795 | struct dentry *subdir_stations; |
| @@ -811,6 +823,9 @@ static inline void sdata_unlock(struct ieee80211_sub_if_data *sdata) | |||
| 811 | __release(&sdata->wdev.mtx); | 823 | __release(&sdata->wdev.mtx); |
| 812 | } | 824 | } |
| 813 | 825 | ||
| 826 | #define sdata_dereference(p, sdata) \ | ||
| 827 | rcu_dereference_protected(p, lockdep_is_held(&sdata->wdev.mtx)) | ||
| 828 | |||
| 814 | static inline void | 829 | static inline void |
| 815 | sdata_assert_lock(struct ieee80211_sub_if_data *sdata) | 830 | sdata_assert_lock(struct ieee80211_sub_if_data *sdata) |
| 816 | { | 831 | { |
| @@ -896,6 +911,24 @@ struct tpt_led_trigger { | |||
| 896 | }; | 911 | }; |
| 897 | #endif | 912 | #endif |
| 898 | 913 | ||
| 914 | /* | ||
| 915 | * struct ieee80211_tx_latency_bin_ranges - Tx latency statistics bins ranges | ||
| 916 | * | ||
| 917 | * Measuring Tx latency statistics. Counts how many Tx frames transmitted in a | ||
| 918 | * certain latency range (in Milliseconds). Each station that uses these | ||
| 919 | * ranges will have bins to count the amount of frames received in that range. | ||
| 920 | * The user can configure the ranges via debugfs. | ||
| 921 | * If ranges is NULL then Tx latency statistics bins are disabled for all | ||
| 922 | * stations. | ||
| 923 | * | ||
| 924 | * @n_ranges: number of ranges that are taken in account | ||
| 925 | * @ranges: the ranges that the user requested or NULL if disabled. | ||
| 926 | */ | ||
| 927 | struct ieee80211_tx_latency_bin_ranges { | ||
| 928 | int n_ranges; | ||
| 929 | u32 ranges[]; | ||
| 930 | }; | ||
| 931 | |||
| 899 | /** | 932 | /** |
| 900 | * mac80211 scan flags - currently active scan mode | 933 | * mac80211 scan flags - currently active scan mode |
| 901 | * | 934 | * |
| @@ -1048,6 +1081,12 @@ struct ieee80211_local { | |||
| 1048 | struct timer_list sta_cleanup; | 1081 | struct timer_list sta_cleanup; |
| 1049 | int sta_generation; | 1082 | int sta_generation; |
| 1050 | 1083 | ||
| 1084 | /* | ||
| 1085 | * Tx latency statistics parameters for all stations. | ||
| 1086 | * Can enable via debugfs (NULL when disabled). | ||
| 1087 | */ | ||
| 1088 | struct ieee80211_tx_latency_bin_ranges __rcu *tx_latency; | ||
| 1089 | |||
| 1051 | struct sk_buff_head pending[IEEE80211_MAX_QUEUES]; | 1090 | struct sk_buff_head pending[IEEE80211_MAX_QUEUES]; |
| 1052 | struct tasklet_struct tx_pending_tasklet; | 1091 | struct tasklet_struct tx_pending_tasklet; |
| 1053 | 1092 | ||
| @@ -1088,12 +1127,12 @@ struct ieee80211_local { | |||
| 1088 | 1127 | ||
| 1089 | struct work_struct sched_scan_stopped_work; | 1128 | struct work_struct sched_scan_stopped_work; |
| 1090 | struct ieee80211_sub_if_data __rcu *sched_scan_sdata; | 1129 | struct ieee80211_sub_if_data __rcu *sched_scan_sdata; |
| 1130 | struct cfg80211_sched_scan_request *sched_scan_req; | ||
| 1091 | 1131 | ||
| 1092 | unsigned long leave_oper_channel_time; | 1132 | unsigned long leave_oper_channel_time; |
| 1093 | enum mac80211_scan_state next_scan_state; | 1133 | enum mac80211_scan_state next_scan_state; |
| 1094 | struct delayed_work scan_work; | 1134 | struct delayed_work scan_work; |
| 1095 | struct ieee80211_sub_if_data __rcu *scan_sdata; | 1135 | struct ieee80211_sub_if_data __rcu *scan_sdata; |
| 1096 | struct cfg80211_chan_def csa_chandef; | ||
| 1097 | /* For backward compatibility only -- do not use */ | 1136 | /* For backward compatibility only -- do not use */ |
| 1098 | struct cfg80211_chan_def _oper_chandef; | 1137 | struct cfg80211_chan_def _oper_chandef; |
| 1099 | 1138 | ||
| @@ -1397,6 +1436,9 @@ void ieee80211_rx_bss_put(struct ieee80211_local *local, | |||
| 1397 | struct ieee80211_bss *bss); | 1436 | struct ieee80211_bss *bss); |
| 1398 | 1437 | ||
| 1399 | /* scheduled scan handling */ | 1438 | /* scheduled scan handling */ |
| 1439 | int | ||
| 1440 | __ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, | ||
| 1441 | struct cfg80211_sched_scan_request *req); | ||
| 1400 | int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, | 1442 | int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, |
| 1401 | struct cfg80211_sched_scan_request *req); | 1443 | struct cfg80211_sched_scan_request *req); |
| 1402 | int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata); | 1444 | int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata); |
| @@ -1415,6 +1457,8 @@ void ieee80211_handle_roc_started(struct ieee80211_roc_work *roc); | |||
| 1415 | 1457 | ||
| 1416 | /* channel switch handling */ | 1458 | /* channel switch handling */ |
| 1417 | void ieee80211_csa_finalize_work(struct work_struct *work); | 1459 | void ieee80211_csa_finalize_work(struct work_struct *work); |
| 1460 | int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, | ||
| 1461 | struct cfg80211_csa_settings *params); | ||
| 1418 | 1462 | ||
| 1419 | /* interface handling */ | 1463 | /* interface handling */ |
| 1420 | int ieee80211_iface_init(void); | 1464 | int ieee80211_iface_init(void); |
| @@ -1437,8 +1481,6 @@ void ieee80211_del_virtual_monitor(struct ieee80211_local *local); | |||
| 1437 | 1481 | ||
| 1438 | bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata); | 1482 | bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata); |
| 1439 | void ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata); | 1483 | void ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata); |
| 1440 | int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata, | ||
| 1441 | struct cfg80211_beacon_data *params); | ||
| 1442 | 1484 | ||
| 1443 | static inline bool ieee80211_sdata_running(struct ieee80211_sub_if_data *sdata) | 1485 | static inline bool ieee80211_sdata_running(struct ieee80211_sub_if_data *sdata) |
| 1444 | { | 1486 | { |
| @@ -1693,6 +1735,7 @@ int __ieee80211_request_smps_mgd(struct ieee80211_sub_if_data *sdata, | |||
| 1693 | int __ieee80211_request_smps_ap(struct ieee80211_sub_if_data *sdata, | 1735 | int __ieee80211_request_smps_ap(struct ieee80211_sub_if_data *sdata, |
| 1694 | enum ieee80211_smps_mode smps_mode); | 1736 | enum ieee80211_smps_mode smps_mode); |
| 1695 | void ieee80211_recalc_smps(struct ieee80211_sub_if_data *sdata); | 1737 | void ieee80211_recalc_smps(struct ieee80211_sub_if_data *sdata); |
| 1738 | void ieee80211_recalc_min_chandef(struct ieee80211_sub_if_data *sdata); | ||
| 1696 | 1739 | ||
| 1697 | size_t ieee80211_ie_split(const u8 *ies, size_t ielen, | 1740 | size_t ieee80211_ie_split(const u8 *ies, size_t ielen, |
| 1698 | const u8 *ids, int n_ids, size_t offset); | 1741 | const u8 *ids, int n_ids, size_t offset); |
| @@ -1731,7 +1774,6 @@ ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata, | |||
| 1731 | /* NOTE: only use ieee80211_vif_change_channel() for channel switch */ | 1774 | /* NOTE: only use ieee80211_vif_change_channel() for channel switch */ |
| 1732 | int __must_check | 1775 | int __must_check |
| 1733 | ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata, | 1776 | ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata, |
| 1734 | const struct cfg80211_chan_def *chandef, | ||
| 1735 | u32 *changed); | 1777 | u32 *changed); |
| 1736 | void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata); | 1778 | void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata); |
| 1737 | void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data *sdata); | 1779 | void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data *sdata); |
| @@ -1740,8 +1782,8 @@ void ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata, | |||
| 1740 | 1782 | ||
| 1741 | void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local, | 1783 | void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local, |
| 1742 | struct ieee80211_chanctx *chanctx); | 1784 | struct ieee80211_chanctx *chanctx); |
| 1743 | void ieee80211_recalc_radar_chanctx(struct ieee80211_local *local, | 1785 | void ieee80211_recalc_chanctx_min_def(struct ieee80211_local *local, |
| 1744 | struct ieee80211_chanctx *chanctx); | 1786 | struct ieee80211_chanctx *ctx); |
| 1745 | 1787 | ||
| 1746 | void ieee80211_dfs_cac_timer(unsigned long data); | 1788 | void ieee80211_dfs_cac_timer(unsigned long data); |
| 1747 | void ieee80211_dfs_cac_timer_work(struct work_struct *work); | 1789 | void ieee80211_dfs_cac_timer_work(struct work_struct *work); |
| @@ -1750,6 +1792,17 @@ void ieee80211_dfs_radar_detected_work(struct work_struct *work); | |||
| 1750 | int ieee80211_send_action_csa(struct ieee80211_sub_if_data *sdata, | 1792 | int ieee80211_send_action_csa(struct ieee80211_sub_if_data *sdata, |
| 1751 | struct cfg80211_csa_settings *csa_settings); | 1793 | struct cfg80211_csa_settings *csa_settings); |
| 1752 | 1794 | ||
| 1795 | bool ieee80211_cs_valid(const struct ieee80211_cipher_scheme *cs); | ||
| 1796 | bool ieee80211_cs_list_valid(const struct ieee80211_cipher_scheme *cs, int n); | ||
| 1797 | const struct ieee80211_cipher_scheme * | ||
| 1798 | ieee80211_cs_get(struct ieee80211_local *local, u32 cipher, | ||
| 1799 | enum nl80211_iftype iftype); | ||
| 1800 | int ieee80211_cs_headroom(struct ieee80211_local *local, | ||
| 1801 | struct cfg80211_crypto_settings *crypto, | ||
| 1802 | enum nl80211_iftype iftype); | ||
| 1803 | void ieee80211_recalc_dtim(struct ieee80211_local *local, | ||
| 1804 | struct ieee80211_sub_if_data *sdata); | ||
| 1805 | |||
| 1753 | #ifdef CONFIG_MAC80211_NOINLINE | 1806 | #ifdef CONFIG_MAC80211_NOINLINE |
| 1754 | #define debug_noinline noinline | 1807 | #define debug_noinline noinline |
| 1755 | #else | 1808 | #else |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index a0757913046e..3dfd20a453ab 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
| @@ -401,6 +401,8 @@ int ieee80211_add_virtual_monitor(struct ieee80211_local *local) | |||
| 401 | snprintf(sdata->name, IFNAMSIZ, "%s-monitor", | 401 | snprintf(sdata->name, IFNAMSIZ, "%s-monitor", |
| 402 | wiphy_name(local->hw.wiphy)); | 402 | wiphy_name(local->hw.wiphy)); |
| 403 | 403 | ||
| 404 | sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM; | ||
| 405 | |||
| 404 | ieee80211_set_default_queues(sdata); | 406 | ieee80211_set_default_queues(sdata); |
| 405 | 407 | ||
| 406 | ret = drv_add_interface(local, sdata); | 408 | ret = drv_add_interface(local, sdata); |
| @@ -416,8 +418,10 @@ int ieee80211_add_virtual_monitor(struct ieee80211_local *local) | |||
| 416 | return ret; | 418 | return ret; |
| 417 | } | 419 | } |
| 418 | 420 | ||
| 421 | mutex_lock(&local->mtx); | ||
| 419 | ret = ieee80211_vif_use_channel(sdata, &local->monitor_chandef, | 422 | ret = ieee80211_vif_use_channel(sdata, &local->monitor_chandef, |
| 420 | IEEE80211_CHANCTX_EXCLUSIVE); | 423 | IEEE80211_CHANCTX_EXCLUSIVE); |
| 424 | mutex_unlock(&local->mtx); | ||
| 421 | if (ret) { | 425 | if (ret) { |
| 422 | drv_remove_interface(local, sdata); | 426 | drv_remove_interface(local, sdata); |
| 423 | kfree(sdata); | 427 | kfree(sdata); |
| @@ -454,7 +458,9 @@ void ieee80211_del_virtual_monitor(struct ieee80211_local *local) | |||
| 454 | 458 | ||
| 455 | synchronize_net(); | 459 | synchronize_net(); |
| 456 | 460 | ||
| 461 | mutex_lock(&local->mtx); | ||
| 457 | ieee80211_vif_release_channel(sdata); | 462 | ieee80211_vif_release_channel(sdata); |
| 463 | mutex_unlock(&local->mtx); | ||
| 458 | 464 | ||
| 459 | drv_remove_interface(local, sdata); | 465 | drv_remove_interface(local, sdata); |
| 460 | 466 | ||
| @@ -749,6 +755,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
| 749 | u32 hw_reconf_flags = 0; | 755 | u32 hw_reconf_flags = 0; |
| 750 | int i, flushed; | 756 | int i, flushed; |
| 751 | struct ps_data *ps; | 757 | struct ps_data *ps; |
| 758 | struct cfg80211_chan_def chandef; | ||
| 752 | 759 | ||
| 753 | clear_bit(SDATA_STATE_RUNNING, &sdata->state); | 760 | clear_bit(SDATA_STATE_RUNNING, &sdata->state); |
| 754 | 761 | ||
| @@ -783,10 +790,8 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
| 783 | * This is relevant only in WDS mode, in all other modes we've | 790 | * This is relevant only in WDS mode, in all other modes we've |
| 784 | * already removed all stations when disconnecting or similar, | 791 | * already removed all stations when disconnecting or similar, |
| 785 | * so warn otherwise. | 792 | * so warn otherwise. |
| 786 | * | ||
| 787 | * We call sta_info_flush_cleanup() later, to combine RCU waits. | ||
| 788 | */ | 793 | */ |
| 789 | flushed = sta_info_flush_defer(sdata); | 794 | flushed = sta_info_flush(sdata); |
| 790 | WARN_ON_ONCE((sdata->vif.type != NL80211_IFTYPE_WDS && flushed > 0) || | 795 | WARN_ON_ONCE((sdata->vif.type != NL80211_IFTYPE_WDS && flushed > 0) || |
| 791 | (sdata->vif.type == NL80211_IFTYPE_WDS && flushed != 1)); | 796 | (sdata->vif.type == NL80211_IFTYPE_WDS && flushed != 1)); |
| 792 | 797 | ||
| @@ -823,11 +828,13 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
| 823 | cancel_delayed_work_sync(&sdata->dfs_cac_timer_work); | 828 | cancel_delayed_work_sync(&sdata->dfs_cac_timer_work); |
| 824 | 829 | ||
| 825 | if (sdata->wdev.cac_started) { | 830 | if (sdata->wdev.cac_started) { |
| 831 | chandef = sdata->vif.bss_conf.chandef; | ||
| 826 | WARN_ON(local->suspended); | 832 | WARN_ON(local->suspended); |
| 827 | mutex_lock(&local->iflist_mtx); | 833 | mutex_lock(&local->mtx); |
| 828 | ieee80211_vif_release_channel(sdata); | 834 | ieee80211_vif_release_channel(sdata); |
| 829 | mutex_unlock(&local->iflist_mtx); | 835 | mutex_unlock(&local->mtx); |
| 830 | cfg80211_cac_event(sdata->dev, NL80211_RADAR_CAC_ABORTED, | 836 | cfg80211_cac_event(sdata->dev, &chandef, |
| 837 | NL80211_RADAR_CAC_ABORTED, | ||
| 831 | GFP_KERNEL); | 838 | GFP_KERNEL); |
| 832 | } | 839 | } |
| 833 | 840 | ||
| @@ -886,23 +893,15 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
| 886 | cancel_work_sync(&sdata->work); | 893 | cancel_work_sync(&sdata->work); |
| 887 | /* | 894 | /* |
| 888 | * When we get here, the interface is marked down. | 895 | * When we get here, the interface is marked down. |
| 896 | * Free the remaining keys, if there are any | ||
| 897 | * (shouldn't be, except maybe in WDS mode?) | ||
| 889 | * | 898 | * |
| 890 | * sta_info_flush_cleanup() requires rcu_barrier() | 899 | * Force the key freeing to always synchronize_net() |
| 891 | * first to wait for the station call_rcu() calls | 900 | * to wait for the RX path in case it is using this |
| 892 | * to complete, and we also need synchronize_rcu() | 901 | * interface enqueuing frames * at this very time on |
| 893 | * to wait for the RX path in case it is using the | ||
| 894 | * interface and enqueuing frames at this very time on | ||
| 895 | * another CPU. | 902 | * another CPU. |
| 896 | */ | 903 | */ |
| 897 | synchronize_rcu(); | 904 | ieee80211_free_keys(sdata, true); |
| 898 | rcu_barrier(); | ||
| 899 | sta_info_flush_cleanup(sdata); | ||
| 900 | |||
| 901 | /* | ||
| 902 | * Free all remaining keys, there shouldn't be any, | ||
| 903 | * except maybe in WDS mode? | ||
| 904 | */ | ||
| 905 | ieee80211_free_keys(sdata); | ||
| 906 | 905 | ||
| 907 | /* fall through */ | 906 | /* fall through */ |
| 908 | case NL80211_IFTYPE_AP: | 907 | case NL80211_IFTYPE_AP: |
| @@ -1013,17 +1012,6 @@ static void ieee80211_set_multicast_list(struct net_device *dev) | |||
| 1013 | atomic_dec(&local->iff_promiscs); | 1012 | atomic_dec(&local->iff_promiscs); |
| 1014 | sdata->flags ^= IEEE80211_SDATA_PROMISC; | 1013 | sdata->flags ^= IEEE80211_SDATA_PROMISC; |
| 1015 | } | 1014 | } |
| 1016 | |||
| 1017 | /* | ||
| 1018 | * TODO: If somebody needs this on AP interfaces, | ||
| 1019 | * it can be enabled easily but multicast | ||
| 1020 | * addresses from VLANs need to be synced. | ||
| 1021 | */ | ||
| 1022 | if (sdata->vif.type != NL80211_IFTYPE_MONITOR && | ||
| 1023 | sdata->vif.type != NL80211_IFTYPE_AP_VLAN && | ||
| 1024 | sdata->vif.type != NL80211_IFTYPE_AP) | ||
| 1025 | drv_set_multicast_list(local, sdata, &dev->mc); | ||
| 1026 | |||
| 1027 | spin_lock_bh(&local->filter_lock); | 1015 | spin_lock_bh(&local->filter_lock); |
| 1028 | __hw_addr_sync(&local->mc_list, &dev->mc, dev->addr_len); | 1016 | __hw_addr_sync(&local->mc_list, &dev->mc, dev->addr_len); |
| 1029 | spin_unlock_bh(&local->filter_lock); | 1017 | spin_unlock_bh(&local->filter_lock); |
| @@ -1036,11 +1024,10 @@ static void ieee80211_set_multicast_list(struct net_device *dev) | |||
| 1036 | */ | 1024 | */ |
| 1037 | static void ieee80211_teardown_sdata(struct ieee80211_sub_if_data *sdata) | 1025 | static void ieee80211_teardown_sdata(struct ieee80211_sub_if_data *sdata) |
| 1038 | { | 1026 | { |
| 1039 | int flushed; | ||
| 1040 | int i; | 1027 | int i; |
| 1041 | 1028 | ||
| 1042 | /* free extra data */ | 1029 | /* free extra data */ |
| 1043 | ieee80211_free_keys(sdata); | 1030 | ieee80211_free_keys(sdata, false); |
| 1044 | 1031 | ||
| 1045 | ieee80211_debugfs_remove_netdev(sdata); | 1032 | ieee80211_debugfs_remove_netdev(sdata); |
| 1046 | 1033 | ||
| @@ -1050,9 +1037,6 @@ static void ieee80211_teardown_sdata(struct ieee80211_sub_if_data *sdata) | |||
| 1050 | 1037 | ||
| 1051 | if (ieee80211_vif_is_mesh(&sdata->vif)) | 1038 | if (ieee80211_vif_is_mesh(&sdata->vif)) |
| 1052 | mesh_rmc_free(sdata); | 1039 | mesh_rmc_free(sdata); |
| 1053 | |||
| 1054 | flushed = sta_info_flush(sdata); | ||
| 1055 | WARN_ON(flushed); | ||
| 1056 | } | 1040 | } |
| 1057 | 1041 | ||
| 1058 | static void ieee80211_uninit(struct net_device *dev) | 1042 | static void ieee80211_uninit(struct net_device *dev) |
| @@ -1272,6 +1256,7 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata, | |||
| 1272 | 1256 | ||
| 1273 | sdata->control_port_protocol = cpu_to_be16(ETH_P_PAE); | 1257 | sdata->control_port_protocol = cpu_to_be16(ETH_P_PAE); |
| 1274 | sdata->control_port_no_encrypt = false; | 1258 | sdata->control_port_no_encrypt = false; |
| 1259 | sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM; | ||
| 1275 | 1260 | ||
| 1276 | sdata->noack_map = 0; | 1261 | sdata->noack_map = 0; |
| 1277 | 1262 | ||
| @@ -1497,8 +1482,8 @@ static void ieee80211_assign_perm_addr(struct ieee80211_local *local, | |||
| 1497 | bool used = false; | 1482 | bool used = false; |
| 1498 | 1483 | ||
| 1499 | list_for_each_entry(sdata, &local->interfaces, list) { | 1484 | list_for_each_entry(sdata, &local->interfaces, list) { |
| 1500 | if (memcmp(local->hw.wiphy->addresses[i].addr, | 1485 | if (ether_addr_equal(local->hw.wiphy->addresses[i].addr, |
| 1501 | sdata->vif.addr, ETH_ALEN) == 0) { | 1486 | sdata->vif.addr)) { |
| 1502 | used = true; | 1487 | used = true; |
| 1503 | break; | 1488 | break; |
| 1504 | } | 1489 | } |
| @@ -1558,8 +1543,7 @@ static void ieee80211_assign_perm_addr(struct ieee80211_local *local, | |||
| 1558 | val += inc; | 1543 | val += inc; |
| 1559 | 1544 | ||
| 1560 | list_for_each_entry(sdata, &local->interfaces, list) { | 1545 | list_for_each_entry(sdata, &local->interfaces, list) { |
| 1561 | if (memcmp(tmp_addr, sdata->vif.addr, | 1546 | if (ether_addr_equal(tmp_addr, sdata->vif.addr)) { |
| 1562 | ETH_ALEN) == 0) { | ||
| 1563 | used = true; | 1547 | used = true; |
| 1564 | break; | 1548 | break; |
| 1565 | } | 1549 | } |
| @@ -1579,15 +1563,6 @@ static void ieee80211_assign_perm_addr(struct ieee80211_local *local, | |||
| 1579 | mutex_unlock(&local->iflist_mtx); | 1563 | mutex_unlock(&local->iflist_mtx); |
| 1580 | } | 1564 | } |
| 1581 | 1565 | ||
| 1582 | static void ieee80211_cleanup_sdata_stas_wk(struct work_struct *wk) | ||
| 1583 | { | ||
| 1584 | struct ieee80211_sub_if_data *sdata; | ||
| 1585 | |||
| 1586 | sdata = container_of(wk, struct ieee80211_sub_if_data, cleanup_stations_wk); | ||
| 1587 | |||
| 1588 | ieee80211_cleanup_sdata_stas(sdata); | ||
| 1589 | } | ||
| 1590 | |||
| 1591 | int ieee80211_if_add(struct ieee80211_local *local, const char *name, | 1566 | int ieee80211_if_add(struct ieee80211_local *local, const char *name, |
| 1592 | struct wireless_dev **new_wdev, enum nl80211_iftype type, | 1567 | struct wireless_dev **new_wdev, enum nl80211_iftype type, |
| 1593 | struct vif_params *params) | 1568 | struct vif_params *params) |
| @@ -1660,9 +1635,6 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, | |||
| 1660 | 1635 | ||
| 1661 | INIT_LIST_HEAD(&sdata->key_list); | 1636 | INIT_LIST_HEAD(&sdata->key_list); |
| 1662 | 1637 | ||
| 1663 | spin_lock_init(&sdata->cleanup_stations_lock); | ||
| 1664 | INIT_LIST_HEAD(&sdata->cleanup_stations); | ||
| 1665 | INIT_WORK(&sdata->cleanup_stations_wk, ieee80211_cleanup_sdata_stas_wk); | ||
| 1666 | INIT_DELAYED_WORK(&sdata->dfs_cac_timer_work, | 1638 | INIT_DELAYED_WORK(&sdata->dfs_cac_timer_work, |
| 1667 | ieee80211_dfs_cac_timer_work); | 1639 | ieee80211_dfs_cac_timer_work); |
| 1668 | INIT_DELAYED_WORK(&sdata->dec_tailroom_needed_wk, | 1640 | INIT_DELAYED_WORK(&sdata->dec_tailroom_needed_wk, |
| @@ -1687,6 +1659,8 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, | |||
| 1687 | sdata->ap_power_level = IEEE80211_UNSET_POWER_LEVEL; | 1659 | sdata->ap_power_level = IEEE80211_UNSET_POWER_LEVEL; |
| 1688 | sdata->user_power_level = local->user_power_level; | 1660 | sdata->user_power_level = local->user_power_level; |
| 1689 | 1661 | ||
| 1662 | sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM; | ||
| 1663 | |||
| 1690 | /* setup type-dependent data */ | 1664 | /* setup type-dependent data */ |
| 1691 | ieee80211_setup_sdata(sdata, type); | 1665 | ieee80211_setup_sdata(sdata, type); |
| 1692 | 1666 | ||
diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 3e51dd7d98b3..6ff65a1ebaa9 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c | |||
| @@ -260,25 +260,29 @@ static void ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, | |||
| 260 | int idx; | 260 | int idx; |
| 261 | bool defunikey, defmultikey, defmgmtkey; | 261 | bool defunikey, defmultikey, defmgmtkey; |
| 262 | 262 | ||
| 263 | /* caller must provide at least one old/new */ | ||
| 264 | if (WARN_ON(!new && !old)) | ||
| 265 | return; | ||
| 266 | |||
| 263 | if (new) | 267 | if (new) |
| 264 | list_add_tail(&new->list, &sdata->key_list); | 268 | list_add_tail(&new->list, &sdata->key_list); |
| 265 | 269 | ||
| 266 | if (sta && pairwise) { | 270 | WARN_ON(new && old && new->conf.keyidx != old->conf.keyidx); |
| 267 | rcu_assign_pointer(sta->ptk, new); | ||
| 268 | } else if (sta) { | ||
| 269 | if (old) | ||
| 270 | idx = old->conf.keyidx; | ||
| 271 | else | ||
| 272 | idx = new->conf.keyidx; | ||
| 273 | rcu_assign_pointer(sta->gtk[idx], new); | ||
| 274 | } else { | ||
| 275 | WARN_ON(new && old && new->conf.keyidx != old->conf.keyidx); | ||
| 276 | 271 | ||
| 277 | if (old) | 272 | if (old) |
| 278 | idx = old->conf.keyidx; | 273 | idx = old->conf.keyidx; |
| 279 | else | 274 | else |
| 280 | idx = new->conf.keyidx; | 275 | idx = new->conf.keyidx; |
| 281 | 276 | ||
| 277 | if (sta) { | ||
| 278 | if (pairwise) { | ||
| 279 | rcu_assign_pointer(sta->ptk[idx], new); | ||
| 280 | sta->ptk_idx = idx; | ||
| 281 | } else { | ||
| 282 | rcu_assign_pointer(sta->gtk[idx], new); | ||
| 283 | sta->gtk_idx = idx; | ||
| 284 | } | ||
| 285 | } else { | ||
| 282 | defunikey = old && | 286 | defunikey = old && |
| 283 | old == key_mtx_dereference(sdata->local, | 287 | old == key_mtx_dereference(sdata->local, |
| 284 | sdata->default_unicast_key); | 288 | sdata->default_unicast_key); |
| @@ -312,9 +316,11 @@ static void ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, | |||
| 312 | list_del(&old->list); | 316 | list_del(&old->list); |
| 313 | } | 317 | } |
| 314 | 318 | ||
| 315 | struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len, | 319 | struct ieee80211_key * |
| 316 | const u8 *key_data, | 320 | ieee80211_key_alloc(u32 cipher, int idx, size_t key_len, |
| 317 | size_t seq_len, const u8 *seq) | 321 | const u8 *key_data, |
| 322 | size_t seq_len, const u8 *seq, | ||
| 323 | const struct ieee80211_cipher_scheme *cs) | ||
| 318 | { | 324 | { |
| 319 | struct ieee80211_key *key; | 325 | struct ieee80211_key *key; |
| 320 | int i, j, err; | 326 | int i, j, err; |
| @@ -393,6 +399,18 @@ struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len, | |||
| 393 | return ERR_PTR(err); | 399 | return ERR_PTR(err); |
| 394 | } | 400 | } |
| 395 | break; | 401 | break; |
| 402 | default: | ||
| 403 | if (cs) { | ||
| 404 | size_t len = (seq_len > MAX_PN_LEN) ? | ||
| 405 | MAX_PN_LEN : seq_len; | ||
| 406 | |||
| 407 | key->conf.iv_len = cs->hdr_len; | ||
| 408 | key->conf.icv_len = cs->mic_len; | ||
| 409 | for (i = 0; i < IEEE80211_NUM_TIDS + 1; i++) | ||
| 410 | for (j = 0; j < len; j++) | ||
| 411 | key->u.gen.rx_pn[i][j] = | ||
| 412 | seq[len - j - 1]; | ||
| 413 | } | ||
| 396 | } | 414 | } |
| 397 | memcpy(key->conf.key, key_data, key_len); | 415 | memcpy(key->conf.key, key_data, key_len); |
| 398 | INIT_LIST_HEAD(&key->list); | 416 | INIT_LIST_HEAD(&key->list); |
| @@ -475,7 +493,7 @@ int ieee80211_key_link(struct ieee80211_key *key, | |||
| 475 | mutex_lock(&sdata->local->key_mtx); | 493 | mutex_lock(&sdata->local->key_mtx); |
| 476 | 494 | ||
| 477 | if (sta && pairwise) | 495 | if (sta && pairwise) |
| 478 | old_key = key_mtx_dereference(sdata->local, sta->ptk); | 496 | old_key = key_mtx_dereference(sdata->local, sta->ptk[idx]); |
| 479 | else if (sta) | 497 | else if (sta) |
| 480 | old_key = key_mtx_dereference(sdata->local, sta->gtk[idx]); | 498 | old_key = key_mtx_dereference(sdata->local, sta->gtk[idx]); |
| 481 | else | 499 | else |
| @@ -571,14 +589,10 @@ void ieee80211_iter_keys(struct ieee80211_hw *hw, | |||
| 571 | } | 589 | } |
| 572 | EXPORT_SYMBOL(ieee80211_iter_keys); | 590 | EXPORT_SYMBOL(ieee80211_iter_keys); |
| 573 | 591 | ||
| 574 | void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata) | 592 | static void ieee80211_free_keys_iface(struct ieee80211_sub_if_data *sdata, |
| 593 | struct list_head *keys) | ||
| 575 | { | 594 | { |
| 576 | struct ieee80211_key *key, *tmp; | 595 | struct ieee80211_key *key, *tmp; |
| 577 | LIST_HEAD(keys); | ||
| 578 | |||
| 579 | cancel_delayed_work_sync(&sdata->dec_tailroom_needed_wk); | ||
| 580 | |||
| 581 | mutex_lock(&sdata->local->key_mtx); | ||
| 582 | 596 | ||
| 583 | sdata->crypto_tx_tailroom_needed_cnt -= | 597 | sdata->crypto_tx_tailroom_needed_cnt -= |
| 584 | sdata->crypto_tx_tailroom_pending_dec; | 598 | sdata->crypto_tx_tailroom_pending_dec; |
| @@ -590,28 +604,51 @@ void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata) | |||
| 590 | ieee80211_key_replace(key->sdata, key->sta, | 604 | ieee80211_key_replace(key->sdata, key->sta, |
| 591 | key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE, | 605 | key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE, |
| 592 | key, NULL); | 606 | key, NULL); |
| 593 | list_add_tail(&key->list, &keys); | 607 | list_add_tail(&key->list, keys); |
| 594 | } | 608 | } |
| 595 | 609 | ||
| 596 | ieee80211_debugfs_key_update_default(sdata); | 610 | ieee80211_debugfs_key_update_default(sdata); |
| 611 | } | ||
| 597 | 612 | ||
| 598 | if (!list_empty(&keys)) { | 613 | void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata, |
| 599 | synchronize_net(); | 614 | bool force_synchronize) |
| 600 | list_for_each_entry_safe(key, tmp, &keys, list) | 615 | { |
| 601 | __ieee80211_key_destroy(key, false); | 616 | struct ieee80211_local *local = sdata->local; |
| 617 | struct ieee80211_sub_if_data *vlan; | ||
| 618 | struct ieee80211_key *key, *tmp; | ||
| 619 | LIST_HEAD(keys); | ||
| 620 | |||
| 621 | cancel_delayed_work_sync(&sdata->dec_tailroom_needed_wk); | ||
| 622 | |||
| 623 | mutex_lock(&local->key_mtx); | ||
| 624 | |||
| 625 | ieee80211_free_keys_iface(sdata, &keys); | ||
| 626 | |||
| 627 | if (sdata->vif.type == NL80211_IFTYPE_AP) { | ||
| 628 | list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) | ||
| 629 | ieee80211_free_keys_iface(vlan, &keys); | ||
| 602 | } | 630 | } |
| 603 | 631 | ||
| 632 | if (!list_empty(&keys) || force_synchronize) | ||
| 633 | synchronize_net(); | ||
| 634 | list_for_each_entry_safe(key, tmp, &keys, list) | ||
| 635 | __ieee80211_key_destroy(key, false); | ||
| 636 | |||
| 604 | WARN_ON_ONCE(sdata->crypto_tx_tailroom_needed_cnt || | 637 | WARN_ON_ONCE(sdata->crypto_tx_tailroom_needed_cnt || |
| 605 | sdata->crypto_tx_tailroom_pending_dec); | 638 | sdata->crypto_tx_tailroom_pending_dec); |
| 639 | if (sdata->vif.type == NL80211_IFTYPE_AP) { | ||
| 640 | list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) | ||
| 641 | WARN_ON_ONCE(vlan->crypto_tx_tailroom_needed_cnt || | ||
| 642 | vlan->crypto_tx_tailroom_pending_dec); | ||
| 643 | } | ||
| 606 | 644 | ||
| 607 | mutex_unlock(&sdata->local->key_mtx); | 645 | mutex_unlock(&local->key_mtx); |
| 608 | } | 646 | } |
| 609 | 647 | ||
| 610 | void ieee80211_free_sta_keys(struct ieee80211_local *local, | 648 | void ieee80211_free_sta_keys(struct ieee80211_local *local, |
| 611 | struct sta_info *sta) | 649 | struct sta_info *sta) |
| 612 | { | 650 | { |
| 613 | struct ieee80211_key *key, *tmp; | 651 | struct ieee80211_key *key; |
| 614 | LIST_HEAD(keys); | ||
| 615 | int i; | 652 | int i; |
| 616 | 653 | ||
| 617 | mutex_lock(&local->key_mtx); | 654 | mutex_lock(&local->key_mtx); |
| @@ -622,25 +659,18 @@ void ieee80211_free_sta_keys(struct ieee80211_local *local, | |||
| 622 | ieee80211_key_replace(key->sdata, key->sta, | 659 | ieee80211_key_replace(key->sdata, key->sta, |
| 623 | key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE, | 660 | key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE, |
| 624 | key, NULL); | 661 | key, NULL); |
| 625 | list_add(&key->list, &keys); | 662 | __ieee80211_key_destroy(key, true); |
| 626 | } | 663 | } |
| 627 | 664 | ||
| 628 | key = key_mtx_dereference(local, sta->ptk); | 665 | for (i = 0; i < NUM_DEFAULT_KEYS; i++) { |
| 629 | if (key) { | 666 | key = key_mtx_dereference(local, sta->ptk[i]); |
| 667 | if (!key) | ||
| 668 | continue; | ||
| 630 | ieee80211_key_replace(key->sdata, key->sta, | 669 | ieee80211_key_replace(key->sdata, key->sta, |
| 631 | key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE, | 670 | key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE, |
| 632 | key, NULL); | 671 | key, NULL); |
| 633 | list_add(&key->list, &keys); | ||
| 634 | } | ||
| 635 | |||
| 636 | /* | ||
| 637 | * NB: the station code relies on this being | ||
| 638 | * done even if there aren't any keys | ||
| 639 | */ | ||
| 640 | synchronize_net(); | ||
| 641 | |||
| 642 | list_for_each_entry_safe(key, tmp, &keys, list) | ||
| 643 | __ieee80211_key_destroy(key, true); | 672 | __ieee80211_key_destroy(key, true); |
| 673 | } | ||
| 644 | 674 | ||
| 645 | mutex_unlock(&local->key_mtx); | 675 | mutex_unlock(&local->key_mtx); |
| 646 | } | 676 | } |
| @@ -877,7 +907,7 @@ ieee80211_gtk_rekey_add(struct ieee80211_vif *vif, | |||
| 877 | 907 | ||
| 878 | key = ieee80211_key_alloc(keyconf->cipher, keyconf->keyidx, | 908 | key = ieee80211_key_alloc(keyconf->cipher, keyconf->keyidx, |
| 879 | keyconf->keylen, keyconf->key, | 909 | keyconf->keylen, keyconf->key, |
| 880 | 0, NULL); | 910 | 0, NULL, NULL); |
| 881 | if (IS_ERR(key)) | 911 | if (IS_ERR(key)) |
| 882 | return ERR_CAST(key); | 912 | return ERR_CAST(key); |
| 883 | 913 | ||
diff --git a/net/mac80211/key.h b/net/mac80211/key.h index aaae0ed37004..19db68663d75 100644 --- a/net/mac80211/key.h +++ b/net/mac80211/key.h | |||
| @@ -18,6 +18,7 @@ | |||
| 18 | 18 | ||
| 19 | #define NUM_DEFAULT_KEYS 4 | 19 | #define NUM_DEFAULT_KEYS 4 |
| 20 | #define NUM_DEFAULT_MGMT_KEYS 2 | 20 | #define NUM_DEFAULT_MGMT_KEYS 2 |
| 21 | #define MAX_PN_LEN 16 | ||
| 21 | 22 | ||
| 22 | struct ieee80211_local; | 23 | struct ieee80211_local; |
| 23 | struct ieee80211_sub_if_data; | 24 | struct ieee80211_sub_if_data; |
| @@ -93,6 +94,10 @@ struct ieee80211_key { | |||
| 93 | u32 replays; /* dot11RSNAStatsCMACReplays */ | 94 | u32 replays; /* dot11RSNAStatsCMACReplays */ |
| 94 | u32 icverrors; /* dot11RSNAStatsCMACICVErrors */ | 95 | u32 icverrors; /* dot11RSNAStatsCMACICVErrors */ |
| 95 | } aes_cmac; | 96 | } aes_cmac; |
| 97 | struct { | ||
| 98 | /* generic cipher scheme */ | ||
| 99 | u8 rx_pn[IEEE80211_NUM_TIDS + 1][MAX_PN_LEN]; | ||
| 100 | } gen; | ||
| 96 | } u; | 101 | } u; |
| 97 | 102 | ||
| 98 | /* number of times this key has been used */ | 103 | /* number of times this key has been used */ |
| @@ -113,9 +118,11 @@ struct ieee80211_key { | |||
| 113 | struct ieee80211_key_conf conf; | 118 | struct ieee80211_key_conf conf; |
| 114 | }; | 119 | }; |
| 115 | 120 | ||
| 116 | struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len, | 121 | struct ieee80211_key * |
| 117 | const u8 *key_data, | 122 | ieee80211_key_alloc(u32 cipher, int idx, size_t key_len, |
| 118 | size_t seq_len, const u8 *seq); | 123 | const u8 *key_data, |
| 124 | size_t seq_len, const u8 *seq, | ||
| 125 | const struct ieee80211_cipher_scheme *cs); | ||
| 119 | /* | 126 | /* |
| 120 | * Insert a key into data structures (sdata, sta if necessary) | 127 | * Insert a key into data structures (sdata, sta if necessary) |
| 121 | * to make it used, free old key. On failure, also free the new key. | 128 | * to make it used, free old key. On failure, also free the new key. |
| @@ -129,7 +136,8 @@ void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx, | |||
| 129 | bool uni, bool multi); | 136 | bool uni, bool multi); |
| 130 | void ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata, | 137 | void ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata, |
| 131 | int idx); | 138 | int idx); |
| 132 | void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata); | 139 | void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata, |
| 140 | bool force_synchronize); | ||
| 133 | void ieee80211_free_sta_keys(struct ieee80211_local *local, | 141 | void ieee80211_free_sta_keys(struct ieee80211_local *local, |
| 134 | struct sta_info *sta); | 142 | struct sta_info *sta); |
| 135 | void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata); | 143 | void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata); |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 7d1c3ac48ed9..d767cfb9b45f 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
| @@ -250,12 +250,8 @@ static void ieee80211_restart_work(struct work_struct *work) | |||
| 250 | /* wait for scan work complete */ | 250 | /* wait for scan work complete */ |
| 251 | flush_workqueue(local->workqueue); | 251 | flush_workqueue(local->workqueue); |
| 252 | 252 | ||
| 253 | mutex_lock(&local->mtx); | 253 | WARN(test_bit(SCAN_HW_SCANNING, &local->scanning), |
| 254 | WARN(test_bit(SCAN_HW_SCANNING, &local->scanning) || | 254 | "%s called with hardware scan in progress\n", __func__); |
| 255 | rcu_dereference_protected(local->sched_scan_sdata, | ||
| 256 | lockdep_is_held(&local->mtx)), | ||
| 257 | "%s called with hardware scan in progress\n", __func__); | ||
| 258 | mutex_unlock(&local->mtx); | ||
| 259 | 255 | ||
| 260 | rtnl_lock(); | 256 | rtnl_lock(); |
| 261 | ieee80211_scan_cancel(local); | 257 | ieee80211_scan_cancel(local); |
| @@ -651,15 +647,14 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
| 651 | } | 647 | } |
| 652 | EXPORT_SYMBOL(ieee80211_alloc_hw); | 648 | EXPORT_SYMBOL(ieee80211_alloc_hw); |
| 653 | 649 | ||
| 654 | int ieee80211_register_hw(struct ieee80211_hw *hw) | 650 | static int ieee80211_init_cipher_suites(struct ieee80211_local *local) |
| 655 | { | 651 | { |
| 656 | struct ieee80211_local *local = hw_to_local(hw); | 652 | bool have_wep = !(IS_ERR(local->wep_tx_tfm) || |
| 657 | int result, i; | 653 | IS_ERR(local->wep_rx_tfm)); |
| 658 | enum ieee80211_band band; | 654 | bool have_mfp = local->hw.flags & IEEE80211_HW_MFP_CAPABLE; |
| 659 | int channels, max_bitrates; | 655 | const struct ieee80211_cipher_scheme *cs = local->hw.cipher_schemes; |
| 660 | bool supp_ht, supp_vht; | 656 | int n_suites = 0, r = 0, w = 0; |
| 661 | netdev_features_t feature_whitelist; | 657 | u32 *suites; |
| 662 | struct cfg80211_chan_def dflt_chandef = {}; | ||
| 663 | static const u32 cipher_suites[] = { | 658 | static const u32 cipher_suites[] = { |
| 664 | /* keep WEP first, it may be removed below */ | 659 | /* keep WEP first, it may be removed below */ |
| 665 | WLAN_CIPHER_SUITE_WEP40, | 660 | WLAN_CIPHER_SUITE_WEP40, |
| @@ -671,6 +666,93 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
| 671 | WLAN_CIPHER_SUITE_AES_CMAC | 666 | WLAN_CIPHER_SUITE_AES_CMAC |
| 672 | }; | 667 | }; |
| 673 | 668 | ||
| 669 | /* Driver specifies the ciphers, we have nothing to do... */ | ||
| 670 | if (local->hw.wiphy->cipher_suites && have_wep) | ||
| 671 | return 0; | ||
| 672 | |||
| 673 | /* Set up cipher suites if driver relies on mac80211 cipher defs */ | ||
| 674 | if (!local->hw.wiphy->cipher_suites && !cs) { | ||
| 675 | local->hw.wiphy->cipher_suites = cipher_suites; | ||
| 676 | local->hw.wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); | ||
| 677 | |||
| 678 | if (!have_mfp) | ||
| 679 | local->hw.wiphy->n_cipher_suites--; | ||
| 680 | |||
| 681 | if (!have_wep) { | ||
| 682 | local->hw.wiphy->cipher_suites += 2; | ||
| 683 | local->hw.wiphy->n_cipher_suites -= 2; | ||
| 684 | } | ||
| 685 | |||
| 686 | return 0; | ||
| 687 | } | ||
| 688 | |||
| 689 | if (!local->hw.wiphy->cipher_suites) { | ||
| 690 | /* | ||
| 691 | * Driver specifies cipher schemes only | ||
| 692 | * We start counting ciphers defined by schemes, TKIP and CCMP | ||
| 693 | */ | ||
| 694 | n_suites = local->hw.n_cipher_schemes + 2; | ||
| 695 | |||
| 696 | /* check if we have WEP40 and WEP104 */ | ||
| 697 | if (have_wep) | ||
| 698 | n_suites += 2; | ||
| 699 | |||
| 700 | /* check if we have AES_CMAC */ | ||
| 701 | if (have_mfp) | ||
| 702 | n_suites++; | ||
| 703 | |||
| 704 | suites = kmalloc(sizeof(u32) * n_suites, GFP_KERNEL); | ||
| 705 | if (!suites) | ||
| 706 | return -ENOMEM; | ||
| 707 | |||
| 708 | suites[w++] = WLAN_CIPHER_SUITE_CCMP; | ||
| 709 | suites[w++] = WLAN_CIPHER_SUITE_TKIP; | ||
| 710 | |||
| 711 | if (have_wep) { | ||
| 712 | suites[w++] = WLAN_CIPHER_SUITE_WEP40; | ||
| 713 | suites[w++] = WLAN_CIPHER_SUITE_WEP104; | ||
| 714 | } | ||
| 715 | |||
| 716 | if (have_mfp) | ||
| 717 | suites[w++] = WLAN_CIPHER_SUITE_AES_CMAC; | ||
| 718 | |||
| 719 | for (r = 0; r < local->hw.n_cipher_schemes; r++) | ||
| 720 | suites[w++] = cs[r].cipher; | ||
| 721 | } else { | ||
| 722 | /* Driver provides cipher suites, but we need to exclude WEP */ | ||
| 723 | suites = kmemdup(local->hw.wiphy->cipher_suites, | ||
| 724 | sizeof(u32) * local->hw.wiphy->n_cipher_suites, | ||
| 725 | GFP_KERNEL); | ||
| 726 | if (!suites) | ||
| 727 | return -ENOMEM; | ||
| 728 | |||
| 729 | for (r = 0; r < local->hw.wiphy->n_cipher_suites; r++) { | ||
| 730 | u32 suite = local->hw.wiphy->cipher_suites[r]; | ||
| 731 | |||
| 732 | if (suite == WLAN_CIPHER_SUITE_WEP40 || | ||
| 733 | suite == WLAN_CIPHER_SUITE_WEP104) | ||
| 734 | continue; | ||
| 735 | suites[w++] = suite; | ||
| 736 | } | ||
| 737 | } | ||
| 738 | |||
| 739 | local->hw.wiphy->cipher_suites = suites; | ||
| 740 | local->hw.wiphy->n_cipher_suites = w; | ||
| 741 | local->wiphy_ciphers_allocated = true; | ||
| 742 | |||
| 743 | return 0; | ||
| 744 | } | ||
| 745 | |||
| 746 | int ieee80211_register_hw(struct ieee80211_hw *hw) | ||
| 747 | { | ||
| 748 | struct ieee80211_local *local = hw_to_local(hw); | ||
| 749 | int result, i; | ||
| 750 | enum ieee80211_band band; | ||
| 751 | int channels, max_bitrates; | ||
| 752 | bool supp_ht, supp_vht; | ||
| 753 | netdev_features_t feature_whitelist; | ||
| 754 | struct cfg80211_chan_def dflt_chandef = {}; | ||
| 755 | |||
| 674 | if (hw->flags & IEEE80211_HW_QUEUE_CONTROL && | 756 | if (hw->flags & IEEE80211_HW_QUEUE_CONTROL && |
| 675 | (local->hw.offchannel_tx_hw_queue == IEEE80211_INVAL_HW_QUEUE || | 757 | (local->hw.offchannel_tx_hw_queue == IEEE80211_INVAL_HW_QUEUE || |
| 676 | local->hw.offchannel_tx_hw_queue >= local->hw.queues)) | 758 | local->hw.offchannel_tx_hw_queue >= local->hw.queues)) |
| @@ -764,17 +846,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
| 764 | /* TODO: consider VHT for RX chains, hopefully it's the same */ | 846 | /* TODO: consider VHT for RX chains, hopefully it's the same */ |
| 765 | } | 847 | } |
| 766 | 848 | ||
| 767 | local->int_scan_req = kzalloc(sizeof(*local->int_scan_req) + | ||
| 768 | sizeof(void *) * channels, GFP_KERNEL); | ||
| 769 | if (!local->int_scan_req) | ||
| 770 | return -ENOMEM; | ||
| 771 | |||
| 772 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { | ||
| 773 | if (!local->hw.wiphy->bands[band]) | ||
| 774 | continue; | ||
| 775 | local->int_scan_req->rates[band] = (u32) -1; | ||
| 776 | } | ||
| 777 | |||
| 778 | /* if low-level driver supports AP, we also support VLAN */ | 849 | /* if low-level driver supports AP, we also support VLAN */ |
| 779 | if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_AP)) { | 850 | if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_AP)) { |
| 780 | hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP_VLAN); | 851 | hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP_VLAN); |
| @@ -798,6 +869,17 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
| 798 | return -EINVAL; | 869 | return -EINVAL; |
| 799 | } | 870 | } |
| 800 | 871 | ||
| 872 | local->int_scan_req = kzalloc(sizeof(*local->int_scan_req) + | ||
| 873 | sizeof(void *) * channels, GFP_KERNEL); | ||
| 874 | if (!local->int_scan_req) | ||
| 875 | return -ENOMEM; | ||
| 876 | |||
| 877 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { | ||
| 878 | if (!local->hw.wiphy->bands[band]) | ||
| 879 | continue; | ||
| 880 | local->int_scan_req->rates[band] = (u32) -1; | ||
| 881 | } | ||
| 882 | |||
| 801 | #ifndef CONFIG_MAC80211_MESH | 883 | #ifndef CONFIG_MAC80211_MESH |
| 802 | /* mesh depends on Kconfig, but drivers should set it if they want */ | 884 | /* mesh depends on Kconfig, but drivers should set it if they want */ |
| 803 | local->hw.wiphy->interface_modes &= ~BIT(NL80211_IFTYPE_MESH_POINT); | 885 | local->hw.wiphy->interface_modes &= ~BIT(NL80211_IFTYPE_MESH_POINT); |
| @@ -851,43 +933,12 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
| 851 | if (local->hw.wiphy->max_scan_ie_len) | 933 | if (local->hw.wiphy->max_scan_ie_len) |
| 852 | local->hw.wiphy->max_scan_ie_len -= local->scan_ies_len; | 934 | local->hw.wiphy->max_scan_ie_len -= local->scan_ies_len; |
| 853 | 935 | ||
| 854 | /* Set up cipher suites unless driver already did */ | 936 | WARN_ON(!ieee80211_cs_list_valid(local->hw.cipher_schemes, |
| 855 | if (!local->hw.wiphy->cipher_suites) { | 937 | local->hw.n_cipher_schemes)); |
| 856 | local->hw.wiphy->cipher_suites = cipher_suites; | 938 | |
| 857 | local->hw.wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); | 939 | result = ieee80211_init_cipher_suites(local); |
| 858 | if (!(local->hw.flags & IEEE80211_HW_MFP_CAPABLE)) | 940 | if (result < 0) |
| 859 | local->hw.wiphy->n_cipher_suites--; | 941 | goto fail_wiphy_register; |
| 860 | } | ||
| 861 | if (IS_ERR(local->wep_tx_tfm) || IS_ERR(local->wep_rx_tfm)) { | ||
| 862 | if (local->hw.wiphy->cipher_suites == cipher_suites) { | ||
| 863 | local->hw.wiphy->cipher_suites += 2; | ||
| 864 | local->hw.wiphy->n_cipher_suites -= 2; | ||
| 865 | } else { | ||
| 866 | u32 *suites; | ||
| 867 | int r, w = 0; | ||
| 868 | |||
| 869 | /* Filter out WEP */ | ||
| 870 | |||
| 871 | suites = kmemdup( | ||
| 872 | local->hw.wiphy->cipher_suites, | ||
| 873 | sizeof(u32) * local->hw.wiphy->n_cipher_suites, | ||
| 874 | GFP_KERNEL); | ||
| 875 | if (!suites) { | ||
| 876 | result = -ENOMEM; | ||
| 877 | goto fail_wiphy_register; | ||
| 878 | } | ||
| 879 | for (r = 0; r < local->hw.wiphy->n_cipher_suites; r++) { | ||
| 880 | u32 suite = local->hw.wiphy->cipher_suites[r]; | ||
| 881 | if (suite == WLAN_CIPHER_SUITE_WEP40 || | ||
| 882 | suite == WLAN_CIPHER_SUITE_WEP104) | ||
| 883 | continue; | ||
| 884 | suites[w++] = suite; | ||
| 885 | } | ||
| 886 | local->hw.wiphy->cipher_suites = suites; | ||
| 887 | local->hw.wiphy->n_cipher_suites = w; | ||
| 888 | local->wiphy_ciphers_allocated = true; | ||
| 889 | } | ||
| 890 | } | ||
| 891 | 942 | ||
| 892 | if (!local->ops->remain_on_channel) | 943 | if (!local->ops->remain_on_channel) |
| 893 | local->hw.wiphy->max_remain_on_channel_duration = 5000; | 944 | local->hw.wiphy->max_remain_on_channel_duration = 5000; |
| @@ -1090,6 +1141,8 @@ void ieee80211_free_hw(struct ieee80211_hw *hw) | |||
| 1090 | ieee80211_free_ack_frame, NULL); | 1141 | ieee80211_free_ack_frame, NULL); |
| 1091 | idr_destroy(&local->ack_status_frames); | 1142 | idr_destroy(&local->ack_status_frames); |
| 1092 | 1143 | ||
| 1144 | kfree(rcu_access_pointer(local->tx_latency)); | ||
| 1145 | |||
| 1093 | wiphy_free(local->hw.wiphy); | 1146 | wiphy_free(local->hw.wiphy); |
| 1094 | } | 1147 | } |
| 1095 | EXPORT_SYMBOL(ieee80211_free_hw); | 1148 | EXPORT_SYMBOL(ieee80211_free_hw); |
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index ba105257d03f..5b919cab1de0 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c | |||
| @@ -259,6 +259,9 @@ int mesh_add_meshconf_ie(struct ieee80211_sub_if_data *sdata, | |||
| 259 | *pos++ = WLAN_EID_MESH_CONFIG; | 259 | *pos++ = WLAN_EID_MESH_CONFIG; |
| 260 | *pos++ = meshconf_len; | 260 | *pos++ = meshconf_len; |
| 261 | 261 | ||
| 262 | /* save a pointer for quick updates in pre-tbtt */ | ||
| 263 | ifmsh->meshconf_offset = pos - skb->data; | ||
| 264 | |||
| 262 | /* Active path selection protocol ID */ | 265 | /* Active path selection protocol ID */ |
| 263 | *pos++ = ifmsh->mesh_pp_id; | 266 | *pos++ = ifmsh->mesh_pp_id; |
| 264 | /* Active path selection metric ID */ | 267 | /* Active path selection metric ID */ |
| @@ -674,8 +677,6 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh) | |||
| 674 | rcu_read_lock(); | 677 | rcu_read_lock(); |
| 675 | csa = rcu_dereference(ifmsh->csa); | 678 | csa = rcu_dereference(ifmsh->csa); |
| 676 | if (csa) { | 679 | if (csa) { |
| 677 | __le16 pre_value; | ||
| 678 | |||
| 679 | pos = skb_put(skb, 13); | 680 | pos = skb_put(skb, 13); |
| 680 | memset(pos, 0, 13); | 681 | memset(pos, 0, 13); |
| 681 | *pos++ = WLAN_EID_CHANNEL_SWITCH; | 682 | *pos++ = WLAN_EID_CHANNEL_SWITCH; |
| @@ -697,8 +698,7 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh) | |||
| 697 | WLAN_EID_CHAN_SWITCH_PARAM_TX_RESTRICT : 0x00; | 698 | WLAN_EID_CHAN_SWITCH_PARAM_TX_RESTRICT : 0x00; |
| 698 | put_unaligned_le16(WLAN_REASON_MESH_CHAN, pos); | 699 | put_unaligned_le16(WLAN_REASON_MESH_CHAN, pos); |
| 699 | pos += 2; | 700 | pos += 2; |
| 700 | pre_value = cpu_to_le16(ifmsh->pre_value); | 701 | put_unaligned_le16(ifmsh->pre_value, pos); |
| 701 | memcpy(pos, &pre_value, 2); | ||
| 702 | pos += 2; | 702 | pos += 2; |
| 703 | } | 703 | } |
| 704 | rcu_read_unlock(); | 704 | rcu_read_unlock(); |
| @@ -726,6 +726,8 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh) | |||
| 726 | 726 | ||
| 727 | bcn->tail_len = skb->len; | 727 | bcn->tail_len = skb->len; |
| 728 | memcpy(bcn->tail, skb->data, bcn->tail_len); | 728 | memcpy(bcn->tail, skb->data, bcn->tail_len); |
| 729 | bcn->meshconf = (struct ieee80211_meshconf_ie *) | ||
| 730 | (bcn->tail + ifmsh->meshconf_offset); | ||
| 729 | 731 | ||
| 730 | dev_kfree_skb(skb); | 732 | dev_kfree_skb(skb); |
| 731 | rcu_assign_pointer(ifmsh->beacon, bcn); | 733 | rcu_assign_pointer(ifmsh->beacon, bcn); |
| @@ -805,6 +807,7 @@ int ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata) | |||
| 805 | return -ENOMEM; | 807 | return -ENOMEM; |
| 806 | } | 808 | } |
| 807 | 809 | ||
| 810 | ieee80211_recalc_dtim(local, sdata); | ||
| 808 | ieee80211_bss_info_change_notify(sdata, changed); | 811 | ieee80211_bss_info_change_notify(sdata, changed); |
| 809 | 812 | ||
| 810 | netif_carrier_on(sdata->dev); | 813 | netif_carrier_on(sdata->dev); |
| @@ -964,7 +967,7 @@ ieee80211_mesh_process_chnswitch(struct ieee80211_sub_if_data *sdata, | |||
| 964 | IEEE80211_MAX_QUEUE_MAP, | 967 | IEEE80211_MAX_QUEUE_MAP, |
| 965 | IEEE80211_QUEUE_STOP_REASON_CSA); | 968 | IEEE80211_QUEUE_STOP_REASON_CSA); |
| 966 | 969 | ||
| 967 | sdata->local->csa_chandef = params.chandef; | 970 | sdata->csa_chandef = params.chandef; |
| 968 | sdata->vif.csa_active = true; | 971 | sdata->vif.csa_active = true; |
| 969 | 972 | ||
| 970 | ieee80211_bss_info_change_notify(sdata, err); | 973 | ieee80211_bss_info_change_notify(sdata, err); |
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index 2bc7fd2f787d..f39a19f9090f 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h | |||
| @@ -215,8 +215,6 @@ int mesh_rmc_check(struct ieee80211_sub_if_data *sdata, | |||
| 215 | bool mesh_matches_local(struct ieee80211_sub_if_data *sdata, | 215 | bool mesh_matches_local(struct ieee80211_sub_if_data *sdata, |
| 216 | struct ieee802_11_elems *ie); | 216 | struct ieee802_11_elems *ie); |
| 217 | void mesh_ids_set_default(struct ieee80211_if_mesh *mesh); | 217 | void mesh_ids_set_default(struct ieee80211_if_mesh *mesh); |
| 218 | void mesh_mgmt_ies_add(struct ieee80211_sub_if_data *sdata, | ||
| 219 | struct sk_buff *skb); | ||
| 220 | int mesh_add_meshconf_ie(struct ieee80211_sub_if_data *sdata, | 218 | int mesh_add_meshconf_ie(struct ieee80211_sub_if_data *sdata, |
| 221 | struct sk_buff *skb); | 219 | struct sk_buff *skb); |
| 222 | int mesh_add_meshid_ie(struct ieee80211_sub_if_data *sdata, | 220 | int mesh_add_meshid_ie(struct ieee80211_sub_if_data *sdata, |
| @@ -303,8 +301,8 @@ void mesh_mpath_table_grow(void); | |||
| 303 | void mesh_mpp_table_grow(void); | 301 | void mesh_mpp_table_grow(void); |
| 304 | /* Mesh paths */ | 302 | /* Mesh paths */ |
| 305 | int mesh_path_error_tx(struct ieee80211_sub_if_data *sdata, | 303 | int mesh_path_error_tx(struct ieee80211_sub_if_data *sdata, |
| 306 | u8 ttl, const u8 *target, __le32 target_sn, | 304 | u8 ttl, const u8 *target, u32 target_sn, |
| 307 | __le16 target_rcode, const u8 *ra); | 305 | u16 target_rcode, const u8 *ra); |
| 308 | void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta); | 306 | void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta); |
| 309 | void mesh_path_flush_pending(struct mesh_path *mpath); | 307 | void mesh_path_flush_pending(struct mesh_path *mpath); |
| 310 | void mesh_path_tx_pending(struct mesh_path *mpath); | 308 | void mesh_path_tx_pending(struct mesh_path *mpath); |
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index 486819cd02cd..f9514685d45a 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c | |||
| @@ -102,12 +102,11 @@ enum mpath_frame_type { | |||
| 102 | static const u8 broadcast_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; | 102 | static const u8 broadcast_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; |
| 103 | 103 | ||
| 104 | static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags, | 104 | static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags, |
| 105 | const u8 *orig_addr, __le32 orig_sn, | 105 | const u8 *orig_addr, u32 orig_sn, |
| 106 | u8 target_flags, const u8 *target, | 106 | u8 target_flags, const u8 *target, |
| 107 | __le32 target_sn, const u8 *da, | 107 | u32 target_sn, const u8 *da, |
| 108 | u8 hop_count, u8 ttl, | 108 | u8 hop_count, u8 ttl, |
| 109 | __le32 lifetime, __le32 metric, | 109 | u32 lifetime, u32 metric, u32 preq_id, |
| 110 | __le32 preq_id, | ||
| 111 | struct ieee80211_sub_if_data *sdata) | 110 | struct ieee80211_sub_if_data *sdata) |
| 112 | { | 111 | { |
| 113 | struct ieee80211_local *local = sdata->local; | 112 | struct ieee80211_local *local = sdata->local; |
| @@ -167,33 +166,33 @@ static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags, | |||
| 167 | if (action == MPATH_PREP) { | 166 | if (action == MPATH_PREP) { |
| 168 | memcpy(pos, target, ETH_ALEN); | 167 | memcpy(pos, target, ETH_ALEN); |
| 169 | pos += ETH_ALEN; | 168 | pos += ETH_ALEN; |
| 170 | memcpy(pos, &target_sn, 4); | 169 | put_unaligned_le32(target_sn, pos); |
| 171 | pos += 4; | 170 | pos += 4; |
| 172 | } else { | 171 | } else { |
| 173 | if (action == MPATH_PREQ) { | 172 | if (action == MPATH_PREQ) { |
| 174 | memcpy(pos, &preq_id, 4); | 173 | put_unaligned_le32(preq_id, pos); |
| 175 | pos += 4; | 174 | pos += 4; |
| 176 | } | 175 | } |
| 177 | memcpy(pos, orig_addr, ETH_ALEN); | 176 | memcpy(pos, orig_addr, ETH_ALEN); |
| 178 | pos += ETH_ALEN; | 177 | pos += ETH_ALEN; |
| 179 | memcpy(pos, &orig_sn, 4); | 178 | put_unaligned_le32(orig_sn, pos); |
| 180 | pos += 4; | 179 | pos += 4; |
| 181 | } | 180 | } |
| 182 | memcpy(pos, &lifetime, 4); /* interval for RANN */ | 181 | put_unaligned_le32(lifetime, pos); /* interval for RANN */ |
| 183 | pos += 4; | 182 | pos += 4; |
| 184 | memcpy(pos, &metric, 4); | 183 | put_unaligned_le32(metric, pos); |
| 185 | pos += 4; | 184 | pos += 4; |
| 186 | if (action == MPATH_PREQ) { | 185 | if (action == MPATH_PREQ) { |
| 187 | *pos++ = 1; /* destination count */ | 186 | *pos++ = 1; /* destination count */ |
| 188 | *pos++ = target_flags; | 187 | *pos++ = target_flags; |
| 189 | memcpy(pos, target, ETH_ALEN); | 188 | memcpy(pos, target, ETH_ALEN); |
| 190 | pos += ETH_ALEN; | 189 | pos += ETH_ALEN; |
| 191 | memcpy(pos, &target_sn, 4); | 190 | put_unaligned_le32(target_sn, pos); |
| 192 | pos += 4; | 191 | pos += 4; |
| 193 | } else if (action == MPATH_PREP) { | 192 | } else if (action == MPATH_PREP) { |
| 194 | memcpy(pos, orig_addr, ETH_ALEN); | 193 | memcpy(pos, orig_addr, ETH_ALEN); |
| 195 | pos += ETH_ALEN; | 194 | pos += ETH_ALEN; |
| 196 | memcpy(pos, &orig_sn, 4); | 195 | put_unaligned_le32(orig_sn, pos); |
| 197 | pos += 4; | 196 | pos += 4; |
| 198 | } | 197 | } |
| 199 | 198 | ||
| @@ -239,8 +238,8 @@ static void prepare_frame_for_deferred_tx(struct ieee80211_sub_if_data *sdata, | |||
| 239 | * frame directly but add it to the pending queue instead. | 238 | * frame directly but add it to the pending queue instead. |
| 240 | */ | 239 | */ |
| 241 | int mesh_path_error_tx(struct ieee80211_sub_if_data *sdata, | 240 | int mesh_path_error_tx(struct ieee80211_sub_if_data *sdata, |
| 242 | u8 ttl, const u8 *target, __le32 target_sn, | 241 | u8 ttl, const u8 *target, u32 target_sn, |
| 243 | __le16 target_rcode, const u8 *ra) | 242 | u16 target_rcode, const u8 *ra) |
| 244 | { | 243 | { |
| 245 | struct ieee80211_local *local = sdata->local; | 244 | struct ieee80211_local *local = sdata->local; |
| 246 | struct sk_buff *skb; | 245 | struct sk_buff *skb; |
| @@ -254,13 +253,13 @@ int mesh_path_error_tx(struct ieee80211_sub_if_data *sdata, | |||
| 254 | return -EAGAIN; | 253 | return -EAGAIN; |
| 255 | 254 | ||
| 256 | skb = dev_alloc_skb(local->tx_headroom + | 255 | skb = dev_alloc_skb(local->tx_headroom + |
| 257 | IEEE80211_ENCRYPT_HEADROOM + | 256 | sdata->encrypt_headroom + |
| 258 | IEEE80211_ENCRYPT_TAILROOM + | 257 | IEEE80211_ENCRYPT_TAILROOM + |
| 259 | hdr_len + | 258 | hdr_len + |
| 260 | 2 + 15 /* PERR IE */); | 259 | 2 + 15 /* PERR IE */); |
| 261 | if (!skb) | 260 | if (!skb) |
| 262 | return -1; | 261 | return -1; |
| 263 | skb_reserve(skb, local->tx_headroom + IEEE80211_ENCRYPT_HEADROOM); | 262 | skb_reserve(skb, local->tx_headroom + sdata->encrypt_headroom); |
| 264 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, hdr_len); | 263 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, hdr_len); |
| 265 | memset(mgmt, 0, hdr_len); | 264 | memset(mgmt, 0, hdr_len); |
| 266 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | 265 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | |
| @@ -293,9 +292,9 @@ int mesh_path_error_tx(struct ieee80211_sub_if_data *sdata, | |||
| 293 | pos++; | 292 | pos++; |
| 294 | memcpy(pos, target, ETH_ALEN); | 293 | memcpy(pos, target, ETH_ALEN); |
| 295 | pos += ETH_ALEN; | 294 | pos += ETH_ALEN; |
| 296 | memcpy(pos, &target_sn, 4); | 295 | put_unaligned_le32(target_sn, pos); |
| 297 | pos += 4; | 296 | pos += 4; |
| 298 | memcpy(pos, &target_rcode, 2); | 297 | put_unaligned_le16(target_rcode, pos); |
| 299 | 298 | ||
| 300 | /* see note in function header */ | 299 | /* see note in function header */ |
| 301 | prepare_frame_for_deferred_tx(sdata, skb); | 300 | prepare_frame_for_deferred_tx(sdata, skb); |
| @@ -592,10 +591,9 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata, | |||
| 592 | if (ttl != 0) { | 591 | if (ttl != 0) { |
| 593 | mhwmp_dbg(sdata, "replying to the PREQ\n"); | 592 | mhwmp_dbg(sdata, "replying to the PREQ\n"); |
| 594 | mesh_path_sel_frame_tx(MPATH_PREP, 0, orig_addr, | 593 | mesh_path_sel_frame_tx(MPATH_PREP, 0, orig_addr, |
| 595 | cpu_to_le32(orig_sn), 0, target_addr, | 594 | orig_sn, 0, target_addr, |
| 596 | cpu_to_le32(target_sn), mgmt->sa, 0, ttl, | 595 | target_sn, mgmt->sa, 0, ttl, |
| 597 | cpu_to_le32(lifetime), cpu_to_le32(metric), | 596 | lifetime, metric, 0, sdata); |
| 598 | 0, sdata); | ||
| 599 | } else { | 597 | } else { |
| 600 | ifmsh->mshstats.dropped_frames_ttl++; | 598 | ifmsh->mshstats.dropped_frames_ttl++; |
| 601 | } | 599 | } |
| @@ -625,11 +623,9 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata, | |||
| 625 | } | 623 | } |
| 626 | 624 | ||
| 627 | mesh_path_sel_frame_tx(MPATH_PREQ, flags, orig_addr, | 625 | mesh_path_sel_frame_tx(MPATH_PREQ, flags, orig_addr, |
| 628 | cpu_to_le32(orig_sn), target_flags, target_addr, | 626 | orig_sn, target_flags, target_addr, |
| 629 | cpu_to_le32(target_sn), da, | 627 | target_sn, da, hopcount, ttl, lifetime, |
| 630 | hopcount, ttl, cpu_to_le32(lifetime), | 628 | metric, preq_id, sdata); |
| 631 | cpu_to_le32(metric), cpu_to_le32(preq_id), | ||
| 632 | sdata); | ||
| 633 | if (!is_multicast_ether_addr(da)) | 629 | if (!is_multicast_ether_addr(da)) |
| 634 | ifmsh->mshstats.fwded_unicast++; | 630 | ifmsh->mshstats.fwded_unicast++; |
| 635 | else | 631 | else |
| @@ -695,11 +691,9 @@ static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata, | |||
| 695 | target_sn = PREP_IE_TARGET_SN(prep_elem); | 691 | target_sn = PREP_IE_TARGET_SN(prep_elem); |
| 696 | orig_sn = PREP_IE_ORIG_SN(prep_elem); | 692 | orig_sn = PREP_IE_ORIG_SN(prep_elem); |
| 697 | 693 | ||
| 698 | mesh_path_sel_frame_tx(MPATH_PREP, flags, orig_addr, | 694 | mesh_path_sel_frame_tx(MPATH_PREP, flags, orig_addr, orig_sn, 0, |
| 699 | cpu_to_le32(orig_sn), 0, target_addr, | 695 | target_addr, target_sn, next_hop, hopcount, |
| 700 | cpu_to_le32(target_sn), next_hop, hopcount, | 696 | ttl, lifetime, metric, 0, sdata); |
| 701 | ttl, cpu_to_le32(lifetime), cpu_to_le32(metric), | ||
| 702 | 0, sdata); | ||
| 703 | rcu_read_unlock(); | 697 | rcu_read_unlock(); |
| 704 | 698 | ||
| 705 | sdata->u.mesh.mshstats.fwded_unicast++; | 699 | sdata->u.mesh.mshstats.fwded_unicast++; |
| @@ -750,8 +744,7 @@ static void hwmp_perr_frame_process(struct ieee80211_sub_if_data *sdata, | |||
| 750 | if (!ifmsh->mshcfg.dot11MeshForwarding) | 744 | if (!ifmsh->mshcfg.dot11MeshForwarding) |
| 751 | goto endperr; | 745 | goto endperr; |
| 752 | mesh_path_error_tx(sdata, ttl, target_addr, | 746 | mesh_path_error_tx(sdata, ttl, target_addr, |
| 753 | cpu_to_le32(target_sn), | 747 | target_sn, target_rcode, |
| 754 | cpu_to_le16(target_rcode), | ||
| 755 | broadcast_addr); | 748 | broadcast_addr); |
| 756 | } else | 749 | } else |
| 757 | spin_unlock_bh(&mpath->state_lock); | 750 | spin_unlock_bh(&mpath->state_lock); |
| @@ -847,11 +840,9 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata, | |||
| 847 | 840 | ||
| 848 | if (ifmsh->mshcfg.dot11MeshForwarding) { | 841 | if (ifmsh->mshcfg.dot11MeshForwarding) { |
| 849 | mesh_path_sel_frame_tx(MPATH_RANN, flags, orig_addr, | 842 | mesh_path_sel_frame_tx(MPATH_RANN, flags, orig_addr, |
| 850 | cpu_to_le32(orig_sn), | 843 | orig_sn, 0, NULL, 0, broadcast_addr, |
| 851 | 0, NULL, 0, broadcast_addr, | 844 | hopcount, ttl, interval, |
| 852 | hopcount, ttl, cpu_to_le32(interval), | 845 | metric + metric_txsta, 0, sdata); |
| 853 | cpu_to_le32(metric + metric_txsta), | ||
| 854 | 0, sdata); | ||
| 855 | } | 846 | } |
| 856 | 847 | ||
| 857 | rcu_read_unlock(); | 848 | rcu_read_unlock(); |
| @@ -1049,11 +1040,9 @@ void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata) | |||
| 1049 | 1040 | ||
| 1050 | spin_unlock_bh(&mpath->state_lock); | 1041 | spin_unlock_bh(&mpath->state_lock); |
| 1051 | da = (mpath->is_root) ? mpath->rann_snd_addr : broadcast_addr; | 1042 | da = (mpath->is_root) ? mpath->rann_snd_addr : broadcast_addr; |
| 1052 | mesh_path_sel_frame_tx(MPATH_PREQ, 0, sdata->vif.addr, | 1043 | mesh_path_sel_frame_tx(MPATH_PREQ, 0, sdata->vif.addr, ifmsh->sn, |
| 1053 | cpu_to_le32(ifmsh->sn), target_flags, mpath->dst, | 1044 | target_flags, mpath->dst, mpath->sn, da, 0, |
| 1054 | cpu_to_le32(mpath->sn), da, 0, | 1045 | ttl, lifetime, 0, ifmsh->preq_id++, sdata); |
| 1055 | ttl, cpu_to_le32(lifetime), 0, | ||
| 1056 | cpu_to_le32(ifmsh->preq_id++), sdata); | ||
| 1057 | mod_timer(&mpath->timer, jiffies + mpath->discovery_timeout); | 1046 | mod_timer(&mpath->timer, jiffies + mpath->discovery_timeout); |
| 1058 | 1047 | ||
| 1059 | enddiscovery: | 1048 | enddiscovery: |
| @@ -1212,10 +1201,9 @@ void mesh_path_tx_root_frame(struct ieee80211_sub_if_data *sdata) | |||
| 1212 | switch (ifmsh->mshcfg.dot11MeshHWMPRootMode) { | 1201 | switch (ifmsh->mshcfg.dot11MeshHWMPRootMode) { |
| 1213 | case IEEE80211_PROACTIVE_RANN: | 1202 | case IEEE80211_PROACTIVE_RANN: |
| 1214 | mesh_path_sel_frame_tx(MPATH_RANN, flags, sdata->vif.addr, | 1203 | mesh_path_sel_frame_tx(MPATH_RANN, flags, sdata->vif.addr, |
| 1215 | cpu_to_le32(++ifmsh->sn), | 1204 | ++ifmsh->sn, 0, NULL, 0, broadcast_addr, |
| 1216 | 0, NULL, 0, broadcast_addr, | 1205 | 0, ifmsh->mshcfg.element_ttl, |
| 1217 | 0, ifmsh->mshcfg.element_ttl, | 1206 | interval, 0, 0, sdata); |
| 1218 | cpu_to_le32(interval), 0, 0, sdata); | ||
| 1219 | break; | 1207 | break; |
| 1220 | case IEEE80211_PROACTIVE_PREQ_WITH_PREP: | 1208 | case IEEE80211_PROACTIVE_PREQ_WITH_PREP: |
| 1221 | flags |= IEEE80211_PREQ_PROACTIVE_PREP_FLAG; | 1209 | flags |= IEEE80211_PREQ_PROACTIVE_PREP_FLAG; |
| @@ -1224,11 +1212,10 @@ void mesh_path_tx_root_frame(struct ieee80211_sub_if_data *sdata) | |||
| 1224 | target_flags |= IEEE80211_PREQ_TO_FLAG | | 1212 | target_flags |= IEEE80211_PREQ_TO_FLAG | |
| 1225 | IEEE80211_PREQ_USN_FLAG; | 1213 | IEEE80211_PREQ_USN_FLAG; |
| 1226 | mesh_path_sel_frame_tx(MPATH_PREQ, flags, sdata->vif.addr, | 1214 | mesh_path_sel_frame_tx(MPATH_PREQ, flags, sdata->vif.addr, |
| 1227 | cpu_to_le32(++ifmsh->sn), target_flags, | 1215 | ++ifmsh->sn, target_flags, |
| 1228 | (u8 *) broadcast_addr, 0, broadcast_addr, | 1216 | (u8 *) broadcast_addr, 0, broadcast_addr, |
| 1229 | 0, ifmsh->mshcfg.element_ttl, | 1217 | 0, ifmsh->mshcfg.element_ttl, interval, |
| 1230 | cpu_to_le32(interval), | 1218 | 0, ifmsh->preq_id++, sdata); |
| 1231 | 0, cpu_to_le32(ifmsh->preq_id++), sdata); | ||
| 1232 | break; | 1219 | break; |
| 1233 | default: | 1220 | default: |
| 1234 | mhwmp_dbg(sdata, "Proactive mechanism not supported\n"); | 1221 | mhwmp_dbg(sdata, "Proactive mechanism not supported\n"); |
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index 89aacfd2756d..7d050ed6fe5a 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c | |||
| @@ -722,7 +722,6 @@ void mesh_plink_broken(struct sta_info *sta) | |||
| 722 | struct mpath_node *node; | 722 | struct mpath_node *node; |
| 723 | struct ieee80211_sub_if_data *sdata = sta->sdata; | 723 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
| 724 | int i; | 724 | int i; |
| 725 | __le16 reason = cpu_to_le16(WLAN_REASON_MESH_PATH_DEST_UNREACHABLE); | ||
| 726 | 725 | ||
| 727 | rcu_read_lock(); | 726 | rcu_read_lock(); |
| 728 | tbl = rcu_dereference(mesh_paths); | 727 | tbl = rcu_dereference(mesh_paths); |
| @@ -736,9 +735,9 @@ void mesh_plink_broken(struct sta_info *sta) | |||
| 736 | ++mpath->sn; | 735 | ++mpath->sn; |
| 737 | spin_unlock_bh(&mpath->state_lock); | 736 | spin_unlock_bh(&mpath->state_lock); |
| 738 | mesh_path_error_tx(sdata, | 737 | mesh_path_error_tx(sdata, |
| 739 | sdata->u.mesh.mshcfg.element_ttl, | 738 | sdata->u.mesh.mshcfg.element_ttl, |
| 740 | mpath->dst, cpu_to_le32(mpath->sn), | 739 | mpath->dst, mpath->sn, |
| 741 | reason, bcast); | 740 | WLAN_REASON_MESH_PATH_DEST_UNREACHABLE, bcast); |
| 742 | } | 741 | } |
| 743 | } | 742 | } |
| 744 | rcu_read_unlock(); | 743 | rcu_read_unlock(); |
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 4301aa5aa227..e8f60aa2e848 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c | |||
| @@ -19,12 +19,6 @@ | |||
| 19 | #define mod_plink_timer(s, t) (mod_timer(&s->plink_timer, \ | 19 | #define mod_plink_timer(s, t) (mod_timer(&s->plink_timer, \ |
| 20 | jiffies + HZ * t / 1000)) | 20 | jiffies + HZ * t / 1000)) |
| 21 | 21 | ||
| 22 | /* We only need a valid sta if user configured a minimum rssi_threshold. */ | ||
| 23 | #define rssi_threshold_check(sta, sdata) \ | ||
| 24 | (sdata->u.mesh.mshcfg.rssi_threshold == 0 ||\ | ||
| 25 | (sta && (s8) -ewma_read(&sta->avg_signal) > \ | ||
| 26 | sdata->u.mesh.mshcfg.rssi_threshold)) | ||
| 27 | |||
| 28 | enum plink_event { | 22 | enum plink_event { |
| 29 | PLINK_UNDEFINED, | 23 | PLINK_UNDEFINED, |
| 30 | OPN_ACPT, | 24 | OPN_ACPT, |
| @@ -61,7 +55,17 @@ static const char * const mplevents[] = { | |||
| 61 | 55 | ||
| 62 | static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, | 56 | static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, |
| 63 | enum ieee80211_self_protected_actioncode action, | 57 | enum ieee80211_self_protected_actioncode action, |
| 64 | u8 *da, __le16 llid, __le16 plid, __le16 reason); | 58 | u8 *da, u16 llid, u16 plid, u16 reason); |
| 59 | |||
| 60 | |||
| 61 | /* We only need a valid sta if user configured a minimum rssi_threshold. */ | ||
| 62 | static bool rssi_threshold_check(struct ieee80211_sub_if_data *sdata, | ||
| 63 | struct sta_info *sta) | ||
| 64 | { | ||
| 65 | s32 rssi_threshold = sdata->u.mesh.mshcfg.rssi_threshold; | ||
| 66 | return rssi_threshold == 0 || | ||
| 67 | (sta && (s8) -ewma_read(&sta->avg_signal) > rssi_threshold); | ||
| 68 | } | ||
| 65 | 69 | ||
| 66 | /** | 70 | /** |
| 67 | * mesh_plink_fsm_restart - restart a mesh peer link finite state machine | 71 | * mesh_plink_fsm_restart - restart a mesh peer link finite state machine |
| @@ -242,7 +246,7 @@ u32 mesh_plink_deactivate(struct sta_info *sta) | |||
| 242 | 246 | ||
| 243 | spin_lock_bh(&sta->lock); | 247 | spin_lock_bh(&sta->lock); |
| 244 | changed = __mesh_plink_deactivate(sta); | 248 | changed = __mesh_plink_deactivate(sta); |
| 245 | sta->reason = cpu_to_le16(WLAN_REASON_MESH_PEER_CANCELED); | 249 | sta->reason = WLAN_REASON_MESH_PEER_CANCELED; |
| 246 | mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE, | 250 | mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE, |
| 247 | sta->sta.addr, sta->llid, sta->plid, | 251 | sta->sta.addr, sta->llid, sta->plid, |
| 248 | sta->reason); | 252 | sta->reason); |
| @@ -253,7 +257,7 @@ u32 mesh_plink_deactivate(struct sta_info *sta) | |||
| 253 | 257 | ||
| 254 | static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, | 258 | static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, |
| 255 | enum ieee80211_self_protected_actioncode action, | 259 | enum ieee80211_self_protected_actioncode action, |
| 256 | u8 *da, __le16 llid, __le16 plid, __le16 reason) | 260 | u8 *da, u16 llid, u16 plid, u16 reason) |
| 257 | { | 261 | { |
| 258 | struct ieee80211_local *local = sdata->local; | 262 | struct ieee80211_local *local = sdata->local; |
| 259 | struct sk_buff *skb; | 263 | struct sk_buff *skb; |
| @@ -279,7 +283,7 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, | |||
| 279 | 2 + 8 + /* peering IE */ | 283 | 2 + 8 + /* peering IE */ |
| 280 | sdata->u.mesh.ie_len); | 284 | sdata->u.mesh.ie_len); |
| 281 | if (!skb) | 285 | if (!skb) |
| 282 | return -1; | 286 | return err; |
| 283 | info = IEEE80211_SKB_CB(skb); | 287 | info = IEEE80211_SKB_CB(skb); |
| 284 | skb_reserve(skb, local->tx_headroom); | 288 | skb_reserve(skb, local->tx_headroom); |
| 285 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, hdr_len); | 289 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, hdr_len); |
| @@ -301,7 +305,7 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, | |||
| 301 | if (action == WLAN_SP_MESH_PEERING_CONFIRM) { | 305 | if (action == WLAN_SP_MESH_PEERING_CONFIRM) { |
| 302 | /* AID */ | 306 | /* AID */ |
| 303 | pos = skb_put(skb, 2); | 307 | pos = skb_put(skb, 2); |
| 304 | memcpy(pos + 2, &plid, 2); | 308 | put_unaligned_le16(plid, pos + 2); |
| 305 | } | 309 | } |
| 306 | if (ieee80211_add_srates_ie(sdata, skb, true, band) || | 310 | if (ieee80211_add_srates_ie(sdata, skb, true, band) || |
| 307 | ieee80211_add_ext_srates_ie(sdata, skb, true, band) || | 311 | ieee80211_add_ext_srates_ie(sdata, skb, true, band) || |
| @@ -343,14 +347,14 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, | |||
| 343 | *pos++ = ie_len; | 347 | *pos++ = ie_len; |
| 344 | memcpy(pos, &peering_proto, 2); | 348 | memcpy(pos, &peering_proto, 2); |
| 345 | pos += 2; | 349 | pos += 2; |
| 346 | memcpy(pos, &llid, 2); | 350 | put_unaligned_le16(llid, pos); |
| 347 | pos += 2; | 351 | pos += 2; |
| 348 | if (include_plid) { | 352 | if (include_plid) { |
| 349 | memcpy(pos, &plid, 2); | 353 | put_unaligned_le16(plid, pos); |
| 350 | pos += 2; | 354 | pos += 2; |
| 351 | } | 355 | } |
| 352 | if (action == WLAN_SP_MESH_PEERING_CLOSE) { | 356 | if (action == WLAN_SP_MESH_PEERING_CLOSE) { |
| 353 | memcpy(pos, &reason, 2); | 357 | put_unaligned_le16(reason, pos); |
| 354 | pos += 2; | 358 | pos += 2; |
| 355 | } | 359 | } |
| 356 | 360 | ||
| @@ -433,6 +437,7 @@ __mesh_sta_info_alloc(struct ieee80211_sub_if_data *sdata, u8 *hw_addr) | |||
| 433 | sta_info_pre_move_state(sta, IEEE80211_STA_AUTHORIZED); | 437 | sta_info_pre_move_state(sta, IEEE80211_STA_AUTHORIZED); |
| 434 | 438 | ||
| 435 | set_sta_flag(sta, WLAN_STA_WME); | 439 | set_sta_flag(sta, WLAN_STA_WME); |
| 440 | sta->sta.wme = true; | ||
| 436 | 441 | ||
| 437 | return sta; | 442 | return sta; |
| 438 | } | 443 | } |
| @@ -518,7 +523,7 @@ void mesh_neighbour_update(struct ieee80211_sub_if_data *sdata, | |||
| 518 | sta->plink_state == NL80211_PLINK_LISTEN && | 523 | sta->plink_state == NL80211_PLINK_LISTEN && |
| 519 | sdata->u.mesh.accepting_plinks && | 524 | sdata->u.mesh.accepting_plinks && |
| 520 | sdata->u.mesh.mshcfg.auto_open_plinks && | 525 | sdata->u.mesh.mshcfg.auto_open_plinks && |
| 521 | rssi_threshold_check(sta, sdata)) | 526 | rssi_threshold_check(sdata, sta)) |
| 522 | changed = mesh_plink_open(sta); | 527 | changed = mesh_plink_open(sta); |
| 523 | 528 | ||
| 524 | ieee80211_mps_frame_release(sta, elems); | 529 | ieee80211_mps_frame_release(sta, elems); |
| @@ -530,9 +535,10 @@ out: | |||
| 530 | static void mesh_plink_timer(unsigned long data) | 535 | static void mesh_plink_timer(unsigned long data) |
| 531 | { | 536 | { |
| 532 | struct sta_info *sta; | 537 | struct sta_info *sta; |
| 533 | __le16 llid, plid, reason; | 538 | u16 reason = 0; |
| 534 | struct ieee80211_sub_if_data *sdata; | 539 | struct ieee80211_sub_if_data *sdata; |
| 535 | struct mesh_config *mshcfg; | 540 | struct mesh_config *mshcfg; |
| 541 | enum ieee80211_self_protected_actioncode action = 0; | ||
| 536 | 542 | ||
| 537 | /* | 543 | /* |
| 538 | * This STA is valid because sta_info_destroy() will | 544 | * This STA is valid because sta_info_destroy() will |
| @@ -553,9 +559,6 @@ static void mesh_plink_timer(unsigned long data) | |||
| 553 | mpl_dbg(sta->sdata, | 559 | mpl_dbg(sta->sdata, |
| 554 | "Mesh plink timer for %pM fired on state %s\n", | 560 | "Mesh plink timer for %pM fired on state %s\n", |
| 555 | sta->sta.addr, mplstates[sta->plink_state]); | 561 | sta->sta.addr, mplstates[sta->plink_state]); |
| 556 | reason = 0; | ||
| 557 | llid = sta->llid; | ||
| 558 | plid = sta->plid; | ||
| 559 | sdata = sta->sdata; | 562 | sdata = sta->sdata; |
| 560 | mshcfg = &sdata->u.mesh.mshcfg; | 563 | mshcfg = &sdata->u.mesh.mshcfg; |
| 561 | 564 | ||
| @@ -574,33 +577,31 @@ static void mesh_plink_timer(unsigned long data) | |||
| 574 | rand % sta->plink_timeout; | 577 | rand % sta->plink_timeout; |
| 575 | ++sta->plink_retries; | 578 | ++sta->plink_retries; |
| 576 | mod_plink_timer(sta, sta->plink_timeout); | 579 | mod_plink_timer(sta, sta->plink_timeout); |
| 577 | spin_unlock_bh(&sta->lock); | 580 | action = WLAN_SP_MESH_PEERING_OPEN; |
| 578 | mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_OPEN, | ||
| 579 | sta->sta.addr, llid, 0, 0); | ||
| 580 | break; | 581 | break; |
| 581 | } | 582 | } |
| 582 | reason = cpu_to_le16(WLAN_REASON_MESH_MAX_RETRIES); | 583 | reason = WLAN_REASON_MESH_MAX_RETRIES; |
| 583 | /* fall through on else */ | 584 | /* fall through on else */ |
| 584 | case NL80211_PLINK_CNF_RCVD: | 585 | case NL80211_PLINK_CNF_RCVD: |
| 585 | /* confirm timer */ | 586 | /* confirm timer */ |
| 586 | if (!reason) | 587 | if (!reason) |
| 587 | reason = cpu_to_le16(WLAN_REASON_MESH_CONFIRM_TIMEOUT); | 588 | reason = WLAN_REASON_MESH_CONFIRM_TIMEOUT; |
| 588 | sta->plink_state = NL80211_PLINK_HOLDING; | 589 | sta->plink_state = NL80211_PLINK_HOLDING; |
| 589 | mod_plink_timer(sta, mshcfg->dot11MeshHoldingTimeout); | 590 | mod_plink_timer(sta, mshcfg->dot11MeshHoldingTimeout); |
| 590 | spin_unlock_bh(&sta->lock); | 591 | action = WLAN_SP_MESH_PEERING_CLOSE; |
| 591 | mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE, | ||
| 592 | sta->sta.addr, llid, plid, reason); | ||
| 593 | break; | 592 | break; |
| 594 | case NL80211_PLINK_HOLDING: | 593 | case NL80211_PLINK_HOLDING: |
| 595 | /* holding timer */ | 594 | /* holding timer */ |
| 596 | del_timer(&sta->plink_timer); | 595 | del_timer(&sta->plink_timer); |
| 597 | mesh_plink_fsm_restart(sta); | 596 | mesh_plink_fsm_restart(sta); |
| 598 | spin_unlock_bh(&sta->lock); | ||
| 599 | break; | 597 | break; |
| 600 | default: | 598 | default: |
| 601 | spin_unlock_bh(&sta->lock); | ||
| 602 | break; | 599 | break; |
| 603 | } | 600 | } |
| 601 | spin_unlock_bh(&sta->lock); | ||
| 602 | if (action) | ||
| 603 | mesh_plink_frame_tx(sdata, action, sta->sta.addr, | ||
| 604 | sta->llid, sta->plid, reason); | ||
| 604 | } | 605 | } |
| 605 | 606 | ||
| 606 | static inline void mesh_plink_timer_set(struct sta_info *sta, int timeout) | 607 | static inline void mesh_plink_timer_set(struct sta_info *sta, int timeout) |
| @@ -612,9 +613,40 @@ static inline void mesh_plink_timer_set(struct sta_info *sta, int timeout) | |||
| 612 | add_timer(&sta->plink_timer); | 613 | add_timer(&sta->plink_timer); |
| 613 | } | 614 | } |
| 614 | 615 | ||
| 616 | static bool llid_in_use(struct ieee80211_sub_if_data *sdata, | ||
| 617 | u16 llid) | ||
| 618 | { | ||
| 619 | struct ieee80211_local *local = sdata->local; | ||
| 620 | bool in_use = false; | ||
| 621 | struct sta_info *sta; | ||
| 622 | |||
| 623 | rcu_read_lock(); | ||
| 624 | list_for_each_entry_rcu(sta, &local->sta_list, list) { | ||
| 625 | if (!memcmp(&sta->llid, &llid, sizeof(llid))) { | ||
| 626 | in_use = true; | ||
| 627 | break; | ||
| 628 | } | ||
| 629 | } | ||
| 630 | rcu_read_unlock(); | ||
| 631 | |||
| 632 | return in_use; | ||
| 633 | } | ||
| 634 | |||
| 635 | static u16 mesh_get_new_llid(struct ieee80211_sub_if_data *sdata) | ||
| 636 | { | ||
| 637 | u16 llid; | ||
| 638 | |||
| 639 | do { | ||
| 640 | get_random_bytes(&llid, sizeof(llid)); | ||
| 641 | /* for mesh PS we still only have the AID range for TIM bits */ | ||
| 642 | llid = (llid % IEEE80211_MAX_AID) + 1; | ||
| 643 | } while (llid_in_use(sdata, llid)); | ||
| 644 | |||
| 645 | return llid; | ||
| 646 | } | ||
| 647 | |||
| 615 | u32 mesh_plink_open(struct sta_info *sta) | 648 | u32 mesh_plink_open(struct sta_info *sta) |
| 616 | { | 649 | { |
| 617 | __le16 llid; | ||
| 618 | struct ieee80211_sub_if_data *sdata = sta->sdata; | 650 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
| 619 | u32 changed; | 651 | u32 changed; |
| 620 | 652 | ||
| @@ -622,8 +654,7 @@ u32 mesh_plink_open(struct sta_info *sta) | |||
| 622 | return 0; | 654 | return 0; |
| 623 | 655 | ||
| 624 | spin_lock_bh(&sta->lock); | 656 | spin_lock_bh(&sta->lock); |
| 625 | get_random_bytes(&llid, 2); | 657 | sta->llid = mesh_get_new_llid(sdata); |
| 626 | sta->llid = llid; | ||
| 627 | if (sta->plink_state != NL80211_PLINK_LISTEN && | 658 | if (sta->plink_state != NL80211_PLINK_LISTEN && |
| 628 | sta->plink_state != NL80211_PLINK_BLOCKED) { | 659 | sta->plink_state != NL80211_PLINK_BLOCKED) { |
| 629 | spin_unlock_bh(&sta->lock); | 660 | spin_unlock_bh(&sta->lock); |
| @@ -640,7 +671,7 @@ u32 mesh_plink_open(struct sta_info *sta) | |||
| 640 | changed = ieee80211_mps_local_status_update(sdata); | 671 | changed = ieee80211_mps_local_status_update(sdata); |
| 641 | 672 | ||
| 642 | mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_OPEN, | 673 | mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_OPEN, |
| 643 | sta->sta.addr, llid, 0, 0); | 674 | sta->sta.addr, sta->llid, 0, 0); |
| 644 | return changed; | 675 | return changed; |
| 645 | } | 676 | } |
| 646 | 677 | ||
| @@ -656,390 +687,147 @@ u32 mesh_plink_block(struct sta_info *sta) | |||
| 656 | return changed; | 687 | return changed; |
| 657 | } | 688 | } |
| 658 | 689 | ||
| 659 | 690 | static void mesh_plink_close(struct ieee80211_sub_if_data *sdata, | |
| 660 | void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, | 691 | struct sta_info *sta, |
| 661 | struct ieee80211_mgmt *mgmt, size_t len, | 692 | enum plink_event event) |
| 662 | struct ieee80211_rx_status *rx_status) | ||
| 663 | { | 693 | { |
| 664 | struct mesh_config *mshcfg = &sdata->u.mesh.mshcfg; | 694 | struct mesh_config *mshcfg = &sdata->u.mesh.mshcfg; |
| 665 | struct ieee802_11_elems elems; | ||
| 666 | struct sta_info *sta; | ||
| 667 | enum plink_event event; | ||
| 668 | enum ieee80211_self_protected_actioncode ftype; | ||
| 669 | size_t baselen; | ||
| 670 | bool matches_local = true; | ||
| 671 | u8 ie_len; | ||
| 672 | u8 *baseaddr; | ||
| 673 | u32 changed = 0; | ||
| 674 | __le16 plid, llid, reason; | ||
| 675 | |||
| 676 | /* need action_code, aux */ | ||
| 677 | if (len < IEEE80211_MIN_ACTION_SIZE + 3) | ||
| 678 | return; | ||
| 679 | |||
| 680 | if (sdata->u.mesh.user_mpm) | ||
| 681 | /* userspace must register for these */ | ||
| 682 | return; | ||
| 683 | |||
| 684 | if (is_multicast_ether_addr(mgmt->da)) { | ||
| 685 | mpl_dbg(sdata, | ||
| 686 | "Mesh plink: ignore frame from multicast address\n"); | ||
| 687 | return; | ||
| 688 | } | ||
| 689 | |||
| 690 | baseaddr = mgmt->u.action.u.self_prot.variable; | ||
| 691 | baselen = (u8 *) mgmt->u.action.u.self_prot.variable - (u8 *) mgmt; | ||
| 692 | if (mgmt->u.action.u.self_prot.action_code == | ||
| 693 | WLAN_SP_MESH_PEERING_CONFIRM) { | ||
| 694 | baseaddr += 4; | ||
| 695 | baselen += 4; | ||
| 696 | } | ||
| 697 | ieee802_11_parse_elems(baseaddr, len - baselen, true, &elems); | ||
| 698 | |||
| 699 | if (!elems.peering) { | ||
| 700 | mpl_dbg(sdata, | ||
| 701 | "Mesh plink: missing necessary peer link ie\n"); | ||
| 702 | return; | ||
| 703 | } | ||
| 704 | 695 | ||
| 705 | if (elems.rsn_len && | 696 | u16 reason = (event == CLS_ACPT) ? |
| 706 | sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE) { | 697 | WLAN_REASON_MESH_CLOSE : WLAN_REASON_MESH_CONFIG; |
| 707 | mpl_dbg(sdata, | ||
| 708 | "Mesh plink: can't establish link with secure peer\n"); | ||
| 709 | return; | ||
| 710 | } | ||
| 711 | 698 | ||
| 712 | ftype = mgmt->u.action.u.self_prot.action_code; | 699 | sta->reason = reason; |
| 713 | ie_len = elems.peering_len; | 700 | sta->plink_state = NL80211_PLINK_HOLDING; |
| 714 | if ((ftype == WLAN_SP_MESH_PEERING_OPEN && ie_len != 4) || | 701 | mod_plink_timer(sta, mshcfg->dot11MeshHoldingTimeout); |
| 715 | (ftype == WLAN_SP_MESH_PEERING_CONFIRM && ie_len != 6) || | 702 | } |
| 716 | (ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len != 6 | ||
| 717 | && ie_len != 8)) { | ||
| 718 | mpl_dbg(sdata, | ||
| 719 | "Mesh plink: incorrect plink ie length %d %d\n", | ||
| 720 | ftype, ie_len); | ||
| 721 | return; | ||
| 722 | } | ||
| 723 | |||
| 724 | if (ftype != WLAN_SP_MESH_PEERING_CLOSE && | ||
| 725 | (!elems.mesh_id || !elems.mesh_config)) { | ||
| 726 | mpl_dbg(sdata, "Mesh plink: missing necessary ie\n"); | ||
| 727 | return; | ||
| 728 | } | ||
| 729 | /* Note the lines below are correct, the llid in the frame is the plid | ||
| 730 | * from the point of view of this host. | ||
| 731 | */ | ||
| 732 | memcpy(&plid, PLINK_GET_LLID(elems.peering), 2); | ||
| 733 | if (ftype == WLAN_SP_MESH_PEERING_CONFIRM || | ||
| 734 | (ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len == 8)) | ||
| 735 | memcpy(&llid, PLINK_GET_PLID(elems.peering), 2); | ||
| 736 | |||
| 737 | /* WARNING: Only for sta pointer, is dropped & re-acquired */ | ||
| 738 | rcu_read_lock(); | ||
| 739 | |||
| 740 | sta = sta_info_get(sdata, mgmt->sa); | ||
| 741 | if (!sta && ftype != WLAN_SP_MESH_PEERING_OPEN) { | ||
| 742 | mpl_dbg(sdata, "Mesh plink: cls or cnf from unknown peer\n"); | ||
| 743 | rcu_read_unlock(); | ||
| 744 | return; | ||
| 745 | } | ||
| 746 | |||
| 747 | if (ftype == WLAN_SP_MESH_PEERING_OPEN && | ||
| 748 | !rssi_threshold_check(sta, sdata)) { | ||
| 749 | mpl_dbg(sdata, "Mesh plink: %pM does not meet rssi threshold\n", | ||
| 750 | mgmt->sa); | ||
| 751 | rcu_read_unlock(); | ||
| 752 | return; | ||
| 753 | } | ||
| 754 | |||
| 755 | if (sta && !test_sta_flag(sta, WLAN_STA_AUTH)) { | ||
| 756 | mpl_dbg(sdata, "Mesh plink: Action frame from non-authed peer\n"); | ||
| 757 | rcu_read_unlock(); | ||
| 758 | return; | ||
| 759 | } | ||
| 760 | 703 | ||
| 761 | if (sta && sta->plink_state == NL80211_PLINK_BLOCKED) { | 704 | static u32 mesh_plink_establish(struct ieee80211_sub_if_data *sdata, |
| 762 | rcu_read_unlock(); | 705 | struct sta_info *sta) |
| 763 | return; | 706 | { |
| 764 | } | 707 | struct mesh_config *mshcfg = &sdata->u.mesh.mshcfg; |
| 708 | u32 changed = 0; | ||
| 765 | 709 | ||
| 766 | /* Now we will figure out the appropriate event... */ | 710 | del_timer(&sta->plink_timer); |
| 767 | event = PLINK_UNDEFINED; | 711 | sta->plink_state = NL80211_PLINK_ESTAB; |
| 768 | if (ftype != WLAN_SP_MESH_PEERING_CLOSE && | 712 | changed |= mesh_plink_inc_estab_count(sdata); |
| 769 | !mesh_matches_local(sdata, &elems)) { | 713 | changed |= mesh_set_ht_prot_mode(sdata); |
| 770 | matches_local = false; | 714 | changed |= mesh_set_short_slot_time(sdata); |
| 771 | switch (ftype) { | 715 | mpl_dbg(sdata, "Mesh plink with %pM ESTABLISHED\n", sta->sta.addr); |
| 772 | case WLAN_SP_MESH_PEERING_OPEN: | 716 | ieee80211_mps_sta_status_update(sta); |
| 773 | event = OPN_RJCT; | 717 | changed |= ieee80211_mps_set_sta_local_pm(sta, mshcfg->power_mode); |
| 774 | break; | 718 | return changed; |
| 775 | case WLAN_SP_MESH_PEERING_CONFIRM: | 719 | } |
| 776 | event = CNF_RJCT; | ||
| 777 | break; | ||
| 778 | default: | ||
| 779 | break; | ||
| 780 | } | ||
| 781 | } | ||
| 782 | 720 | ||
| 783 | if (!sta && !matches_local) { | 721 | /** |
| 784 | rcu_read_unlock(); | 722 | * mesh_plink_fsm - step @sta MPM based on @event |
| 785 | reason = cpu_to_le16(WLAN_REASON_MESH_CONFIG); | 723 | * |
| 786 | llid = 0; | 724 | * @sdata: interface |
| 787 | mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE, | 725 | * @sta: mesh neighbor |
| 788 | mgmt->sa, llid, plid, reason); | 726 | * @event: peering event |
| 789 | return; | 727 | * |
| 790 | } else if (!sta) { | 728 | * Return: changed MBSS flags |
| 791 | /* ftype == WLAN_SP_MESH_PEERING_OPEN */ | 729 | */ |
| 792 | if (!mesh_plink_free_count(sdata)) { | 730 | static u32 mesh_plink_fsm(struct ieee80211_sub_if_data *sdata, |
| 793 | mpl_dbg(sdata, "Mesh plink error: no more free plinks\n"); | 731 | struct sta_info *sta, enum plink_event event) |
| 794 | rcu_read_unlock(); | 732 | { |
| 795 | return; | 733 | struct mesh_config *mshcfg = &sdata->u.mesh.mshcfg; |
| 796 | } | 734 | enum ieee80211_self_protected_actioncode action = 0; |
| 797 | event = OPN_ACPT; | 735 | u32 changed = 0; |
| 798 | } else if (matches_local) { | ||
| 799 | switch (ftype) { | ||
| 800 | case WLAN_SP_MESH_PEERING_OPEN: | ||
| 801 | if (!mesh_plink_free_count(sdata) || | ||
| 802 | (sta->plid && sta->plid != plid)) | ||
| 803 | event = OPN_IGNR; | ||
| 804 | else | ||
| 805 | event = OPN_ACPT; | ||
| 806 | break; | ||
| 807 | case WLAN_SP_MESH_PEERING_CONFIRM: | ||
| 808 | if (!mesh_plink_free_count(sdata) || | ||
| 809 | (sta->llid != llid || sta->plid != plid)) | ||
| 810 | event = CNF_IGNR; | ||
| 811 | else | ||
| 812 | event = CNF_ACPT; | ||
| 813 | break; | ||
| 814 | case WLAN_SP_MESH_PEERING_CLOSE: | ||
| 815 | if (sta->plink_state == NL80211_PLINK_ESTAB) | ||
| 816 | /* Do not check for llid or plid. This does not | ||
| 817 | * follow the standard but since multiple plinks | ||
| 818 | * per sta are not supported, it is necessary in | ||
| 819 | * order to avoid a livelock when MP A sees an | ||
| 820 | * establish peer link to MP B but MP B does not | ||
| 821 | * see it. This can be caused by a timeout in | ||
| 822 | * B's peer link establishment or B beign | ||
| 823 | * restarted. | ||
| 824 | */ | ||
| 825 | event = CLS_ACPT; | ||
| 826 | else if (sta->plid != plid) | ||
| 827 | event = CLS_IGNR; | ||
| 828 | else if (ie_len == 7 && sta->llid != llid) | ||
| 829 | event = CLS_IGNR; | ||
| 830 | else | ||
| 831 | event = CLS_ACPT; | ||
| 832 | break; | ||
| 833 | default: | ||
| 834 | mpl_dbg(sdata, "Mesh plink: unknown frame subtype\n"); | ||
| 835 | rcu_read_unlock(); | ||
| 836 | return; | ||
| 837 | } | ||
| 838 | } | ||
| 839 | 736 | ||
| 840 | if (event == OPN_ACPT) { | 737 | mpl_dbg(sdata, "peer %pM in state %s got event %s\n", sta->sta.addr, |
| 841 | rcu_read_unlock(); | 738 | mplstates[sta->plink_state], mplevents[event]); |
| 842 | /* allocate sta entry if necessary and update info */ | ||
| 843 | sta = mesh_sta_info_get(sdata, mgmt->sa, &elems); | ||
| 844 | if (!sta) { | ||
| 845 | mpl_dbg(sdata, "Mesh plink: failed to init peer!\n"); | ||
| 846 | rcu_read_unlock(); | ||
| 847 | return; | ||
| 848 | } | ||
| 849 | } | ||
| 850 | 739 | ||
| 851 | mpl_dbg(sdata, "peer %pM in state %s got event %s\n", mgmt->sa, | ||
| 852 | mplstates[sta->plink_state], mplevents[event]); | ||
| 853 | reason = 0; | ||
| 854 | spin_lock_bh(&sta->lock); | 740 | spin_lock_bh(&sta->lock); |
| 855 | switch (sta->plink_state) { | 741 | switch (sta->plink_state) { |
| 856 | /* spin_unlock as soon as state is updated at each case */ | ||
| 857 | case NL80211_PLINK_LISTEN: | 742 | case NL80211_PLINK_LISTEN: |
| 858 | switch (event) { | 743 | switch (event) { |
| 859 | case CLS_ACPT: | 744 | case CLS_ACPT: |
| 860 | mesh_plink_fsm_restart(sta); | 745 | mesh_plink_fsm_restart(sta); |
| 861 | spin_unlock_bh(&sta->lock); | ||
| 862 | break; | 746 | break; |
| 863 | case OPN_ACPT: | 747 | case OPN_ACPT: |
| 864 | sta->plink_state = NL80211_PLINK_OPN_RCVD; | 748 | sta->plink_state = NL80211_PLINK_OPN_RCVD; |
| 865 | sta->plid = plid; | 749 | sta->llid = mesh_get_new_llid(sdata); |
| 866 | get_random_bytes(&llid, 2); | ||
| 867 | sta->llid = llid; | ||
| 868 | mesh_plink_timer_set(sta, | 750 | mesh_plink_timer_set(sta, |
| 869 | mshcfg->dot11MeshRetryTimeout); | 751 | mshcfg->dot11MeshRetryTimeout); |
| 870 | 752 | ||
| 871 | /* set the non-peer mode to active during peering */ | 753 | /* set the non-peer mode to active during peering */ |
| 872 | changed |= ieee80211_mps_local_status_update(sdata); | 754 | changed |= ieee80211_mps_local_status_update(sdata); |
| 873 | 755 | action = WLAN_SP_MESH_PEERING_OPEN; | |
| 874 | spin_unlock_bh(&sta->lock); | ||
| 875 | mesh_plink_frame_tx(sdata, | ||
| 876 | WLAN_SP_MESH_PEERING_OPEN, | ||
| 877 | sta->sta.addr, llid, 0, 0); | ||
| 878 | mesh_plink_frame_tx(sdata, | ||
| 879 | WLAN_SP_MESH_PEERING_CONFIRM, | ||
| 880 | sta->sta.addr, llid, plid, 0); | ||
| 881 | break; | 756 | break; |
| 882 | default: | 757 | default: |
| 883 | spin_unlock_bh(&sta->lock); | ||
| 884 | break; | 758 | break; |
| 885 | } | 759 | } |
| 886 | break; | 760 | break; |
| 887 | |||
| 888 | case NL80211_PLINK_OPN_SNT: | 761 | case NL80211_PLINK_OPN_SNT: |
| 889 | switch (event) { | 762 | switch (event) { |
| 890 | case OPN_RJCT: | 763 | case OPN_RJCT: |
| 891 | case CNF_RJCT: | 764 | case CNF_RJCT: |
| 892 | reason = cpu_to_le16(WLAN_REASON_MESH_CONFIG); | ||
| 893 | case CLS_ACPT: | 765 | case CLS_ACPT: |
| 894 | if (!reason) | 766 | mesh_plink_close(sdata, sta, event); |
| 895 | reason = cpu_to_le16(WLAN_REASON_MESH_CLOSE); | 767 | action = WLAN_SP_MESH_PEERING_CLOSE; |
| 896 | sta->reason = reason; | ||
| 897 | sta->plink_state = NL80211_PLINK_HOLDING; | ||
| 898 | if (!mod_plink_timer(sta, | ||
| 899 | mshcfg->dot11MeshHoldingTimeout)) | ||
| 900 | sta->ignore_plink_timer = true; | ||
| 901 | |||
| 902 | llid = sta->llid; | ||
| 903 | spin_unlock_bh(&sta->lock); | ||
| 904 | mesh_plink_frame_tx(sdata, | ||
| 905 | WLAN_SP_MESH_PEERING_CLOSE, | ||
| 906 | sta->sta.addr, llid, plid, reason); | ||
| 907 | break; | 768 | break; |
| 908 | case OPN_ACPT: | 769 | case OPN_ACPT: |
| 909 | /* retry timer is left untouched */ | 770 | /* retry timer is left untouched */ |
| 910 | sta->plink_state = NL80211_PLINK_OPN_RCVD; | 771 | sta->plink_state = NL80211_PLINK_OPN_RCVD; |
| 911 | sta->plid = plid; | 772 | action = WLAN_SP_MESH_PEERING_CONFIRM; |
| 912 | llid = sta->llid; | ||
| 913 | spin_unlock_bh(&sta->lock); | ||
| 914 | mesh_plink_frame_tx(sdata, | ||
| 915 | WLAN_SP_MESH_PEERING_CONFIRM, | ||
| 916 | sta->sta.addr, llid, plid, 0); | ||
| 917 | break; | 773 | break; |
| 918 | case CNF_ACPT: | 774 | case CNF_ACPT: |
| 919 | sta->plink_state = NL80211_PLINK_CNF_RCVD; | 775 | sta->plink_state = NL80211_PLINK_CNF_RCVD; |
| 920 | if (!mod_plink_timer(sta, | 776 | if (!mod_plink_timer(sta, |
| 921 | mshcfg->dot11MeshConfirmTimeout)) | 777 | mshcfg->dot11MeshConfirmTimeout)) |
| 922 | sta->ignore_plink_timer = true; | 778 | sta->ignore_plink_timer = true; |
| 923 | |||
| 924 | spin_unlock_bh(&sta->lock); | ||
| 925 | break; | 779 | break; |
| 926 | default: | 780 | default: |
| 927 | spin_unlock_bh(&sta->lock); | ||
| 928 | break; | 781 | break; |
| 929 | } | 782 | } |
| 930 | break; | 783 | break; |
| 931 | |||
| 932 | case NL80211_PLINK_OPN_RCVD: | 784 | case NL80211_PLINK_OPN_RCVD: |
| 933 | switch (event) { | 785 | switch (event) { |
| 934 | case OPN_RJCT: | 786 | case OPN_RJCT: |
| 935 | case CNF_RJCT: | 787 | case CNF_RJCT: |
| 936 | reason = cpu_to_le16(WLAN_REASON_MESH_CONFIG); | ||
| 937 | case CLS_ACPT: | 788 | case CLS_ACPT: |
| 938 | if (!reason) | 789 | mesh_plink_close(sdata, sta, event); |
| 939 | reason = cpu_to_le16(WLAN_REASON_MESH_CLOSE); | 790 | action = WLAN_SP_MESH_PEERING_CLOSE; |
| 940 | sta->reason = reason; | ||
| 941 | sta->plink_state = NL80211_PLINK_HOLDING; | ||
| 942 | if (!mod_plink_timer(sta, | ||
| 943 | mshcfg->dot11MeshHoldingTimeout)) | ||
| 944 | sta->ignore_plink_timer = true; | ||
| 945 | |||
| 946 | llid = sta->llid; | ||
| 947 | spin_unlock_bh(&sta->lock); | ||
| 948 | mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE, | ||
| 949 | sta->sta.addr, llid, plid, reason); | ||
| 950 | break; | 791 | break; |
| 951 | case OPN_ACPT: | 792 | case OPN_ACPT: |
| 952 | llid = sta->llid; | 793 | action = WLAN_SP_MESH_PEERING_CONFIRM; |
| 953 | spin_unlock_bh(&sta->lock); | ||
| 954 | mesh_plink_frame_tx(sdata, | ||
| 955 | WLAN_SP_MESH_PEERING_CONFIRM, | ||
| 956 | sta->sta.addr, llid, plid, 0); | ||
| 957 | break; | 794 | break; |
| 958 | case CNF_ACPT: | 795 | case CNF_ACPT: |
| 959 | del_timer(&sta->plink_timer); | 796 | changed |= mesh_plink_establish(sdata, sta); |
| 960 | sta->plink_state = NL80211_PLINK_ESTAB; | ||
| 961 | spin_unlock_bh(&sta->lock); | ||
| 962 | changed |= mesh_plink_inc_estab_count(sdata); | ||
| 963 | changed |= mesh_set_ht_prot_mode(sdata); | ||
| 964 | changed |= mesh_set_short_slot_time(sdata); | ||
| 965 | mpl_dbg(sdata, "Mesh plink with %pM ESTABLISHED\n", | ||
| 966 | sta->sta.addr); | ||
| 967 | ieee80211_mps_sta_status_update(sta); | ||
| 968 | changed |= ieee80211_mps_set_sta_local_pm(sta, | ||
| 969 | mshcfg->power_mode); | ||
| 970 | break; | 797 | break; |
| 971 | default: | 798 | default: |
| 972 | spin_unlock_bh(&sta->lock); | ||
| 973 | break; | 799 | break; |
| 974 | } | 800 | } |
| 975 | break; | 801 | break; |
| 976 | |||
| 977 | case NL80211_PLINK_CNF_RCVD: | 802 | case NL80211_PLINK_CNF_RCVD: |
| 978 | switch (event) { | 803 | switch (event) { |
| 979 | case OPN_RJCT: | 804 | case OPN_RJCT: |
| 980 | case CNF_RJCT: | 805 | case CNF_RJCT: |
| 981 | reason = cpu_to_le16(WLAN_REASON_MESH_CONFIG); | ||
| 982 | case CLS_ACPT: | 806 | case CLS_ACPT: |
| 983 | if (!reason) | 807 | mesh_plink_close(sdata, sta, event); |
| 984 | reason = cpu_to_le16(WLAN_REASON_MESH_CLOSE); | 808 | action = WLAN_SP_MESH_PEERING_CLOSE; |
| 985 | sta->reason = reason; | ||
| 986 | sta->plink_state = NL80211_PLINK_HOLDING; | ||
| 987 | if (!mod_plink_timer(sta, | ||
| 988 | mshcfg->dot11MeshHoldingTimeout)) | ||
| 989 | sta->ignore_plink_timer = true; | ||
| 990 | |||
| 991 | llid = sta->llid; | ||
| 992 | spin_unlock_bh(&sta->lock); | ||
| 993 | mesh_plink_frame_tx(sdata, | ||
| 994 | WLAN_SP_MESH_PEERING_CLOSE, | ||
| 995 | sta->sta.addr, llid, plid, reason); | ||
| 996 | break; | 809 | break; |
| 997 | case OPN_ACPT: | 810 | case OPN_ACPT: |
| 998 | del_timer(&sta->plink_timer); | 811 | changed |= mesh_plink_establish(sdata, sta); |
| 999 | sta->plink_state = NL80211_PLINK_ESTAB; | 812 | action = WLAN_SP_MESH_PEERING_CONFIRM; |
| 1000 | spin_unlock_bh(&sta->lock); | ||
| 1001 | changed |= mesh_plink_inc_estab_count(sdata); | ||
| 1002 | changed |= mesh_set_ht_prot_mode(sdata); | ||
| 1003 | changed |= mesh_set_short_slot_time(sdata); | ||
| 1004 | mpl_dbg(sdata, "Mesh plink with %pM ESTABLISHED\n", | ||
| 1005 | sta->sta.addr); | ||
| 1006 | mesh_plink_frame_tx(sdata, | ||
| 1007 | WLAN_SP_MESH_PEERING_CONFIRM, | ||
| 1008 | sta->sta.addr, llid, plid, 0); | ||
| 1009 | ieee80211_mps_sta_status_update(sta); | ||
| 1010 | changed |= ieee80211_mps_set_sta_local_pm(sta, | ||
| 1011 | mshcfg->power_mode); | ||
| 1012 | break; | 813 | break; |
| 1013 | default: | 814 | default: |
| 1014 | spin_unlock_bh(&sta->lock); | ||
| 1015 | break; | 815 | break; |
| 1016 | } | 816 | } |
| 1017 | break; | 817 | break; |
| 1018 | |||
| 1019 | case NL80211_PLINK_ESTAB: | 818 | case NL80211_PLINK_ESTAB: |
| 1020 | switch (event) { | 819 | switch (event) { |
| 1021 | case CLS_ACPT: | 820 | case CLS_ACPT: |
| 1022 | reason = cpu_to_le16(WLAN_REASON_MESH_CLOSE); | ||
| 1023 | sta->reason = reason; | ||
| 1024 | changed |= __mesh_plink_deactivate(sta); | 821 | changed |= __mesh_plink_deactivate(sta); |
| 1025 | sta->plink_state = NL80211_PLINK_HOLDING; | ||
| 1026 | llid = sta->llid; | ||
| 1027 | mod_plink_timer(sta, mshcfg->dot11MeshHoldingTimeout); | ||
| 1028 | spin_unlock_bh(&sta->lock); | ||
| 1029 | changed |= mesh_set_ht_prot_mode(sdata); | 822 | changed |= mesh_set_ht_prot_mode(sdata); |
| 1030 | changed |= mesh_set_short_slot_time(sdata); | 823 | changed |= mesh_set_short_slot_time(sdata); |
| 1031 | mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE, | 824 | mesh_plink_close(sdata, sta, event); |
| 1032 | sta->sta.addr, llid, plid, reason); | 825 | action = WLAN_SP_MESH_PEERING_CLOSE; |
| 1033 | break; | 826 | break; |
| 1034 | case OPN_ACPT: | 827 | case OPN_ACPT: |
| 1035 | llid = sta->llid; | 828 | action = WLAN_SP_MESH_PEERING_CONFIRM; |
| 1036 | spin_unlock_bh(&sta->lock); | ||
| 1037 | mesh_plink_frame_tx(sdata, | ||
| 1038 | WLAN_SP_MESH_PEERING_CONFIRM, | ||
| 1039 | sta->sta.addr, llid, plid, 0); | ||
| 1040 | break; | 829 | break; |
| 1041 | default: | 830 | default: |
| 1042 | spin_unlock_bh(&sta->lock); | ||
| 1043 | break; | 831 | break; |
| 1044 | } | 832 | } |
| 1045 | break; | 833 | break; |
| @@ -1049,32 +837,271 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, | |||
| 1049 | if (del_timer(&sta->plink_timer)) | 837 | if (del_timer(&sta->plink_timer)) |
| 1050 | sta->ignore_plink_timer = 1; | 838 | sta->ignore_plink_timer = 1; |
| 1051 | mesh_plink_fsm_restart(sta); | 839 | mesh_plink_fsm_restart(sta); |
| 1052 | spin_unlock_bh(&sta->lock); | ||
| 1053 | break; | 840 | break; |
| 1054 | case OPN_ACPT: | 841 | case OPN_ACPT: |
| 1055 | case CNF_ACPT: | 842 | case CNF_ACPT: |
| 1056 | case OPN_RJCT: | 843 | case OPN_RJCT: |
| 1057 | case CNF_RJCT: | 844 | case CNF_RJCT: |
| 1058 | llid = sta->llid; | 845 | action = WLAN_SP_MESH_PEERING_CLOSE; |
| 1059 | reason = sta->reason; | ||
| 1060 | spin_unlock_bh(&sta->lock); | ||
| 1061 | mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE, | ||
| 1062 | sta->sta.addr, llid, plid, reason); | ||
| 1063 | break; | 846 | break; |
| 1064 | default: | 847 | default: |
| 1065 | spin_unlock_bh(&sta->lock); | 848 | break; |
| 1066 | } | 849 | } |
| 1067 | break; | 850 | break; |
| 1068 | default: | 851 | default: |
| 1069 | /* should not get here, PLINK_BLOCKED is dealt with at the | 852 | /* should not get here, PLINK_BLOCKED is dealt with at the |
| 1070 | * beginning of the function | 853 | * beginning of the function |
| 1071 | */ | 854 | */ |
| 1072 | spin_unlock_bh(&sta->lock); | ||
| 1073 | break; | 855 | break; |
| 1074 | } | 856 | } |
| 857 | spin_unlock_bh(&sta->lock); | ||
| 858 | if (action) { | ||
| 859 | mesh_plink_frame_tx(sdata, action, sta->sta.addr, | ||
| 860 | sta->llid, sta->plid, sta->reason); | ||
| 861 | |||
| 862 | /* also send confirm in open case */ | ||
| 863 | if (action == WLAN_SP_MESH_PEERING_OPEN) { | ||
| 864 | mesh_plink_frame_tx(sdata, | ||
| 865 | WLAN_SP_MESH_PEERING_CONFIRM, | ||
| 866 | sta->sta.addr, sta->llid, | ||
| 867 | sta->plid, 0); | ||
| 868 | } | ||
| 869 | } | ||
| 870 | |||
| 871 | return changed; | ||
| 872 | } | ||
| 873 | |||
| 874 | /* | ||
| 875 | * mesh_plink_get_event - get correct MPM event | ||
| 876 | * | ||
| 877 | * @sdata: interface | ||
| 878 | * @sta: peer, leave NULL if processing a frame from a new suitable peer | ||
| 879 | * @elems: peering management IEs | ||
| 880 | * @ftype: frame type | ||
| 881 | * @llid: peer's peer link ID | ||
| 882 | * @plid: peer's local link ID | ||
| 883 | * | ||
| 884 | * Return: new peering event for @sta, but PLINK_UNDEFINED should be treated as | ||
| 885 | * an error. | ||
| 886 | */ | ||
| 887 | static enum plink_event | ||
| 888 | mesh_plink_get_event(struct ieee80211_sub_if_data *sdata, | ||
| 889 | struct sta_info *sta, | ||
| 890 | struct ieee802_11_elems *elems, | ||
| 891 | enum ieee80211_self_protected_actioncode ftype, | ||
| 892 | u16 llid, u16 plid) | ||
| 893 | { | ||
| 894 | enum plink_event event = PLINK_UNDEFINED; | ||
| 895 | u8 ie_len = elems->peering_len; | ||
| 896 | bool matches_local; | ||
| 897 | |||
| 898 | matches_local = (ftype == WLAN_SP_MESH_PEERING_CLOSE || | ||
| 899 | mesh_matches_local(sdata, elems)); | ||
| 900 | |||
| 901 | /* deny open request from non-matching peer */ | ||
| 902 | if (!matches_local && !sta) { | ||
| 903 | event = OPN_RJCT; | ||
| 904 | goto out; | ||
| 905 | } | ||
| 906 | |||
| 907 | if (!sta) { | ||
| 908 | if (ftype != WLAN_SP_MESH_PEERING_OPEN) { | ||
| 909 | mpl_dbg(sdata, "Mesh plink: cls or cnf from unknown peer\n"); | ||
| 910 | goto out; | ||
| 911 | } | ||
| 912 | /* ftype == WLAN_SP_MESH_PEERING_OPEN */ | ||
| 913 | if (!mesh_plink_free_count(sdata)) { | ||
| 914 | mpl_dbg(sdata, "Mesh plink error: no more free plinks\n"); | ||
| 915 | goto out; | ||
| 916 | } | ||
| 917 | } else { | ||
| 918 | if (!test_sta_flag(sta, WLAN_STA_AUTH)) { | ||
| 919 | mpl_dbg(sdata, "Mesh plink: Action frame from non-authed peer\n"); | ||
| 920 | goto out; | ||
| 921 | } | ||
| 922 | if (sta->plink_state == NL80211_PLINK_BLOCKED) | ||
| 923 | goto out; | ||
| 924 | } | ||
| 925 | |||
| 926 | /* new matching peer */ | ||
| 927 | if (!sta) { | ||
| 928 | event = OPN_ACPT; | ||
| 929 | goto out; | ||
| 930 | } | ||
| 931 | |||
| 932 | switch (ftype) { | ||
| 933 | case WLAN_SP_MESH_PEERING_OPEN: | ||
| 934 | if (!matches_local) | ||
| 935 | event = OPN_RJCT; | ||
| 936 | if (!mesh_plink_free_count(sdata) || | ||
| 937 | (sta->plid && sta->plid != plid)) | ||
| 938 | event = OPN_IGNR; | ||
| 939 | else | ||
| 940 | event = OPN_ACPT; | ||
| 941 | break; | ||
| 942 | case WLAN_SP_MESH_PEERING_CONFIRM: | ||
| 943 | if (!matches_local) | ||
| 944 | event = CNF_RJCT; | ||
| 945 | if (!mesh_plink_free_count(sdata) || | ||
| 946 | (sta->llid != llid || sta->plid != plid)) | ||
| 947 | event = CNF_IGNR; | ||
| 948 | else | ||
| 949 | event = CNF_ACPT; | ||
| 950 | break; | ||
| 951 | case WLAN_SP_MESH_PEERING_CLOSE: | ||
| 952 | if (sta->plink_state == NL80211_PLINK_ESTAB) | ||
| 953 | /* Do not check for llid or plid. This does not | ||
| 954 | * follow the standard but since multiple plinks | ||
| 955 | * per sta are not supported, it is necessary in | ||
| 956 | * order to avoid a livelock when MP A sees an | ||
| 957 | * establish peer link to MP B but MP B does not | ||
| 958 | * see it. This can be caused by a timeout in | ||
| 959 | * B's peer link establishment or B beign | ||
| 960 | * restarted. | ||
| 961 | */ | ||
| 962 | event = CLS_ACPT; | ||
| 963 | else if (sta->plid != plid) | ||
| 964 | event = CLS_IGNR; | ||
| 965 | else if (ie_len == 8 && sta->llid != llid) | ||
| 966 | event = CLS_IGNR; | ||
| 967 | else | ||
| 968 | event = CLS_ACPT; | ||
| 969 | break; | ||
| 970 | default: | ||
| 971 | mpl_dbg(sdata, "Mesh plink: unknown frame subtype\n"); | ||
| 972 | break; | ||
| 973 | } | ||
| 974 | |||
| 975 | out: | ||
| 976 | return event; | ||
| 977 | } | ||
| 1075 | 978 | ||
| 979 | static void | ||
| 980 | mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata, | ||
| 981 | struct ieee80211_mgmt *mgmt, | ||
| 982 | struct ieee802_11_elems *elems) | ||
| 983 | { | ||
| 984 | |||
| 985 | struct sta_info *sta; | ||
| 986 | enum plink_event event; | ||
| 987 | enum ieee80211_self_protected_actioncode ftype; | ||
| 988 | u32 changed = 0; | ||
| 989 | u8 ie_len = elems->peering_len; | ||
| 990 | __le16 _plid, _llid; | ||
| 991 | u16 plid, llid = 0; | ||
| 992 | |||
| 993 | if (!elems->peering) { | ||
| 994 | mpl_dbg(sdata, | ||
| 995 | "Mesh plink: missing necessary peer link ie\n"); | ||
| 996 | return; | ||
| 997 | } | ||
| 998 | |||
| 999 | if (elems->rsn_len && | ||
| 1000 | sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE) { | ||
| 1001 | mpl_dbg(sdata, | ||
| 1002 | "Mesh plink: can't establish link with secure peer\n"); | ||
| 1003 | return; | ||
| 1004 | } | ||
| 1005 | |||
| 1006 | ftype = mgmt->u.action.u.self_prot.action_code; | ||
| 1007 | if ((ftype == WLAN_SP_MESH_PEERING_OPEN && ie_len != 4) || | ||
| 1008 | (ftype == WLAN_SP_MESH_PEERING_CONFIRM && ie_len != 6) || | ||
| 1009 | (ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len != 6 | ||
| 1010 | && ie_len != 8)) { | ||
| 1011 | mpl_dbg(sdata, | ||
| 1012 | "Mesh plink: incorrect plink ie length %d %d\n", | ||
| 1013 | ftype, ie_len); | ||
| 1014 | return; | ||
| 1015 | } | ||
| 1016 | |||
| 1017 | if (ftype != WLAN_SP_MESH_PEERING_CLOSE && | ||
| 1018 | (!elems->mesh_id || !elems->mesh_config)) { | ||
| 1019 | mpl_dbg(sdata, "Mesh plink: missing necessary ie\n"); | ||
| 1020 | return; | ||
| 1021 | } | ||
| 1022 | /* Note the lines below are correct, the llid in the frame is the plid | ||
| 1023 | * from the point of view of this host. | ||
| 1024 | */ | ||
| 1025 | memcpy(&_plid, PLINK_GET_LLID(elems->peering), sizeof(__le16)); | ||
| 1026 | plid = le16_to_cpu(_plid); | ||
| 1027 | if (ftype == WLAN_SP_MESH_PEERING_CONFIRM || | ||
| 1028 | (ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len == 8)) { | ||
| 1029 | memcpy(&_llid, PLINK_GET_PLID(elems->peering), sizeof(__le16)); | ||
| 1030 | llid = le16_to_cpu(_llid); | ||
| 1031 | } | ||
| 1032 | |||
| 1033 | /* WARNING: Only for sta pointer, is dropped & re-acquired */ | ||
| 1034 | rcu_read_lock(); | ||
| 1035 | |||
| 1036 | sta = sta_info_get(sdata, mgmt->sa); | ||
| 1037 | |||
| 1038 | if (ftype == WLAN_SP_MESH_PEERING_OPEN && | ||
| 1039 | !rssi_threshold_check(sdata, sta)) { | ||
| 1040 | mpl_dbg(sdata, "Mesh plink: %pM does not meet rssi threshold\n", | ||
| 1041 | mgmt->sa); | ||
| 1042 | goto unlock_rcu; | ||
| 1043 | } | ||
| 1044 | |||
| 1045 | /* Now we will figure out the appropriate event... */ | ||
| 1046 | event = mesh_plink_get_event(sdata, sta, elems, ftype, llid, plid); | ||
| 1047 | |||
| 1048 | if (event == OPN_ACPT) { | ||
| 1049 | rcu_read_unlock(); | ||
| 1050 | /* allocate sta entry if necessary and update info */ | ||
| 1051 | sta = mesh_sta_info_get(sdata, mgmt->sa, elems); | ||
| 1052 | if (!sta) { | ||
| 1053 | mpl_dbg(sdata, "Mesh plink: failed to init peer!\n"); | ||
| 1054 | goto unlock_rcu; | ||
| 1055 | } | ||
| 1056 | sta->plid = plid; | ||
| 1057 | } else if (!sta && event == OPN_RJCT) { | ||
| 1058 | mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE, | ||
| 1059 | mgmt->sa, 0, plid, | ||
| 1060 | WLAN_REASON_MESH_CONFIG); | ||
| 1061 | goto unlock_rcu; | ||
| 1062 | } else if (!sta || event == PLINK_UNDEFINED) { | ||
| 1063 | /* something went wrong */ | ||
| 1064 | goto unlock_rcu; | ||
| 1065 | } | ||
| 1066 | |||
| 1067 | changed |= mesh_plink_fsm(sdata, sta, event); | ||
| 1068 | |||
| 1069 | unlock_rcu: | ||
| 1076 | rcu_read_unlock(); | 1070 | rcu_read_unlock(); |
| 1077 | 1071 | ||
| 1078 | if (changed) | 1072 | if (changed) |
| 1079 | ieee80211_mbss_info_change_notify(sdata, changed); | 1073 | ieee80211_mbss_info_change_notify(sdata, changed); |
| 1080 | } | 1074 | } |
| 1075 | |||
| 1076 | void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, | ||
| 1077 | struct ieee80211_mgmt *mgmt, size_t len, | ||
| 1078 | struct ieee80211_rx_status *rx_status) | ||
| 1079 | { | ||
| 1080 | struct ieee802_11_elems elems; | ||
| 1081 | size_t baselen; | ||
| 1082 | u8 *baseaddr; | ||
| 1083 | |||
| 1084 | /* need action_code, aux */ | ||
| 1085 | if (len < IEEE80211_MIN_ACTION_SIZE + 3) | ||
| 1086 | return; | ||
| 1087 | |||
| 1088 | if (sdata->u.mesh.user_mpm) | ||
| 1089 | /* userspace must register for these */ | ||
| 1090 | return; | ||
| 1091 | |||
| 1092 | if (is_multicast_ether_addr(mgmt->da)) { | ||
| 1093 | mpl_dbg(sdata, | ||
| 1094 | "Mesh plink: ignore frame from multicast address\n"); | ||
| 1095 | return; | ||
| 1096 | } | ||
| 1097 | |||
| 1098 | baseaddr = mgmt->u.action.u.self_prot.variable; | ||
| 1099 | baselen = (u8 *) mgmt->u.action.u.self_prot.variable - (u8 *) mgmt; | ||
| 1100 | if (mgmt->u.action.u.self_prot.action_code == | ||
| 1101 | WLAN_SP_MESH_PEERING_CONFIRM) { | ||
| 1102 | baseaddr += 4; | ||
| 1103 | baselen += 4; | ||
| 1104 | } | ||
| 1105 | ieee802_11_parse_elems(baseaddr, len - baselen, true, &elems); | ||
| 1106 | mesh_process_plink_frame(sdata, mgmt, &elems); | ||
| 1107 | } | ||
diff --git a/net/mac80211/mesh_ps.c b/net/mac80211/mesh_ps.c index 0f79b78b5e86..2802f9d9279d 100644 --- a/net/mac80211/mesh_ps.c +++ b/net/mac80211/mesh_ps.c | |||
| @@ -576,10 +576,9 @@ void ieee80211_mps_frame_release(struct sta_info *sta, | |||
| 576 | int ac, buffer_local = 0; | 576 | int ac, buffer_local = 0; |
| 577 | bool has_buffered = false; | 577 | bool has_buffered = false; |
| 578 | 578 | ||
| 579 | /* TIM map only for LLID <= IEEE80211_MAX_AID */ | ||
| 580 | if (sta->plink_state == NL80211_PLINK_ESTAB) | 579 | if (sta->plink_state == NL80211_PLINK_ESTAB) |
| 581 | has_buffered = ieee80211_check_tim(elems->tim, elems->tim_len, | 580 | has_buffered = ieee80211_check_tim(elems->tim, elems->tim_len, |
| 582 | le16_to_cpu(sta->llid) % IEEE80211_MAX_AID); | 581 | sta->llid); |
| 583 | 582 | ||
| 584 | if (has_buffered) | 583 | if (has_buffered) |
| 585 | mps_dbg(sta->sdata, "%pM indicates buffered frames\n", | 584 | mps_dbg(sta->sdata, "%pM indicates buffered frames\n", |
diff --git a/net/mac80211/mesh_sync.c b/net/mac80211/mesh_sync.c index 05a256b38e24..2bc5dc25d5ad 100644 --- a/net/mac80211/mesh_sync.c +++ b/net/mac80211/mesh_sync.c | |||
| @@ -92,12 +92,20 @@ static void mesh_sync_offset_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, | |||
| 92 | if (stype != IEEE80211_STYPE_BEACON) | 92 | if (stype != IEEE80211_STYPE_BEACON) |
| 93 | return; | 93 | return; |
| 94 | 94 | ||
| 95 | /* The current tsf is a first approximation for the timestamp | 95 | /* |
| 96 | * for the received beacon. Further down we try to get a | 96 | * Get time when timestamp field was received. If we don't |
| 97 | * better value from the rx_status->mactime field if | 97 | * have rx timestamps, then use current tsf as an approximation. |
| 98 | * available. Also we have to call drv_get_tsf() before | 98 | * drv_get_tsf() must be called before entering the rcu-read |
| 99 | * entering the rcu-read section.*/ | 99 | * section. |
| 100 | t_r = drv_get_tsf(local, sdata); | 100 | */ |
| 101 | if (ieee80211_have_rx_timestamp(rx_status)) | ||
| 102 | t_r = ieee80211_calculate_rx_timestamp(local, rx_status, | ||
| 103 | 24 + 12 + | ||
| 104 | elems->total_len + | ||
| 105 | FCS_LEN, | ||
| 106 | 24); | ||
| 107 | else | ||
| 108 | t_r = drv_get_tsf(local, sdata); | ||
| 101 | 109 | ||
| 102 | rcu_read_lock(); | 110 | rcu_read_lock(); |
| 103 | sta = sta_info_get(sdata, mgmt->sa); | 111 | sta = sta_info_get(sdata, mgmt->sa); |
| @@ -117,14 +125,6 @@ static void mesh_sync_offset_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, | |||
| 117 | goto no_sync; | 125 | goto no_sync; |
| 118 | } | 126 | } |
| 119 | 127 | ||
| 120 | if (ieee80211_have_rx_timestamp(rx_status)) | ||
| 121 | /* time when timestamp field was received */ | ||
| 122 | t_r = ieee80211_calculate_rx_timestamp(local, rx_status, | ||
| 123 | 24 + 12 + | ||
| 124 | elems->total_len + | ||
| 125 | FCS_LEN, | ||
| 126 | 24); | ||
| 127 | |||
| 128 | /* Timing offset calculation (see 13.13.2.2.2) */ | 128 | /* Timing offset calculation (see 13.13.2.2.2) */ |
| 129 | t_t = le64_to_cpu(mgmt->u.beacon.timestamp); | 129 | t_t = le64_to_cpu(mgmt->u.beacon.timestamp); |
| 130 | sta->t_offset = t_t - t_r; | 130 | sta->t_offset = t_t - t_r; |
| @@ -164,12 +164,15 @@ no_sync: | |||
| 164 | rcu_read_unlock(); | 164 | rcu_read_unlock(); |
| 165 | } | 165 | } |
| 166 | 166 | ||
| 167 | static void mesh_sync_offset_adjust_tbtt(struct ieee80211_sub_if_data *sdata) | 167 | static void mesh_sync_offset_adjust_tbtt(struct ieee80211_sub_if_data *sdata, |
| 168 | struct beacon_data *beacon) | ||
| 168 | { | 169 | { |
| 169 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | 170 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
| 171 | u8 cap; | ||
| 170 | 172 | ||
| 171 | WARN_ON(ifmsh->mesh_sp_id != IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET); | 173 | WARN_ON(ifmsh->mesh_sp_id != IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET); |
| 172 | BUG_ON(!rcu_read_lock_held()); | 174 | BUG_ON(!rcu_read_lock_held()); |
| 175 | cap = beacon->meshconf->meshconf_cap; | ||
| 173 | 176 | ||
| 174 | spin_lock_bh(&ifmsh->sync_offset_lock); | 177 | spin_lock_bh(&ifmsh->sync_offset_lock); |
| 175 | 178 | ||
| @@ -194,6 +197,10 @@ static void mesh_sync_offset_adjust_tbtt(struct ieee80211_sub_if_data *sdata) | |||
| 194 | ifmsh->adjusting_tbtt = false; | 197 | ifmsh->adjusting_tbtt = false; |
| 195 | } | 198 | } |
| 196 | spin_unlock_bh(&ifmsh->sync_offset_lock); | 199 | spin_unlock_bh(&ifmsh->sync_offset_lock); |
| 200 | |||
| 201 | beacon->meshconf->meshconf_cap = ifmsh->adjusting_tbtt ? | ||
| 202 | IEEE80211_MESHCONF_CAPAB_TBTT_ADJUSTING | cap : | ||
| 203 | ~IEEE80211_MESHCONF_CAPAB_TBTT_ADJUSTING & cap; | ||
| 197 | } | 204 | } |
| 198 | 205 | ||
| 199 | static const struct sync_method sync_methods[] = { | 206 | static const struct sync_method sync_methods[] = { |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index b3a3ce316656..fc1d82465b3c 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
| @@ -330,6 +330,16 @@ static int ieee80211_config_bw(struct ieee80211_sub_if_data *sdata, | |||
| 330 | if (WARN_ON_ONCE(!sta)) | 330 | if (WARN_ON_ONCE(!sta)) |
| 331 | return -EINVAL; | 331 | return -EINVAL; |
| 332 | 332 | ||
| 333 | /* | ||
| 334 | * if bss configuration changed store the new one - | ||
| 335 | * this may be applicable even if channel is identical | ||
| 336 | */ | ||
| 337 | ht_opmode = le16_to_cpu(ht_oper->operation_mode); | ||
| 338 | if (sdata->vif.bss_conf.ht_operation_mode != ht_opmode) { | ||
| 339 | *changed |= BSS_CHANGED_HT; | ||
| 340 | sdata->vif.bss_conf.ht_operation_mode = ht_opmode; | ||
| 341 | } | ||
| 342 | |||
| 333 | chan = sdata->vif.bss_conf.chandef.chan; | 343 | chan = sdata->vif.bss_conf.chandef.chan; |
| 334 | sband = local->hw.wiphy->bands[chan->band]; | 344 | sband = local->hw.wiphy->bands[chan->band]; |
| 335 | 345 | ||
| @@ -416,14 +426,6 @@ static int ieee80211_config_bw(struct ieee80211_sub_if_data *sdata, | |||
| 416 | IEEE80211_RC_BW_CHANGED); | 426 | IEEE80211_RC_BW_CHANGED); |
| 417 | } | 427 | } |
| 418 | 428 | ||
| 419 | ht_opmode = le16_to_cpu(ht_oper->operation_mode); | ||
| 420 | |||
| 421 | /* if bss configuration changed store the new one */ | ||
| 422 | if (sdata->vif.bss_conf.ht_operation_mode != ht_opmode) { | ||
| 423 | *changed |= BSS_CHANGED_HT; | ||
| 424 | sdata->vif.bss_conf.ht_operation_mode = ht_opmode; | ||
| 425 | } | ||
| 426 | |||
| 427 | return 0; | 429 | return 0; |
| 428 | } | 430 | } |
| 429 | 431 | ||
| @@ -714,7 +716,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) | |||
| 714 | } | 716 | } |
| 715 | 717 | ||
| 716 | /* if present, add any custom IEs that go before HT */ | 718 | /* if present, add any custom IEs that go before HT */ |
| 717 | if (assoc_data->ie_len && assoc_data->ie) { | 719 | if (assoc_data->ie_len) { |
| 718 | static const u8 before_ht[] = { | 720 | static const u8 before_ht[] = { |
| 719 | WLAN_EID_SSID, | 721 | WLAN_EID_SSID, |
| 720 | WLAN_EID_SUPP_RATES, | 722 | WLAN_EID_SUPP_RATES, |
| @@ -748,7 +750,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) | |||
| 748 | &assoc_data->ap_vht_cap); | 750 | &assoc_data->ap_vht_cap); |
| 749 | 751 | ||
| 750 | /* if present, add any custom non-vendor IEs that go after HT */ | 752 | /* if present, add any custom non-vendor IEs that go after HT */ |
| 751 | if (assoc_data->ie_len && assoc_data->ie) { | 753 | if (assoc_data->ie_len) { |
| 752 | noffset = ieee80211_ie_split_vendor(assoc_data->ie, | 754 | noffset = ieee80211_ie_split_vendor(assoc_data->ie, |
| 753 | assoc_data->ie_len, | 755 | assoc_data->ie_len, |
| 754 | offset); | 756 | offset); |
| @@ -779,7 +781,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) | |||
| 779 | } | 781 | } |
| 780 | 782 | ||
| 781 | /* add any remaining custom (i.e. vendor specific here) IEs */ | 783 | /* add any remaining custom (i.e. vendor specific here) IEs */ |
| 782 | if (assoc_data->ie_len && assoc_data->ie) { | 784 | if (assoc_data->ie_len) { |
| 783 | noffset = assoc_data->ie_len; | 785 | noffset = assoc_data->ie_len; |
| 784 | pos = skb_put(skb, noffset - offset); | 786 | pos = skb_put(skb, noffset - offset); |
| 785 | memcpy(pos, assoc_data->ie + offset, noffset - offset); | 787 | memcpy(pos, assoc_data->ie + offset, noffset - offset); |
| @@ -886,8 +888,9 @@ static void ieee80211_chswitch_work(struct work_struct *work) | |||
| 886 | if (!ifmgd->associated) | 888 | if (!ifmgd->associated) |
| 887 | goto out; | 889 | goto out; |
| 888 | 890 | ||
| 889 | ret = ieee80211_vif_change_channel(sdata, &local->csa_chandef, | 891 | mutex_lock(&local->mtx); |
| 890 | &changed); | 892 | ret = ieee80211_vif_change_channel(sdata, &changed); |
| 893 | mutex_unlock(&local->mtx); | ||
| 891 | if (ret) { | 894 | if (ret) { |
| 892 | sdata_info(sdata, | 895 | sdata_info(sdata, |
| 893 | "vif channel switch failed, disconnecting\n"); | 896 | "vif channel switch failed, disconnecting\n"); |
| @@ -897,7 +900,7 @@ static void ieee80211_chswitch_work(struct work_struct *work) | |||
| 897 | } | 900 | } |
| 898 | 901 | ||
| 899 | if (!local->use_chanctx) { | 902 | if (!local->use_chanctx) { |
| 900 | local->_oper_chandef = local->csa_chandef; | 903 | local->_oper_chandef = sdata->csa_chandef; |
| 901 | /* Call "hw_config" only if doing sw channel switch. | 904 | /* Call "hw_config" only if doing sw channel switch. |
| 902 | * Otherwise update the channel directly | 905 | * Otherwise update the channel directly |
| 903 | */ | 906 | */ |
| @@ -908,7 +911,7 @@ static void ieee80211_chswitch_work(struct work_struct *work) | |||
| 908 | } | 911 | } |
| 909 | 912 | ||
| 910 | /* XXX: shouldn't really modify cfg80211-owned data! */ | 913 | /* XXX: shouldn't really modify cfg80211-owned data! */ |
| 911 | ifmgd->associated->channel = local->csa_chandef.chan; | 914 | ifmgd->associated->channel = sdata->csa_chandef.chan; |
| 912 | 915 | ||
| 913 | /* XXX: wait for a beacon first? */ | 916 | /* XXX: wait for a beacon first? */ |
| 914 | ieee80211_wake_queues_by_reason(&local->hw, | 917 | ieee80211_wake_queues_by_reason(&local->hw, |
| @@ -1035,7 +1038,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
| 1035 | } | 1038 | } |
| 1036 | mutex_unlock(&local->chanctx_mtx); | 1039 | mutex_unlock(&local->chanctx_mtx); |
| 1037 | 1040 | ||
| 1038 | local->csa_chandef = csa_ie.chandef; | 1041 | sdata->csa_chandef = csa_ie.chandef; |
| 1039 | 1042 | ||
| 1040 | if (csa_ie.mode) | 1043 | if (csa_ie.mode) |
| 1041 | ieee80211_stop_queues_by_reason(&local->hw, | 1044 | ieee80211_stop_queues_by_reason(&local->hw, |
| @@ -1398,10 +1401,16 @@ void ieee80211_dfs_cac_timer_work(struct work_struct *work) | |||
| 1398 | struct ieee80211_sub_if_data *sdata = | 1401 | struct ieee80211_sub_if_data *sdata = |
| 1399 | container_of(delayed_work, struct ieee80211_sub_if_data, | 1402 | container_of(delayed_work, struct ieee80211_sub_if_data, |
| 1400 | dfs_cac_timer_work); | 1403 | dfs_cac_timer_work); |
| 1404 | struct cfg80211_chan_def chandef = sdata->vif.bss_conf.chandef; | ||
| 1401 | 1405 | ||
| 1402 | ieee80211_vif_release_channel(sdata); | 1406 | mutex_lock(&sdata->local->mtx); |
| 1403 | 1407 | if (sdata->wdev.cac_started) { | |
| 1404 | cfg80211_cac_event(sdata->dev, NL80211_RADAR_CAC_FINISHED, GFP_KERNEL); | 1408 | ieee80211_vif_release_channel(sdata); |
| 1409 | cfg80211_cac_event(sdata->dev, &chandef, | ||
| 1410 | NL80211_RADAR_CAC_FINISHED, | ||
| 1411 | GFP_KERNEL); | ||
| 1412 | } | ||
| 1413 | mutex_unlock(&sdata->local->mtx); | ||
| 1405 | } | 1414 | } |
| 1406 | 1415 | ||
| 1407 | /* MLME */ | 1416 | /* MLME */ |
| @@ -1695,7 +1704,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
| 1695 | memset(ifmgd->bssid, 0, ETH_ALEN); | 1704 | memset(ifmgd->bssid, 0, ETH_ALEN); |
| 1696 | 1705 | ||
| 1697 | /* remove AP and TDLS peers */ | 1706 | /* remove AP and TDLS peers */ |
| 1698 | sta_info_flush_defer(sdata); | 1707 | sta_info_flush(sdata); |
| 1699 | 1708 | ||
| 1700 | /* finally reset all BSS / config parameters */ | 1709 | /* finally reset all BSS / config parameters */ |
| 1701 | changed |= ieee80211_reset_erp_info(sdata); | 1710 | changed |= ieee80211_reset_erp_info(sdata); |
| @@ -1744,7 +1753,11 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
| 1744 | ifmgd->have_beacon = false; | 1753 | ifmgd->have_beacon = false; |
| 1745 | 1754 | ||
| 1746 | ifmgd->flags = 0; | 1755 | ifmgd->flags = 0; |
| 1756 | mutex_lock(&local->mtx); | ||
| 1747 | ieee80211_vif_release_channel(sdata); | 1757 | ieee80211_vif_release_channel(sdata); |
| 1758 | mutex_unlock(&local->mtx); | ||
| 1759 | |||
| 1760 | sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM; | ||
| 1748 | } | 1761 | } |
| 1749 | 1762 | ||
| 1750 | void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, | 1763 | void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, |
| @@ -2065,7 +2078,9 @@ static void ieee80211_destroy_auth_data(struct ieee80211_sub_if_data *sdata, | |||
| 2065 | memset(sdata->u.mgd.bssid, 0, ETH_ALEN); | 2078 | memset(sdata->u.mgd.bssid, 0, ETH_ALEN); |
| 2066 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID); | 2079 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID); |
| 2067 | sdata->u.mgd.flags = 0; | 2080 | sdata->u.mgd.flags = 0; |
| 2081 | mutex_lock(&sdata->local->mtx); | ||
| 2068 | ieee80211_vif_release_channel(sdata); | 2082 | ieee80211_vif_release_channel(sdata); |
| 2083 | mutex_unlock(&sdata->local->mtx); | ||
| 2069 | } | 2084 | } |
| 2070 | 2085 | ||
| 2071 | cfg80211_put_bss(sdata->local->hw.wiphy, auth_data->bss); | 2086 | cfg80211_put_bss(sdata->local->hw.wiphy, auth_data->bss); |
| @@ -2314,7 +2329,9 @@ static void ieee80211_destroy_assoc_data(struct ieee80211_sub_if_data *sdata, | |||
| 2314 | memset(sdata->u.mgd.bssid, 0, ETH_ALEN); | 2329 | memset(sdata->u.mgd.bssid, 0, ETH_ALEN); |
| 2315 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID); | 2330 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID); |
| 2316 | sdata->u.mgd.flags = 0; | 2331 | sdata->u.mgd.flags = 0; |
| 2332 | mutex_lock(&sdata->local->mtx); | ||
| 2317 | ieee80211_vif_release_channel(sdata); | 2333 | ieee80211_vif_release_channel(sdata); |
| 2334 | mutex_unlock(&sdata->local->mtx); | ||
| 2318 | } | 2335 | } |
| 2319 | 2336 | ||
| 2320 | kfree(assoc_data); | 2337 | kfree(assoc_data); |
| @@ -3665,6 +3682,7 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, | |||
| 3665 | /* will change later if needed */ | 3682 | /* will change later if needed */ |
| 3666 | sdata->smps_mode = IEEE80211_SMPS_OFF; | 3683 | sdata->smps_mode = IEEE80211_SMPS_OFF; |
| 3667 | 3684 | ||
| 3685 | mutex_lock(&local->mtx); | ||
| 3668 | /* | 3686 | /* |
| 3669 | * If this fails (possibly due to channel context sharing | 3687 | * If this fails (possibly due to channel context sharing |
| 3670 | * on incompatible channels, e.g. 80+80 and 160 sharing the | 3688 | * on incompatible channels, e.g. 80+80 and 160 sharing the |
| @@ -3676,13 +3694,15 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, | |||
| 3676 | /* don't downgrade for 5 and 10 MHz channels, though. */ | 3694 | /* don't downgrade for 5 and 10 MHz channels, though. */ |
| 3677 | if (chandef.width == NL80211_CHAN_WIDTH_5 || | 3695 | if (chandef.width == NL80211_CHAN_WIDTH_5 || |
| 3678 | chandef.width == NL80211_CHAN_WIDTH_10) | 3696 | chandef.width == NL80211_CHAN_WIDTH_10) |
| 3679 | return ret; | 3697 | goto out; |
| 3680 | 3698 | ||
| 3681 | while (ret && chandef.width != NL80211_CHAN_WIDTH_20_NOHT) { | 3699 | while (ret && chandef.width != NL80211_CHAN_WIDTH_20_NOHT) { |
| 3682 | ifmgd->flags |= ieee80211_chandef_downgrade(&chandef); | 3700 | ifmgd->flags |= ieee80211_chandef_downgrade(&chandef); |
| 3683 | ret = ieee80211_vif_use_channel(sdata, &chandef, | 3701 | ret = ieee80211_vif_use_channel(sdata, &chandef, |
| 3684 | IEEE80211_CHANCTX_SHARED); | 3702 | IEEE80211_CHANCTX_SHARED); |
| 3685 | } | 3703 | } |
| 3704 | out: | ||
| 3705 | mutex_unlock(&local->mtx); | ||
| 3686 | return ret; | 3706 | return ret; |
| 3687 | } | 3707 | } |
| 3688 | 3708 | ||
| @@ -4191,6 +4211,8 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
| 4191 | 4211 | ||
| 4192 | sdata->control_port_protocol = req->crypto.control_port_ethertype; | 4212 | sdata->control_port_protocol = req->crypto.control_port_ethertype; |
| 4193 | sdata->control_port_no_encrypt = req->crypto.control_port_no_encrypt; | 4213 | sdata->control_port_no_encrypt = req->crypto.control_port_no_encrypt; |
| 4214 | sdata->encrypt_headroom = ieee80211_cs_headroom(local, &req->crypto, | ||
| 4215 | sdata->vif.type); | ||
| 4194 | 4216 | ||
| 4195 | /* kick off associate process */ | 4217 | /* kick off associate process */ |
| 4196 | 4218 | ||
diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index 340126204343..af64fb8e8add 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c | |||
| @@ -37,9 +37,8 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) | |||
| 37 | IEEE80211_MAX_QUEUE_MAP, | 37 | IEEE80211_MAX_QUEUE_MAP, |
| 38 | IEEE80211_QUEUE_STOP_REASON_SUSPEND); | 38 | IEEE80211_QUEUE_STOP_REASON_SUSPEND); |
| 39 | 39 | ||
| 40 | /* flush out all packets and station cleanup call_rcu()s */ | 40 | /* flush out all packets */ |
| 41 | synchronize_net(); | 41 | synchronize_net(); |
| 42 | rcu_barrier(); | ||
| 43 | 42 | ||
| 44 | ieee80211_flush_queues(local, NULL); | 43 | ieee80211_flush_queues(local, NULL); |
| 45 | 44 | ||
diff --git a/net/mac80211/rate.h b/net/mac80211/rate.h index 505bc0dea074..b95e16c07081 100644 --- a/net/mac80211/rate.h +++ b/net/mac80211/rate.h | |||
| @@ -54,6 +54,8 @@ static inline void rate_control_rate_init(struct sta_info *sta) | |||
| 54 | struct ieee80211_supported_band *sband; | 54 | struct ieee80211_supported_band *sband; |
| 55 | struct ieee80211_chanctx_conf *chanctx_conf; | 55 | struct ieee80211_chanctx_conf *chanctx_conf; |
| 56 | 56 | ||
| 57 | ieee80211_sta_set_rx_nss(sta); | ||
| 58 | |||
| 57 | if (!ref) | 59 | if (!ref) |
| 58 | return; | 60 | return; |
| 59 | 61 | ||
| @@ -67,8 +69,6 @@ static inline void rate_control_rate_init(struct sta_info *sta) | |||
| 67 | 69 | ||
| 68 | sband = local->hw.wiphy->bands[chanctx_conf->def.chan->band]; | 70 | sband = local->hw.wiphy->bands[chanctx_conf->def.chan->band]; |
| 69 | 71 | ||
| 70 | ieee80211_sta_set_rx_nss(sta); | ||
| 71 | |||
| 72 | ref->ops->rate_init(ref->priv, sband, &chanctx_conf->def, ista, | 72 | ref->ops->rate_init(ref->priv, sband, &chanctx_conf->def, ista, |
| 73 | priv_sta); | 73 | priv_sta); |
| 74 | rcu_read_unlock(); | 74 | rcu_read_unlock(); |
diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c index 7fa1b36e6202..f3d88b0c054c 100644 --- a/net/mac80211/rc80211_minstrel.c +++ b/net/mac80211/rc80211_minstrel.c | |||
| @@ -135,7 +135,7 @@ minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi) | |||
| 135 | u32 usecs; | 135 | u32 usecs; |
| 136 | int i; | 136 | int i; |
| 137 | 137 | ||
| 138 | for (i=0; i < MAX_THR_RATES; i++) | 138 | for (i = 0; i < MAX_THR_RATES; i++) |
| 139 | tmp_tp_rate[i] = 0; | 139 | tmp_tp_rate[i] = 0; |
| 140 | 140 | ||
| 141 | for (i = 0; i < mi->n_rates; i++) { | 141 | for (i = 0; i < mi->n_rates; i++) { |
| @@ -190,7 +190,7 @@ minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi) | |||
| 190 | * choose the maximum throughput rate as max_prob_rate | 190 | * choose the maximum throughput rate as max_prob_rate |
| 191 | * (2) if all success probabilities < 95%, the rate with | 191 | * (2) if all success probabilities < 95%, the rate with |
| 192 | * highest success probability is choosen as max_prob_rate */ | 192 | * highest success probability is choosen as max_prob_rate */ |
| 193 | if (mr->probability >= MINSTREL_FRAC(95,100)) { | 193 | if (mr->probability >= MINSTREL_FRAC(95, 100)) { |
| 194 | if (mr->cur_tp >= mi->r[tmp_prob_rate].cur_tp) | 194 | if (mr->cur_tp >= mi->r[tmp_prob_rate].cur_tp) |
| 195 | tmp_prob_rate = i; | 195 | tmp_prob_rate = i; |
| 196 | } else { | 196 | } else { |
| @@ -220,7 +220,7 @@ minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi) | |||
| 220 | 220 | ||
| 221 | static void | 221 | static void |
| 222 | minstrel_tx_status(void *priv, struct ieee80211_supported_band *sband, | 222 | minstrel_tx_status(void *priv, struct ieee80211_supported_band *sband, |
| 223 | struct ieee80211_sta *sta, void *priv_sta, | 223 | struct ieee80211_sta *sta, void *priv_sta, |
| 224 | struct sk_buff *skb) | 224 | struct sk_buff *skb) |
| 225 | { | 225 | { |
| 226 | struct minstrel_priv *mp = priv; | 226 | struct minstrel_priv *mp = priv; |
| @@ -260,7 +260,7 @@ minstrel_tx_status(void *priv, struct ieee80211_supported_band *sband, | |||
| 260 | 260 | ||
| 261 | static inline unsigned int | 261 | static inline unsigned int |
| 262 | minstrel_get_retry_count(struct minstrel_rate *mr, | 262 | minstrel_get_retry_count(struct minstrel_rate *mr, |
| 263 | struct ieee80211_tx_info *info) | 263 | struct ieee80211_tx_info *info) |
| 264 | { | 264 | { |
| 265 | unsigned int retry = mr->adjusted_retry_count; | 265 | unsigned int retry = mr->adjusted_retry_count; |
| 266 | 266 | ||
| @@ -422,10 +422,9 @@ init_sample_table(struct minstrel_sta_info *mi) | |||
| 422 | memset(mi->sample_table, 0xff, SAMPLE_COLUMNS * mi->n_rates); | 422 | memset(mi->sample_table, 0xff, SAMPLE_COLUMNS * mi->n_rates); |
| 423 | 423 | ||
| 424 | for (col = 0; col < SAMPLE_COLUMNS; col++) { | 424 | for (col = 0; col < SAMPLE_COLUMNS; col++) { |
| 425 | prandom_bytes(rnd, sizeof(rnd)); | ||
| 425 | for (i = 0; i < mi->n_rates; i++) { | 426 | for (i = 0; i < mi->n_rates; i++) { |
| 426 | get_random_bytes(rnd, sizeof(rnd)); | ||
| 427 | new_idx = (i + rnd[i & 7]) % mi->n_rates; | 427 | new_idx = (i + rnd[i & 7]) % mi->n_rates; |
| 428 | |||
| 429 | while (SAMPLE_TBL(mi, new_idx, col) != 0xff) | 428 | while (SAMPLE_TBL(mi, new_idx, col) != 0xff) |
| 430 | new_idx = (new_idx + 1) % mi->n_rates; | 429 | new_idx = (new_idx + 1) % mi->n_rates; |
| 431 | 430 | ||
diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c index 4096ff6cc24f..c1b5b73c5b91 100644 --- a/net/mac80211/rc80211_minstrel_ht.c +++ b/net/mac80211/rc80211_minstrel_ht.c | |||
| @@ -63,7 +63,7 @@ | |||
| 63 | 63 | ||
| 64 | #define CCK_DURATION(_bitrate, _short, _len) \ | 64 | #define CCK_DURATION(_bitrate, _short, _len) \ |
| 65 | (1000 * (10 /* SIFS */ + \ | 65 | (1000 * (10 /* SIFS */ + \ |
| 66 | (_short ? 72 + 24 : 144 + 48 ) + \ | 66 | (_short ? 72 + 24 : 144 + 48) + \ |
| 67 | (8 * (_len + 4) * 10) / (_bitrate))) | 67 | (8 * (_len + 4) * 10) / (_bitrate))) |
| 68 | 68 | ||
| 69 | #define CCK_ACK_DURATION(_bitrate, _short) \ | 69 | #define CCK_ACK_DURATION(_bitrate, _short) \ |
| @@ -135,7 +135,7 @@ minstrel_ht_update_rates(struct minstrel_priv *mp, struct minstrel_ht_sta *mi); | |||
| 135 | static int | 135 | static int |
| 136 | minstrel_ht_get_group_idx(struct ieee80211_tx_rate *rate) | 136 | minstrel_ht_get_group_idx(struct ieee80211_tx_rate *rate) |
| 137 | { | 137 | { |
| 138 | return GROUP_IDX((rate->idx / MCS_GROUP_RATES) + 1, | 138 | return GROUP_IDX((rate->idx / 8) + 1, |
| 139 | !!(rate->flags & IEEE80211_TX_RC_SHORT_GI), | 139 | !!(rate->flags & IEEE80211_TX_RC_SHORT_GI), |
| 140 | !!(rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)); | 140 | !!(rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)); |
| 141 | } | 141 | } |
| @@ -148,7 +148,7 @@ minstrel_ht_get_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, | |||
| 148 | 148 | ||
| 149 | if (rate->flags & IEEE80211_TX_RC_MCS) { | 149 | if (rate->flags & IEEE80211_TX_RC_MCS) { |
| 150 | group = minstrel_ht_get_group_idx(rate); | 150 | group = minstrel_ht_get_group_idx(rate); |
| 151 | idx = rate->idx % MCS_GROUP_RATES; | 151 | idx = rate->idx % 8; |
| 152 | } else { | 152 | } else { |
| 153 | group = MINSTREL_CCK_GROUP; | 153 | group = MINSTREL_CCK_GROUP; |
| 154 | 154 | ||
| @@ -637,8 +637,7 @@ minstrel_ht_set_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, | |||
| 637 | idx = mp->cck_rates[index % ARRAY_SIZE(mp->cck_rates)]; | 637 | idx = mp->cck_rates[index % ARRAY_SIZE(mp->cck_rates)]; |
| 638 | flags = 0; | 638 | flags = 0; |
| 639 | } else { | 639 | } else { |
| 640 | idx = index % MCS_GROUP_RATES + | 640 | idx = index % MCS_GROUP_RATES + (group->streams - 1) * 8; |
| 641 | (group->streams - 1) * MCS_GROUP_RATES; | ||
| 642 | flags = IEEE80211_TX_RC_MCS | group->flags; | 641 | flags = IEEE80211_TX_RC_MCS | group->flags; |
| 643 | } | 642 | } |
| 644 | 643 | ||
| @@ -702,12 +701,16 @@ minstrel_get_sample_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) | |||
| 702 | if (!mi->sample_tries) | 701 | if (!mi->sample_tries) |
| 703 | return -1; | 702 | return -1; |
| 704 | 703 | ||
| 705 | mg = &mi->groups[mi->sample_group]; | 704 | sample_group = mi->sample_group; |
| 705 | mg = &mi->groups[sample_group]; | ||
| 706 | sample_idx = sample_table[mg->column][mg->index]; | 706 | sample_idx = sample_table[mg->column][mg->index]; |
| 707 | minstrel_next_sample_idx(mi); | ||
| 708 | |||
| 709 | if (!(mg->supported & BIT(sample_idx))) | ||
| 710 | return -1; | ||
| 711 | |||
| 707 | mr = &mg->rates[sample_idx]; | 712 | mr = &mg->rates[sample_idx]; |
| 708 | sample_group = mi->sample_group; | ||
| 709 | sample_idx += sample_group * MCS_GROUP_RATES; | 713 | sample_idx += sample_group * MCS_GROUP_RATES; |
| 710 | minstrel_next_sample_idx(mi); | ||
| 711 | 714 | ||
| 712 | /* | 715 | /* |
| 713 | * Sampling might add some overhead (RTS, no aggregation) | 716 | * Sampling might add some overhead (RTS, no aggregation) |
| @@ -818,7 +821,7 @@ minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, | |||
| 818 | } | 821 | } |
| 819 | 822 | ||
| 820 | rate->idx = sample_idx % MCS_GROUP_RATES + | 823 | rate->idx = sample_idx % MCS_GROUP_RATES + |
| 821 | (sample_group->streams - 1) * MCS_GROUP_RATES; | 824 | (sample_group->streams - 1) * 8; |
| 822 | rate->flags = IEEE80211_TX_RC_MCS | sample_group->flags; | 825 | rate->flags = IEEE80211_TX_RC_MCS | sample_group->flags; |
| 823 | } | 826 | } |
| 824 | 827 | ||
| @@ -1053,10 +1056,9 @@ init_sample_table(void) | |||
| 1053 | 1056 | ||
| 1054 | memset(sample_table, 0xff, sizeof(sample_table)); | 1057 | memset(sample_table, 0xff, sizeof(sample_table)); |
| 1055 | for (col = 0; col < SAMPLE_COLUMNS; col++) { | 1058 | for (col = 0; col < SAMPLE_COLUMNS; col++) { |
| 1059 | prandom_bytes(rnd, sizeof(rnd)); | ||
| 1056 | for (i = 0; i < MCS_GROUP_RATES; i++) { | 1060 | for (i = 0; i < MCS_GROUP_RATES; i++) { |
| 1057 | get_random_bytes(rnd, sizeof(rnd)); | ||
| 1058 | new_idx = (i + rnd[i]) % MCS_GROUP_RATES; | 1061 | new_idx = (i + rnd[i]) % MCS_GROUP_RATES; |
| 1059 | |||
| 1060 | while (sample_table[col][new_idx] != 0xff) | 1062 | while (sample_table[col][new_idx] != 0xff) |
| 1061 | new_idx = (new_idx + 1) % MCS_GROUP_RATES; | 1063 | new_idx = (new_idx + 1) % MCS_GROUP_RATES; |
| 1062 | 1064 | ||
diff --git a/net/mac80211/rc80211_minstrel_ht_debugfs.c b/net/mac80211/rc80211_minstrel_ht_debugfs.c index df44a5ad8270..3e7d793de0c3 100644 --- a/net/mac80211/rc80211_minstrel_ht_debugfs.c +++ b/net/mac80211/rc80211_minstrel_ht_debugfs.c | |||
| @@ -54,8 +54,7 @@ minstrel_ht_stats_dump(struct minstrel_ht_sta *mi, int i, char *p) | |||
| 54 | int r = bitrates[j % 4]; | 54 | int r = bitrates[j % 4]; |
| 55 | p += sprintf(p, " %2u.%1uM", r / 10, r % 10); | 55 | p += sprintf(p, " %2u.%1uM", r / 10, r % 10); |
| 56 | } else { | 56 | } else { |
| 57 | p += sprintf(p, " MCS%-2u", (mg->streams - 1) * | 57 | p += sprintf(p, " MCS%-2u", (mg->streams - 1) * 8 + j); |
| 58 | MCS_GROUP_RATES + j); | ||
| 59 | } | 58 | } |
| 60 | 59 | ||
| 61 | tp = mr->cur_tp / 10; | 60 | tp = mr->cur_tp / 10; |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 2b0debb0422b..c24ca0d0f469 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
| @@ -638,6 +638,27 @@ static int ieee80211_get_mmie_keyidx(struct sk_buff *skb) | |||
| 638 | return le16_to_cpu(mmie->key_id); | 638 | return le16_to_cpu(mmie->key_id); |
| 639 | } | 639 | } |
| 640 | 640 | ||
| 641 | static int iwl80211_get_cs_keyid(const struct ieee80211_cipher_scheme *cs, | ||
| 642 | struct sk_buff *skb) | ||
| 643 | { | ||
| 644 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | ||
| 645 | __le16 fc; | ||
| 646 | int hdrlen; | ||
| 647 | u8 keyid; | ||
| 648 | |||
| 649 | fc = hdr->frame_control; | ||
| 650 | hdrlen = ieee80211_hdrlen(fc); | ||
| 651 | |||
| 652 | if (skb->len < hdrlen + cs->hdr_len) | ||
| 653 | return -EINVAL; | ||
| 654 | |||
| 655 | skb_copy_bits(skb, hdrlen + cs->key_idx_off, &keyid, 1); | ||
| 656 | keyid &= cs->key_idx_mask; | ||
| 657 | keyid >>= cs->key_idx_shift; | ||
| 658 | |||
| 659 | return keyid; | ||
| 660 | } | ||
| 661 | |||
| 641 | static ieee80211_rx_result ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) | 662 | static ieee80211_rx_result ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) |
| 642 | { | 663 | { |
| 643 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; | 664 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; |
| @@ -729,9 +750,7 @@ static void ieee80211_release_reorder_frames(struct ieee80211_sub_if_data *sdata | |||
| 729 | lockdep_assert_held(&tid_agg_rx->reorder_lock); | 750 | lockdep_assert_held(&tid_agg_rx->reorder_lock); |
| 730 | 751 | ||
| 731 | while (ieee80211_sn_less(tid_agg_rx->head_seq_num, head_seq_num)) { | 752 | while (ieee80211_sn_less(tid_agg_rx->head_seq_num, head_seq_num)) { |
| 732 | index = ieee80211_sn_sub(tid_agg_rx->head_seq_num, | 753 | index = tid_agg_rx->head_seq_num % tid_agg_rx->buf_size; |
| 733 | tid_agg_rx->ssn) % | ||
| 734 | tid_agg_rx->buf_size; | ||
| 735 | ieee80211_release_reorder_frame(sdata, tid_agg_rx, index, | 754 | ieee80211_release_reorder_frame(sdata, tid_agg_rx, index, |
| 736 | frames); | 755 | frames); |
| 737 | } | 756 | } |
| @@ -757,8 +776,7 @@ static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata, | |||
| 757 | lockdep_assert_held(&tid_agg_rx->reorder_lock); | 776 | lockdep_assert_held(&tid_agg_rx->reorder_lock); |
| 758 | 777 | ||
| 759 | /* release the buffer until next missing frame */ | 778 | /* release the buffer until next missing frame */ |
| 760 | index = ieee80211_sn_sub(tid_agg_rx->head_seq_num, | 779 | index = tid_agg_rx->head_seq_num % tid_agg_rx->buf_size; |
| 761 | tid_agg_rx->ssn) % tid_agg_rx->buf_size; | ||
| 762 | if (!tid_agg_rx->reorder_buf[index] && | 780 | if (!tid_agg_rx->reorder_buf[index] && |
| 763 | tid_agg_rx->stored_mpdu_num) { | 781 | tid_agg_rx->stored_mpdu_num) { |
| 764 | /* | 782 | /* |
| @@ -793,15 +811,11 @@ static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata, | |||
| 793 | } else while (tid_agg_rx->reorder_buf[index]) { | 811 | } else while (tid_agg_rx->reorder_buf[index]) { |
| 794 | ieee80211_release_reorder_frame(sdata, tid_agg_rx, index, | 812 | ieee80211_release_reorder_frame(sdata, tid_agg_rx, index, |
| 795 | frames); | 813 | frames); |
| 796 | index = ieee80211_sn_sub(tid_agg_rx->head_seq_num, | 814 | index = tid_agg_rx->head_seq_num % tid_agg_rx->buf_size; |
| 797 | tid_agg_rx->ssn) % | ||
| 798 | tid_agg_rx->buf_size; | ||
| 799 | } | 815 | } |
| 800 | 816 | ||
| 801 | if (tid_agg_rx->stored_mpdu_num) { | 817 | if (tid_agg_rx->stored_mpdu_num) { |
| 802 | j = index = ieee80211_sn_sub(tid_agg_rx->head_seq_num, | 818 | j = index = tid_agg_rx->head_seq_num % tid_agg_rx->buf_size; |
| 803 | tid_agg_rx->ssn) % | ||
| 804 | tid_agg_rx->buf_size; | ||
| 805 | 819 | ||
| 806 | for (; j != (index - 1) % tid_agg_rx->buf_size; | 820 | for (; j != (index - 1) % tid_agg_rx->buf_size; |
| 807 | j = (j + 1) % tid_agg_rx->buf_size) { | 821 | j = (j + 1) % tid_agg_rx->buf_size) { |
| @@ -861,8 +875,7 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_sub_if_data *sdata | |||
| 861 | 875 | ||
| 862 | /* Now the new frame is always in the range of the reordering buffer */ | 876 | /* Now the new frame is always in the range of the reordering buffer */ |
| 863 | 877 | ||
| 864 | index = ieee80211_sn_sub(mpdu_seq_num, | 878 | index = mpdu_seq_num % tid_agg_rx->buf_size; |
| 865 | tid_agg_rx->ssn) % tid_agg_rx->buf_size; | ||
| 866 | 879 | ||
| 867 | /* check if we already stored this frame */ | 880 | /* check if we already stored this frame */ |
| 868 | if (tid_agg_rx->reorder_buf[index]) { | 881 | if (tid_agg_rx->reorder_buf[index]) { |
| @@ -1369,6 +1382,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) | |||
| 1369 | struct ieee80211_key *sta_ptk = NULL; | 1382 | struct ieee80211_key *sta_ptk = NULL; |
| 1370 | int mmie_keyidx = -1; | 1383 | int mmie_keyidx = -1; |
| 1371 | __le16 fc; | 1384 | __le16 fc; |
| 1385 | const struct ieee80211_cipher_scheme *cs = NULL; | ||
| 1372 | 1386 | ||
| 1373 | /* | 1387 | /* |
| 1374 | * Key selection 101 | 1388 | * Key selection 101 |
| @@ -1406,11 +1420,19 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) | |||
| 1406 | 1420 | ||
| 1407 | /* start without a key */ | 1421 | /* start without a key */ |
| 1408 | rx->key = NULL; | 1422 | rx->key = NULL; |
| 1423 | fc = hdr->frame_control; | ||
| 1409 | 1424 | ||
| 1410 | if (rx->sta) | 1425 | if (rx->sta) { |
| 1411 | sta_ptk = rcu_dereference(rx->sta->ptk); | 1426 | int keyid = rx->sta->ptk_idx; |
| 1412 | 1427 | ||
| 1413 | fc = hdr->frame_control; | 1428 | if (ieee80211_has_protected(fc) && rx->sta->cipher_scheme) { |
| 1429 | cs = rx->sta->cipher_scheme; | ||
| 1430 | keyid = iwl80211_get_cs_keyid(cs, rx->skb); | ||
| 1431 | if (unlikely(keyid < 0)) | ||
| 1432 | return RX_DROP_UNUSABLE; | ||
| 1433 | } | ||
| 1434 | sta_ptk = rcu_dereference(rx->sta->ptk[keyid]); | ||
| 1435 | } | ||
| 1414 | 1436 | ||
| 1415 | if (!ieee80211_has_protected(fc)) | 1437 | if (!ieee80211_has_protected(fc)) |
| 1416 | mmie_keyidx = ieee80211_get_mmie_keyidx(rx->skb); | 1438 | mmie_keyidx = ieee80211_get_mmie_keyidx(rx->skb); |
| @@ -1472,6 +1494,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) | |||
| 1472 | return RX_CONTINUE; | 1494 | return RX_CONTINUE; |
| 1473 | } else { | 1495 | } else { |
| 1474 | u8 keyid; | 1496 | u8 keyid; |
| 1497 | |||
| 1475 | /* | 1498 | /* |
| 1476 | * The device doesn't give us the IV so we won't be | 1499 | * The device doesn't give us the IV so we won't be |
| 1477 | * able to look up the key. That's ok though, we | 1500 | * able to look up the key. That's ok though, we |
| @@ -1487,15 +1510,21 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) | |||
| 1487 | 1510 | ||
| 1488 | hdrlen = ieee80211_hdrlen(fc); | 1511 | hdrlen = ieee80211_hdrlen(fc); |
| 1489 | 1512 | ||
| 1490 | if (rx->skb->len < 8 + hdrlen) | 1513 | if (cs) { |
| 1491 | return RX_DROP_UNUSABLE; /* TODO: count this? */ | 1514 | keyidx = iwl80211_get_cs_keyid(cs, rx->skb); |
| 1492 | 1515 | ||
| 1493 | /* | 1516 | if (unlikely(keyidx < 0)) |
| 1494 | * no need to call ieee80211_wep_get_keyidx, | 1517 | return RX_DROP_UNUSABLE; |
| 1495 | * it verifies a bunch of things we've done already | 1518 | } else { |
| 1496 | */ | 1519 | if (rx->skb->len < 8 + hdrlen) |
| 1497 | skb_copy_bits(rx->skb, hdrlen + 3, &keyid, 1); | 1520 | return RX_DROP_UNUSABLE; /* TODO: count this? */ |
| 1498 | keyidx = keyid >> 6; | 1521 | /* |
| 1522 | * no need to call ieee80211_wep_get_keyidx, | ||
| 1523 | * it verifies a bunch of things we've done already | ||
| 1524 | */ | ||
| 1525 | skb_copy_bits(rx->skb, hdrlen + 3, &keyid, 1); | ||
| 1526 | keyidx = keyid >> 6; | ||
| 1527 | } | ||
| 1499 | 1528 | ||
| 1500 | /* check per-station GTK first, if multicast packet */ | 1529 | /* check per-station GTK first, if multicast packet */ |
| 1501 | if (is_multicast_ether_addr(hdr->addr1) && rx->sta) | 1530 | if (is_multicast_ether_addr(hdr->addr1) && rx->sta) |
| @@ -1543,11 +1572,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) | |||
| 1543 | result = ieee80211_crypto_aes_cmac_decrypt(rx); | 1572 | result = ieee80211_crypto_aes_cmac_decrypt(rx); |
| 1544 | break; | 1573 | break; |
| 1545 | default: | 1574 | default: |
| 1546 | /* | 1575 | result = ieee80211_crypto_hw_decrypt(rx); |
| 1547 | * We can reach here only with HW-only algorithms | ||
| 1548 | * but why didn't it decrypt the frame?! | ||
| 1549 | */ | ||
| 1550 | return RX_DROP_UNUSABLE; | ||
| 1551 | } | 1576 | } |
| 1552 | 1577 | ||
| 1553 | /* the hdr variable is invalid after the decrypt handlers */ | 1578 | /* the hdr variable is invalid after the decrypt handlers */ |
| @@ -1938,20 +1963,17 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx) | |||
| 1938 | } | 1963 | } |
| 1939 | } | 1964 | } |
| 1940 | 1965 | ||
| 1941 | if (skb) { | ||
| 1942 | int align __maybe_unused; | ||
| 1943 | |||
| 1944 | #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS | 1966 | #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS |
| 1945 | /* | 1967 | if (skb) { |
| 1946 | * 'align' will only take the values 0 or 2 here | 1968 | /* 'align' will only take the values 0 or 2 here since all |
| 1947 | * since all frames are required to be aligned | 1969 | * frames are required to be aligned to 2-byte boundaries |
| 1948 | * to 2-byte boundaries when being passed to | 1970 | * when being passed to mac80211; the code here works just |
| 1949 | * mac80211; the code here works just as well if | 1971 | * as well if that isn't true, but mac80211 assumes it can |
| 1950 | * that isn't true, but mac80211 assumes it can | 1972 | * access fields as 2-byte aligned (e.g. for ether_addr_equal) |
| 1951 | * access fields as 2-byte aligned (e.g. for | ||
| 1952 | * compare_ether_addr) | ||
| 1953 | */ | 1973 | */ |
| 1954 | align = ((unsigned long)(skb->data + sizeof(struct ethhdr))) & 3; | 1974 | int align; |
| 1975 | |||
| 1976 | align = (unsigned long)(skb->data + sizeof(struct ethhdr)) & 3; | ||
| 1955 | if (align) { | 1977 | if (align) { |
| 1956 | if (WARN_ON(skb_headroom(skb) < 3)) { | 1978 | if (WARN_ON(skb_headroom(skb) < 3)) { |
| 1957 | dev_kfree_skb(skb); | 1979 | dev_kfree_skb(skb); |
| @@ -1964,14 +1986,14 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx) | |||
| 1964 | skb_set_tail_pointer(skb, len); | 1986 | skb_set_tail_pointer(skb, len); |
| 1965 | } | 1987 | } |
| 1966 | } | 1988 | } |
| 1989 | } | ||
| 1967 | #endif | 1990 | #endif |
| 1968 | 1991 | ||
| 1969 | if (skb) { | 1992 | if (skb) { |
| 1970 | /* deliver to local stack */ | 1993 | /* deliver to local stack */ |
| 1971 | skb->protocol = eth_type_trans(skb, dev); | 1994 | skb->protocol = eth_type_trans(skb, dev); |
| 1972 | memset(skb->cb, 0, sizeof(skb->cb)); | 1995 | memset(skb->cb, 0, sizeof(skb->cb)); |
| 1973 | netif_receive_skb(skb); | 1996 | netif_receive_skb(skb); |
| 1974 | } | ||
| 1975 | } | 1997 | } |
| 1976 | 1998 | ||
| 1977 | if (xmit_skb) { | 1999 | if (xmit_skb) { |
| @@ -2057,7 +2079,6 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) | |||
| 2057 | struct ieee80211_sub_if_data *sdata = rx->sdata; | 2079 | struct ieee80211_sub_if_data *sdata = rx->sdata; |
| 2058 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); | 2080 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); |
| 2059 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | 2081 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
| 2060 | __le16 reason = cpu_to_le16(WLAN_REASON_MESH_PATH_NOFORWARD); | ||
| 2061 | u16 q, hdrlen; | 2082 | u16 q, hdrlen; |
| 2062 | 2083 | ||
| 2063 | hdr = (struct ieee80211_hdr *) skb->data; | 2084 | hdr = (struct ieee80211_hdr *) skb->data; |
| @@ -2165,7 +2186,9 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) | |||
| 2165 | } else { | 2186 | } else { |
| 2166 | /* unable to resolve next hop */ | 2187 | /* unable to resolve next hop */ |
| 2167 | mesh_path_error_tx(sdata, ifmsh->mshcfg.element_ttl, | 2188 | mesh_path_error_tx(sdata, ifmsh->mshcfg.element_ttl, |
| 2168 | fwd_hdr->addr3, 0, reason, fwd_hdr->addr2); | 2189 | fwd_hdr->addr3, 0, |
| 2190 | WLAN_REASON_MESH_PATH_NOFORWARD, | ||
| 2191 | fwd_hdr->addr2); | ||
| 2169 | IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_no_route); | 2192 | IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_no_route); |
| 2170 | kfree_skb(fwd_skb); | 2193 | kfree_skb(fwd_skb); |
| 2171 | return RX_DROP_MONITOR; | 2194 | return RX_DROP_MONITOR; |
| @@ -3053,8 +3076,8 @@ void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid) | |||
| 3053 | 3076 | ||
| 3054 | /* main receive path */ | 3077 | /* main receive path */ |
| 3055 | 3078 | ||
| 3056 | static int prepare_for_handlers(struct ieee80211_rx_data *rx, | 3079 | static bool prepare_for_handlers(struct ieee80211_rx_data *rx, |
| 3057 | struct ieee80211_hdr *hdr) | 3080 | struct ieee80211_hdr *hdr) |
| 3058 | { | 3081 | { |
| 3059 | struct ieee80211_sub_if_data *sdata = rx->sdata; | 3082 | struct ieee80211_sub_if_data *sdata = rx->sdata; |
| 3060 | struct sk_buff *skb = rx->skb; | 3083 | struct sk_buff *skb = rx->skb; |
| @@ -3065,29 +3088,29 @@ static int prepare_for_handlers(struct ieee80211_rx_data *rx, | |||
| 3065 | switch (sdata->vif.type) { | 3088 | switch (sdata->vif.type) { |
| 3066 | case NL80211_IFTYPE_STATION: | 3089 | case NL80211_IFTYPE_STATION: |
| 3067 | if (!bssid && !sdata->u.mgd.use_4addr) | 3090 | if (!bssid && !sdata->u.mgd.use_4addr) |
| 3068 | return 0; | 3091 | return false; |
| 3069 | if (!multicast && | 3092 | if (!multicast && |
| 3070 | !ether_addr_equal(sdata->vif.addr, hdr->addr1)) { | 3093 | !ether_addr_equal(sdata->vif.addr, hdr->addr1)) { |
| 3071 | if (!(sdata->dev->flags & IFF_PROMISC) || | 3094 | if (!(sdata->dev->flags & IFF_PROMISC) || |
| 3072 | sdata->u.mgd.use_4addr) | 3095 | sdata->u.mgd.use_4addr) |
| 3073 | return 0; | 3096 | return false; |
| 3074 | status->rx_flags &= ~IEEE80211_RX_RA_MATCH; | 3097 | status->rx_flags &= ~IEEE80211_RX_RA_MATCH; |
| 3075 | } | 3098 | } |
| 3076 | break; | 3099 | break; |
| 3077 | case NL80211_IFTYPE_ADHOC: | 3100 | case NL80211_IFTYPE_ADHOC: |
| 3078 | if (!bssid) | 3101 | if (!bssid) |
| 3079 | return 0; | 3102 | return false; |
| 3080 | if (ether_addr_equal(sdata->vif.addr, hdr->addr2) || | 3103 | if (ether_addr_equal(sdata->vif.addr, hdr->addr2) || |
| 3081 | ether_addr_equal(sdata->u.ibss.bssid, hdr->addr2)) | 3104 | ether_addr_equal(sdata->u.ibss.bssid, hdr->addr2)) |
| 3082 | return 0; | 3105 | return false; |
| 3083 | if (ieee80211_is_beacon(hdr->frame_control)) { | 3106 | if (ieee80211_is_beacon(hdr->frame_control)) { |
| 3084 | return 1; | 3107 | return true; |
| 3085 | } else if (!ieee80211_bssid_match(bssid, sdata->u.ibss.bssid)) { | 3108 | } else if (!ieee80211_bssid_match(bssid, sdata->u.ibss.bssid)) { |
| 3086 | return 0; | 3109 | return false; |
| 3087 | } else if (!multicast && | 3110 | } else if (!multicast && |
| 3088 | !ether_addr_equal(sdata->vif.addr, hdr->addr1)) { | 3111 | !ether_addr_equal(sdata->vif.addr, hdr->addr1)) { |
| 3089 | if (!(sdata->dev->flags & IFF_PROMISC)) | 3112 | if (!(sdata->dev->flags & IFF_PROMISC)) |
| 3090 | return 0; | 3113 | return false; |
| 3091 | status->rx_flags &= ~IEEE80211_RX_RA_MATCH; | 3114 | status->rx_flags &= ~IEEE80211_RX_RA_MATCH; |
| 3092 | } else if (!rx->sta) { | 3115 | } else if (!rx->sta) { |
| 3093 | int rate_idx; | 3116 | int rate_idx; |
| @@ -3103,7 +3126,7 @@ static int prepare_for_handlers(struct ieee80211_rx_data *rx, | |||
| 3103 | if (!multicast && | 3126 | if (!multicast && |
| 3104 | !ether_addr_equal(sdata->vif.addr, hdr->addr1)) { | 3127 | !ether_addr_equal(sdata->vif.addr, hdr->addr1)) { |
| 3105 | if (!(sdata->dev->flags & IFF_PROMISC)) | 3128 | if (!(sdata->dev->flags & IFF_PROMISC)) |
| 3106 | return 0; | 3129 | return false; |
| 3107 | 3130 | ||
| 3108 | status->rx_flags &= ~IEEE80211_RX_RA_MATCH; | 3131 | status->rx_flags &= ~IEEE80211_RX_RA_MATCH; |
| 3109 | } | 3132 | } |
| @@ -3112,7 +3135,7 @@ static int prepare_for_handlers(struct ieee80211_rx_data *rx, | |||
| 3112 | case NL80211_IFTYPE_AP: | 3135 | case NL80211_IFTYPE_AP: |
| 3113 | if (!bssid) { | 3136 | if (!bssid) { |
| 3114 | if (!ether_addr_equal(sdata->vif.addr, hdr->addr1)) | 3137 | if (!ether_addr_equal(sdata->vif.addr, hdr->addr1)) |
| 3115 | return 0; | 3138 | return false; |
| 3116 | } else if (!ieee80211_bssid_match(bssid, sdata->vif.addr)) { | 3139 | } else if (!ieee80211_bssid_match(bssid, sdata->vif.addr)) { |
| 3117 | /* | 3140 | /* |
| 3118 | * Accept public action frames even when the | 3141 | * Accept public action frames even when the |
| @@ -3122,26 +3145,26 @@ static int prepare_for_handlers(struct ieee80211_rx_data *rx, | |||
| 3122 | */ | 3145 | */ |
| 3123 | if (!multicast && | 3146 | if (!multicast && |
| 3124 | !ether_addr_equal(sdata->vif.addr, hdr->addr1)) | 3147 | !ether_addr_equal(sdata->vif.addr, hdr->addr1)) |
| 3125 | return 0; | 3148 | return false; |
| 3126 | if (ieee80211_is_public_action(hdr, skb->len)) | 3149 | if (ieee80211_is_public_action(hdr, skb->len)) |
| 3127 | return 1; | 3150 | return true; |
| 3128 | if (!ieee80211_is_beacon(hdr->frame_control)) | 3151 | if (!ieee80211_is_beacon(hdr->frame_control)) |
| 3129 | return 0; | 3152 | return false; |
| 3130 | status->rx_flags &= ~IEEE80211_RX_RA_MATCH; | 3153 | status->rx_flags &= ~IEEE80211_RX_RA_MATCH; |
| 3131 | } | 3154 | } |
| 3132 | break; | 3155 | break; |
| 3133 | case NL80211_IFTYPE_WDS: | 3156 | case NL80211_IFTYPE_WDS: |
| 3134 | if (bssid || !ieee80211_is_data(hdr->frame_control)) | 3157 | if (bssid || !ieee80211_is_data(hdr->frame_control)) |
| 3135 | return 0; | 3158 | return false; |
| 3136 | if (!ether_addr_equal(sdata->u.wds.remote_addr, hdr->addr2)) | 3159 | if (!ether_addr_equal(sdata->u.wds.remote_addr, hdr->addr2)) |
| 3137 | return 0; | 3160 | return false; |
| 3138 | break; | 3161 | break; |
| 3139 | case NL80211_IFTYPE_P2P_DEVICE: | 3162 | case NL80211_IFTYPE_P2P_DEVICE: |
| 3140 | if (!ieee80211_is_public_action(hdr, skb->len) && | 3163 | if (!ieee80211_is_public_action(hdr, skb->len) && |
| 3141 | !ieee80211_is_probe_req(hdr->frame_control) && | 3164 | !ieee80211_is_probe_req(hdr->frame_control) && |
| 3142 | !ieee80211_is_probe_resp(hdr->frame_control) && | 3165 | !ieee80211_is_probe_resp(hdr->frame_control) && |
| 3143 | !ieee80211_is_beacon(hdr->frame_control)) | 3166 | !ieee80211_is_beacon(hdr->frame_control)) |
| 3144 | return 0; | 3167 | return false; |
| 3145 | if (!ether_addr_equal(sdata->vif.addr, hdr->addr1) && | 3168 | if (!ether_addr_equal(sdata->vif.addr, hdr->addr1) && |
| 3146 | !multicast) | 3169 | !multicast) |
| 3147 | status->rx_flags &= ~IEEE80211_RX_RA_MATCH; | 3170 | status->rx_flags &= ~IEEE80211_RX_RA_MATCH; |
| @@ -3152,7 +3175,7 @@ static int prepare_for_handlers(struct ieee80211_rx_data *rx, | |||
| 3152 | break; | 3175 | break; |
| 3153 | } | 3176 | } |
| 3154 | 3177 | ||
| 3155 | return 1; | 3178 | return true; |
| 3156 | } | 3179 | } |
| 3157 | 3180 | ||
| 3158 | /* | 3181 | /* |
| @@ -3168,13 +3191,11 @@ static bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx, | |||
| 3168 | struct ieee80211_sub_if_data *sdata = rx->sdata; | 3191 | struct ieee80211_sub_if_data *sdata = rx->sdata; |
| 3169 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); | 3192 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); |
| 3170 | struct ieee80211_hdr *hdr = (void *)skb->data; | 3193 | struct ieee80211_hdr *hdr = (void *)skb->data; |
| 3171 | int prepares; | ||
| 3172 | 3194 | ||
| 3173 | rx->skb = skb; | 3195 | rx->skb = skb; |
| 3174 | status->rx_flags |= IEEE80211_RX_RA_MATCH; | 3196 | status->rx_flags |= IEEE80211_RX_RA_MATCH; |
| 3175 | prepares = prepare_for_handlers(rx, hdr); | ||
| 3176 | 3197 | ||
| 3177 | if (!prepares) | 3198 | if (!prepare_for_handlers(rx, hdr)) |
| 3178 | return false; | 3199 | return false; |
| 3179 | 3200 | ||
| 3180 | if (!consume) { | 3201 | if (!consume) { |
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index bcc4833d7542..88c81616f8f7 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c | |||
| @@ -271,10 +271,11 @@ static bool ieee80211_prep_hw_scan(struct ieee80211_local *local) | |||
| 271 | return true; | 271 | return true; |
| 272 | } | 272 | } |
| 273 | 273 | ||
| 274 | static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted, | 274 | static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) |
| 275 | bool was_hw_scan) | ||
| 276 | { | 275 | { |
| 277 | struct ieee80211_local *local = hw_to_local(hw); | 276 | struct ieee80211_local *local = hw_to_local(hw); |
| 277 | bool hw_scan = local->ops->hw_scan; | ||
| 278 | bool was_scanning = local->scanning; | ||
| 278 | 279 | ||
| 279 | lockdep_assert_held(&local->mtx); | 280 | lockdep_assert_held(&local->mtx); |
| 280 | 281 | ||
| @@ -290,7 +291,7 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted, | |||
| 290 | if (WARN_ON(!local->scan_req)) | 291 | if (WARN_ON(!local->scan_req)) |
| 291 | return; | 292 | return; |
| 292 | 293 | ||
| 293 | if (was_hw_scan && !aborted && ieee80211_prep_hw_scan(local)) { | 294 | if (hw_scan && !aborted && ieee80211_prep_hw_scan(local)) { |
| 294 | int rc; | 295 | int rc; |
| 295 | 296 | ||
| 296 | rc = drv_hw_scan(local, | 297 | rc = drv_hw_scan(local, |
| @@ -316,7 +317,7 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted, | |||
| 316 | /* Set power back to normal operating levels. */ | 317 | /* Set power back to normal operating levels. */ |
| 317 | ieee80211_hw_config(local, 0); | 318 | ieee80211_hw_config(local, 0); |
| 318 | 319 | ||
| 319 | if (!was_hw_scan) { | 320 | if (!hw_scan) { |
| 320 | ieee80211_configure_filter(local); | 321 | ieee80211_configure_filter(local); |
| 321 | drv_sw_scan_complete(local); | 322 | drv_sw_scan_complete(local); |
| 322 | ieee80211_offchannel_return(local); | 323 | ieee80211_offchannel_return(local); |
| @@ -327,7 +328,8 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted, | |||
| 327 | ieee80211_mlme_notify_scan_completed(local); | 328 | ieee80211_mlme_notify_scan_completed(local); |
| 328 | ieee80211_ibss_notify_scan_completed(local); | 329 | ieee80211_ibss_notify_scan_completed(local); |
| 329 | ieee80211_mesh_notify_scan_completed(local); | 330 | ieee80211_mesh_notify_scan_completed(local); |
| 330 | ieee80211_start_next_roc(local); | 331 | if (was_scanning) |
| 332 | ieee80211_start_next_roc(local); | ||
| 331 | } | 333 | } |
| 332 | 334 | ||
| 333 | void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) | 335 | void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) |
| @@ -526,7 +528,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, | |||
| 526 | ieee80211_hw_config(local, 0); | 528 | ieee80211_hw_config(local, 0); |
| 527 | 529 | ||
| 528 | if ((req->channels[0]->flags & | 530 | if ((req->channels[0]->flags & |
| 529 | IEEE80211_CHAN_PASSIVE_SCAN) || | 531 | IEEE80211_CHAN_NO_IR) || |
| 530 | !local->scan_req->n_ssids) { | 532 | !local->scan_req->n_ssids) { |
| 531 | next_delay = IEEE80211_PASSIVE_CHANNEL_TIME; | 533 | next_delay = IEEE80211_PASSIVE_CHANNEL_TIME; |
| 532 | } else { | 534 | } else { |
| @@ -572,7 +574,7 @@ ieee80211_scan_get_channel_time(struct ieee80211_channel *chan) | |||
| 572 | * TODO: channel switching also consumes quite some time, | 574 | * TODO: channel switching also consumes quite some time, |
| 573 | * add that delay as well to get a better estimation | 575 | * add that delay as well to get a better estimation |
| 574 | */ | 576 | */ |
| 575 | if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN) | 577 | if (chan->flags & IEEE80211_CHAN_NO_IR) |
| 576 | return IEEE80211_PASSIVE_CHANNEL_TIME; | 578 | return IEEE80211_PASSIVE_CHANNEL_TIME; |
| 577 | return IEEE80211_PROBE_DELAY + IEEE80211_CHANNEL_TIME; | 579 | return IEEE80211_PROBE_DELAY + IEEE80211_CHANNEL_TIME; |
| 578 | } | 580 | } |
| @@ -696,7 +698,7 @@ static void ieee80211_scan_state_set_channel(struct ieee80211_local *local, | |||
| 696 | * | 698 | * |
| 697 | * In any case, it is not necessary for a passive scan. | 699 | * In any case, it is not necessary for a passive scan. |
| 698 | */ | 700 | */ |
| 699 | if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN || | 701 | if (chan->flags & IEEE80211_CHAN_NO_IR || |
| 700 | !local->scan_req->n_ssids) { | 702 | !local->scan_req->n_ssids) { |
| 701 | *next_delay = IEEE80211_PASSIVE_CHANNEL_TIME; | 703 | *next_delay = IEEE80211_PASSIVE_CHANNEL_TIME; |
| 702 | local->next_scan_state = SCAN_DECISION; | 704 | local->next_scan_state = SCAN_DECISION; |
| @@ -747,7 +749,7 @@ void ieee80211_scan_work(struct work_struct *work) | |||
| 747 | container_of(work, struct ieee80211_local, scan_work.work); | 749 | container_of(work, struct ieee80211_local, scan_work.work); |
| 748 | struct ieee80211_sub_if_data *sdata; | 750 | struct ieee80211_sub_if_data *sdata; |
| 749 | unsigned long next_delay = 0; | 751 | unsigned long next_delay = 0; |
| 750 | bool aborted, hw_scan; | 752 | bool aborted; |
| 751 | 753 | ||
| 752 | mutex_lock(&local->mtx); | 754 | mutex_lock(&local->mtx); |
| 753 | 755 | ||
| @@ -786,14 +788,6 @@ void ieee80211_scan_work(struct work_struct *work) | |||
| 786 | } | 788 | } |
| 787 | 789 | ||
| 788 | /* | 790 | /* |
| 789 | * Avoid re-scheduling when the sdata is going away. | ||
| 790 | */ | ||
| 791 | if (!ieee80211_sdata_running(sdata)) { | ||
| 792 | aborted = true; | ||
| 793 | goto out_complete; | ||
| 794 | } | ||
| 795 | |||
| 796 | /* | ||
| 797 | * as long as no delay is required advance immediately | 791 | * as long as no delay is required advance immediately |
| 798 | * without scheduling a new work | 792 | * without scheduling a new work |
| 799 | */ | 793 | */ |
| @@ -834,8 +828,7 @@ void ieee80211_scan_work(struct work_struct *work) | |||
| 834 | goto out; | 828 | goto out; |
| 835 | 829 | ||
| 836 | out_complete: | 830 | out_complete: |
| 837 | hw_scan = test_bit(SCAN_HW_SCANNING, &local->scanning); | 831 | __ieee80211_scan_completed(&local->hw, aborted); |
| 838 | __ieee80211_scan_completed(&local->hw, aborted, hw_scan); | ||
| 839 | out: | 832 | out: |
| 840 | mutex_unlock(&local->mtx); | 833 | mutex_unlock(&local->mtx); |
| 841 | } | 834 | } |
| @@ -881,7 +874,7 @@ int ieee80211_request_ibss_scan(struct ieee80211_sub_if_data *sdata, | |||
| 881 | struct ieee80211_channel *tmp_ch = | 874 | struct ieee80211_channel *tmp_ch = |
| 882 | &local->hw.wiphy->bands[band]->channels[i]; | 875 | &local->hw.wiphy->bands[band]->channels[i]; |
| 883 | 876 | ||
| 884 | if (tmp_ch->flags & (IEEE80211_CHAN_NO_IBSS | | 877 | if (tmp_ch->flags & (IEEE80211_CHAN_NO_IR | |
| 885 | IEEE80211_CHAN_DISABLED)) | 878 | IEEE80211_CHAN_DISABLED)) |
| 886 | continue; | 879 | continue; |
| 887 | 880 | ||
| @@ -895,7 +888,7 @@ int ieee80211_request_ibss_scan(struct ieee80211_sub_if_data *sdata, | |||
| 895 | 888 | ||
| 896 | local->int_scan_req->n_channels = n_ch; | 889 | local->int_scan_req->n_channels = n_ch; |
| 897 | } else { | 890 | } else { |
| 898 | if (WARN_ON_ONCE(chan->flags & (IEEE80211_CHAN_NO_IBSS | | 891 | if (WARN_ON_ONCE(chan->flags & (IEEE80211_CHAN_NO_IR | |
| 899 | IEEE80211_CHAN_DISABLED))) | 892 | IEEE80211_CHAN_DISABLED))) |
| 900 | goto unlock; | 893 | goto unlock; |
| 901 | 894 | ||
| @@ -973,13 +966,13 @@ void ieee80211_scan_cancel(struct ieee80211_local *local) | |||
| 973 | */ | 966 | */ |
| 974 | cancel_delayed_work(&local->scan_work); | 967 | cancel_delayed_work(&local->scan_work); |
| 975 | /* and clean up */ | 968 | /* and clean up */ |
| 976 | __ieee80211_scan_completed(&local->hw, true, false); | 969 | __ieee80211_scan_completed(&local->hw, true); |
| 977 | out: | 970 | out: |
| 978 | mutex_unlock(&local->mtx); | 971 | mutex_unlock(&local->mtx); |
| 979 | } | 972 | } |
| 980 | 973 | ||
| 981 | int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, | 974 | int __ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, |
| 982 | struct cfg80211_sched_scan_request *req) | 975 | struct cfg80211_sched_scan_request *req) |
| 983 | { | 976 | { |
| 984 | struct ieee80211_local *local = sdata->local; | 977 | struct ieee80211_local *local = sdata->local; |
| 985 | struct ieee80211_sched_scan_ies sched_scan_ies = {}; | 978 | struct ieee80211_sched_scan_ies sched_scan_ies = {}; |
| @@ -989,17 +982,10 @@ int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, | |||
| 989 | iebufsz = 2 + IEEE80211_MAX_SSID_LEN + | 982 | iebufsz = 2 + IEEE80211_MAX_SSID_LEN + |
| 990 | local->scan_ies_len + req->ie_len; | 983 | local->scan_ies_len + req->ie_len; |
| 991 | 984 | ||
| 992 | mutex_lock(&local->mtx); | 985 | lockdep_assert_held(&local->mtx); |
| 993 | |||
| 994 | if (rcu_access_pointer(local->sched_scan_sdata)) { | ||
| 995 | ret = -EBUSY; | ||
| 996 | goto out; | ||
| 997 | } | ||
| 998 | 986 | ||
| 999 | if (!local->ops->sched_scan_start) { | 987 | if (!local->ops->sched_scan_start) |
| 1000 | ret = -ENOTSUPP; | 988 | return -ENOTSUPP; |
| 1001 | goto out; | ||
| 1002 | } | ||
| 1003 | 989 | ||
| 1004 | for (i = 0; i < IEEE80211_NUM_BANDS; i++) { | 990 | for (i = 0; i < IEEE80211_NUM_BANDS; i++) { |
| 1005 | if (!local->hw.wiphy->bands[i]) | 991 | if (!local->hw.wiphy->bands[i]) |
| @@ -1020,13 +1006,39 @@ int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, | |||
| 1020 | } | 1006 | } |
| 1021 | 1007 | ||
| 1022 | ret = drv_sched_scan_start(local, sdata, req, &sched_scan_ies); | 1008 | ret = drv_sched_scan_start(local, sdata, req, &sched_scan_ies); |
| 1023 | if (ret == 0) | 1009 | if (ret == 0) { |
| 1024 | rcu_assign_pointer(local->sched_scan_sdata, sdata); | 1010 | rcu_assign_pointer(local->sched_scan_sdata, sdata); |
| 1011 | local->sched_scan_req = req; | ||
| 1012 | } | ||
| 1025 | 1013 | ||
| 1026 | out_free: | 1014 | out_free: |
| 1027 | while (i > 0) | 1015 | while (i > 0) |
| 1028 | kfree(sched_scan_ies.ie[--i]); | 1016 | kfree(sched_scan_ies.ie[--i]); |
| 1029 | out: | 1017 | |
| 1018 | if (ret) { | ||
| 1019 | /* Clean in case of failure after HW restart or upon resume. */ | ||
| 1020 | rcu_assign_pointer(local->sched_scan_sdata, NULL); | ||
| 1021 | local->sched_scan_req = NULL; | ||
| 1022 | } | ||
| 1023 | |||
| 1024 | return ret; | ||
| 1025 | } | ||
| 1026 | |||
| 1027 | int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, | ||
| 1028 | struct cfg80211_sched_scan_request *req) | ||
| 1029 | { | ||
| 1030 | struct ieee80211_local *local = sdata->local; | ||
| 1031 | int ret; | ||
| 1032 | |||
| 1033 | mutex_lock(&local->mtx); | ||
| 1034 | |||
| 1035 | if (rcu_access_pointer(local->sched_scan_sdata)) { | ||
| 1036 | mutex_unlock(&local->mtx); | ||
| 1037 | return -EBUSY; | ||
| 1038 | } | ||
| 1039 | |||
| 1040 | ret = __ieee80211_request_sched_scan_start(sdata, req); | ||
| 1041 | |||
| 1030 | mutex_unlock(&local->mtx); | 1042 | mutex_unlock(&local->mtx); |
| 1031 | return ret; | 1043 | return ret; |
| 1032 | } | 1044 | } |
| @@ -1043,6 +1055,9 @@ int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata) | |||
| 1043 | goto out; | 1055 | goto out; |
| 1044 | } | 1056 | } |
| 1045 | 1057 | ||
| 1058 | /* We don't want to restart sched scan anymore. */ | ||
| 1059 | local->sched_scan_req = NULL; | ||
| 1060 | |||
| 1046 | if (rcu_access_pointer(local->sched_scan_sdata)) | 1061 | if (rcu_access_pointer(local->sched_scan_sdata)) |
| 1047 | drv_sched_scan_stop(local, sdata); | 1062 | drv_sched_scan_stop(local, sdata); |
| 1048 | 1063 | ||
| @@ -1077,6 +1092,9 @@ void ieee80211_sched_scan_stopped_work(struct work_struct *work) | |||
| 1077 | 1092 | ||
| 1078 | rcu_assign_pointer(local->sched_scan_sdata, NULL); | 1093 | rcu_assign_pointer(local->sched_scan_sdata, NULL); |
| 1079 | 1094 | ||
| 1095 | /* If sched scan was aborted by the driver. */ | ||
| 1096 | local->sched_scan_req = NULL; | ||
| 1097 | |||
| 1080 | mutex_unlock(&local->mtx); | 1098 | mutex_unlock(&local->mtx); |
| 1081 | 1099 | ||
| 1082 | cfg80211_sched_scan_stopped(local->hw.wiphy); | 1100 | cfg80211_sched_scan_stopped(local->hw.wiphy); |
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 1eb66e26e49d..decd30c1e290 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
| @@ -99,23 +99,6 @@ static void cleanup_single_sta(struct sta_info *sta) | |||
| 99 | struct ieee80211_local *local = sdata->local; | 99 | struct ieee80211_local *local = sdata->local; |
| 100 | struct ps_data *ps; | 100 | struct ps_data *ps; |
| 101 | 101 | ||
| 102 | /* | ||
| 103 | * At this point, when being called as call_rcu callback, | ||
| 104 | * neither mac80211 nor the driver can reference this | ||
| 105 | * sta struct any more except by still existing timers | ||
| 106 | * associated with this station that we clean up below. | ||
| 107 | * | ||
| 108 | * Note though that this still uses the sdata and even | ||
| 109 | * calls the driver in AP and mesh mode, so interfaces | ||
| 110 | * of those types mush use call sta_info_flush_cleanup() | ||
| 111 | * (typically via sta_info_flush()) before deconfiguring | ||
| 112 | * the driver. | ||
| 113 | * | ||
| 114 | * In station mode, nothing happens here so it doesn't | ||
| 115 | * have to (and doesn't) do that, this is intentional to | ||
| 116 | * speed up roaming. | ||
| 117 | */ | ||
| 118 | |||
| 119 | if (test_sta_flag(sta, WLAN_STA_PS_STA)) { | 102 | if (test_sta_flag(sta, WLAN_STA_PS_STA)) { |
| 120 | if (sta->sdata->vif.type == NL80211_IFTYPE_AP || | 103 | if (sta->sdata->vif.type == NL80211_IFTYPE_AP || |
| 121 | sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | 104 | sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN) |
| @@ -160,37 +143,6 @@ static void cleanup_single_sta(struct sta_info *sta) | |||
| 160 | sta_info_free(local, sta); | 143 | sta_info_free(local, sta); |
| 161 | } | 144 | } |
| 162 | 145 | ||
| 163 | void ieee80211_cleanup_sdata_stas(struct ieee80211_sub_if_data *sdata) | ||
| 164 | { | ||
| 165 | struct sta_info *sta; | ||
| 166 | |||
| 167 | spin_lock_bh(&sdata->cleanup_stations_lock); | ||
| 168 | while (!list_empty(&sdata->cleanup_stations)) { | ||
| 169 | sta = list_first_entry(&sdata->cleanup_stations, | ||
| 170 | struct sta_info, list); | ||
| 171 | list_del(&sta->list); | ||
| 172 | spin_unlock_bh(&sdata->cleanup_stations_lock); | ||
| 173 | |||
| 174 | cleanup_single_sta(sta); | ||
| 175 | |||
| 176 | spin_lock_bh(&sdata->cleanup_stations_lock); | ||
| 177 | } | ||
| 178 | |||
| 179 | spin_unlock_bh(&sdata->cleanup_stations_lock); | ||
| 180 | } | ||
| 181 | |||
| 182 | static void free_sta_rcu(struct rcu_head *h) | ||
| 183 | { | ||
| 184 | struct sta_info *sta = container_of(h, struct sta_info, rcu_head); | ||
| 185 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
| 186 | |||
| 187 | spin_lock(&sdata->cleanup_stations_lock); | ||
| 188 | list_add_tail(&sta->list, &sdata->cleanup_stations); | ||
| 189 | spin_unlock(&sdata->cleanup_stations_lock); | ||
| 190 | |||
| 191 | ieee80211_queue_work(&sdata->local->hw, &sdata->cleanup_stations_wk); | ||
| 192 | } | ||
| 193 | |||
| 194 | /* protected by RCU */ | 146 | /* protected by RCU */ |
| 195 | struct sta_info *sta_info_get(struct ieee80211_sub_if_data *sdata, | 147 | struct sta_info *sta_info_get(struct ieee80211_sub_if_data *sdata, |
| 196 | const u8 *addr) | 148 | const u8 *addr) |
| @@ -266,9 +218,17 @@ struct sta_info *sta_info_get_by_idx(struct ieee80211_sub_if_data *sdata, | |||
| 266 | */ | 218 | */ |
| 267 | void sta_info_free(struct ieee80211_local *local, struct sta_info *sta) | 219 | void sta_info_free(struct ieee80211_local *local, struct sta_info *sta) |
| 268 | { | 220 | { |
| 221 | int i; | ||
| 222 | |||
| 269 | if (sta->rate_ctrl) | 223 | if (sta->rate_ctrl) |
| 270 | rate_control_free_sta(sta); | 224 | rate_control_free_sta(sta); |
| 271 | 225 | ||
| 226 | if (sta->tx_lat) { | ||
| 227 | for (i = 0; i < IEEE80211_NUM_TIDS; i++) | ||
| 228 | kfree(sta->tx_lat[i].bins); | ||
| 229 | kfree(sta->tx_lat); | ||
| 230 | } | ||
| 231 | |||
| 272 | sta_dbg(sta->sdata, "Destroyed STA %pM\n", sta->sta.addr); | 232 | sta_dbg(sta->sdata, "Destroyed STA %pM\n", sta->sta.addr); |
| 273 | 233 | ||
| 274 | kfree(sta); | 234 | kfree(sta); |
| @@ -333,12 +293,42 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | |||
| 333 | struct ieee80211_local *local = sdata->local; | 293 | struct ieee80211_local *local = sdata->local; |
| 334 | struct sta_info *sta; | 294 | struct sta_info *sta; |
| 335 | struct timespec uptime; | 295 | struct timespec uptime; |
| 296 | struct ieee80211_tx_latency_bin_ranges *tx_latency; | ||
| 336 | int i; | 297 | int i; |
| 337 | 298 | ||
| 338 | sta = kzalloc(sizeof(*sta) + local->hw.sta_data_size, gfp); | 299 | sta = kzalloc(sizeof(*sta) + local->hw.sta_data_size, gfp); |
| 339 | if (!sta) | 300 | if (!sta) |
| 340 | return NULL; | 301 | return NULL; |
| 341 | 302 | ||
| 303 | rcu_read_lock(); | ||
| 304 | tx_latency = rcu_dereference(local->tx_latency); | ||
| 305 | /* init stations Tx latency statistics && TID bins */ | ||
| 306 | if (tx_latency) { | ||
| 307 | sta->tx_lat = kzalloc(IEEE80211_NUM_TIDS * | ||
| 308 | sizeof(struct ieee80211_tx_latency_stat), | ||
| 309 | GFP_ATOMIC); | ||
| 310 | if (!sta->tx_lat) { | ||
| 311 | rcu_read_unlock(); | ||
| 312 | goto free; | ||
| 313 | } | ||
| 314 | |||
| 315 | if (tx_latency->n_ranges) { | ||
| 316 | for (i = 0; i < IEEE80211_NUM_TIDS; i++) { | ||
| 317 | /* size of bins is size of the ranges +1 */ | ||
| 318 | sta->tx_lat[i].bin_count = | ||
| 319 | tx_latency->n_ranges + 1; | ||
| 320 | sta->tx_lat[i].bins = | ||
| 321 | kcalloc(sta->tx_lat[i].bin_count, | ||
| 322 | sizeof(u32), GFP_ATOMIC); | ||
| 323 | if (!sta->tx_lat[i].bins) { | ||
| 324 | rcu_read_unlock(); | ||
| 325 | goto free; | ||
| 326 | } | ||
| 327 | } | ||
| 328 | } | ||
| 329 | } | ||
| 330 | rcu_read_unlock(); | ||
| 331 | |||
| 342 | spin_lock_init(&sta->lock); | 332 | spin_lock_init(&sta->lock); |
| 343 | INIT_WORK(&sta->drv_unblock_wk, sta_unblock); | 333 | INIT_WORK(&sta->drv_unblock_wk, sta_unblock); |
| 344 | INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work); | 334 | INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work); |
| @@ -363,10 +353,8 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | |||
| 363 | for (i = 0; i < ARRAY_SIZE(sta->chain_signal_avg); i++) | 353 | for (i = 0; i < ARRAY_SIZE(sta->chain_signal_avg); i++) |
| 364 | ewma_init(&sta->chain_signal_avg[i], 1024, 8); | 354 | ewma_init(&sta->chain_signal_avg[i], 1024, 8); |
| 365 | 355 | ||
| 366 | if (sta_prepare_rate_control(local, sta, gfp)) { | 356 | if (sta_prepare_rate_control(local, sta, gfp)) |
| 367 | kfree(sta); | 357 | goto free; |
| 368 | return NULL; | ||
| 369 | } | ||
| 370 | 358 | ||
| 371 | for (i = 0; i < IEEE80211_NUM_TIDS; i++) { | 359 | for (i = 0; i < IEEE80211_NUM_TIDS; i++) { |
| 372 | /* | 360 | /* |
| @@ -411,8 +399,16 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | |||
| 411 | } | 399 | } |
| 412 | 400 | ||
| 413 | sta_dbg(sdata, "Allocated STA %pM\n", sta->sta.addr); | 401 | sta_dbg(sdata, "Allocated STA %pM\n", sta->sta.addr); |
| 414 | |||
| 415 | return sta; | 402 | return sta; |
| 403 | |||
| 404 | free: | ||
| 405 | if (sta->tx_lat) { | ||
| 406 | for (i = 0; i < IEEE80211_NUM_TIDS; i++) | ||
| 407 | kfree(sta->tx_lat[i].bins); | ||
| 408 | kfree(sta->tx_lat); | ||
| 409 | } | ||
| 410 | kfree(sta); | ||
| 411 | return NULL; | ||
| 416 | } | 412 | } |
| 417 | 413 | ||
| 418 | static int sta_info_insert_check(struct sta_info *sta) | 414 | static int sta_info_insert_check(struct sta_info *sta) |
| @@ -507,6 +503,7 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU) | |||
| 507 | 503 | ||
| 508 | set_sta_flag(sta, WLAN_STA_INSERTED); | 504 | set_sta_flag(sta, WLAN_STA_INSERTED); |
| 509 | 505 | ||
| 506 | ieee80211_recalc_min_chandef(sdata); | ||
| 510 | ieee80211_sta_debugfs_add(sta); | 507 | ieee80211_sta_debugfs_add(sta); |
| 511 | rate_control_add_sta_debugfs(sta); | 508 | rate_control_add_sta_debugfs(sta); |
| 512 | 509 | ||
| @@ -630,8 +627,8 @@ void sta_info_recalc_tim(struct sta_info *sta) | |||
| 630 | #ifdef CONFIG_MAC80211_MESH | 627 | #ifdef CONFIG_MAC80211_MESH |
| 631 | } else if (ieee80211_vif_is_mesh(&sta->sdata->vif)) { | 628 | } else if (ieee80211_vif_is_mesh(&sta->sdata->vif)) { |
| 632 | ps = &sta->sdata->u.mesh.ps; | 629 | ps = &sta->sdata->u.mesh.ps; |
| 633 | /* TIM map only for PLID <= IEEE80211_MAX_AID */ | 630 | /* TIM map only for 1 <= PLID <= IEEE80211_MAX_AID */ |
| 634 | id = le16_to_cpu(sta->plid) % IEEE80211_MAX_AID; | 631 | id = sta->plid % (IEEE80211_MAX_AID + 1); |
| 635 | #endif | 632 | #endif |
| 636 | } else { | 633 | } else { |
| 637 | return; | 634 | return; |
| @@ -807,7 +804,7 @@ static bool sta_info_cleanup_expire_buffered(struct ieee80211_local *local, | |||
| 807 | return have_buffered; | 804 | return have_buffered; |
| 808 | } | 805 | } |
| 809 | 806 | ||
| 810 | int __must_check __sta_info_destroy(struct sta_info *sta) | 807 | static int __must_check __sta_info_destroy_part1(struct sta_info *sta) |
| 811 | { | 808 | { |
| 812 | struct ieee80211_local *local; | 809 | struct ieee80211_local *local; |
| 813 | struct ieee80211_sub_if_data *sdata; | 810 | struct ieee80211_sub_if_data *sdata; |
| @@ -833,12 +830,35 @@ int __must_check __sta_info_destroy(struct sta_info *sta) | |||
| 833 | ieee80211_sta_tear_down_BA_sessions(sta, AGG_STOP_DESTROY_STA); | 830 | ieee80211_sta_tear_down_BA_sessions(sta, AGG_STOP_DESTROY_STA); |
| 834 | 831 | ||
| 835 | ret = sta_info_hash_del(local, sta); | 832 | ret = sta_info_hash_del(local, sta); |
| 836 | if (ret) | 833 | if (WARN_ON(ret)) |
| 837 | return ret; | 834 | return ret; |
| 838 | 835 | ||
| 839 | list_del_rcu(&sta->list); | 836 | list_del_rcu(&sta->list); |
| 840 | 837 | ||
| 841 | /* this always calls synchronize_net() */ | 838 | drv_sta_pre_rcu_remove(local, sta->sdata, sta); |
| 839 | |||
| 840 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN && | ||
| 841 | rcu_access_pointer(sdata->u.vlan.sta) == sta) | ||
| 842 | RCU_INIT_POINTER(sdata->u.vlan.sta, NULL); | ||
| 843 | |||
| 844 | return 0; | ||
| 845 | } | ||
| 846 | |||
| 847 | static void __sta_info_destroy_part2(struct sta_info *sta) | ||
| 848 | { | ||
| 849 | struct ieee80211_local *local = sta->local; | ||
| 850 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
| 851 | int ret; | ||
| 852 | |||
| 853 | /* | ||
| 854 | * NOTE: This assumes at least synchronize_net() was done | ||
| 855 | * after _part1 and before _part2! | ||
| 856 | */ | ||
| 857 | |||
| 858 | might_sleep(); | ||
| 859 | lockdep_assert_held(&local->sta_mtx); | ||
| 860 | |||
| 861 | /* now keys can no longer be reached */ | ||
| 842 | ieee80211_free_sta_keys(local, sta); | 862 | ieee80211_free_sta_keys(local, sta); |
| 843 | 863 | ||
| 844 | sta->dead = true; | 864 | sta->dead = true; |
| @@ -846,9 +866,6 @@ int __must_check __sta_info_destroy(struct sta_info *sta) | |||
| 846 | local->num_sta--; | 866 | local->num_sta--; |
| 847 | local->sta_generation++; | 867 | local->sta_generation++; |
| 848 | 868 | ||
| 849 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | ||
| 850 | RCU_INIT_POINTER(sdata->u.vlan.sta, NULL); | ||
| 851 | |||
| 852 | while (sta->sta_state > IEEE80211_STA_NONE) { | 869 | while (sta->sta_state > IEEE80211_STA_NONE) { |
| 853 | ret = sta_info_move_state(sta, sta->sta_state - 1); | 870 | ret = sta_info_move_state(sta, sta->sta_state - 1); |
| 854 | if (ret) { | 871 | if (ret) { |
| @@ -869,8 +886,21 @@ int __must_check __sta_info_destroy(struct sta_info *sta) | |||
| 869 | 886 | ||
| 870 | rate_control_remove_sta_debugfs(sta); | 887 | rate_control_remove_sta_debugfs(sta); |
| 871 | ieee80211_sta_debugfs_remove(sta); | 888 | ieee80211_sta_debugfs_remove(sta); |
| 889 | ieee80211_recalc_min_chandef(sdata); | ||
| 890 | |||
| 891 | cleanup_single_sta(sta); | ||
| 892 | } | ||
| 872 | 893 | ||
| 873 | call_rcu(&sta->rcu_head, free_sta_rcu); | 894 | int __must_check __sta_info_destroy(struct sta_info *sta) |
| 895 | { | ||
| 896 | int err = __sta_info_destroy_part1(sta); | ||
| 897 | |||
| 898 | if (err) | ||
| 899 | return err; | ||
| 900 | |||
| 901 | synchronize_net(); | ||
| 902 | |||
| 903 | __sta_info_destroy_part2(sta); | ||
| 874 | 904 | ||
| 875 | return 0; | 905 | return 0; |
| 876 | } | 906 | } |
| @@ -940,32 +970,38 @@ void sta_info_stop(struct ieee80211_local *local) | |||
| 940 | } | 970 | } |
| 941 | 971 | ||
| 942 | 972 | ||
| 943 | int sta_info_flush_defer(struct ieee80211_sub_if_data *sdata) | 973 | int __sta_info_flush(struct ieee80211_sub_if_data *sdata, bool vlans) |
| 944 | { | 974 | { |
| 945 | struct ieee80211_local *local = sdata->local; | 975 | struct ieee80211_local *local = sdata->local; |
| 946 | struct sta_info *sta, *tmp; | 976 | struct sta_info *sta, *tmp; |
| 977 | LIST_HEAD(free_list); | ||
| 947 | int ret = 0; | 978 | int ret = 0; |
| 948 | 979 | ||
| 949 | might_sleep(); | 980 | might_sleep(); |
| 950 | 981 | ||
| 982 | WARN_ON(vlans && sdata->vif.type != NL80211_IFTYPE_AP); | ||
| 983 | WARN_ON(vlans && !sdata->bss); | ||
| 984 | |||
| 951 | mutex_lock(&local->sta_mtx); | 985 | mutex_lock(&local->sta_mtx); |
| 952 | list_for_each_entry_safe(sta, tmp, &local->sta_list, list) { | 986 | list_for_each_entry_safe(sta, tmp, &local->sta_list, list) { |
| 953 | if (sdata == sta->sdata) { | 987 | if (sdata == sta->sdata || |
| 954 | WARN_ON(__sta_info_destroy(sta)); | 988 | (vlans && sdata->bss == sta->sdata->bss)) { |
| 989 | if (!WARN_ON(__sta_info_destroy_part1(sta))) | ||
| 990 | list_add(&sta->free_list, &free_list); | ||
| 955 | ret++; | 991 | ret++; |
| 956 | } | 992 | } |
| 957 | } | 993 | } |
| 994 | |||
| 995 | if (!list_empty(&free_list)) { | ||
| 996 | synchronize_net(); | ||
| 997 | list_for_each_entry_safe(sta, tmp, &free_list, free_list) | ||
| 998 | __sta_info_destroy_part2(sta); | ||
| 999 | } | ||
| 958 | mutex_unlock(&local->sta_mtx); | 1000 | mutex_unlock(&local->sta_mtx); |
| 959 | 1001 | ||
| 960 | return ret; | 1002 | return ret; |
| 961 | } | 1003 | } |
| 962 | 1004 | ||
| 963 | void sta_info_flush_cleanup(struct ieee80211_sub_if_data *sdata) | ||
| 964 | { | ||
| 965 | ieee80211_cleanup_sdata_stas(sdata); | ||
| 966 | cancel_work_sync(&sdata->cleanup_stations_wk); | ||
| 967 | } | ||
| 968 | |||
| 969 | void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata, | 1005 | void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata, |
| 970 | unsigned long exp_time) | 1006 | unsigned long exp_time) |
| 971 | { | 1007 | { |
| @@ -1117,7 +1153,8 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta) | |||
| 1117 | 1153 | ||
| 1118 | static void ieee80211_send_null_response(struct ieee80211_sub_if_data *sdata, | 1154 | static void ieee80211_send_null_response(struct ieee80211_sub_if_data *sdata, |
| 1119 | struct sta_info *sta, int tid, | 1155 | struct sta_info *sta, int tid, |
| 1120 | enum ieee80211_frame_release_type reason) | 1156 | enum ieee80211_frame_release_type reason, |
| 1157 | bool call_driver) | ||
| 1121 | { | 1158 | { |
| 1122 | struct ieee80211_local *local = sdata->local; | 1159 | struct ieee80211_local *local = sdata->local; |
| 1123 | struct ieee80211_qos_hdr *nullfunc; | 1160 | struct ieee80211_qos_hdr *nullfunc; |
| @@ -1175,7 +1212,9 @@ static void ieee80211_send_null_response(struct ieee80211_sub_if_data *sdata, | |||
| 1175 | IEEE80211_TX_STATUS_EOSP | | 1212 | IEEE80211_TX_STATUS_EOSP | |
| 1176 | IEEE80211_TX_CTL_REQ_TX_STATUS; | 1213 | IEEE80211_TX_CTL_REQ_TX_STATUS; |
| 1177 | 1214 | ||
| 1178 | drv_allow_buffered_frames(local, sta, BIT(tid), 1, reason, false); | 1215 | if (call_driver) |
| 1216 | drv_allow_buffered_frames(local, sta, BIT(tid), 1, | ||
| 1217 | reason, false); | ||
| 1179 | 1218 | ||
| 1180 | skb->dev = sdata->dev; | 1219 | skb->dev = sdata->dev; |
| 1181 | 1220 | ||
| @@ -1191,6 +1230,17 @@ static void ieee80211_send_null_response(struct ieee80211_sub_if_data *sdata, | |||
| 1191 | rcu_read_unlock(); | 1230 | rcu_read_unlock(); |
| 1192 | } | 1231 | } |
| 1193 | 1232 | ||
| 1233 | static int find_highest_prio_tid(unsigned long tids) | ||
| 1234 | { | ||
| 1235 | /* lower 3 TIDs aren't ordered perfectly */ | ||
| 1236 | if (tids & 0xF8) | ||
| 1237 | return fls(tids) - 1; | ||
| 1238 | /* TID 0 is BE just like TID 3 */ | ||
| 1239 | if (tids & BIT(0)) | ||
| 1240 | return 0; | ||
| 1241 | return fls(tids) - 1; | ||
| 1242 | } | ||
| 1243 | |||
| 1194 | static void | 1244 | static void |
| 1195 | ieee80211_sta_ps_deliver_response(struct sta_info *sta, | 1245 | ieee80211_sta_ps_deliver_response(struct sta_info *sta, |
| 1196 | int n_frames, u8 ignored_acs, | 1246 | int n_frames, u8 ignored_acs, |
| @@ -1198,7 +1248,6 @@ ieee80211_sta_ps_deliver_response(struct sta_info *sta, | |||
| 1198 | { | 1248 | { |
| 1199 | struct ieee80211_sub_if_data *sdata = sta->sdata; | 1249 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
| 1200 | struct ieee80211_local *local = sdata->local; | 1250 | struct ieee80211_local *local = sdata->local; |
| 1201 | bool found = false; | ||
| 1202 | bool more_data = false; | 1251 | bool more_data = false; |
| 1203 | int ac; | 1252 | int ac; |
| 1204 | unsigned long driver_release_tids = 0; | 1253 | unsigned long driver_release_tids = 0; |
| @@ -1209,9 +1258,7 @@ ieee80211_sta_ps_deliver_response(struct sta_info *sta, | |||
| 1209 | 1258 | ||
| 1210 | __skb_queue_head_init(&frames); | 1259 | __skb_queue_head_init(&frames); |
| 1211 | 1260 | ||
| 1212 | /* | 1261 | /* Get response frame(s) and more data bit for the last one. */ |
| 1213 | * Get response frame(s) and more data bit for it. | ||
| 1214 | */ | ||
| 1215 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { | 1262 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { |
| 1216 | unsigned long tids; | 1263 | unsigned long tids; |
| 1217 | 1264 | ||
| @@ -1220,43 +1267,48 @@ ieee80211_sta_ps_deliver_response(struct sta_info *sta, | |||
| 1220 | 1267 | ||
| 1221 | tids = ieee80211_tids_for_ac(ac); | 1268 | tids = ieee80211_tids_for_ac(ac); |
| 1222 | 1269 | ||
| 1223 | if (!found) { | 1270 | /* if we already have frames from software, then we can't also |
| 1224 | driver_release_tids = sta->driver_buffered_tids & tids; | 1271 | * release from hardware queues |
| 1225 | if (driver_release_tids) { | 1272 | */ |
| 1226 | found = true; | 1273 | if (skb_queue_empty(&frames)) |
| 1227 | } else { | 1274 | driver_release_tids |= sta->driver_buffered_tids & tids; |
| 1228 | struct sk_buff *skb; | ||
| 1229 | |||
| 1230 | while (n_frames > 0) { | ||
| 1231 | skb = skb_dequeue(&sta->tx_filtered[ac]); | ||
| 1232 | if (!skb) { | ||
| 1233 | skb = skb_dequeue( | ||
| 1234 | &sta->ps_tx_buf[ac]); | ||
| 1235 | if (skb) | ||
| 1236 | local->total_ps_buffered--; | ||
| 1237 | } | ||
| 1238 | if (!skb) | ||
| 1239 | break; | ||
| 1240 | n_frames--; | ||
| 1241 | found = true; | ||
| 1242 | __skb_queue_tail(&frames, skb); | ||
| 1243 | } | ||
| 1244 | } | ||
| 1245 | 1275 | ||
| 1246 | /* | 1276 | if (driver_release_tids) { |
| 1247 | * If the driver has data on more than one TID then | 1277 | /* If the driver has data on more than one TID then |
| 1248 | * certainly there's more data if we release just a | 1278 | * certainly there's more data if we release just a |
| 1249 | * single frame now (from a single TID). | 1279 | * single frame now (from a single TID). This will |
| 1280 | * only happen for PS-Poll. | ||
| 1250 | */ | 1281 | */ |
| 1251 | if (reason == IEEE80211_FRAME_RELEASE_PSPOLL && | 1282 | if (reason == IEEE80211_FRAME_RELEASE_PSPOLL && |
| 1252 | hweight16(driver_release_tids) > 1) { | 1283 | hweight16(driver_release_tids) > 1) { |
| 1253 | more_data = true; | 1284 | more_data = true; |
| 1254 | driver_release_tids = | 1285 | driver_release_tids = |
| 1255 | BIT(ffs(driver_release_tids) - 1); | 1286 | BIT(find_highest_prio_tid( |
| 1287 | driver_release_tids)); | ||
| 1256 | break; | 1288 | break; |
| 1257 | } | 1289 | } |
| 1290 | } else { | ||
| 1291 | struct sk_buff *skb; | ||
| 1292 | |||
| 1293 | while (n_frames > 0) { | ||
| 1294 | skb = skb_dequeue(&sta->tx_filtered[ac]); | ||
| 1295 | if (!skb) { | ||
| 1296 | skb = skb_dequeue( | ||
| 1297 | &sta->ps_tx_buf[ac]); | ||
| 1298 | if (skb) | ||
| 1299 | local->total_ps_buffered--; | ||
| 1300 | } | ||
| 1301 | if (!skb) | ||
| 1302 | break; | ||
| 1303 | n_frames--; | ||
| 1304 | __skb_queue_tail(&frames, skb); | ||
| 1305 | } | ||
| 1258 | } | 1306 | } |
| 1259 | 1307 | ||
| 1308 | /* If we have more frames buffered on this AC, then set the | ||
| 1309 | * more-data bit and abort the loop since we can't send more | ||
| 1310 | * data from other ACs before the buffered frames from this. | ||
| 1311 | */ | ||
| 1260 | if (!skb_queue_empty(&sta->tx_filtered[ac]) || | 1312 | if (!skb_queue_empty(&sta->tx_filtered[ac]) || |
| 1261 | !skb_queue_empty(&sta->ps_tx_buf[ac])) { | 1313 | !skb_queue_empty(&sta->ps_tx_buf[ac])) { |
| 1262 | more_data = true; | 1314 | more_data = true; |
| @@ -1264,7 +1316,7 @@ ieee80211_sta_ps_deliver_response(struct sta_info *sta, | |||
| 1264 | } | 1316 | } |
| 1265 | } | 1317 | } |
| 1266 | 1318 | ||
| 1267 | if (!found) { | 1319 | if (skb_queue_empty(&frames) && !driver_release_tids) { |
| 1268 | int tid; | 1320 | int tid; |
| 1269 | 1321 | ||
| 1270 | /* | 1322 | /* |
| @@ -1285,15 +1337,13 @@ ieee80211_sta_ps_deliver_response(struct sta_info *sta, | |||
| 1285 | /* This will evaluate to 1, 3, 5 or 7. */ | 1337 | /* This will evaluate to 1, 3, 5 or 7. */ |
| 1286 | tid = 7 - ((ffs(~ignored_acs) - 1) << 1); | 1338 | tid = 7 - ((ffs(~ignored_acs) - 1) << 1); |
| 1287 | 1339 | ||
| 1288 | ieee80211_send_null_response(sdata, sta, tid, reason); | 1340 | ieee80211_send_null_response(sdata, sta, tid, reason, true); |
| 1289 | return; | 1341 | } else if (!driver_release_tids) { |
| 1290 | } | ||
| 1291 | |||
| 1292 | if (!driver_release_tids) { | ||
| 1293 | struct sk_buff_head pending; | 1342 | struct sk_buff_head pending; |
| 1294 | struct sk_buff *skb; | 1343 | struct sk_buff *skb; |
| 1295 | int num = 0; | 1344 | int num = 0; |
| 1296 | u16 tids = 0; | 1345 | u16 tids = 0; |
| 1346 | bool need_null = false; | ||
| 1297 | 1347 | ||
| 1298 | skb_queue_head_init(&pending); | 1348 | skb_queue_head_init(&pending); |
| 1299 | 1349 | ||
| @@ -1327,22 +1377,57 @@ ieee80211_sta_ps_deliver_response(struct sta_info *sta, | |||
| 1327 | ieee80211_is_qos_nullfunc(hdr->frame_control)) | 1377 | ieee80211_is_qos_nullfunc(hdr->frame_control)) |
| 1328 | qoshdr = ieee80211_get_qos_ctl(hdr); | 1378 | qoshdr = ieee80211_get_qos_ctl(hdr); |
| 1329 | 1379 | ||
| 1330 | /* end service period after last frame */ | 1380 | tids |= BIT(skb->priority); |
| 1331 | if (skb_queue_empty(&frames)) { | 1381 | |
| 1332 | if (reason == IEEE80211_FRAME_RELEASE_UAPSD && | 1382 | __skb_queue_tail(&pending, skb); |
| 1333 | qoshdr) | 1383 | |
| 1334 | *qoshdr |= IEEE80211_QOS_CTL_EOSP; | 1384 | /* end service period after last frame or add one */ |
| 1385 | if (!skb_queue_empty(&frames)) | ||
| 1386 | continue; | ||
| 1335 | 1387 | ||
| 1388 | if (reason != IEEE80211_FRAME_RELEASE_UAPSD) { | ||
| 1389 | /* for PS-Poll, there's only one frame */ | ||
| 1336 | info->flags |= IEEE80211_TX_STATUS_EOSP | | 1390 | info->flags |= IEEE80211_TX_STATUS_EOSP | |
| 1337 | IEEE80211_TX_CTL_REQ_TX_STATUS; | 1391 | IEEE80211_TX_CTL_REQ_TX_STATUS; |
| 1392 | break; | ||
| 1338 | } | 1393 | } |
| 1339 | 1394 | ||
| 1340 | if (qoshdr) | 1395 | /* For uAPSD, things are a bit more complicated. If the |
| 1341 | tids |= BIT(*qoshdr & IEEE80211_QOS_CTL_TID_MASK); | 1396 | * last frame has a QoS header (i.e. is a QoS-data or |
| 1342 | else | 1397 | * QoS-nulldata frame) then just set the EOSP bit there |
| 1343 | tids |= BIT(0); | 1398 | * and be done. |
| 1399 | * If the frame doesn't have a QoS header (which means | ||
| 1400 | * it should be a bufferable MMPDU) then we can't set | ||
| 1401 | * the EOSP bit in the QoS header; add a QoS-nulldata | ||
| 1402 | * frame to the list to send it after the MMPDU. | ||
| 1403 | * | ||
| 1404 | * Note that this code is only in the mac80211-release | ||
| 1405 | * code path, we assume that the driver will not buffer | ||
| 1406 | * anything but QoS-data frames, or if it does, will | ||
| 1407 | * create the QoS-nulldata frame by itself if needed. | ||
| 1408 | * | ||
| 1409 | * Cf. 802.11-2012 10.2.1.10 (c). | ||
| 1410 | */ | ||
| 1411 | if (qoshdr) { | ||
| 1412 | *qoshdr |= IEEE80211_QOS_CTL_EOSP; | ||
| 1344 | 1413 | ||
| 1345 | __skb_queue_tail(&pending, skb); | 1414 | info->flags |= IEEE80211_TX_STATUS_EOSP | |
| 1415 | IEEE80211_TX_CTL_REQ_TX_STATUS; | ||
| 1416 | } else { | ||
| 1417 | /* The standard isn't completely clear on this | ||
| 1418 | * as it says the more-data bit should be set | ||
| 1419 | * if there are more BUs. The QoS-Null frame | ||
| 1420 | * we're about to send isn't buffered yet, we | ||
| 1421 | * only create it below, but let's pretend it | ||
| 1422 | * was buffered just in case some clients only | ||
| 1423 | * expect more-data=0 when eosp=1. | ||
| 1424 | */ | ||
| 1425 | hdr->frame_control |= | ||
| 1426 | cpu_to_le16(IEEE80211_FCTL_MOREDATA); | ||
| 1427 | need_null = true; | ||
| 1428 | num++; | ||
| 1429 | } | ||
| 1430 | break; | ||
| 1346 | } | 1431 | } |
| 1347 | 1432 | ||
| 1348 | drv_allow_buffered_frames(local, sta, tids, num, | 1433 | drv_allow_buffered_frames(local, sta, tids, num, |
| @@ -1350,17 +1435,22 @@ ieee80211_sta_ps_deliver_response(struct sta_info *sta, | |||
| 1350 | 1435 | ||
| 1351 | ieee80211_add_pending_skbs(local, &pending); | 1436 | ieee80211_add_pending_skbs(local, &pending); |
| 1352 | 1437 | ||
| 1438 | if (need_null) | ||
| 1439 | ieee80211_send_null_response( | ||
| 1440 | sdata, sta, find_highest_prio_tid(tids), | ||
| 1441 | reason, false); | ||
| 1442 | |||
| 1353 | sta_info_recalc_tim(sta); | 1443 | sta_info_recalc_tim(sta); |
| 1354 | } else { | 1444 | } else { |
| 1355 | /* | 1445 | /* |
| 1356 | * We need to release a frame that is buffered somewhere in the | 1446 | * We need to release a frame that is buffered somewhere in the |
| 1357 | * driver ... it'll have to handle that. | 1447 | * driver ... it'll have to handle that. |
| 1358 | * Note that, as per the comment above, it'll also have to see | 1448 | * Note that the driver also has to check the number of frames |
| 1359 | * if there is more than just one frame on the specific TID that | 1449 | * on the TIDs we're releasing from - if there are more than |
| 1360 | * we're releasing from, and it needs to set the more-data bit | 1450 | * n_frames it has to set the more-data bit (if we didn't ask |
| 1361 | * accordingly if we tell it that there's no more data. If we do | 1451 | * it to set it anyway due to other buffered frames); if there |
| 1362 | * tell it there's more data, then of course the more-data bit | 1452 | * are fewer than n_frames it has to make sure to adjust that |
| 1363 | * needs to be set anyway. | 1453 | * to allow the service period to end properly. |
| 1364 | */ | 1454 | */ |
| 1365 | drv_release_buffered_frames(local, sta, driver_release_tids, | 1455 | drv_release_buffered_frames(local, sta, driver_release_tids, |
| 1366 | n_frames, reason, more_data); | 1456 | n_frames, reason, more_data); |
| @@ -1368,9 +1458,9 @@ ieee80211_sta_ps_deliver_response(struct sta_info *sta, | |||
| 1368 | /* | 1458 | /* |
| 1369 | * Note that we don't recalculate the TIM bit here as it would | 1459 | * Note that we don't recalculate the TIM bit here as it would |
| 1370 | * most likely have no effect at all unless the driver told us | 1460 | * most likely have no effect at all unless the driver told us |
| 1371 | * that the TID became empty before returning here from the | 1461 | * that the TID(s) became empty before returning here from the |
| 1372 | * release function. | 1462 | * release function. |
| 1373 | * Either way, however, when the driver tells us that the TID | 1463 | * Either way, however, when the driver tells us that the TID(s) |
| 1374 | * became empty we'll do the TIM recalculation. | 1464 | * became empty we'll do the TIM recalculation. |
| 1375 | */ | 1465 | */ |
| 1376 | } | 1466 | } |
| @@ -1459,6 +1549,8 @@ void ieee80211_sta_set_buffered(struct ieee80211_sta *pubsta, | |||
| 1459 | if (WARN_ON(tid >= IEEE80211_NUM_TIDS)) | 1549 | if (WARN_ON(tid >= IEEE80211_NUM_TIDS)) |
| 1460 | return; | 1550 | return; |
| 1461 | 1551 | ||
| 1552 | trace_api_sta_set_buffered(sta->local, pubsta, tid, buffered); | ||
| 1553 | |||
| 1462 | if (buffered) | 1554 | if (buffered) |
| 1463 | set_bit(tid, &sta->driver_buffered_tids); | 1555 | set_bit(tid, &sta->driver_buffered_tids); |
| 1464 | else | 1556 | else |
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 3ef06a26b9cb..d77ff7090630 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h | |||
| @@ -220,6 +220,25 @@ struct sta_ampdu_mlme { | |||
| 220 | u8 dialog_token_allocator; | 220 | u8 dialog_token_allocator; |
| 221 | }; | 221 | }; |
| 222 | 222 | ||
| 223 | /* | ||
| 224 | * struct ieee80211_tx_latency_stat - Tx latency statistics | ||
| 225 | * | ||
| 226 | * Measures TX latency and jitter for a station per TID. | ||
| 227 | * | ||
| 228 | * @max: worst case latency | ||
| 229 | * @sum: sum of all latencies | ||
| 230 | * @counter: amount of Tx frames sent from interface | ||
| 231 | * @bins: each bin counts how many frames transmitted within a certain | ||
| 232 | * latency range. when disabled it is NULL. | ||
| 233 | * @bin_count: amount of bins. | ||
| 234 | */ | ||
| 235 | struct ieee80211_tx_latency_stat { | ||
| 236 | u32 max; | ||
| 237 | u32 sum; | ||
| 238 | u32 counter; | ||
| 239 | u32 *bins; | ||
| 240 | u32 bin_count; | ||
| 241 | }; | ||
| 223 | 242 | ||
| 224 | /** | 243 | /** |
| 225 | * struct sta_info - STA information | 244 | * struct sta_info - STA information |
| @@ -228,11 +247,14 @@ struct sta_ampdu_mlme { | |||
| 228 | * mac80211 is communicating with. | 247 | * mac80211 is communicating with. |
| 229 | * | 248 | * |
| 230 | * @list: global linked list entry | 249 | * @list: global linked list entry |
| 250 | * @free_list: list entry for keeping track of stations to free | ||
| 231 | * @hnext: hash table linked list pointer | 251 | * @hnext: hash table linked list pointer |
| 232 | * @local: pointer to the global information | 252 | * @local: pointer to the global information |
| 233 | * @sdata: virtual interface this station belongs to | 253 | * @sdata: virtual interface this station belongs to |
| 234 | * @ptk: peer key negotiated with this station, if any | 254 | * @ptk: peer keys negotiated with this station, if any |
| 255 | * @ptk_idx: last installed peer key index | ||
| 235 | * @gtk: group keys negotiated with this station, if any | 256 | * @gtk: group keys negotiated with this station, if any |
| 257 | * @gtk_idx: last installed group key index | ||
| 236 | * @rate_ctrl: rate control algorithm reference | 258 | * @rate_ctrl: rate control algorithm reference |
| 237 | * @rate_ctrl_priv: rate control private per-STA pointer | 259 | * @rate_ctrl_priv: rate control private per-STA pointer |
| 238 | * @last_tx_rate: rate used for last transmit, to report to userspace as | 260 | * @last_tx_rate: rate used for last transmit, to report to userspace as |
| @@ -274,6 +296,7 @@ struct sta_ampdu_mlme { | |||
| 274 | * @tid_seq: per-TID sequence numbers for sending to this STA | 296 | * @tid_seq: per-TID sequence numbers for sending to this STA |
| 275 | * @ampdu_mlme: A-MPDU state machine state | 297 | * @ampdu_mlme: A-MPDU state machine state |
| 276 | * @timer_to_tid: identity mapping to ID timers | 298 | * @timer_to_tid: identity mapping to ID timers |
| 299 | * @tx_lat: Tx latency statistics | ||
| 277 | * @llid: Local link ID | 300 | * @llid: Local link ID |
| 278 | * @plid: Peer link ID | 301 | * @plid: Peer link ID |
| 279 | * @reason: Cancel reason on PLINK_HOLDING state | 302 | * @reason: Cancel reason on PLINK_HOLDING state |
| @@ -303,16 +326,19 @@ struct sta_ampdu_mlme { | |||
| 303 | * @chain_signal_avg: signal average (per chain) | 326 | * @chain_signal_avg: signal average (per chain) |
| 304 | * @known_smps_mode: the smps_mode the client thinks we are in. Relevant for | 327 | * @known_smps_mode: the smps_mode the client thinks we are in. Relevant for |
| 305 | * AP only. | 328 | * AP only. |
| 329 | * @cipher_scheme: optional cipher scheme for this station | ||
| 306 | */ | 330 | */ |
| 307 | struct sta_info { | 331 | struct sta_info { |
| 308 | /* General information, mostly static */ | 332 | /* General information, mostly static */ |
| 309 | struct list_head list; | 333 | struct list_head list, free_list; |
| 310 | struct rcu_head rcu_head; | 334 | struct rcu_head rcu_head; |
| 311 | struct sta_info __rcu *hnext; | 335 | struct sta_info __rcu *hnext; |
| 312 | struct ieee80211_local *local; | 336 | struct ieee80211_local *local; |
| 313 | struct ieee80211_sub_if_data *sdata; | 337 | struct ieee80211_sub_if_data *sdata; |
| 314 | struct ieee80211_key __rcu *gtk[NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS]; | 338 | struct ieee80211_key __rcu *gtk[NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS]; |
| 315 | struct ieee80211_key __rcu *ptk; | 339 | struct ieee80211_key __rcu *ptk[NUM_DEFAULT_KEYS]; |
| 340 | u8 gtk_idx; | ||
| 341 | u8 ptk_idx; | ||
| 316 | struct rate_control_ref *rate_ctrl; | 342 | struct rate_control_ref *rate_ctrl; |
| 317 | void *rate_ctrl_priv; | 343 | void *rate_ctrl_priv; |
| 318 | spinlock_t lock; | 344 | spinlock_t lock; |
| @@ -380,14 +406,16 @@ struct sta_info { | |||
| 380 | struct sta_ampdu_mlme ampdu_mlme; | 406 | struct sta_ampdu_mlme ampdu_mlme; |
| 381 | u8 timer_to_tid[IEEE80211_NUM_TIDS]; | 407 | u8 timer_to_tid[IEEE80211_NUM_TIDS]; |
| 382 | 408 | ||
| 409 | struct ieee80211_tx_latency_stat *tx_lat; | ||
| 410 | |||
| 383 | #ifdef CONFIG_MAC80211_MESH | 411 | #ifdef CONFIG_MAC80211_MESH |
| 384 | /* | 412 | /* |
| 385 | * Mesh peer link attributes | 413 | * Mesh peer link attributes |
| 386 | * TODO: move to a sub-structure that is referenced with pointer? | 414 | * TODO: move to a sub-structure that is referenced with pointer? |
| 387 | */ | 415 | */ |
| 388 | __le16 llid; | 416 | u16 llid; |
| 389 | __le16 plid; | 417 | u16 plid; |
| 390 | __le16 reason; | 418 | u16 reason; |
| 391 | u8 plink_retries; | 419 | u8 plink_retries; |
| 392 | bool ignore_plink_timer; | 420 | bool ignore_plink_timer; |
| 393 | enum nl80211_plink_state plink_state; | 421 | enum nl80211_plink_state plink_state; |
| @@ -414,6 +442,7 @@ struct sta_info { | |||
| 414 | unsigned int beacon_loss_count; | 442 | unsigned int beacon_loss_count; |
| 415 | 443 | ||
| 416 | enum ieee80211_smps_mode known_smps_mode; | 444 | enum ieee80211_smps_mode known_smps_mode; |
| 445 | const struct ieee80211_cipher_scheme *cipher_scheme; | ||
| 417 | 446 | ||
| 418 | /* keep last! */ | 447 | /* keep last! */ |
| 419 | struct ieee80211_sta sta; | 448 | struct ieee80211_sta sta; |
| @@ -577,21 +606,6 @@ void sta_info_recalc_tim(struct sta_info *sta); | |||
| 577 | 606 | ||
| 578 | void sta_info_init(struct ieee80211_local *local); | 607 | void sta_info_init(struct ieee80211_local *local); |
| 579 | void sta_info_stop(struct ieee80211_local *local); | 608 | void sta_info_stop(struct ieee80211_local *local); |
| 580 | int sta_info_flush_defer(struct ieee80211_sub_if_data *sdata); | ||
| 581 | |||
| 582 | /** | ||
| 583 | * sta_info_flush_cleanup - flush the sta_info cleanup queue | ||
| 584 | * @sdata: the interface | ||
| 585 | * | ||
| 586 | * Flushes the sta_info cleanup queue for a given interface; | ||
| 587 | * this is necessary before the interface is removed or, for | ||
| 588 | * AP/mesh interfaces, before it is deconfigured. | ||
| 589 | * | ||
| 590 | * Note an rcu_barrier() must precede the function, after all | ||
| 591 | * stations have been flushed/removed to ensure the call_rcu() | ||
| 592 | * calls that add stations to the cleanup queue have completed. | ||
| 593 | */ | ||
| 594 | void sta_info_flush_cleanup(struct ieee80211_sub_if_data *sdata); | ||
| 595 | 609 | ||
| 596 | /** | 610 | /** |
| 597 | * sta_info_flush - flush matching STA entries from the STA table | 611 | * sta_info_flush - flush matching STA entries from the STA table |
| @@ -599,15 +613,13 @@ void sta_info_flush_cleanup(struct ieee80211_sub_if_data *sdata); | |||
| 599 | * Returns the number of removed STA entries. | 613 | * Returns the number of removed STA entries. |
| 600 | * | 614 | * |
| 601 | * @sdata: sdata to remove all stations from | 615 | * @sdata: sdata to remove all stations from |
| 616 | * @vlans: if the given interface is an AP interface, also flush VLANs | ||
| 602 | */ | 617 | */ |
| 618 | int __sta_info_flush(struct ieee80211_sub_if_data *sdata, bool vlans); | ||
| 619 | |||
| 603 | static inline int sta_info_flush(struct ieee80211_sub_if_data *sdata) | 620 | static inline int sta_info_flush(struct ieee80211_sub_if_data *sdata) |
| 604 | { | 621 | { |
| 605 | int ret = sta_info_flush_defer(sdata); | 622 | return __sta_info_flush(sdata, false); |
| 606 | |||
| 607 | rcu_barrier(); | ||
| 608 | sta_info_flush_cleanup(sdata); | ||
| 609 | |||
| 610 | return ret; | ||
| 611 | } | 623 | } |
| 612 | 624 | ||
| 613 | void sta_set_rate_info_tx(struct sta_info *sta, | 625 | void sta_set_rate_info_tx(struct sta_info *sta, |
| @@ -623,6 +635,4 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta); | |||
| 623 | void ieee80211_sta_ps_deliver_poll_response(struct sta_info *sta); | 635 | void ieee80211_sta_ps_deliver_poll_response(struct sta_info *sta); |
| 624 | void ieee80211_sta_ps_deliver_uapsd(struct sta_info *sta); | 636 | void ieee80211_sta_ps_deliver_uapsd(struct sta_info *sta); |
| 625 | 637 | ||
| 626 | void ieee80211_cleanup_sdata_stas(struct ieee80211_sub_if_data *sdata); | ||
| 627 | |||
| 628 | #endif /* STA_INFO_H */ | 638 | #endif /* STA_INFO_H */ |
diff --git a/net/mac80211/status.c b/net/mac80211/status.c index 52a152b01b06..1ee85c402439 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c | |||
| @@ -11,6 +11,7 @@ | |||
| 11 | 11 | ||
| 12 | #include <linux/export.h> | 12 | #include <linux/export.h> |
| 13 | #include <linux/etherdevice.h> | 13 | #include <linux/etherdevice.h> |
| 14 | #include <linux/time.h> | ||
| 14 | #include <net/mac80211.h> | 15 | #include <net/mac80211.h> |
| 15 | #include <asm/unaligned.h> | 16 | #include <asm/unaligned.h> |
| 16 | #include "ieee80211_i.h" | 17 | #include "ieee80211_i.h" |
| @@ -463,6 +464,77 @@ static void ieee80211_report_used_skb(struct ieee80211_local *local, | |||
| 463 | } | 464 | } |
| 464 | 465 | ||
| 465 | /* | 466 | /* |
| 467 | * Measure Tx frame completion and removal time for Tx latency statistics | ||
| 468 | * calculation. A single Tx frame latency should be measured from when it | ||
| 469 | * is entering the Kernel until we receive Tx complete confirmation indication | ||
| 470 | * and remove the skb. | ||
| 471 | */ | ||
| 472 | static void ieee80211_tx_latency_end_msrmnt(struct ieee80211_local *local, | ||
| 473 | struct sk_buff *skb, | ||
| 474 | struct sta_info *sta, | ||
| 475 | struct ieee80211_hdr *hdr) | ||
| 476 | { | ||
| 477 | ktime_t skb_dprt; | ||
| 478 | struct timespec dprt_time; | ||
| 479 | u32 msrmnt; | ||
| 480 | u16 tid; | ||
| 481 | u8 *qc; | ||
| 482 | int i, bin_range_count, bin_count; | ||
| 483 | u32 *bin_ranges; | ||
| 484 | __le16 fc; | ||
| 485 | struct ieee80211_tx_latency_stat *tx_lat; | ||
| 486 | struct ieee80211_tx_latency_bin_ranges *tx_latency; | ||
| 487 | ktime_t skb_arv = skb->tstamp; | ||
| 488 | |||
| 489 | tx_latency = rcu_dereference(local->tx_latency); | ||
| 490 | |||
| 491 | /* assert Tx latency stats are enabled & frame arrived when enabled */ | ||
| 492 | if (!tx_latency || !ktime_to_ns(skb_arv)) | ||
| 493 | return; | ||
| 494 | |||
| 495 | fc = hdr->frame_control; | ||
| 496 | |||
| 497 | if (!ieee80211_is_data(fc)) /* make sure it is a data frame */ | ||
| 498 | return; | ||
| 499 | |||
| 500 | /* get frame tid */ | ||
| 501 | if (ieee80211_is_data_qos(hdr->frame_control)) { | ||
| 502 | qc = ieee80211_get_qos_ctl(hdr); | ||
| 503 | tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; | ||
| 504 | } else { | ||
| 505 | tid = 0; | ||
| 506 | } | ||
| 507 | |||
| 508 | tx_lat = &sta->tx_lat[tid]; | ||
| 509 | |||
| 510 | ktime_get_ts(&dprt_time); /* time stamp completion time */ | ||
| 511 | skb_dprt = ktime_set(dprt_time.tv_sec, dprt_time.tv_nsec); | ||
| 512 | msrmnt = ktime_to_ms(ktime_sub(skb_dprt, skb_arv)); | ||
| 513 | |||
| 514 | if (tx_lat->max < msrmnt) /* update stats */ | ||
| 515 | tx_lat->max = msrmnt; | ||
| 516 | tx_lat->counter++; | ||
| 517 | tx_lat->sum += msrmnt; | ||
| 518 | |||
| 519 | if (!tx_lat->bins) /* bins not activated */ | ||
| 520 | return; | ||
| 521 | |||
| 522 | /* count how many Tx frames transmitted with the appropriate latency */ | ||
| 523 | bin_range_count = tx_latency->n_ranges; | ||
| 524 | bin_ranges = tx_latency->ranges; | ||
| 525 | bin_count = tx_lat->bin_count; | ||
| 526 | |||
| 527 | for (i = 0; i < bin_range_count; i++) { | ||
| 528 | if (msrmnt <= bin_ranges[i]) { | ||
| 529 | tx_lat->bins[i]++; | ||
| 530 | break; | ||
| 531 | } | ||
| 532 | } | ||
| 533 | if (i == bin_range_count) /* msrmnt is bigger than the biggest range */ | ||
| 534 | tx_lat->bins[i]++; | ||
| 535 | } | ||
| 536 | |||
| 537 | /* | ||
| 466 | * Use a static threshold for now, best value to be determined | 538 | * Use a static threshold for now, best value to be determined |
| 467 | * by testing ... | 539 | * by testing ... |
| 468 | * Should it depend on: | 540 | * Should it depend on: |
| @@ -620,6 +692,12 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
| 620 | 692 | ||
| 621 | if (acked) | 693 | if (acked) |
| 622 | sta->last_ack_signal = info->status.ack_signal; | 694 | sta->last_ack_signal = info->status.ack_signal; |
| 695 | |||
| 696 | /* | ||
| 697 | * Measure frame removal for tx latency | ||
| 698 | * statistics calculation | ||
| 699 | */ | ||
| 700 | ieee80211_tx_latency_end_msrmnt(local, skb, sta, hdr); | ||
| 623 | } | 701 | } |
| 624 | 702 | ||
| 625 | rcu_read_unlock(); | 703 | rcu_read_unlock(); |
diff --git a/net/mac80211/tkip.c b/net/mac80211/tkip.c index 124b1fdc20d0..0ae207771a58 100644 --- a/net/mac80211/tkip.c +++ b/net/mac80211/tkip.c | |||
| @@ -186,7 +186,7 @@ void ieee80211_get_tkip_p1k_iv(struct ieee80211_key_conf *keyconf, | |||
| 186 | EXPORT_SYMBOL(ieee80211_get_tkip_p1k_iv); | 186 | EXPORT_SYMBOL(ieee80211_get_tkip_p1k_iv); |
| 187 | 187 | ||
| 188 | void ieee80211_get_tkip_rx_p1k(struct ieee80211_key_conf *keyconf, | 188 | void ieee80211_get_tkip_rx_p1k(struct ieee80211_key_conf *keyconf, |
| 189 | const u8 *ta, u32 iv32, u16 *p1k) | 189 | const u8 *ta, u32 iv32, u16 *p1k) |
| 190 | { | 190 | { |
| 191 | const u8 *tk = &keyconf->key[NL80211_TKIP_DATA_OFFSET_ENCR_KEY]; | 191 | const u8 *tk = &keyconf->key[NL80211_TKIP_DATA_OFFSET_ENCR_KEY]; |
| 192 | struct tkip_ctx ctx; | 192 | struct tkip_ctx ctx; |
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index d4cee98533fd..a0b0aea76525 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h | |||
| @@ -41,14 +41,31 @@ | |||
| 41 | #define CHANDEF_PR_ARG __entry->control_freq, __entry->chan_width, \ | 41 | #define CHANDEF_PR_ARG __entry->control_freq, __entry->chan_width, \ |
| 42 | __entry->center_freq1, __entry->center_freq2 | 42 | __entry->center_freq1, __entry->center_freq2 |
| 43 | 43 | ||
| 44 | #define MIN_CHANDEF_ENTRY \ | ||
| 45 | __field(u32, min_control_freq) \ | ||
| 46 | __field(u32, min_chan_width) \ | ||
| 47 | __field(u32, min_center_freq1) \ | ||
| 48 | __field(u32, min_center_freq2) | ||
| 49 | |||
| 50 | #define MIN_CHANDEF_ASSIGN(c) \ | ||
| 51 | __entry->min_control_freq = (c)->chan ? (c)->chan->center_freq : 0; \ | ||
| 52 | __entry->min_chan_width = (c)->width; \ | ||
| 53 | __entry->min_center_freq1 = (c)->center_freq1; \ | ||
| 54 | __entry->min_center_freq2 = (c)->center_freq2; | ||
| 55 | #define MIN_CHANDEF_PR_FMT " min_control:%d MHz min_width:%d min_center: %d/%d MHz" | ||
| 56 | #define MIN_CHANDEF_PR_ARG __entry->min_control_freq, __entry->min_chan_width, \ | ||
| 57 | __entry->min_center_freq1, __entry->min_center_freq2 | ||
| 58 | |||
| 44 | #define CHANCTX_ENTRY CHANDEF_ENTRY \ | 59 | #define CHANCTX_ENTRY CHANDEF_ENTRY \ |
| 60 | MIN_CHANDEF_ENTRY \ | ||
| 45 | __field(u8, rx_chains_static) \ | 61 | __field(u8, rx_chains_static) \ |
| 46 | __field(u8, rx_chains_dynamic) | 62 | __field(u8, rx_chains_dynamic) |
| 47 | #define CHANCTX_ASSIGN CHANDEF_ASSIGN(&ctx->conf.def) \ | 63 | #define CHANCTX_ASSIGN CHANDEF_ASSIGN(&ctx->conf.def) \ |
| 64 | MIN_CHANDEF_ASSIGN(&ctx->conf.min_def) \ | ||
| 48 | __entry->rx_chains_static = ctx->conf.rx_chains_static; \ | 65 | __entry->rx_chains_static = ctx->conf.rx_chains_static; \ |
| 49 | __entry->rx_chains_dynamic = ctx->conf.rx_chains_dynamic | 66 | __entry->rx_chains_dynamic = ctx->conf.rx_chains_dynamic |
| 50 | #define CHANCTX_PR_FMT CHANDEF_PR_FMT " chains:%d/%d" | 67 | #define CHANCTX_PR_FMT CHANDEF_PR_FMT MIN_CHANDEF_PR_FMT " chains:%d/%d" |
| 51 | #define CHANCTX_PR_ARG CHANDEF_PR_ARG, \ | 68 | #define CHANCTX_PR_ARG CHANDEF_PR_ARG, MIN_CHANDEF_PR_ARG, \ |
| 52 | __entry->rx_chains_static, __entry->rx_chains_dynamic | 69 | __entry->rx_chains_static, __entry->rx_chains_dynamic |
| 53 | 70 | ||
| 54 | 71 | ||
| @@ -426,30 +443,6 @@ TRACE_EVENT(drv_prepare_multicast, | |||
| 426 | ) | 443 | ) |
| 427 | ); | 444 | ); |
| 428 | 445 | ||
| 429 | TRACE_EVENT(drv_set_multicast_list, | ||
| 430 | TP_PROTO(struct ieee80211_local *local, | ||
| 431 | struct ieee80211_sub_if_data *sdata, int mc_count), | ||
| 432 | |||
| 433 | TP_ARGS(local, sdata, mc_count), | ||
| 434 | |||
| 435 | TP_STRUCT__entry( | ||
| 436 | LOCAL_ENTRY | ||
| 437 | __field(bool, allmulti) | ||
| 438 | __field(int, mc_count) | ||
| 439 | ), | ||
| 440 | |||
| 441 | TP_fast_assign( | ||
| 442 | LOCAL_ASSIGN; | ||
| 443 | __entry->allmulti = sdata->flags & IEEE80211_SDATA_ALLMULTI; | ||
| 444 | __entry->mc_count = mc_count; | ||
| 445 | ), | ||
| 446 | |||
| 447 | TP_printk( | ||
| 448 | LOCAL_PR_FMT " configure mc filter, count=%d, allmulti=%d", | ||
| 449 | LOCAL_PR_ARG, __entry->mc_count, __entry->allmulti | ||
| 450 | ) | ||
| 451 | ); | ||
| 452 | |||
| 453 | TRACE_EVENT(drv_configure_filter, | 446 | TRACE_EVENT(drv_configure_filter, |
| 454 | TP_PROTO(struct ieee80211_local *local, | 447 | TP_PROTO(struct ieee80211_local *local, |
| 455 | unsigned int changed_flags, | 448 | unsigned int changed_flags, |
| @@ -560,7 +553,7 @@ TRACE_EVENT(drv_update_tkip_key, | |||
| 560 | 553 | ||
| 561 | TP_printk( | 554 | TP_printk( |
| 562 | LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT " iv32:%#x", | 555 | LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT " iv32:%#x", |
| 563 | LOCAL_PR_ARG,VIF_PR_ARG,STA_PR_ARG, __entry->iv32 | 556 | LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->iv32 |
| 564 | ) | 557 | ) |
| 565 | ); | 558 | ); |
| 566 | 559 | ||
| @@ -773,7 +766,7 @@ TRACE_EVENT(drv_sta_rc_update, | |||
| 773 | ) | 766 | ) |
| 774 | ); | 767 | ); |
| 775 | 768 | ||
| 776 | TRACE_EVENT(drv_sta_add, | 769 | DECLARE_EVENT_CLASS(sta_event, |
| 777 | TP_PROTO(struct ieee80211_local *local, | 770 | TP_PROTO(struct ieee80211_local *local, |
| 778 | struct ieee80211_sub_if_data *sdata, | 771 | struct ieee80211_sub_if_data *sdata, |
| 779 | struct ieee80211_sta *sta), | 772 | struct ieee80211_sta *sta), |
| @@ -798,29 +791,25 @@ TRACE_EVENT(drv_sta_add, | |||
| 798 | ) | 791 | ) |
| 799 | ); | 792 | ); |
| 800 | 793 | ||
| 801 | TRACE_EVENT(drv_sta_remove, | 794 | DEFINE_EVENT(sta_event, drv_sta_add, |
| 802 | TP_PROTO(struct ieee80211_local *local, | 795 | TP_PROTO(struct ieee80211_local *local, |
| 803 | struct ieee80211_sub_if_data *sdata, | 796 | struct ieee80211_sub_if_data *sdata, |
| 804 | struct ieee80211_sta *sta), | 797 | struct ieee80211_sta *sta), |
| 798 | TP_ARGS(local, sdata, sta) | ||
| 799 | ); | ||
| 805 | 800 | ||
| 806 | TP_ARGS(local, sdata, sta), | 801 | DEFINE_EVENT(sta_event, drv_sta_remove, |
| 807 | 802 | TP_PROTO(struct ieee80211_local *local, | |
| 808 | TP_STRUCT__entry( | 803 | struct ieee80211_sub_if_data *sdata, |
| 809 | LOCAL_ENTRY | 804 | struct ieee80211_sta *sta), |
| 810 | VIF_ENTRY | 805 | TP_ARGS(local, sdata, sta) |
| 811 | STA_ENTRY | 806 | ); |
| 812 | ), | ||
| 813 | |||
| 814 | TP_fast_assign( | ||
| 815 | LOCAL_ASSIGN; | ||
| 816 | VIF_ASSIGN; | ||
| 817 | STA_ASSIGN; | ||
| 818 | ), | ||
| 819 | 807 | ||
| 820 | TP_printk( | 808 | DEFINE_EVENT(sta_event, drv_sta_pre_rcu_remove, |
| 821 | LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT, | 809 | TP_PROTO(struct ieee80211_local *local, |
| 822 | LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG | 810 | struct ieee80211_sub_if_data *sdata, |
| 823 | ) | 811 | struct ieee80211_sta *sta), |
| 812 | TP_ARGS(local, sdata, sta) | ||
| 824 | ); | 813 | ); |
| 825 | 814 | ||
| 826 | TRACE_EVENT(drv_conf_tx, | 815 | TRACE_EVENT(drv_conf_tx, |
| @@ -1846,6 +1835,33 @@ TRACE_EVENT(api_eosp, | |||
| 1846 | ) | 1835 | ) |
| 1847 | ); | 1836 | ); |
| 1848 | 1837 | ||
| 1838 | TRACE_EVENT(api_sta_set_buffered, | ||
| 1839 | TP_PROTO(struct ieee80211_local *local, | ||
| 1840 | struct ieee80211_sta *sta, | ||
| 1841 | u8 tid, bool buffered), | ||
| 1842 | |||
| 1843 | TP_ARGS(local, sta, tid, buffered), | ||
| 1844 | |||
| 1845 | TP_STRUCT__entry( | ||
| 1846 | LOCAL_ENTRY | ||
| 1847 | STA_ENTRY | ||
| 1848 | __field(u8, tid) | ||
| 1849 | __field(bool, buffered) | ||
| 1850 | ), | ||
| 1851 | |||
| 1852 | TP_fast_assign( | ||
| 1853 | LOCAL_ASSIGN; | ||
| 1854 | STA_ASSIGN; | ||
| 1855 | __entry->tid = tid; | ||
| 1856 | __entry->buffered = buffered; | ||
| 1857 | ), | ||
| 1858 | |||
| 1859 | TP_printk( | ||
| 1860 | LOCAL_PR_FMT STA_PR_FMT " tid:%d buffered:%d", | ||
| 1861 | LOCAL_PR_ARG, STA_PR_ARG, __entry->tid, __entry->buffered | ||
| 1862 | ) | ||
| 1863 | ); | ||
| 1864 | |||
| 1849 | /* | 1865 | /* |
| 1850 | * Tracing for internal functions | 1866 | * Tracing for internal functions |
| 1851 | * (which may also be called in response to driver calls) | 1867 | * (which may also be called in response to driver calls) |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index ca7fa7f0613d..27c990bf2320 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
| @@ -19,6 +19,7 @@ | |||
| 19 | #include <linux/bitmap.h> | 19 | #include <linux/bitmap.h> |
| 20 | #include <linux/rcupdate.h> | 20 | #include <linux/rcupdate.h> |
| 21 | #include <linux/export.h> | 21 | #include <linux/export.h> |
| 22 | #include <linux/time.h> | ||
| 22 | #include <net/net_namespace.h> | 23 | #include <net/net_namespace.h> |
| 23 | #include <net/ieee80211_radiotap.h> | 24 | #include <net/ieee80211_radiotap.h> |
| 24 | #include <net/cfg80211.h> | 25 | #include <net/cfg80211.h> |
| @@ -489,6 +490,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) | |||
| 489 | info->control.jiffies = jiffies; | 490 | info->control.jiffies = jiffies; |
| 490 | info->control.vif = &tx->sdata->vif; | 491 | info->control.vif = &tx->sdata->vif; |
| 491 | info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; | 492 | info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; |
| 493 | info->flags &= ~IEEE80211_TX_TEMPORARY_FLAGS; | ||
| 492 | skb_queue_tail(&sta->ps_tx_buf[ac], tx->skb); | 494 | skb_queue_tail(&sta->ps_tx_buf[ac], tx->skb); |
| 493 | 495 | ||
| 494 | if (!timer_pending(&local->sta_cleanup)) | 496 | if (!timer_pending(&local->sta_cleanup)) |
| @@ -560,7 +562,8 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) | |||
| 560 | 562 | ||
| 561 | if (unlikely(info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT)) | 563 | if (unlikely(info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT)) |
| 562 | tx->key = NULL; | 564 | tx->key = NULL; |
| 563 | else if (tx->sta && (key = rcu_dereference(tx->sta->ptk))) | 565 | else if (tx->sta && |
| 566 | (key = rcu_dereference(tx->sta->ptk[tx->sta->ptk_idx]))) | ||
| 564 | tx->key = key; | 567 | tx->key = key; |
| 565 | else if (ieee80211_is_mgmt(hdr->frame_control) && | 568 | else if (ieee80211_is_mgmt(hdr->frame_control) && |
| 566 | is_multicast_ether_addr(hdr->addr1) && | 569 | is_multicast_ether_addr(hdr->addr1) && |
| @@ -843,15 +846,16 @@ static int ieee80211_fragment(struct ieee80211_tx_data *tx, | |||
| 843 | rem -= fraglen; | 846 | rem -= fraglen; |
| 844 | tmp = dev_alloc_skb(local->tx_headroom + | 847 | tmp = dev_alloc_skb(local->tx_headroom + |
| 845 | frag_threshold + | 848 | frag_threshold + |
| 846 | IEEE80211_ENCRYPT_HEADROOM + | 849 | tx->sdata->encrypt_headroom + |
| 847 | IEEE80211_ENCRYPT_TAILROOM); | 850 | IEEE80211_ENCRYPT_TAILROOM); |
| 848 | if (!tmp) | 851 | if (!tmp) |
| 849 | return -ENOMEM; | 852 | return -ENOMEM; |
| 850 | 853 | ||
| 851 | __skb_queue_tail(&tx->skbs, tmp); | 854 | __skb_queue_tail(&tx->skbs, tmp); |
| 852 | 855 | ||
| 853 | skb_reserve(tmp, local->tx_headroom + | 856 | skb_reserve(tmp, |
| 854 | IEEE80211_ENCRYPT_HEADROOM); | 857 | local->tx_headroom + tx->sdata->encrypt_headroom); |
| 858 | |||
| 855 | /* copy control information */ | 859 | /* copy control information */ |
| 856 | memcpy(tmp->cb, skb->cb, sizeof(tmp->cb)); | 860 | memcpy(tmp->cb, skb->cb, sizeof(tmp->cb)); |
| 857 | 861 | ||
| @@ -1073,6 +1077,7 @@ static bool ieee80211_tx_prep_agg(struct ieee80211_tx_data *tx, | |||
| 1073 | queued = true; | 1077 | queued = true; |
| 1074 | info->control.vif = &tx->sdata->vif; | 1078 | info->control.vif = &tx->sdata->vif; |
| 1075 | info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; | 1079 | info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; |
| 1080 | info->flags &= ~IEEE80211_TX_TEMPORARY_FLAGS; | ||
| 1076 | __skb_queue_tail(&tid_tx->pending, skb); | 1081 | __skb_queue_tail(&tid_tx->pending, skb); |
| 1077 | if (skb_queue_len(&tid_tx->pending) > STA_MAX_TX_BUFFER) | 1082 | if (skb_queue_len(&tid_tx->pending) > STA_MAX_TX_BUFFER) |
| 1078 | purge_skb = __skb_dequeue(&tid_tx->pending); | 1083 | purge_skb = __skb_dequeue(&tid_tx->pending); |
| @@ -1488,7 +1493,7 @@ void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, | |||
| 1488 | 1493 | ||
| 1489 | headroom = local->tx_headroom; | 1494 | headroom = local->tx_headroom; |
| 1490 | if (may_encrypt) | 1495 | if (may_encrypt) |
| 1491 | headroom += IEEE80211_ENCRYPT_HEADROOM; | 1496 | headroom += sdata->encrypt_headroom; |
| 1492 | headroom -= skb_headroom(skb); | 1497 | headroom -= skb_headroom(skb); |
| 1493 | headroom = max_t(int, 0, headroom); | 1498 | headroom = max_t(int, 0, headroom); |
| 1494 | 1499 | ||
| @@ -1727,8 +1732,7 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb, | |||
| 1727 | * radar detection by itself. We can do that later by adding a | 1732 | * radar detection by itself. We can do that later by adding a |
| 1728 | * monitor flag interfaces used for AP support. | 1733 | * monitor flag interfaces used for AP support. |
| 1729 | */ | 1734 | */ |
| 1730 | if ((chan->flags & (IEEE80211_CHAN_NO_IBSS | IEEE80211_CHAN_RADAR | | 1735 | if ((chan->flags & (IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_RADAR))) |
| 1731 | IEEE80211_CHAN_PASSIVE_SCAN))) | ||
| 1732 | goto fail_rcu; | 1736 | goto fail_rcu; |
| 1733 | 1737 | ||
| 1734 | ieee80211_xmit(sdata, skb, chan->band); | 1738 | ieee80211_xmit(sdata, skb, chan->band); |
| @@ -1743,6 +1747,26 @@ fail: | |||
| 1743 | return NETDEV_TX_OK; /* meaning, we dealt with the skb */ | 1747 | return NETDEV_TX_OK; /* meaning, we dealt with the skb */ |
| 1744 | } | 1748 | } |
| 1745 | 1749 | ||
| 1750 | /* | ||
| 1751 | * Measure Tx frame arrival time for Tx latency statistics calculation | ||
| 1752 | * A single Tx frame latency should be measured from when it is entering the | ||
| 1753 | * Kernel until we receive Tx complete confirmation indication and the skb is | ||
| 1754 | * freed. | ||
| 1755 | */ | ||
| 1756 | static void ieee80211_tx_latency_start_msrmnt(struct ieee80211_local *local, | ||
| 1757 | struct sk_buff *skb) | ||
| 1758 | { | ||
| 1759 | struct timespec skb_arv; | ||
| 1760 | struct ieee80211_tx_latency_bin_ranges *tx_latency; | ||
| 1761 | |||
| 1762 | tx_latency = rcu_dereference(local->tx_latency); | ||
| 1763 | if (!tx_latency) | ||
| 1764 | return; | ||
| 1765 | |||
| 1766 | ktime_get_ts(&skb_arv); | ||
| 1767 | skb->tstamp = ktime_set(skb_arv.tv_sec, skb_arv.tv_nsec); | ||
| 1768 | } | ||
| 1769 | |||
| 1746 | /** | 1770 | /** |
| 1747 | * ieee80211_subif_start_xmit - netif start_xmit function for Ethernet-type | 1771 | * ieee80211_subif_start_xmit - netif start_xmit function for Ethernet-type |
| 1748 | * subinterfaces (wlan#, WDS, and VLAN interfaces) | 1772 | * subinterfaces (wlan#, WDS, and VLAN interfaces) |
| @@ -1793,6 +1817,9 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
| 1793 | 1817 | ||
| 1794 | rcu_read_lock(); | 1818 | rcu_read_lock(); |
| 1795 | 1819 | ||
| 1820 | /* Measure frame arrival for Tx latency statistics calculation */ | ||
| 1821 | ieee80211_tx_latency_start_msrmnt(local, skb); | ||
| 1822 | |||
| 1796 | switch (sdata->vif.type) { | 1823 | switch (sdata->vif.type) { |
| 1797 | case NL80211_IFTYPE_AP_VLAN: | 1824 | case NL80211_IFTYPE_AP_VLAN: |
| 1798 | sta = rcu_dereference(sdata->u.vlan.sta); | 1825 | sta = rcu_dereference(sdata->u.vlan.sta); |
| @@ -2112,7 +2139,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
| 2112 | */ | 2139 | */ |
| 2113 | 2140 | ||
| 2114 | if (head_need > 0 || skb_cloned(skb)) { | 2141 | if (head_need > 0 || skb_cloned(skb)) { |
| 2115 | head_need += IEEE80211_ENCRYPT_HEADROOM; | 2142 | head_need += sdata->encrypt_headroom; |
| 2116 | head_need += local->tx_headroom; | 2143 | head_need += local->tx_headroom; |
| 2117 | head_need = max_t(int, 0, head_need); | 2144 | head_need = max_t(int, 0, head_need); |
| 2118 | if (ieee80211_skb_resize(sdata, skb, head_need, true)) { | 2145 | if (ieee80211_skb_resize(sdata, skb, head_need, true)) { |
| @@ -2139,7 +2166,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
| 2139 | if (ieee80211_is_data_qos(fc)) { | 2166 | if (ieee80211_is_data_qos(fc)) { |
| 2140 | __le16 *qos_control; | 2167 | __le16 *qos_control; |
| 2141 | 2168 | ||
| 2142 | qos_control = (__le16*) skb_push(skb, 2); | 2169 | qos_control = (__le16 *) skb_push(skb, 2); |
| 2143 | memcpy(skb_push(skb, hdrlen - 2), &hdr, hdrlen - 2); | 2170 | memcpy(skb_push(skb, hdrlen - 2), &hdr, hdrlen - 2); |
| 2144 | /* | 2171 | /* |
| 2145 | * Maybe we could actually set some fields here, for now just | 2172 | * Maybe we could actually set some fields here, for now just |
| @@ -2301,7 +2328,7 @@ static void __ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata, | |||
| 2301 | if (atomic_read(&ps->num_sta_ps) > 0) | 2328 | if (atomic_read(&ps->num_sta_ps) > 0) |
| 2302 | /* in the hope that this is faster than | 2329 | /* in the hope that this is faster than |
| 2303 | * checking byte-for-byte */ | 2330 | * checking byte-for-byte */ |
| 2304 | have_bits = !bitmap_empty((unsigned long*)ps->tim, | 2331 | have_bits = !bitmap_empty((unsigned long *)ps->tim, |
| 2305 | IEEE80211_MAX_AID+1); | 2332 | IEEE80211_MAX_AID+1); |
| 2306 | 2333 | ||
| 2307 | if (ps->dtim_count == 0) | 2334 | if (ps->dtim_count == 0) |
| @@ -2527,7 +2554,8 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, | |||
| 2527 | */ | 2554 | */ |
| 2528 | skb = dev_alloc_skb(local->tx_headroom + | 2555 | skb = dev_alloc_skb(local->tx_headroom + |
| 2529 | beacon->head_len + | 2556 | beacon->head_len + |
| 2530 | beacon->tail_len + 256); | 2557 | beacon->tail_len + 256 + |
| 2558 | local->hw.extra_beacon_tailroom); | ||
| 2531 | if (!skb) | 2559 | if (!skb) |
| 2532 | goto out; | 2560 | goto out; |
| 2533 | 2561 | ||
| @@ -2559,7 +2587,8 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, | |||
| 2559 | ieee80211_update_csa(sdata, presp); | 2587 | ieee80211_update_csa(sdata, presp); |
| 2560 | 2588 | ||
| 2561 | 2589 | ||
| 2562 | skb = dev_alloc_skb(local->tx_headroom + presp->head_len); | 2590 | skb = dev_alloc_skb(local->tx_headroom + presp->head_len + |
| 2591 | local->hw.extra_beacon_tailroom); | ||
| 2563 | if (!skb) | 2592 | if (!skb) |
| 2564 | goto out; | 2593 | goto out; |
| 2565 | skb_reserve(skb, local->tx_headroom); | 2594 | skb_reserve(skb, local->tx_headroom); |
| @@ -2580,13 +2609,13 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, | |||
| 2580 | ieee80211_update_csa(sdata, bcn); | 2609 | ieee80211_update_csa(sdata, bcn); |
| 2581 | 2610 | ||
| 2582 | if (ifmsh->sync_ops) | 2611 | if (ifmsh->sync_ops) |
| 2583 | ifmsh->sync_ops->adjust_tbtt( | 2612 | ifmsh->sync_ops->adjust_tbtt(sdata, bcn); |
| 2584 | sdata); | ||
| 2585 | 2613 | ||
| 2586 | skb = dev_alloc_skb(local->tx_headroom + | 2614 | skb = dev_alloc_skb(local->tx_headroom + |
| 2587 | bcn->head_len + | 2615 | bcn->head_len + |
| 2588 | 256 + /* TIM IE */ | 2616 | 256 + /* TIM IE */ |
| 2589 | bcn->tail_len); | 2617 | bcn->tail_len + |
| 2618 | local->hw.extra_beacon_tailroom); | ||
| 2590 | if (!skb) | 2619 | if (!skb) |
| 2591 | goto out; | 2620 | goto out; |
| 2592 | skb_reserve(skb, local->tx_headroom); | 2621 | skb_reserve(skb, local->tx_headroom); |
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 9f9b9bd3fd44..676dc0967f37 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
| @@ -76,7 +76,7 @@ u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len, | |||
| 76 | } | 76 | } |
| 77 | 77 | ||
| 78 | if (ieee80211_is_ctl(fc)) { | 78 | if (ieee80211_is_ctl(fc)) { |
| 79 | if(ieee80211_is_pspoll(fc)) | 79 | if (ieee80211_is_pspoll(fc)) |
| 80 | return hdr->addr1; | 80 | return hdr->addr1; |
| 81 | 81 | ||
| 82 | if (ieee80211_is_back_req(fc)) { | 82 | if (ieee80211_is_back_req(fc)) { |
| @@ -642,6 +642,17 @@ void ieee80211_iterate_active_interfaces_rtnl( | |||
| 642 | } | 642 | } |
| 643 | EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_rtnl); | 643 | EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_rtnl); |
| 644 | 644 | ||
| 645 | struct ieee80211_vif *wdev_to_ieee80211_vif(struct wireless_dev *wdev) | ||
| 646 | { | ||
| 647 | struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); | ||
| 648 | |||
| 649 | if (!ieee80211_sdata_running(sdata) || | ||
| 650 | !(sdata->flags & IEEE80211_SDATA_IN_DRIVER)) | ||
| 651 | return NULL; | ||
| 652 | return &sdata->vif; | ||
| 653 | } | ||
| 654 | EXPORT_SYMBOL_GPL(wdev_to_ieee80211_vif); | ||
| 655 | |||
| 645 | /* | 656 | /* |
| 646 | * Nothing should have been stuffed into the workqueue during | 657 | * Nothing should have been stuffed into the workqueue during |
| 647 | * the suspend->resume cycle. If this WARN is seen then there | 658 | * the suspend->resume cycle. If this WARN is seen then there |
| @@ -1451,6 +1462,8 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
| 1451 | struct sta_info *sta; | 1462 | struct sta_info *sta; |
| 1452 | int res, i; | 1463 | int res, i; |
| 1453 | bool reconfig_due_to_wowlan = false; | 1464 | bool reconfig_due_to_wowlan = false; |
| 1465 | struct ieee80211_sub_if_data *sched_scan_sdata; | ||
| 1466 | bool sched_scan_stopped = false; | ||
| 1454 | 1467 | ||
| 1455 | #ifdef CONFIG_PM | 1468 | #ifdef CONFIG_PM |
| 1456 | if (local->suspended) | 1469 | if (local->suspended) |
| @@ -1754,6 +1767,27 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
| 1754 | #else | 1767 | #else |
| 1755 | WARN_ON(1); | 1768 | WARN_ON(1); |
| 1756 | #endif | 1769 | #endif |
| 1770 | |||
| 1771 | /* | ||
| 1772 | * Reconfigure sched scan if it was interrupted by FW restart or | ||
| 1773 | * suspend. | ||
| 1774 | */ | ||
| 1775 | mutex_lock(&local->mtx); | ||
| 1776 | sched_scan_sdata = rcu_dereference_protected(local->sched_scan_sdata, | ||
| 1777 | lockdep_is_held(&local->mtx)); | ||
| 1778 | if (sched_scan_sdata && local->sched_scan_req) | ||
| 1779 | /* | ||
| 1780 | * Sched scan stopped, but we don't want to report it. Instead, | ||
| 1781 | * we're trying to reschedule. | ||
| 1782 | */ | ||
| 1783 | if (__ieee80211_request_sched_scan_start(sched_scan_sdata, | ||
| 1784 | local->sched_scan_req)) | ||
| 1785 | sched_scan_stopped = true; | ||
| 1786 | mutex_unlock(&local->mtx); | ||
| 1787 | |||
| 1788 | if (sched_scan_stopped) | ||
| 1789 | cfg80211_sched_scan_stopped(local->hw.wiphy); | ||
| 1790 | |||
| 1757 | return 0; | 1791 | return 0; |
| 1758 | } | 1792 | } |
| 1759 | 1793 | ||
| @@ -1804,6 +1838,26 @@ void ieee80211_recalc_smps(struct ieee80211_sub_if_data *sdata) | |||
| 1804 | mutex_unlock(&local->chanctx_mtx); | 1838 | mutex_unlock(&local->chanctx_mtx); |
| 1805 | } | 1839 | } |
| 1806 | 1840 | ||
| 1841 | void ieee80211_recalc_min_chandef(struct ieee80211_sub_if_data *sdata) | ||
| 1842 | { | ||
| 1843 | struct ieee80211_local *local = sdata->local; | ||
| 1844 | struct ieee80211_chanctx_conf *chanctx_conf; | ||
| 1845 | struct ieee80211_chanctx *chanctx; | ||
| 1846 | |||
| 1847 | mutex_lock(&local->chanctx_mtx); | ||
| 1848 | |||
| 1849 | chanctx_conf = rcu_dereference_protected(sdata->vif.chanctx_conf, | ||
| 1850 | lockdep_is_held(&local->chanctx_mtx)); | ||
| 1851 | |||
| 1852 | if (WARN_ON_ONCE(!chanctx_conf)) | ||
| 1853 | goto unlock; | ||
| 1854 | |||
| 1855 | chanctx = container_of(chanctx_conf, struct ieee80211_chanctx, conf); | ||
| 1856 | ieee80211_recalc_chanctx_min_def(local, chanctx); | ||
| 1857 | unlock: | ||
| 1858 | mutex_unlock(&local->chanctx_mtx); | ||
| 1859 | } | ||
| 1860 | |||
| 1807 | static bool ieee80211_id_in_list(const u8 *ids, int n_ids, u8 id) | 1861 | static bool ieee80211_id_in_list(const u8 *ids, int n_ids, u8 id) |
| 1808 | { | 1862 | { |
| 1809 | int i; | 1863 | int i; |
| @@ -2259,19 +2313,28 @@ u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local, | |||
| 2259 | void ieee80211_dfs_cac_cancel(struct ieee80211_local *local) | 2313 | void ieee80211_dfs_cac_cancel(struct ieee80211_local *local) |
| 2260 | { | 2314 | { |
| 2261 | struct ieee80211_sub_if_data *sdata; | 2315 | struct ieee80211_sub_if_data *sdata; |
| 2316 | struct cfg80211_chan_def chandef; | ||
| 2262 | 2317 | ||
| 2318 | mutex_lock(&local->mtx); | ||
| 2263 | mutex_lock(&local->iflist_mtx); | 2319 | mutex_lock(&local->iflist_mtx); |
| 2264 | list_for_each_entry(sdata, &local->interfaces, list) { | 2320 | list_for_each_entry(sdata, &local->interfaces, list) { |
| 2265 | cancel_delayed_work_sync(&sdata->dfs_cac_timer_work); | 2321 | /* it might be waiting for the local->mtx, but then |
| 2322 | * by the time it gets it, sdata->wdev.cac_started | ||
| 2323 | * will no longer be true | ||
| 2324 | */ | ||
| 2325 | cancel_delayed_work(&sdata->dfs_cac_timer_work); | ||
| 2266 | 2326 | ||
| 2267 | if (sdata->wdev.cac_started) { | 2327 | if (sdata->wdev.cac_started) { |
| 2328 | chandef = sdata->vif.bss_conf.chandef; | ||
| 2268 | ieee80211_vif_release_channel(sdata); | 2329 | ieee80211_vif_release_channel(sdata); |
| 2269 | cfg80211_cac_event(sdata->dev, | 2330 | cfg80211_cac_event(sdata->dev, |
| 2331 | &chandef, | ||
| 2270 | NL80211_RADAR_CAC_ABORTED, | 2332 | NL80211_RADAR_CAC_ABORTED, |
| 2271 | GFP_KERNEL); | 2333 | GFP_KERNEL); |
| 2272 | } | 2334 | } |
| 2273 | } | 2335 | } |
| 2274 | mutex_unlock(&local->iflist_mtx); | 2336 | mutex_unlock(&local->iflist_mtx); |
| 2337 | mutex_unlock(&local->mtx); | ||
| 2275 | } | 2338 | } |
| 2276 | 2339 | ||
| 2277 | void ieee80211_dfs_radar_detected_work(struct work_struct *work) | 2340 | void ieee80211_dfs_radar_detected_work(struct work_struct *work) |
| @@ -2445,7 +2508,6 @@ int ieee80211_send_action_csa(struct ieee80211_sub_if_data *sdata, | |||
| 2445 | 2508 | ||
| 2446 | if (ieee80211_vif_is_mesh(&sdata->vif)) { | 2509 | if (ieee80211_vif_is_mesh(&sdata->vif)) { |
| 2447 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | 2510 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
| 2448 | __le16 pre_value; | ||
| 2449 | 2511 | ||
| 2450 | skb_put(skb, 8); | 2512 | skb_put(skb, 8); |
| 2451 | *pos++ = WLAN_EID_CHAN_SWITCH_PARAM; /* EID */ | 2513 | *pos++ = WLAN_EID_CHAN_SWITCH_PARAM; /* EID */ |
| @@ -2457,11 +2519,259 @@ int ieee80211_send_action_csa(struct ieee80211_sub_if_data *sdata, | |||
| 2457 | WLAN_EID_CHAN_SWITCH_PARAM_TX_RESTRICT : 0x00; | 2519 | WLAN_EID_CHAN_SWITCH_PARAM_TX_RESTRICT : 0x00; |
| 2458 | put_unaligned_le16(WLAN_REASON_MESH_CHAN, pos); /* Reason Cd */ | 2520 | put_unaligned_le16(WLAN_REASON_MESH_CHAN, pos); /* Reason Cd */ |
| 2459 | pos += 2; | 2521 | pos += 2; |
| 2460 | pre_value = cpu_to_le16(ifmsh->pre_value); | 2522 | put_unaligned_le16(ifmsh->pre_value, pos);/* Precedence Value */ |
| 2461 | memcpy(pos, &pre_value, 2); /* Precedence Value */ | ||
| 2462 | pos += 2; | 2523 | pos += 2; |
| 2463 | } | 2524 | } |
| 2464 | 2525 | ||
| 2465 | ieee80211_tx_skb(sdata, skb); | 2526 | ieee80211_tx_skb(sdata, skb); |
| 2466 | return 0; | 2527 | return 0; |
| 2467 | } | 2528 | } |
| 2529 | |||
| 2530 | bool ieee80211_cs_valid(const struct ieee80211_cipher_scheme *cs) | ||
| 2531 | { | ||
| 2532 | return !(cs == NULL || cs->cipher == 0 || | ||
| 2533 | cs->hdr_len < cs->pn_len + cs->pn_off || | ||
| 2534 | cs->hdr_len <= cs->key_idx_off || | ||
| 2535 | cs->key_idx_shift > 7 || | ||
| 2536 | cs->key_idx_mask == 0); | ||
| 2537 | } | ||
| 2538 | |||
| 2539 | bool ieee80211_cs_list_valid(const struct ieee80211_cipher_scheme *cs, int n) | ||
| 2540 | { | ||
| 2541 | int i; | ||
| 2542 | |||
| 2543 | /* Ensure we have enough iftype bitmap space for all iftype values */ | ||
| 2544 | WARN_ON((NUM_NL80211_IFTYPES / 8 + 1) > sizeof(cs[0].iftype)); | ||
| 2545 | |||
| 2546 | for (i = 0; i < n; i++) | ||
| 2547 | if (!ieee80211_cs_valid(&cs[i])) | ||
| 2548 | return false; | ||
| 2549 | |||
| 2550 | return true; | ||
| 2551 | } | ||
| 2552 | |||
| 2553 | const struct ieee80211_cipher_scheme * | ||
| 2554 | ieee80211_cs_get(struct ieee80211_local *local, u32 cipher, | ||
| 2555 | enum nl80211_iftype iftype) | ||
| 2556 | { | ||
| 2557 | const struct ieee80211_cipher_scheme *l = local->hw.cipher_schemes; | ||
| 2558 | int n = local->hw.n_cipher_schemes; | ||
| 2559 | int i; | ||
| 2560 | const struct ieee80211_cipher_scheme *cs = NULL; | ||
| 2561 | |||
| 2562 | for (i = 0; i < n; i++) { | ||
| 2563 | if (l[i].cipher == cipher) { | ||
| 2564 | cs = &l[i]; | ||
| 2565 | break; | ||
| 2566 | } | ||
| 2567 | } | ||
| 2568 | |||
| 2569 | if (!cs || !(cs->iftype & BIT(iftype))) | ||
| 2570 | return NULL; | ||
| 2571 | |||
| 2572 | return cs; | ||
| 2573 | } | ||
| 2574 | |||
| 2575 | int ieee80211_cs_headroom(struct ieee80211_local *local, | ||
| 2576 | struct cfg80211_crypto_settings *crypto, | ||
| 2577 | enum nl80211_iftype iftype) | ||
| 2578 | { | ||
| 2579 | const struct ieee80211_cipher_scheme *cs; | ||
| 2580 | int headroom = IEEE80211_ENCRYPT_HEADROOM; | ||
| 2581 | int i; | ||
| 2582 | |||
| 2583 | for (i = 0; i < crypto->n_ciphers_pairwise; i++) { | ||
| 2584 | cs = ieee80211_cs_get(local, crypto->ciphers_pairwise[i], | ||
| 2585 | iftype); | ||
| 2586 | |||
| 2587 | if (cs && headroom < cs->hdr_len) | ||
| 2588 | headroom = cs->hdr_len; | ||
| 2589 | } | ||
| 2590 | |||
| 2591 | cs = ieee80211_cs_get(local, crypto->cipher_group, iftype); | ||
| 2592 | if (cs && headroom < cs->hdr_len) | ||
| 2593 | headroom = cs->hdr_len; | ||
| 2594 | |||
| 2595 | return headroom; | ||
| 2596 | } | ||
| 2597 | |||
| 2598 | static bool | ||
| 2599 | ieee80211_extend_noa_desc(struct ieee80211_noa_data *data, u32 tsf, int i) | ||
| 2600 | { | ||
| 2601 | s32 end = data->desc[i].start + data->desc[i].duration - (tsf + 1); | ||
| 2602 | int skip; | ||
| 2603 | |||
| 2604 | if (end > 0) | ||
| 2605 | return false; | ||
| 2606 | |||
| 2607 | /* End time is in the past, check for repetitions */ | ||
| 2608 | skip = DIV_ROUND_UP(-end, data->desc[i].interval); | ||
| 2609 | if (data->count[i] < 255) { | ||
| 2610 | if (data->count[i] <= skip) { | ||
| 2611 | data->count[i] = 0; | ||
| 2612 | return false; | ||
| 2613 | } | ||
| 2614 | |||
| 2615 | data->count[i] -= skip; | ||
| 2616 | } | ||
| 2617 | |||
| 2618 | data->desc[i].start += skip * data->desc[i].interval; | ||
| 2619 | |||
| 2620 | return true; | ||
| 2621 | } | ||
| 2622 | |||
| 2623 | static bool | ||
| 2624 | ieee80211_extend_absent_time(struct ieee80211_noa_data *data, u32 tsf, | ||
| 2625 | s32 *offset) | ||
| 2626 | { | ||
| 2627 | bool ret = false; | ||
| 2628 | int i; | ||
| 2629 | |||
| 2630 | for (i = 0; i < IEEE80211_P2P_NOA_DESC_MAX; i++) { | ||
| 2631 | s32 cur; | ||
| 2632 | |||
| 2633 | if (!data->count[i]) | ||
| 2634 | continue; | ||
| 2635 | |||
| 2636 | if (ieee80211_extend_noa_desc(data, tsf + *offset, i)) | ||
| 2637 | ret = true; | ||
| 2638 | |||
| 2639 | cur = data->desc[i].start - tsf; | ||
| 2640 | if (cur > *offset) | ||
| 2641 | continue; | ||
| 2642 | |||
| 2643 | cur = data->desc[i].start + data->desc[i].duration - tsf; | ||
| 2644 | if (cur > *offset) | ||
| 2645 | *offset = cur; | ||
| 2646 | } | ||
| 2647 | |||
| 2648 | return ret; | ||
| 2649 | } | ||
| 2650 | |||
| 2651 | static u32 | ||
| 2652 | ieee80211_get_noa_absent_time(struct ieee80211_noa_data *data, u32 tsf) | ||
| 2653 | { | ||
| 2654 | s32 offset = 0; | ||
| 2655 | int tries = 0; | ||
| 2656 | /* | ||
| 2657 | * arbitrary limit, used to avoid infinite loops when combined NoA | ||
| 2658 | * descriptors cover the full time period. | ||
| 2659 | */ | ||
| 2660 | int max_tries = 5; | ||
| 2661 | |||
| 2662 | ieee80211_extend_absent_time(data, tsf, &offset); | ||
| 2663 | do { | ||
| 2664 | if (!ieee80211_extend_absent_time(data, tsf, &offset)) | ||
| 2665 | break; | ||
| 2666 | |||
| 2667 | tries++; | ||
| 2668 | } while (tries < max_tries); | ||
| 2669 | |||
| 2670 | return offset; | ||
| 2671 | } | ||
| 2672 | |||
| 2673 | void ieee80211_update_p2p_noa(struct ieee80211_noa_data *data, u32 tsf) | ||
| 2674 | { | ||
| 2675 | u32 next_offset = BIT(31) - 1; | ||
| 2676 | int i; | ||
| 2677 | |||
| 2678 | data->absent = 0; | ||
| 2679 | data->has_next_tsf = false; | ||
| 2680 | for (i = 0; i < IEEE80211_P2P_NOA_DESC_MAX; i++) { | ||
| 2681 | s32 start; | ||
| 2682 | |||
| 2683 | if (!data->count[i]) | ||
| 2684 | continue; | ||
| 2685 | |||
| 2686 | ieee80211_extend_noa_desc(data, tsf, i); | ||
| 2687 | start = data->desc[i].start - tsf; | ||
| 2688 | if (start <= 0) | ||
| 2689 | data->absent |= BIT(i); | ||
| 2690 | |||
| 2691 | if (next_offset > start) | ||
| 2692 | next_offset = start; | ||
| 2693 | |||
| 2694 | data->has_next_tsf = true; | ||
| 2695 | } | ||
| 2696 | |||
| 2697 | if (data->absent) | ||
| 2698 | next_offset = ieee80211_get_noa_absent_time(data, tsf); | ||
| 2699 | |||
| 2700 | data->next_tsf = tsf + next_offset; | ||
| 2701 | } | ||
| 2702 | EXPORT_SYMBOL(ieee80211_update_p2p_noa); | ||
| 2703 | |||
| 2704 | int ieee80211_parse_p2p_noa(const struct ieee80211_p2p_noa_attr *attr, | ||
| 2705 | struct ieee80211_noa_data *data, u32 tsf) | ||
| 2706 | { | ||
| 2707 | int ret = 0; | ||
| 2708 | int i; | ||
| 2709 | |||
| 2710 | memset(data, 0, sizeof(*data)); | ||
| 2711 | |||
| 2712 | for (i = 0; i < IEEE80211_P2P_NOA_DESC_MAX; i++) { | ||
| 2713 | const struct ieee80211_p2p_noa_desc *desc = &attr->desc[i]; | ||
| 2714 | |||
| 2715 | if (!desc->count || !desc->duration) | ||
| 2716 | continue; | ||
| 2717 | |||
| 2718 | data->count[i] = desc->count; | ||
| 2719 | data->desc[i].start = le32_to_cpu(desc->start_time); | ||
| 2720 | data->desc[i].duration = le32_to_cpu(desc->duration); | ||
| 2721 | data->desc[i].interval = le32_to_cpu(desc->interval); | ||
| 2722 | |||
| 2723 | if (data->count[i] > 1 && | ||
| 2724 | data->desc[i].interval < data->desc[i].duration) | ||
| 2725 | continue; | ||
| 2726 | |||
| 2727 | ieee80211_extend_noa_desc(data, tsf, i); | ||
| 2728 | ret++; | ||
| 2729 | } | ||
| 2730 | |||
| 2731 | if (ret) | ||
| 2732 | ieee80211_update_p2p_noa(data, tsf); | ||
| 2733 | |||
| 2734 | return ret; | ||
| 2735 | } | ||
| 2736 | EXPORT_SYMBOL(ieee80211_parse_p2p_noa); | ||
| 2737 | |||
| 2738 | void ieee80211_recalc_dtim(struct ieee80211_local *local, | ||
| 2739 | struct ieee80211_sub_if_data *sdata) | ||
| 2740 | { | ||
| 2741 | u64 tsf = drv_get_tsf(local, sdata); | ||
| 2742 | u64 dtim_count = 0; | ||
| 2743 | u16 beacon_int = sdata->vif.bss_conf.beacon_int * 1024; | ||
| 2744 | u8 dtim_period = sdata->vif.bss_conf.dtim_period; | ||
| 2745 | struct ps_data *ps; | ||
| 2746 | u8 bcns_from_dtim; | ||
| 2747 | |||
| 2748 | if (tsf == -1ULL || !beacon_int || !dtim_period) | ||
| 2749 | return; | ||
| 2750 | |||
| 2751 | if (sdata->vif.type == NL80211_IFTYPE_AP || | ||
| 2752 | sdata->vif.type == NL80211_IFTYPE_AP_VLAN) { | ||
| 2753 | if (!sdata->bss) | ||
| 2754 | return; | ||
| 2755 | |||
| 2756 | ps = &sdata->bss->ps; | ||
| 2757 | } else if (ieee80211_vif_is_mesh(&sdata->vif)) { | ||
| 2758 | ps = &sdata->u.mesh.ps; | ||
| 2759 | } else { | ||
| 2760 | return; | ||
| 2761 | } | ||
| 2762 | |||
| 2763 | /* | ||
| 2764 | * actually finds last dtim_count, mac80211 will update in | ||
| 2765 | * __beacon_add_tim(). | ||
| 2766 | * dtim_count = dtim_period - (tsf / bcn_int) % dtim_period | ||
| 2767 | */ | ||
| 2768 | do_div(tsf, beacon_int); | ||
| 2769 | bcns_from_dtim = do_div(tsf, dtim_period); | ||
| 2770 | /* just had a DTIM */ | ||
| 2771 | if (!bcns_from_dtim) | ||
| 2772 | dtim_count = 0; | ||
| 2773 | else | ||
| 2774 | dtim_count = dtim_period - bcns_from_dtim; | ||
| 2775 | |||
| 2776 | ps->dtim_count = dtim_count; | ||
| 2777 | } | ||
diff --git a/net/mac80211/vht.c b/net/mac80211/vht.c index de0112785aae..d75f35c6e1a0 100644 --- a/net/mac80211/vht.c +++ b/net/mac80211/vht.c | |||
| @@ -182,16 +182,15 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, | |||
| 182 | IEEE80211_VHT_CAP_SHORT_GI_160); | 182 | IEEE80211_VHT_CAP_SHORT_GI_160); |
| 183 | 183 | ||
| 184 | /* remaining ones */ | 184 | /* remaining ones */ |
| 185 | if (own_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE) { | 185 | if (own_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE) |
| 186 | vht_cap->cap |= cap_info & | 186 | vht_cap->cap |= cap_info & |
| 187 | (IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE | | 187 | (IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE | |
| 188 | IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MAX); | 188 | IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK); |
| 189 | } | ||
| 190 | 189 | ||
| 191 | if (own_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE) | 190 | if (own_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE) |
| 192 | vht_cap->cap |= cap_info & | 191 | vht_cap->cap |= cap_info & |
| 193 | (IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE | | 192 | (IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE | |
| 194 | IEEE80211_VHT_CAP_BEAMFORMEE_STS_MAX); | 193 | IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK); |
| 195 | 194 | ||
| 196 | if (own_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE) | 195 | if (own_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE) |
| 197 | vht_cap->cap |= cap_info & | 196 | vht_cap->cap |= cap_info & |
diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c index afba19cb6f87..21211c60ca98 100644 --- a/net/mac80211/wme.c +++ b/net/mac80211/wme.c | |||
| @@ -106,6 +106,7 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata, | |||
| 106 | struct sta_info *sta = NULL; | 106 | struct sta_info *sta = NULL; |
| 107 | const u8 *ra = NULL; | 107 | const u8 *ra = NULL; |
| 108 | bool qos = false; | 108 | bool qos = false; |
| 109 | struct mac80211_qos_map *qos_map; | ||
| 109 | 110 | ||
| 110 | if (local->hw.queues < IEEE80211_NUM_ACS || skb->len < 6) { | 111 | if (local->hw.queues < IEEE80211_NUM_ACS || skb->len < 6) { |
| 111 | skb->priority = 0; /* required for correct WPA/11i MIC */ | 112 | skb->priority = 0; /* required for correct WPA/11i MIC */ |
| @@ -155,7 +156,11 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata, | |||
| 155 | 156 | ||
| 156 | /* use the data classifier to determine what 802.1d tag the | 157 | /* use the data classifier to determine what 802.1d tag the |
| 157 | * data frame has */ | 158 | * data frame has */ |
| 158 | skb->priority = cfg80211_classify8021d(skb); | 159 | rcu_read_lock(); |
| 160 | qos_map = rcu_dereference(sdata->qos_map); | ||
| 161 | skb->priority = cfg80211_classify8021d(skb, qos_map ? | ||
| 162 | &qos_map->qos_map : NULL); | ||
| 163 | rcu_read_unlock(); | ||
| 159 | 164 | ||
| 160 | return ieee80211_downgrade_queue(sdata, skb); | 165 | return ieee80211_downgrade_queue(sdata, skb); |
| 161 | } | 166 | } |
diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index d65728220763..21448d629b15 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c | |||
| @@ -127,7 +127,7 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx) | |||
| 127 | * APs with pairwise keys should never receive Michael MIC | 127 | * APs with pairwise keys should never receive Michael MIC |
| 128 | * errors for non-zero keyidx because these are reserved for | 128 | * errors for non-zero keyidx because these are reserved for |
| 129 | * group keys and only the AP is sending real multicast | 129 | * group keys and only the AP is sending real multicast |
| 130 | * frames in the BSS. ( | 130 | * frames in the BSS. |
| 131 | */ | 131 | */ |
| 132 | return RX_DROP_UNUSABLE; | 132 | return RX_DROP_UNUSABLE; |
| 133 | } | 133 | } |
| @@ -545,6 +545,106 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx) | |||
| 545 | return RX_CONTINUE; | 545 | return RX_CONTINUE; |
| 546 | } | 546 | } |
| 547 | 547 | ||
| 548 | static ieee80211_tx_result | ||
| 549 | ieee80211_crypto_cs_encrypt(struct ieee80211_tx_data *tx, | ||
| 550 | struct sk_buff *skb) | ||
| 551 | { | ||
| 552 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | ||
| 553 | struct ieee80211_key *key = tx->key; | ||
| 554 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||
| 555 | const struct ieee80211_cipher_scheme *cs = key->sta->cipher_scheme; | ||
| 556 | int hdrlen; | ||
| 557 | u8 *pos; | ||
| 558 | |||
| 559 | if (info->control.hw_key && | ||
| 560 | !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)) { | ||
| 561 | /* hwaccel has no need for preallocated head room */ | ||
| 562 | return TX_CONTINUE; | ||
| 563 | } | ||
| 564 | |||
| 565 | if (unlikely(skb_headroom(skb) < cs->hdr_len && | ||
| 566 | pskb_expand_head(skb, cs->hdr_len, 0, GFP_ATOMIC))) | ||
| 567 | return TX_DROP; | ||
| 568 | |||
| 569 | hdrlen = ieee80211_hdrlen(hdr->frame_control); | ||
| 570 | |||
| 571 | pos = skb_push(skb, cs->hdr_len); | ||
| 572 | memmove(pos, pos + cs->hdr_len, hdrlen); | ||
| 573 | skb_set_network_header(skb, skb_network_offset(skb) + cs->hdr_len); | ||
| 574 | |||
| 575 | return TX_CONTINUE; | ||
| 576 | } | ||
| 577 | |||
| 578 | static inline int ieee80211_crypto_cs_pn_compare(u8 *pn1, u8 *pn2, int len) | ||
| 579 | { | ||
| 580 | int i; | ||
| 581 | |||
| 582 | /* pn is little endian */ | ||
| 583 | for (i = len - 1; i >= 0; i--) { | ||
| 584 | if (pn1[i] < pn2[i]) | ||
| 585 | return -1; | ||
| 586 | else if (pn1[i] > pn2[i]) | ||
| 587 | return 1; | ||
| 588 | } | ||
| 589 | |||
| 590 | return 0; | ||
| 591 | } | ||
| 592 | |||
| 593 | static ieee80211_rx_result | ||
| 594 | ieee80211_crypto_cs_decrypt(struct ieee80211_rx_data *rx) | ||
| 595 | { | ||
| 596 | struct ieee80211_key *key = rx->key; | ||
| 597 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; | ||
| 598 | const struct ieee80211_cipher_scheme *cs = NULL; | ||
| 599 | int hdrlen = ieee80211_hdrlen(hdr->frame_control); | ||
| 600 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); | ||
| 601 | int data_len; | ||
| 602 | u8 *rx_pn; | ||
| 603 | u8 *skb_pn; | ||
| 604 | u8 qos_tid; | ||
| 605 | |||
| 606 | if (!rx->sta || !rx->sta->cipher_scheme || | ||
| 607 | !(status->flag & RX_FLAG_DECRYPTED)) | ||
| 608 | return RX_DROP_UNUSABLE; | ||
| 609 | |||
| 610 | if (!ieee80211_is_data(hdr->frame_control)) | ||
| 611 | return RX_CONTINUE; | ||
| 612 | |||
| 613 | cs = rx->sta->cipher_scheme; | ||
| 614 | |||
| 615 | data_len = rx->skb->len - hdrlen - cs->hdr_len; | ||
| 616 | |||
| 617 | if (data_len < 0) | ||
| 618 | return RX_DROP_UNUSABLE; | ||
| 619 | |||
| 620 | if (ieee80211_is_data_qos(hdr->frame_control)) | ||
| 621 | qos_tid = *ieee80211_get_qos_ctl(hdr) & | ||
| 622 | IEEE80211_QOS_CTL_TID_MASK; | ||
| 623 | else | ||
| 624 | qos_tid = 0; | ||
| 625 | |||
| 626 | if (skb_linearize(rx->skb)) | ||
| 627 | return RX_DROP_UNUSABLE; | ||
| 628 | |||
| 629 | hdr = (struct ieee80211_hdr *)rx->skb->data; | ||
| 630 | |||
| 631 | rx_pn = key->u.gen.rx_pn[qos_tid]; | ||
| 632 | skb_pn = rx->skb->data + hdrlen + cs->pn_off; | ||
| 633 | |||
| 634 | if (ieee80211_crypto_cs_pn_compare(skb_pn, rx_pn, cs->pn_len) <= 0) | ||
| 635 | return RX_DROP_UNUSABLE; | ||
| 636 | |||
| 637 | memcpy(rx_pn, skb_pn, cs->pn_len); | ||
| 638 | |||
| 639 | /* remove security header and MIC */ | ||
| 640 | if (pskb_trim(rx->skb, rx->skb->len - cs->mic_len)) | ||
| 641 | return RX_DROP_UNUSABLE; | ||
| 642 | |||
| 643 | memmove(rx->skb->data + cs->hdr_len, rx->skb->data, hdrlen); | ||
| 644 | skb_pull(rx->skb, cs->hdr_len); | ||
| 645 | |||
| 646 | return RX_CONTINUE; | ||
| 647 | } | ||
| 548 | 648 | ||
| 549 | static void bip_aad(struct sk_buff *skb, u8 *aad) | 649 | static void bip_aad(struct sk_buff *skb, u8 *aad) |
| 550 | { | 650 | { |
| @@ -685,6 +785,7 @@ ieee80211_crypto_hw_encrypt(struct ieee80211_tx_data *tx) | |||
| 685 | { | 785 | { |
| 686 | struct sk_buff *skb; | 786 | struct sk_buff *skb; |
| 687 | struct ieee80211_tx_info *info = NULL; | 787 | struct ieee80211_tx_info *info = NULL; |
| 788 | ieee80211_tx_result res; | ||
| 688 | 789 | ||
| 689 | skb_queue_walk(&tx->skbs, skb) { | 790 | skb_queue_walk(&tx->skbs, skb) { |
| 690 | info = IEEE80211_SKB_CB(skb); | 791 | info = IEEE80211_SKB_CB(skb); |
| @@ -692,9 +793,24 @@ ieee80211_crypto_hw_encrypt(struct ieee80211_tx_data *tx) | |||
| 692 | /* handle hw-only algorithm */ | 793 | /* handle hw-only algorithm */ |
| 693 | if (!info->control.hw_key) | 794 | if (!info->control.hw_key) |
| 694 | return TX_DROP; | 795 | return TX_DROP; |
| 796 | |||
| 797 | if (tx->key->sta->cipher_scheme) { | ||
| 798 | res = ieee80211_crypto_cs_encrypt(tx, skb); | ||
| 799 | if (res != TX_CONTINUE) | ||
| 800 | return res; | ||
| 801 | } | ||
| 695 | } | 802 | } |
| 696 | 803 | ||
| 697 | ieee80211_tx_set_protected(tx); | 804 | ieee80211_tx_set_protected(tx); |
| 698 | 805 | ||
| 699 | return TX_CONTINUE; | 806 | return TX_CONTINUE; |
| 700 | } | 807 | } |
| 808 | |||
| 809 | ieee80211_rx_result | ||
| 810 | ieee80211_crypto_hw_decrypt(struct ieee80211_rx_data *rx) | ||
| 811 | { | ||
| 812 | if (rx->sta->cipher_scheme) | ||
| 813 | return ieee80211_crypto_cs_decrypt(rx); | ||
| 814 | |||
| 815 | return RX_DROP_UNUSABLE; | ||
| 816 | } | ||
diff --git a/net/mac80211/wpa.h b/net/mac80211/wpa.h index 07e33f899c71..62e5a12dfe0a 100644 --- a/net/mac80211/wpa.h +++ b/net/mac80211/wpa.h | |||
| @@ -34,5 +34,7 @@ ieee80211_rx_result | |||
| 34 | ieee80211_crypto_aes_cmac_decrypt(struct ieee80211_rx_data *rx); | 34 | ieee80211_crypto_aes_cmac_decrypt(struct ieee80211_rx_data *rx); |
| 35 | ieee80211_tx_result | 35 | ieee80211_tx_result |
| 36 | ieee80211_crypto_hw_encrypt(struct ieee80211_tx_data *tx); | 36 | ieee80211_crypto_hw_encrypt(struct ieee80211_tx_data *tx); |
| 37 | ieee80211_rx_result | ||
| 38 | ieee80211_crypto_hw_decrypt(struct ieee80211_rx_data *rx); | ||
| 37 | 39 | ||
| 38 | #endif /* WPA_H */ | 40 | #endif /* WPA_H */ |
diff --git a/net/mac802154/wpan.c b/net/mac802154/wpan.c index e24bcf977296..372d8a222b91 100644 --- a/net/mac802154/wpan.c +++ b/net/mac802154/wpan.c | |||
| @@ -444,8 +444,8 @@ mac802154_subif_frame(struct mac802154_sub_if_data *sdata, struct sk_buff *skb) | |||
| 444 | case IEEE802154_FC_TYPE_DATA: | 444 | case IEEE802154_FC_TYPE_DATA: |
| 445 | return mac802154_process_data(sdata->dev, skb); | 445 | return mac802154_process_data(sdata->dev, skb); |
| 446 | default: | 446 | default: |
| 447 | pr_warning("ieee802154: bad frame received (type = %d)\n", | 447 | pr_warn("ieee802154: bad frame received (type = %d)\n", |
| 448 | mac_cb_type(skb)); | 448 | mac_cb_type(skb)); |
| 449 | kfree_skb(skb); | 449 | kfree_skb(skb); |
| 450 | return NET_RX_DROP; | 450 | return NET_RX_DROP; |
| 451 | } | 451 | } |
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index c3398cd99b94..c37467562fd0 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig | |||
| @@ -414,47 +414,112 @@ config NETFILTER_SYNPROXY | |||
| 414 | endif # NF_CONNTRACK | 414 | endif # NF_CONNTRACK |
| 415 | 415 | ||
| 416 | config NF_TABLES | 416 | config NF_TABLES |
| 417 | depends on NETFILTER_NETLINK | 417 | select NETFILTER_NETLINK |
| 418 | tristate "Netfilter nf_tables support" | 418 | tristate "Netfilter nf_tables support" |
| 419 | help | ||
| 420 | nftables is the new packet classification framework that intends to | ||
| 421 | replace the existing {ip,ip6,arp,eb}_tables infrastructure. It | ||
| 422 | provides a pseudo-state machine with an extensible instruction-set | ||
| 423 | (also known as expressions) that the userspace 'nft' utility | ||
| 424 | (http://www.netfilter.org/projects/nftables) uses to build the | ||
| 425 | rule-set. It also comes with the generic set infrastructure that | ||
| 426 | allows you to construct mappings between matchings and actions | ||
| 427 | for performance lookups. | ||
| 428 | |||
| 429 | To compile it as a module, choose M here. | ||
| 430 | |||
| 431 | config NF_TABLES_INET | ||
| 432 | depends on NF_TABLES && IPV6 | ||
| 433 | select NF_TABLES_IPV4 | ||
| 434 | select NF_TABLES_IPV6 | ||
| 435 | tristate "Netfilter nf_tables mixed IPv4/IPv6 tables support" | ||
| 436 | help | ||
| 437 | This option enables support for a mixed IPv4/IPv6 "inet" table. | ||
| 419 | 438 | ||
| 420 | config NFT_EXTHDR | 439 | config NFT_EXTHDR |
| 421 | depends on NF_TABLES | 440 | depends on NF_TABLES |
| 422 | tristate "Netfilter nf_tables IPv6 exthdr module" | 441 | tristate "Netfilter nf_tables IPv6 exthdr module" |
| 442 | help | ||
| 443 | This option adds the "exthdr" expression that you can use to match | ||
| 444 | IPv6 extension headers. | ||
| 423 | 445 | ||
| 424 | config NFT_META | 446 | config NFT_META |
| 425 | depends on NF_TABLES | 447 | depends on NF_TABLES |
| 426 | tristate "Netfilter nf_tables meta module" | 448 | tristate "Netfilter nf_tables meta module" |
| 449 | help | ||
| 450 | This option adds the "meta" expression that you can use to match and | ||
| 451 | to set packet metainformation such as the packet mark. | ||
| 427 | 452 | ||
| 428 | config NFT_CT | 453 | config NFT_CT |
| 429 | depends on NF_TABLES | 454 | depends on NF_TABLES |
| 430 | depends on NF_CONNTRACK | 455 | depends on NF_CONNTRACK |
| 431 | tristate "Netfilter nf_tables conntrack module" | 456 | tristate "Netfilter nf_tables conntrack module" |
| 457 | help | ||
| 458 | This option adds the "meta" expression that you can use to match | ||
| 459 | connection tracking information such as the flow state. | ||
| 432 | 460 | ||
| 433 | config NFT_RBTREE | 461 | config NFT_RBTREE |
| 434 | depends on NF_TABLES | 462 | depends on NF_TABLES |
| 435 | tristate "Netfilter nf_tables rbtree set module" | 463 | tristate "Netfilter nf_tables rbtree set module" |
| 464 | help | ||
| 465 | This option adds the "rbtree" set type (Red Black tree) that is used | ||
| 466 | to build interval-based sets. | ||
| 436 | 467 | ||
| 437 | config NFT_HASH | 468 | config NFT_HASH |
| 438 | depends on NF_TABLES | 469 | depends on NF_TABLES |
| 439 | tristate "Netfilter nf_tables hash set module" | 470 | tristate "Netfilter nf_tables hash set module" |
| 471 | help | ||
| 472 | This option adds the "hash" set type that is used to build one-way | ||
| 473 | mappings between matchings and actions. | ||
| 440 | 474 | ||
| 441 | config NFT_COUNTER | 475 | config NFT_COUNTER |
| 442 | depends on NF_TABLES | 476 | depends on NF_TABLES |
| 443 | tristate "Netfilter nf_tables counter module" | 477 | tristate "Netfilter nf_tables counter module" |
| 478 | help | ||
| 479 | This option adds the "counter" expression that you can use to | ||
| 480 | include packet and byte counters in a rule. | ||
| 444 | 481 | ||
| 445 | config NFT_LOG | 482 | config NFT_LOG |
| 446 | depends on NF_TABLES | 483 | depends on NF_TABLES |
| 447 | tristate "Netfilter nf_tables log module" | 484 | tristate "Netfilter nf_tables log module" |
| 485 | help | ||
| 486 | This option adds the "log" expression that you can use to log | ||
| 487 | packets matching some criteria. | ||
| 448 | 488 | ||
| 449 | config NFT_LIMIT | 489 | config NFT_LIMIT |
| 450 | depends on NF_TABLES | 490 | depends on NF_TABLES |
| 451 | tristate "Netfilter nf_tables limit module" | 491 | tristate "Netfilter nf_tables limit module" |
| 492 | help | ||
| 493 | This option adds the "limit" expression that you can use to | ||
| 494 | ratelimit rule matchings. | ||
| 452 | 495 | ||
| 453 | config NFT_NAT | 496 | config NFT_NAT |
| 454 | depends on NF_TABLES | 497 | depends on NF_TABLES |
| 455 | depends on NF_CONNTRACK | 498 | depends on NF_CONNTRACK |
| 456 | depends on NF_NAT | 499 | depends on NF_NAT |
| 457 | tristate "Netfilter nf_tables nat module" | 500 | tristate "Netfilter nf_tables nat module" |
| 501 | help | ||
| 502 | This option adds the "nat" expression that you can use to perform | ||
| 503 | typical Network Address Translation (NAT) packet transformations. | ||
| 504 | |||
| 505 | config NFT_QUEUE | ||
| 506 | depends on NF_TABLES | ||
| 507 | depends on NETFILTER_XTABLES | ||
| 508 | depends on NETFILTER_NETLINK_QUEUE | ||
| 509 | tristate "Netfilter nf_tables queue module" | ||
| 510 | help | ||
| 511 | This is required if you intend to use the userspace queueing | ||
| 512 | infrastructure (also known as NFQUEUE) from nftables. | ||
| 513 | |||
| 514 | config NFT_REJECT | ||
| 515 | depends on NF_TABLES | ||
| 516 | depends on NF_TABLES_IPV6 || !NF_TABLES_IPV6 | ||
| 517 | default m if NETFILTER_ADVANCED=n | ||
| 518 | tristate "Netfilter nf_tables reject support" | ||
| 519 | help | ||
| 520 | This option adds the "reject" expression that you can use to | ||
| 521 | explicitly deny and notify via TCP reset/ICMP informational errors | ||
| 522 | unallowed traffic. | ||
| 458 | 523 | ||
| 459 | config NFT_COMPAT | 524 | config NFT_COMPAT |
| 460 | depends on NF_TABLES | 525 | depends on NF_TABLES |
| @@ -858,6 +923,16 @@ config NETFILTER_XT_MATCH_BPF | |||
| 858 | 923 | ||
| 859 | To compile it as a module, choose M here. If unsure, say N. | 924 | To compile it as a module, choose M here. If unsure, say N. |
| 860 | 925 | ||
| 926 | config NETFILTER_XT_MATCH_CGROUP | ||
| 927 | tristate '"control group" match support' | ||
| 928 | depends on NETFILTER_ADVANCED | ||
| 929 | depends on CGROUPS | ||
| 930 | select CGROUP_NET_CLASSID | ||
| 931 | ---help--- | ||
| 932 | Socket/process control group matching allows you to match locally | ||
| 933 | generated packets based on which net_cls control group processes | ||
| 934 | belong to. | ||
| 935 | |||
| 861 | config NETFILTER_XT_MATCH_CLUSTER | 936 | config NETFILTER_XT_MATCH_CLUSTER |
| 862 | tristate '"cluster" match support' | 937 | tristate '"cluster" match support' |
| 863 | depends on NF_CONNTRACK | 938 | depends on NF_CONNTRACK |
| @@ -1035,6 +1110,15 @@ config NETFILTER_XT_MATCH_HL | |||
| 1035 | in the IPv6 header, or the time-to-live field in the IPv4 | 1110 | in the IPv6 header, or the time-to-live field in the IPv4 |
| 1036 | header of the packet. | 1111 | header of the packet. |
| 1037 | 1112 | ||
| 1113 | config NETFILTER_XT_MATCH_IPCOMP | ||
| 1114 | tristate '"ipcomp" match support' | ||
| 1115 | depends on NETFILTER_ADVANCED | ||
| 1116 | help | ||
| 1117 | This match extension allows you to match a range of CPIs(16 bits) | ||
| 1118 | inside IPComp header of IPSec packets. | ||
| 1119 | |||
| 1120 | To compile it as a module, choose M here. If unsure, say N. | ||
| 1121 | |||
| 1038 | config NETFILTER_XT_MATCH_IPRANGE | 1122 | config NETFILTER_XT_MATCH_IPRANGE |
| 1039 | tristate '"iprange" address range match support' | 1123 | tristate '"iprange" address range match support' |
| 1040 | depends on NETFILTER_ADVANCED | 1124 | depends on NETFILTER_ADVANCED |
| @@ -1055,6 +1139,16 @@ config NETFILTER_XT_MATCH_IPVS | |||
| 1055 | 1139 | ||
| 1056 | If unsure, say N. | 1140 | If unsure, say N. |
| 1057 | 1141 | ||
| 1142 | config NETFILTER_XT_MATCH_L2TP | ||
| 1143 | tristate '"l2tp" match support' | ||
| 1144 | depends on NETFILTER_ADVANCED | ||
| 1145 | default L2TP | ||
| 1146 | ---help--- | ||
| 1147 | This option adds an "L2TP" match, which allows you to match against | ||
| 1148 | L2TP protocol header fields. | ||
| 1149 | |||
| 1150 | To compile it as a module, choose M here. If unsure, say N. | ||
| 1151 | |||
| 1058 | config NETFILTER_XT_MATCH_LENGTH | 1152 | config NETFILTER_XT_MATCH_LENGTH |
| 1059 | tristate '"length" match support' | 1153 | tristate '"length" match support' |
| 1060 | depends on NETFILTER_ADVANCED | 1154 | depends on NETFILTER_ADVANCED |
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile index 394483b2c193..ee9c4de5f8ed 100644 --- a/net/netfilter/Makefile +++ b/net/netfilter/Makefile | |||
| @@ -70,13 +70,15 @@ nf_tables-objs += nft_immediate.o nft_cmp.o nft_lookup.o | |||
| 70 | nf_tables-objs += nft_bitwise.o nft_byteorder.o nft_payload.o | 70 | nf_tables-objs += nft_bitwise.o nft_byteorder.o nft_payload.o |
| 71 | 71 | ||
| 72 | obj-$(CONFIG_NF_TABLES) += nf_tables.o | 72 | obj-$(CONFIG_NF_TABLES) += nf_tables.o |
| 73 | obj-$(CONFIG_NF_TABLES_INET) += nf_tables_inet.o | ||
| 73 | obj-$(CONFIG_NFT_COMPAT) += nft_compat.o | 74 | obj-$(CONFIG_NFT_COMPAT) += nft_compat.o |
| 74 | obj-$(CONFIG_NFT_EXTHDR) += nft_exthdr.o | 75 | obj-$(CONFIG_NFT_EXTHDR) += nft_exthdr.o |
| 75 | obj-$(CONFIG_NFT_META) += nft_meta.o | 76 | obj-$(CONFIG_NFT_META) += nft_meta.o |
| 76 | obj-$(CONFIG_NFT_CT) += nft_ct.o | 77 | obj-$(CONFIG_NFT_CT) += nft_ct.o |
| 77 | obj-$(CONFIG_NFT_LIMIT) += nft_limit.o | 78 | obj-$(CONFIG_NFT_LIMIT) += nft_limit.o |
| 78 | obj-$(CONFIG_NFT_NAT) += nft_nat.o | 79 | obj-$(CONFIG_NFT_NAT) += nft_nat.o |
| 79 | #nf_tables-objs += nft_meta_target.o | 80 | obj-$(CONFIG_NFT_QUEUE) += nft_queue.o |
| 81 | obj-$(CONFIG_NFT_REJECT) += nft_reject.o | ||
| 80 | obj-$(CONFIG_NFT_RBTREE) += nft_rbtree.o | 82 | obj-$(CONFIG_NFT_RBTREE) += nft_rbtree.o |
| 81 | obj-$(CONFIG_NFT_HASH) += nft_hash.o | 83 | obj-$(CONFIG_NFT_HASH) += nft_hash.o |
| 82 | obj-$(CONFIG_NFT_COUNTER) += nft_counter.o | 84 | obj-$(CONFIG_NFT_COUNTER) += nft_counter.o |
| @@ -133,8 +135,10 @@ obj-$(CONFIG_NETFILTER_XT_MATCH_ESP) += xt_esp.o | |||
| 133 | obj-$(CONFIG_NETFILTER_XT_MATCH_HASHLIMIT) += xt_hashlimit.o | 135 | obj-$(CONFIG_NETFILTER_XT_MATCH_HASHLIMIT) += xt_hashlimit.o |
| 134 | obj-$(CONFIG_NETFILTER_XT_MATCH_HELPER) += xt_helper.o | 136 | obj-$(CONFIG_NETFILTER_XT_MATCH_HELPER) += xt_helper.o |
| 135 | obj-$(CONFIG_NETFILTER_XT_MATCH_HL) += xt_hl.o | 137 | obj-$(CONFIG_NETFILTER_XT_MATCH_HL) += xt_hl.o |
| 138 | obj-$(CONFIG_NETFILTER_XT_MATCH_IPCOMP) += xt_ipcomp.o | ||
| 136 | obj-$(CONFIG_NETFILTER_XT_MATCH_IPRANGE) += xt_iprange.o | 139 | obj-$(CONFIG_NETFILTER_XT_MATCH_IPRANGE) += xt_iprange.o |
| 137 | obj-$(CONFIG_NETFILTER_XT_MATCH_IPVS) += xt_ipvs.o | 140 | obj-$(CONFIG_NETFILTER_XT_MATCH_IPVS) += xt_ipvs.o |
| 141 | obj-$(CONFIG_NETFILTER_XT_MATCH_L2TP) += xt_l2tp.o | ||
| 138 | obj-$(CONFIG_NETFILTER_XT_MATCH_LENGTH) += xt_length.o | 142 | obj-$(CONFIG_NETFILTER_XT_MATCH_LENGTH) += xt_length.o |
| 139 | obj-$(CONFIG_NETFILTER_XT_MATCH_LIMIT) += xt_limit.o | 143 | obj-$(CONFIG_NETFILTER_XT_MATCH_LIMIT) += xt_limit.o |
| 140 | obj-$(CONFIG_NETFILTER_XT_MATCH_MAC) += xt_mac.o | 144 | obj-$(CONFIG_NETFILTER_XT_MATCH_MAC) += xt_mac.o |
| @@ -142,6 +146,7 @@ obj-$(CONFIG_NETFILTER_XT_MATCH_MULTIPORT) += xt_multiport.o | |||
| 142 | obj-$(CONFIG_NETFILTER_XT_MATCH_NFACCT) += xt_nfacct.o | 146 | obj-$(CONFIG_NETFILTER_XT_MATCH_NFACCT) += xt_nfacct.o |
| 143 | obj-$(CONFIG_NETFILTER_XT_MATCH_OSF) += xt_osf.o | 147 | obj-$(CONFIG_NETFILTER_XT_MATCH_OSF) += xt_osf.o |
| 144 | obj-$(CONFIG_NETFILTER_XT_MATCH_OWNER) += xt_owner.o | 148 | obj-$(CONFIG_NETFILTER_XT_MATCH_OWNER) += xt_owner.o |
| 149 | obj-$(CONFIG_NETFILTER_XT_MATCH_CGROUP) += xt_cgroup.o | ||
| 145 | obj-$(CONFIG_NETFILTER_XT_MATCH_PHYSDEV) += xt_physdev.o | 150 | obj-$(CONFIG_NETFILTER_XT_MATCH_PHYSDEV) += xt_physdev.o |
| 146 | obj-$(CONFIG_NETFILTER_XT_MATCH_PKTTYPE) += xt_pkttype.o | 151 | obj-$(CONFIG_NETFILTER_XT_MATCH_PKTTYPE) += xt_pkttype.o |
| 147 | obj-$(CONFIG_NETFILTER_XT_MATCH_POLICY) += xt_policy.o | 152 | obj-$(CONFIG_NETFILTER_XT_MATCH_POLICY) += xt_policy.o |
diff --git a/net/netfilter/ipset/Kconfig b/net/netfilter/ipset/Kconfig index a2d6263b6c64..44cd4f58adf0 100644 --- a/net/netfilter/ipset/Kconfig +++ b/net/netfilter/ipset/Kconfig | |||
| @@ -21,7 +21,7 @@ config IP_SET_MAX | |||
| 21 | You can define here default value of the maximum number | 21 | You can define here default value of the maximum number |
| 22 | of IP sets for the kernel. | 22 | of IP sets for the kernel. |
| 23 | 23 | ||
| 24 | The value can be overriden by the 'max_sets' module | 24 | The value can be overridden by the 'max_sets' module |
| 25 | parameter of the 'ip_set' module. | 25 | parameter of the 'ip_set' module. |
| 26 | 26 | ||
| 27 | config IP_SET_BITMAP_IP | 27 | config IP_SET_BITMAP_IP |
diff --git a/net/netfilter/ipset/ip_set_core.c b/net/netfilter/ipset/ip_set_core.c index bac7e01df67f..de770ec39e51 100644 --- a/net/netfilter/ipset/ip_set_core.c +++ b/net/netfilter/ipset/ip_set_core.c | |||
| @@ -625,34 +625,6 @@ EXPORT_SYMBOL_GPL(ip_set_name_byindex); | |||
| 625 | */ | 625 | */ |
| 626 | 626 | ||
| 627 | /* | 627 | /* |
| 628 | * Find set by name, reference it once. The reference makes sure the | ||
| 629 | * thing pointed to, does not go away under our feet. | ||
| 630 | * | ||
| 631 | * The nfnl mutex is used in the function. | ||
| 632 | */ | ||
| 633 | ip_set_id_t | ||
| 634 | ip_set_nfnl_get(struct net *net, const char *name) | ||
| 635 | { | ||
| 636 | ip_set_id_t i, index = IPSET_INVALID_ID; | ||
| 637 | struct ip_set *s; | ||
| 638 | struct ip_set_net *inst = ip_set_pernet(net); | ||
| 639 | |||
| 640 | nfnl_lock(NFNL_SUBSYS_IPSET); | ||
| 641 | for (i = 0; i < inst->ip_set_max; i++) { | ||
| 642 | s = nfnl_set(inst, i); | ||
| 643 | if (s != NULL && STREQ(s->name, name)) { | ||
| 644 | __ip_set_get(s); | ||
| 645 | index = i; | ||
| 646 | break; | ||
| 647 | } | ||
| 648 | } | ||
| 649 | nfnl_unlock(NFNL_SUBSYS_IPSET); | ||
| 650 | |||
| 651 | return index; | ||
| 652 | } | ||
| 653 | EXPORT_SYMBOL_GPL(ip_set_nfnl_get); | ||
| 654 | |||
| 655 | /* | ||
| 656 | * Find set by index, reference it once. The reference makes sure the | 628 | * Find set by index, reference it once. The reference makes sure the |
| 657 | * thing pointed to, does not go away under our feet. | 629 | * thing pointed to, does not go away under our feet. |
| 658 | * | 630 | * |
diff --git a/net/netfilter/ipset/ip_set_hash_netiface.c b/net/netfilter/ipset/ip_set_hash_netiface.c index 3f64a66bf5d9..b827a0f1f351 100644 --- a/net/netfilter/ipset/ip_set_hash_netiface.c +++ b/net/netfilter/ipset/ip_set_hash_netiface.c | |||
| @@ -46,31 +46,12 @@ struct iface_node { | |||
| 46 | static void | 46 | static void |
| 47 | rbtree_destroy(struct rb_root *root) | 47 | rbtree_destroy(struct rb_root *root) |
| 48 | { | 48 | { |
| 49 | struct rb_node *p, *n = root->rb_node; | 49 | struct iface_node *node, *next; |
| 50 | struct iface_node *node; | ||
| 51 | |||
| 52 | /* Non-recursive destroy, like in ext3 */ | ||
| 53 | while (n) { | ||
| 54 | if (n->rb_left) { | ||
| 55 | n = n->rb_left; | ||
| 56 | continue; | ||
| 57 | } | ||
| 58 | if (n->rb_right) { | ||
| 59 | n = n->rb_right; | ||
| 60 | continue; | ||
| 61 | } | ||
| 62 | p = rb_parent(n); | ||
| 63 | node = rb_entry(n, struct iface_node, node); | ||
| 64 | if (!p) | ||
| 65 | *root = RB_ROOT; | ||
| 66 | else if (p->rb_left == n) | ||
| 67 | p->rb_left = NULL; | ||
| 68 | else if (p->rb_right == n) | ||
| 69 | p->rb_right = NULL; | ||
| 70 | 50 | ||
| 51 | rbtree_postorder_for_each_entry_safe(node, next, root, node) | ||
| 71 | kfree(node); | 52 | kfree(node); |
| 72 | n = p; | 53 | |
| 73 | } | 54 | *root = RB_ROOT; |
| 74 | } | 55 | } |
| 75 | 56 | ||
| 76 | static int | 57 | static int |
diff --git a/net/netfilter/ipvs/ip_vs_conn.c b/net/netfilter/ipvs/ip_vs_conn.c index 4c8e5c0aa1ab..59a1a85bcb3e 100644 --- a/net/netfilter/ipvs/ip_vs_conn.c +++ b/net/netfilter/ipvs/ip_vs_conn.c | |||
| @@ -1209,7 +1209,7 @@ void ip_vs_random_dropentry(struct net *net) | |||
| 1209 | * Randomly scan 1/32 of the whole table every second | 1209 | * Randomly scan 1/32 of the whole table every second |
| 1210 | */ | 1210 | */ |
| 1211 | for (idx = 0; idx < (ip_vs_conn_tab_size>>5); idx++) { | 1211 | for (idx = 0; idx < (ip_vs_conn_tab_size>>5); idx++) { |
| 1212 | unsigned int hash = net_random() & ip_vs_conn_tab_mask; | 1212 | unsigned int hash = prandom_u32() & ip_vs_conn_tab_mask; |
| 1213 | 1213 | ||
| 1214 | hlist_for_each_entry_rcu(cp, &ip_vs_conn_tab[hash], c_list) { | 1214 | hlist_for_each_entry_rcu(cp, &ip_vs_conn_tab[hash], c_list) { |
| 1215 | if (cp->flags & IP_VS_CONN_F_TEMPLATE) | 1215 | if (cp->flags & IP_VS_CONN_F_TEMPLATE) |
diff --git a/net/netfilter/ipvs/ip_vs_nfct.c b/net/netfilter/ipvs/ip_vs_nfct.c index 5a355a46d1dc..5882bbfd198c 100644 --- a/net/netfilter/ipvs/ip_vs_nfct.c +++ b/net/netfilter/ipvs/ip_vs_nfct.c | |||
| @@ -19,8 +19,7 @@ | |||
| 19 | * GNU General Public License for more details. | 19 | * GNU General Public License for more details. |
| 20 | * | 20 | * |
| 21 | * You should have received a copy of the GNU General Public License | 21 | * You should have received a copy of the GNU General Public License |
| 22 | * along with this program; if not, write to the Free Software | 22 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 23 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 24 | * | 23 | * |
| 25 | * | 24 | * |
| 26 | * Authors: | 25 | * Authors: |
diff --git a/net/netfilter/ipvs/ip_vs_sync.c b/net/netfilter/ipvs/ip_vs_sync.c index f63c2388f38d..db801263ee9f 100644 --- a/net/netfilter/ipvs/ip_vs_sync.c +++ b/net/netfilter/ipvs/ip_vs_sync.c | |||
| @@ -1637,7 +1637,10 @@ static int sync_thread_master(void *data) | |||
| 1637 | continue; | 1637 | continue; |
| 1638 | } | 1638 | } |
| 1639 | while (ip_vs_send_sync_msg(tinfo->sock, sb->mesg) < 0) { | 1639 | while (ip_vs_send_sync_msg(tinfo->sock, sb->mesg) < 0) { |
| 1640 | int ret = __wait_event_interruptible(*sk_sleep(sk), | 1640 | /* (Ab)use interruptible sleep to avoid increasing |
| 1641 | * the load avg. | ||
| 1642 | */ | ||
| 1643 | __wait_event_interruptible(*sk_sleep(sk), | ||
| 1641 | sock_writeable(sk) || | 1644 | sock_writeable(sk) || |
| 1642 | kthread_should_stop()); | 1645 | kthread_should_stop()); |
| 1643 | if (unlikely(kthread_should_stop())) | 1646 | if (unlikely(kthread_should_stop())) |
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 43549eb7a7be..8824ed0ccc9c 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c | |||
| @@ -60,12 +60,6 @@ int (*nfnetlink_parse_nat_setup_hook)(struct nf_conn *ct, | |||
| 60 | const struct nlattr *attr) __read_mostly; | 60 | const struct nlattr *attr) __read_mostly; |
| 61 | EXPORT_SYMBOL_GPL(nfnetlink_parse_nat_setup_hook); | 61 | EXPORT_SYMBOL_GPL(nfnetlink_parse_nat_setup_hook); |
| 62 | 62 | ||
| 63 | int (*nf_nat_seq_adjust_hook)(struct sk_buff *skb, | ||
| 64 | struct nf_conn *ct, | ||
| 65 | enum ip_conntrack_info ctinfo, | ||
| 66 | unsigned int protoff); | ||
| 67 | EXPORT_SYMBOL_GPL(nf_nat_seq_adjust_hook); | ||
| 68 | |||
| 69 | DEFINE_SPINLOCK(nf_conntrack_lock); | 63 | DEFINE_SPINLOCK(nf_conntrack_lock); |
| 70 | EXPORT_SYMBOL_GPL(nf_conntrack_lock); | 64 | EXPORT_SYMBOL_GPL(nf_conntrack_lock); |
| 71 | 65 | ||
| @@ -361,15 +355,6 @@ begin: | |||
| 361 | return NULL; | 355 | return NULL; |
| 362 | } | 356 | } |
| 363 | 357 | ||
| 364 | struct nf_conntrack_tuple_hash * | ||
| 365 | __nf_conntrack_find(struct net *net, u16 zone, | ||
| 366 | const struct nf_conntrack_tuple *tuple) | ||
| 367 | { | ||
| 368 | return ____nf_conntrack_find(net, zone, tuple, | ||
| 369 | hash_conntrack_raw(tuple, zone)); | ||
| 370 | } | ||
| 371 | EXPORT_SYMBOL_GPL(__nf_conntrack_find); | ||
| 372 | |||
| 373 | /* Find a connection corresponding to a tuple. */ | 358 | /* Find a connection corresponding to a tuple. */ |
| 374 | static struct nf_conntrack_tuple_hash * | 359 | static struct nf_conntrack_tuple_hash * |
| 375 | __nf_conntrack_find_get(struct net *net, u16 zone, | 360 | __nf_conntrack_find_get(struct net *net, u16 zone, |
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 08870b859046..bb322d0beb48 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c | |||
| @@ -2118,8 +2118,16 @@ ctnetlink_nfqueue_parse_ct(const struct nlattr *cda[], struct nf_conn *ct) | |||
| 2118 | return err; | 2118 | return err; |
| 2119 | } | 2119 | } |
| 2120 | #if defined(CONFIG_NF_CONNTRACK_MARK) | 2120 | #if defined(CONFIG_NF_CONNTRACK_MARK) |
| 2121 | if (cda[CTA_MARK]) | 2121 | if (cda[CTA_MARK]) { |
| 2122 | ct->mark = ntohl(nla_get_be32(cda[CTA_MARK])); | 2122 | u32 mask = 0, mark, newmark; |
| 2123 | if (cda[CTA_MARK_MASK]) | ||
| 2124 | mask = ~ntohl(nla_get_be32(cda[CTA_MARK_MASK])); | ||
| 2125 | |||
| 2126 | mark = ntohl(nla_get_be32(cda[CTA_MARK])); | ||
| 2127 | newmark = (ct->mark & mask) ^ mark; | ||
| 2128 | if (newmark != ct->mark) | ||
| 2129 | ct->mark = newmark; | ||
| 2130 | } | ||
| 2123 | #endif | 2131 | #endif |
| 2124 | return 0; | 2132 | return 0; |
| 2125 | } | 2133 | } |
diff --git a/net/netfilter/nf_conntrack_proto.c b/net/netfilter/nf_conntrack_proto.c index ce3004156eeb..b65d5864b6d9 100644 --- a/net/netfilter/nf_conntrack_proto.c +++ b/net/netfilter/nf_conntrack_proto.c | |||
| @@ -92,12 +92,6 @@ nf_ct_l3proto_find_get(u_int16_t l3proto) | |||
| 92 | } | 92 | } |
| 93 | EXPORT_SYMBOL_GPL(nf_ct_l3proto_find_get); | 93 | EXPORT_SYMBOL_GPL(nf_ct_l3proto_find_get); |
| 94 | 94 | ||
| 95 | void nf_ct_l3proto_put(struct nf_conntrack_l3proto *p) | ||
| 96 | { | ||
| 97 | module_put(p->me); | ||
| 98 | } | ||
| 99 | EXPORT_SYMBOL_GPL(nf_ct_l3proto_put); | ||
| 100 | |||
| 101 | int | 95 | int |
| 102 | nf_ct_l3proto_try_module_get(unsigned short l3proto) | 96 | nf_ct_l3proto_try_module_get(unsigned short l3proto) |
| 103 | { | 97 | { |
diff --git a/net/netfilter/nf_conntrack_proto_dccp.c b/net/netfilter/nf_conntrack_proto_dccp.c index a99b6c3427b0..cb372f96f10d 100644 --- a/net/netfilter/nf_conntrack_proto_dccp.c +++ b/net/netfilter/nf_conntrack_proto_dccp.c | |||
| @@ -428,7 +428,7 @@ static bool dccp_new(struct nf_conn *ct, const struct sk_buff *skb, | |||
| 428 | const char *msg; | 428 | const char *msg; |
| 429 | u_int8_t state; | 429 | u_int8_t state; |
| 430 | 430 | ||
| 431 | dh = skb_header_pointer(skb, dataoff, sizeof(_dh), &dh); | 431 | dh = skb_header_pointer(skb, dataoff, sizeof(_dh), &_dh); |
| 432 | BUG_ON(dh == NULL); | 432 | BUG_ON(dh == NULL); |
| 433 | 433 | ||
| 434 | state = dccp_state_table[CT_DCCP_ROLE_CLIENT][dh->dccph_type][CT_DCCP_NONE]; | 434 | state = dccp_state_table[CT_DCCP_ROLE_CLIENT][dh->dccph_type][CT_DCCP_NONE]; |
| @@ -457,7 +457,7 @@ static bool dccp_new(struct nf_conn *ct, const struct sk_buff *skb, | |||
| 457 | out_invalid: | 457 | out_invalid: |
| 458 | if (LOG_INVALID(net, IPPROTO_DCCP)) | 458 | if (LOG_INVALID(net, IPPROTO_DCCP)) |
| 459 | nf_log_packet(net, nf_ct_l3num(ct), 0, skb, NULL, NULL, | 459 | nf_log_packet(net, nf_ct_l3num(ct), 0, skb, NULL, NULL, |
| 460 | NULL, msg); | 460 | NULL, "%s", msg); |
| 461 | return false; | 461 | return false; |
| 462 | } | 462 | } |
| 463 | 463 | ||
| @@ -486,7 +486,7 @@ static int dccp_packet(struct nf_conn *ct, const struct sk_buff *skb, | |||
| 486 | u_int8_t type, old_state, new_state; | 486 | u_int8_t type, old_state, new_state; |
| 487 | enum ct_dccp_roles role; | 487 | enum ct_dccp_roles role; |
| 488 | 488 | ||
| 489 | dh = skb_header_pointer(skb, dataoff, sizeof(_dh), &dh); | 489 | dh = skb_header_pointer(skb, dataoff, sizeof(_dh), &_dh); |
| 490 | BUG_ON(dh == NULL); | 490 | BUG_ON(dh == NULL); |
| 491 | type = dh->dccph_type; | 491 | type = dh->dccph_type; |
| 492 | 492 | ||
| @@ -577,7 +577,7 @@ static int dccp_error(struct net *net, struct nf_conn *tmpl, | |||
| 577 | unsigned int cscov; | 577 | unsigned int cscov; |
| 578 | const char *msg; | 578 | const char *msg; |
| 579 | 579 | ||
| 580 | dh = skb_header_pointer(skb, dataoff, sizeof(_dh), &dh); | 580 | dh = skb_header_pointer(skb, dataoff, sizeof(_dh), &_dh); |
| 581 | if (dh == NULL) { | 581 | if (dh == NULL) { |
| 582 | msg = "nf_ct_dccp: short packet "; | 582 | msg = "nf_ct_dccp: short packet "; |
| 583 | goto out_invalid; | 583 | goto out_invalid; |
| @@ -614,7 +614,7 @@ static int dccp_error(struct net *net, struct nf_conn *tmpl, | |||
| 614 | 614 | ||
| 615 | out_invalid: | 615 | out_invalid: |
| 616 | if (LOG_INVALID(net, IPPROTO_DCCP)) | 616 | if (LOG_INVALID(net, IPPROTO_DCCP)) |
| 617 | nf_log_packet(net, pf, 0, skb, NULL, NULL, NULL, msg); | 617 | nf_log_packet(net, pf, 0, skb, NULL, NULL, NULL, "%s", msg); |
| 618 | return -NF_ACCEPT; | 618 | return -NF_ACCEPT; |
| 619 | } | 619 | } |
| 620 | 620 | ||
diff --git a/net/netfilter/nf_nat_core.c b/net/netfilter/nf_nat_core.c index 63a815402211..d3f5cd6dd962 100644 --- a/net/netfilter/nf_nat_core.c +++ b/net/netfilter/nf_nat_core.c | |||
| @@ -315,7 +315,7 @@ get_unique_tuple(struct nf_conntrack_tuple *tuple, | |||
| 315 | * manips not an issue. | 315 | * manips not an issue. |
| 316 | */ | 316 | */ |
| 317 | if (maniptype == NF_NAT_MANIP_SRC && | 317 | if (maniptype == NF_NAT_MANIP_SRC && |
| 318 | !(range->flags & NF_NAT_RANGE_PROTO_RANDOM)) { | 318 | !(range->flags & NF_NAT_RANGE_PROTO_RANDOM_ALL)) { |
| 319 | /* try the original tuple first */ | 319 | /* try the original tuple first */ |
| 320 | if (in_range(l3proto, l4proto, orig_tuple, range)) { | 320 | if (in_range(l3proto, l4proto, orig_tuple, range)) { |
| 321 | if (!nf_nat_used_tuple(orig_tuple, ct)) { | 321 | if (!nf_nat_used_tuple(orig_tuple, ct)) { |
| @@ -339,7 +339,7 @@ get_unique_tuple(struct nf_conntrack_tuple *tuple, | |||
| 339 | */ | 339 | */ |
| 340 | 340 | ||
| 341 | /* Only bother mapping if it's not already in range and unique */ | 341 | /* Only bother mapping if it's not already in range and unique */ |
| 342 | if (!(range->flags & NF_NAT_RANGE_PROTO_RANDOM)) { | 342 | if (!(range->flags & NF_NAT_RANGE_PROTO_RANDOM_ALL)) { |
| 343 | if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED) { | 343 | if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED) { |
| 344 | if (l4proto->in_range(tuple, maniptype, | 344 | if (l4proto->in_range(tuple, maniptype, |
| 345 | &range->min_proto, | 345 | &range->min_proto, |
diff --git a/net/netfilter/nf_nat_proto_common.c b/net/netfilter/nf_nat_proto_common.c index 9baaf734c142..83a72a235cae 100644 --- a/net/netfilter/nf_nat_proto_common.c +++ b/net/netfilter/nf_nat_proto_common.c | |||
| @@ -74,22 +74,24 @@ void nf_nat_l4proto_unique_tuple(const struct nf_nat_l3proto *l3proto, | |||
| 74 | range_size = ntohs(range->max_proto.all) - min + 1; | 74 | range_size = ntohs(range->max_proto.all) - min + 1; |
| 75 | } | 75 | } |
| 76 | 76 | ||
| 77 | if (range->flags & NF_NAT_RANGE_PROTO_RANDOM) | 77 | if (range->flags & NF_NAT_RANGE_PROTO_RANDOM) { |
| 78 | off = l3proto->secure_port(tuple, maniptype == NF_NAT_MANIP_SRC | 78 | off = l3proto->secure_port(tuple, maniptype == NF_NAT_MANIP_SRC |
| 79 | ? tuple->dst.u.all | 79 | ? tuple->dst.u.all |
| 80 | : tuple->src.u.all); | 80 | : tuple->src.u.all); |
| 81 | else | 81 | } else if (range->flags & NF_NAT_RANGE_PROTO_RANDOM_FULLY) { |
| 82 | off = prandom_u32(); | ||
| 83 | } else { | ||
| 82 | off = *rover; | 84 | off = *rover; |
| 85 | } | ||
| 83 | 86 | ||
| 84 | for (i = 0; ; ++off) { | 87 | for (i = 0; ; ++off) { |
| 85 | *portptr = htons(min + off % range_size); | 88 | *portptr = htons(min + off % range_size); |
| 86 | if (++i != range_size && nf_nat_used_tuple(tuple, ct)) | 89 | if (++i != range_size && nf_nat_used_tuple(tuple, ct)) |
| 87 | continue; | 90 | continue; |
| 88 | if (!(range->flags & NF_NAT_RANGE_PROTO_RANDOM)) | 91 | if (!(range->flags & NF_NAT_RANGE_PROTO_RANDOM_ALL)) |
| 89 | *rover = off; | 92 | *rover = off; |
| 90 | return; | 93 | return; |
| 91 | } | 94 | } |
| 92 | return; | ||
| 93 | } | 95 | } |
| 94 | EXPORT_SYMBOL_GPL(nf_nat_l4proto_unique_tuple); | 96 | EXPORT_SYMBOL_GPL(nf_nat_l4proto_unique_tuple); |
| 95 | 97 | ||
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index 71a9f49a768b..117bbaaddde6 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c | |||
| @@ -124,37 +124,43 @@ static inline u64 nf_tables_alloc_handle(struct nft_table *table) | |||
| 124 | return ++table->hgenerator; | 124 | return ++table->hgenerator; |
| 125 | } | 125 | } |
| 126 | 126 | ||
| 127 | static struct nf_chain_type *chain_type[AF_MAX][NFT_CHAIN_T_MAX]; | 127 | static const struct nf_chain_type *chain_type[AF_MAX][NFT_CHAIN_T_MAX]; |
| 128 | 128 | ||
| 129 | static int __nf_tables_chain_type_lookup(int family, const struct nlattr *nla) | 129 | static const struct nf_chain_type * |
| 130 | __nf_tables_chain_type_lookup(int family, const struct nlattr *nla) | ||
| 130 | { | 131 | { |
| 131 | int i; | 132 | int i; |
| 132 | 133 | ||
| 133 | for (i=0; i<NFT_CHAIN_T_MAX; i++) { | 134 | for (i = 0; i < NFT_CHAIN_T_MAX; i++) { |
| 134 | if (chain_type[family][i] != NULL && | 135 | if (chain_type[family][i] != NULL && |
| 135 | !nla_strcmp(nla, chain_type[family][i]->name)) | 136 | !nla_strcmp(nla, chain_type[family][i]->name)) |
| 136 | return i; | 137 | return chain_type[family][i]; |
| 137 | } | 138 | } |
| 138 | return -1; | 139 | return NULL; |
| 139 | } | 140 | } |
| 140 | 141 | ||
| 141 | static int nf_tables_chain_type_lookup(const struct nft_af_info *afi, | 142 | static const struct nf_chain_type * |
| 142 | const struct nlattr *nla, | 143 | nf_tables_chain_type_lookup(const struct nft_af_info *afi, |
| 143 | bool autoload) | 144 | const struct nlattr *nla, |
| 145 | bool autoload) | ||
| 144 | { | 146 | { |
| 145 | int type; | 147 | const struct nf_chain_type *type; |
| 146 | 148 | ||
| 147 | type = __nf_tables_chain_type_lookup(afi->family, nla); | 149 | type = __nf_tables_chain_type_lookup(afi->family, nla); |
| 150 | if (type != NULL) | ||
| 151 | return type; | ||
| 148 | #ifdef CONFIG_MODULES | 152 | #ifdef CONFIG_MODULES |
| 149 | if (type < 0 && autoload) { | 153 | if (autoload) { |
| 150 | nfnl_unlock(NFNL_SUBSYS_NFTABLES); | 154 | nfnl_unlock(NFNL_SUBSYS_NFTABLES); |
| 151 | request_module("nft-chain-%u-%*.s", afi->family, | 155 | request_module("nft-chain-%u-%*.s", afi->family, |
| 152 | nla_len(nla)-1, (const char *)nla_data(nla)); | 156 | nla_len(nla)-1, (const char *)nla_data(nla)); |
| 153 | nfnl_lock(NFNL_SUBSYS_NFTABLES); | 157 | nfnl_lock(NFNL_SUBSYS_NFTABLES); |
| 154 | type = __nf_tables_chain_type_lookup(afi->family, nla); | 158 | type = __nf_tables_chain_type_lookup(afi->family, nla); |
| 159 | if (type != NULL) | ||
| 160 | return ERR_PTR(-EAGAIN); | ||
| 155 | } | 161 | } |
| 156 | #endif | 162 | #endif |
| 157 | return type; | 163 | return ERR_PTR(-ENOENT); |
| 158 | } | 164 | } |
| 159 | 165 | ||
| 160 | static const struct nla_policy nft_table_policy[NFTA_TABLE_MAX + 1] = { | 166 | static const struct nla_policy nft_table_policy[NFTA_TABLE_MAX + 1] = { |
| @@ -180,7 +186,8 @@ static int nf_tables_fill_table_info(struct sk_buff *skb, u32 portid, u32 seq, | |||
| 180 | nfmsg->res_id = 0; | 186 | nfmsg->res_id = 0; |
| 181 | 187 | ||
| 182 | if (nla_put_string(skb, NFTA_TABLE_NAME, table->name) || | 188 | if (nla_put_string(skb, NFTA_TABLE_NAME, table->name) || |
| 183 | nla_put_be32(skb, NFTA_TABLE_FLAGS, htonl(table->flags))) | 189 | nla_put_be32(skb, NFTA_TABLE_FLAGS, htonl(table->flags)) || |
| 190 | nla_put_be32(skb, NFTA_TABLE_USE, htonl(table->use))) | ||
| 184 | goto nla_put_failure; | 191 | goto nla_put_failure; |
| 185 | 192 | ||
| 186 | return nlmsg_end(skb, nlh); | 193 | return nlmsg_end(skb, nlh); |
| @@ -306,7 +313,8 @@ err: | |||
| 306 | return err; | 313 | return err; |
| 307 | } | 314 | } |
| 308 | 315 | ||
| 309 | static int nf_tables_table_enable(struct nft_table *table) | 316 | static int nf_tables_table_enable(const struct nft_af_info *afi, |
| 317 | struct nft_table *table) | ||
| 310 | { | 318 | { |
| 311 | struct nft_chain *chain; | 319 | struct nft_chain *chain; |
| 312 | int err, i = 0; | 320 | int err, i = 0; |
| @@ -315,7 +323,7 @@ static int nf_tables_table_enable(struct nft_table *table) | |||
| 315 | if (!(chain->flags & NFT_BASE_CHAIN)) | 323 | if (!(chain->flags & NFT_BASE_CHAIN)) |
| 316 | continue; | 324 | continue; |
| 317 | 325 | ||
| 318 | err = nf_register_hook(&nft_base_chain(chain)->ops); | 326 | err = nf_register_hooks(nft_base_chain(chain)->ops, afi->nops); |
| 319 | if (err < 0) | 327 | if (err < 0) |
| 320 | goto err; | 328 | goto err; |
| 321 | 329 | ||
| @@ -330,18 +338,20 @@ err: | |||
| 330 | if (i-- <= 0) | 338 | if (i-- <= 0) |
| 331 | break; | 339 | break; |
| 332 | 340 | ||
| 333 | nf_unregister_hook(&nft_base_chain(chain)->ops); | 341 | nf_unregister_hooks(nft_base_chain(chain)->ops, afi->nops); |
| 334 | } | 342 | } |
| 335 | return err; | 343 | return err; |
| 336 | } | 344 | } |
| 337 | 345 | ||
| 338 | static int nf_tables_table_disable(struct nft_table *table) | 346 | static int nf_tables_table_disable(const struct nft_af_info *afi, |
| 347 | struct nft_table *table) | ||
| 339 | { | 348 | { |
| 340 | struct nft_chain *chain; | 349 | struct nft_chain *chain; |
| 341 | 350 | ||
| 342 | list_for_each_entry(chain, &table->chains, list) { | 351 | list_for_each_entry(chain, &table->chains, list) { |
| 343 | if (chain->flags & NFT_BASE_CHAIN) | 352 | if (chain->flags & NFT_BASE_CHAIN) |
| 344 | nf_unregister_hook(&nft_base_chain(chain)->ops); | 353 | nf_unregister_hooks(nft_base_chain(chain)->ops, |
| 354 | afi->nops); | ||
| 345 | } | 355 | } |
| 346 | 356 | ||
| 347 | return 0; | 357 | return 0; |
| @@ -356,7 +366,7 @@ static int nf_tables_updtable(struct sock *nlsk, struct sk_buff *skb, | |||
| 356 | int family = nfmsg->nfgen_family, ret = 0; | 366 | int family = nfmsg->nfgen_family, ret = 0; |
| 357 | 367 | ||
| 358 | if (nla[NFTA_TABLE_FLAGS]) { | 368 | if (nla[NFTA_TABLE_FLAGS]) { |
| 359 | __be32 flags; | 369 | u32 flags; |
| 360 | 370 | ||
| 361 | flags = ntohl(nla_get_be32(nla[NFTA_TABLE_FLAGS])); | 371 | flags = ntohl(nla_get_be32(nla[NFTA_TABLE_FLAGS])); |
| 362 | if (flags & ~NFT_TABLE_F_DORMANT) | 372 | if (flags & ~NFT_TABLE_F_DORMANT) |
| @@ -364,12 +374,12 @@ static int nf_tables_updtable(struct sock *nlsk, struct sk_buff *skb, | |||
| 364 | 374 | ||
| 365 | if ((flags & NFT_TABLE_F_DORMANT) && | 375 | if ((flags & NFT_TABLE_F_DORMANT) && |
| 366 | !(table->flags & NFT_TABLE_F_DORMANT)) { | 376 | !(table->flags & NFT_TABLE_F_DORMANT)) { |
| 367 | ret = nf_tables_table_disable(table); | 377 | ret = nf_tables_table_disable(afi, table); |
| 368 | if (ret >= 0) | 378 | if (ret >= 0) |
| 369 | table->flags |= NFT_TABLE_F_DORMANT; | 379 | table->flags |= NFT_TABLE_F_DORMANT; |
| 370 | } else if (!(flags & NFT_TABLE_F_DORMANT) && | 380 | } else if (!(flags & NFT_TABLE_F_DORMANT) && |
| 371 | table->flags & NFT_TABLE_F_DORMANT) { | 381 | table->flags & NFT_TABLE_F_DORMANT) { |
| 372 | ret = nf_tables_table_enable(table); | 382 | ret = nf_tables_table_enable(afi, table); |
| 373 | if (ret >= 0) | 383 | if (ret >= 0) |
| 374 | table->flags &= ~NFT_TABLE_F_DORMANT; | 384 | table->flags &= ~NFT_TABLE_F_DORMANT; |
| 375 | } | 385 | } |
| @@ -392,6 +402,7 @@ static int nf_tables_newtable(struct sock *nlsk, struct sk_buff *skb, | |||
| 392 | struct nft_table *table; | 402 | struct nft_table *table; |
| 393 | struct net *net = sock_net(skb->sk); | 403 | struct net *net = sock_net(skb->sk); |
| 394 | int family = nfmsg->nfgen_family; | 404 | int family = nfmsg->nfgen_family; |
| 405 | u32 flags = 0; | ||
| 395 | 406 | ||
| 396 | afi = nf_tables_afinfo_lookup(net, family, true); | 407 | afi = nf_tables_afinfo_lookup(net, family, true); |
| 397 | if (IS_ERR(afi)) | 408 | if (IS_ERR(afi)) |
| @@ -413,25 +424,25 @@ static int nf_tables_newtable(struct sock *nlsk, struct sk_buff *skb, | |||
| 413 | return nf_tables_updtable(nlsk, skb, nlh, nla, afi, table); | 424 | return nf_tables_updtable(nlsk, skb, nlh, nla, afi, table); |
| 414 | } | 425 | } |
| 415 | 426 | ||
| 427 | if (nla[NFTA_TABLE_FLAGS]) { | ||
| 428 | flags = ntohl(nla_get_be32(nla[NFTA_TABLE_FLAGS])); | ||
| 429 | if (flags & ~NFT_TABLE_F_DORMANT) | ||
| 430 | return -EINVAL; | ||
| 431 | } | ||
| 432 | |||
| 433 | if (!try_module_get(afi->owner)) | ||
| 434 | return -EAFNOSUPPORT; | ||
| 435 | |||
| 416 | table = kzalloc(sizeof(*table) + nla_len(name), GFP_KERNEL); | 436 | table = kzalloc(sizeof(*table) + nla_len(name), GFP_KERNEL); |
| 417 | if (table == NULL) | 437 | if (table == NULL) { |
| 438 | module_put(afi->owner); | ||
| 418 | return -ENOMEM; | 439 | return -ENOMEM; |
| 440 | } | ||
| 419 | 441 | ||
| 420 | nla_strlcpy(table->name, name, nla_len(name)); | 442 | nla_strlcpy(table->name, name, nla_len(name)); |
| 421 | INIT_LIST_HEAD(&table->chains); | 443 | INIT_LIST_HEAD(&table->chains); |
| 422 | INIT_LIST_HEAD(&table->sets); | 444 | INIT_LIST_HEAD(&table->sets); |
| 423 | 445 | table->flags = flags; | |
| 424 | if (nla[NFTA_TABLE_FLAGS]) { | ||
| 425 | __be32 flags; | ||
| 426 | |||
| 427 | flags = ntohl(nla_get_be32(nla[NFTA_TABLE_FLAGS])); | ||
| 428 | if (flags & ~NFT_TABLE_F_DORMANT) { | ||
| 429 | kfree(table); | ||
| 430 | return -EINVAL; | ||
| 431 | } | ||
| 432 | |||
| 433 | table->flags |= flags; | ||
| 434 | } | ||
| 435 | 446 | ||
| 436 | list_add_tail(&table->list, &afi->tables); | 447 | list_add_tail(&table->list, &afi->tables); |
| 437 | nf_tables_table_notify(skb, nlh, table, NFT_MSG_NEWTABLE, family); | 448 | nf_tables_table_notify(skb, nlh, table, NFT_MSG_NEWTABLE, family); |
| @@ -456,16 +467,17 @@ static int nf_tables_deltable(struct sock *nlsk, struct sk_buff *skb, | |||
| 456 | if (IS_ERR(table)) | 467 | if (IS_ERR(table)) |
| 457 | return PTR_ERR(table); | 468 | return PTR_ERR(table); |
| 458 | 469 | ||
| 459 | if (table->use) | 470 | if (!list_empty(&table->chains) || !list_empty(&table->sets)) |
| 460 | return -EBUSY; | 471 | return -EBUSY; |
| 461 | 472 | ||
| 462 | list_del(&table->list); | 473 | list_del(&table->list); |
| 463 | nf_tables_table_notify(skb, nlh, table, NFT_MSG_DELTABLE, family); | 474 | nf_tables_table_notify(skb, nlh, table, NFT_MSG_DELTABLE, family); |
| 464 | kfree(table); | 475 | kfree(table); |
| 476 | module_put(afi->owner); | ||
| 465 | return 0; | 477 | return 0; |
| 466 | } | 478 | } |
| 467 | 479 | ||
| 468 | int nft_register_chain_type(struct nf_chain_type *ctype) | 480 | int nft_register_chain_type(const struct nf_chain_type *ctype) |
| 469 | { | 481 | { |
| 470 | int err = 0; | 482 | int err = 0; |
| 471 | 483 | ||
| @@ -474,10 +486,6 @@ int nft_register_chain_type(struct nf_chain_type *ctype) | |||
| 474 | err = -EBUSY; | 486 | err = -EBUSY; |
| 475 | goto out; | 487 | goto out; |
| 476 | } | 488 | } |
| 477 | |||
| 478 | if (!try_module_get(ctype->me)) | ||
| 479 | goto out; | ||
| 480 | |||
| 481 | chain_type[ctype->family][ctype->type] = ctype; | 489 | chain_type[ctype->family][ctype->type] = ctype; |
| 482 | out: | 490 | out: |
| 483 | nfnl_unlock(NFNL_SUBSYS_NFTABLES); | 491 | nfnl_unlock(NFNL_SUBSYS_NFTABLES); |
| @@ -485,11 +493,10 @@ out: | |||
| 485 | } | 493 | } |
| 486 | EXPORT_SYMBOL_GPL(nft_register_chain_type); | 494 | EXPORT_SYMBOL_GPL(nft_register_chain_type); |
| 487 | 495 | ||
| 488 | void nft_unregister_chain_type(struct nf_chain_type *ctype) | 496 | void nft_unregister_chain_type(const struct nf_chain_type *ctype) |
| 489 | { | 497 | { |
| 490 | nfnl_lock(NFNL_SUBSYS_NFTABLES); | 498 | nfnl_lock(NFNL_SUBSYS_NFTABLES); |
| 491 | chain_type[ctype->family][ctype->type] = NULL; | 499 | chain_type[ctype->family][ctype->type] = NULL; |
| 492 | module_put(ctype->me); | ||
| 493 | nfnl_unlock(NFNL_SUBSYS_NFTABLES); | 500 | nfnl_unlock(NFNL_SUBSYS_NFTABLES); |
| 494 | } | 501 | } |
| 495 | EXPORT_SYMBOL_GPL(nft_unregister_chain_type); | 502 | EXPORT_SYMBOL_GPL(nft_unregister_chain_type); |
| @@ -597,7 +604,7 @@ static int nf_tables_fill_chain_info(struct sk_buff *skb, u32 portid, u32 seq, | |||
| 597 | 604 | ||
| 598 | if (chain->flags & NFT_BASE_CHAIN) { | 605 | if (chain->flags & NFT_BASE_CHAIN) { |
| 599 | const struct nft_base_chain *basechain = nft_base_chain(chain); | 606 | const struct nft_base_chain *basechain = nft_base_chain(chain); |
| 600 | const struct nf_hook_ops *ops = &basechain->ops; | 607 | const struct nf_hook_ops *ops = &basechain->ops[0]; |
| 601 | struct nlattr *nest; | 608 | struct nlattr *nest; |
| 602 | 609 | ||
| 603 | nest = nla_nest_start(skb, NFTA_CHAIN_HOOK); | 610 | nest = nla_nest_start(skb, NFTA_CHAIN_HOOK); |
| @@ -613,9 +620,8 @@ static int nf_tables_fill_chain_info(struct sk_buff *skb, u32 portid, u32 seq, | |||
| 613 | htonl(basechain->policy))) | 620 | htonl(basechain->policy))) |
| 614 | goto nla_put_failure; | 621 | goto nla_put_failure; |
| 615 | 622 | ||
| 616 | if (nla_put_string(skb, NFTA_CHAIN_TYPE, | 623 | if (nla_put_string(skb, NFTA_CHAIN_TYPE, basechain->type->name)) |
| 617 | chain_type[ops->pf][nft_base_chain(chain)->type]->name)) | 624 | goto nla_put_failure; |
| 618 | goto nla_put_failure; | ||
| 619 | 625 | ||
| 620 | if (nft_dump_stats(skb, nft_base_chain(chain)->stats)) | 626 | if (nft_dump_stats(skb, nft_base_chain(chain)->stats)) |
| 621 | goto nla_put_failure; | 627 | goto nla_put_failure; |
| @@ -756,22 +762,6 @@ err: | |||
| 756 | return err; | 762 | return err; |
| 757 | } | 763 | } |
| 758 | 764 | ||
| 759 | static int | ||
| 760 | nf_tables_chain_policy(struct nft_base_chain *chain, const struct nlattr *attr) | ||
| 761 | { | ||
| 762 | switch (ntohl(nla_get_be32(attr))) { | ||
| 763 | case NF_DROP: | ||
| 764 | chain->policy = NF_DROP; | ||
| 765 | break; | ||
| 766 | case NF_ACCEPT: | ||
| 767 | chain->policy = NF_ACCEPT; | ||
| 768 | break; | ||
| 769 | default: | ||
| 770 | return -EINVAL; | ||
| 771 | } | ||
| 772 | return 0; | ||
| 773 | } | ||
| 774 | |||
| 775 | static const struct nla_policy nft_counter_policy[NFTA_COUNTER_MAX + 1] = { | 765 | static const struct nla_policy nft_counter_policy[NFTA_COUNTER_MAX + 1] = { |
| 776 | [NFTA_COUNTER_PACKETS] = { .type = NLA_U64 }, | 766 | [NFTA_COUNTER_PACKETS] = { .type = NLA_U64 }, |
| 777 | [NFTA_COUNTER_BYTES] = { .type = NLA_U64 }, | 767 | [NFTA_COUNTER_BYTES] = { .type = NLA_U64 }, |
| @@ -830,7 +820,9 @@ static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb, | |||
| 830 | struct nlattr *ha[NFTA_HOOK_MAX + 1]; | 820 | struct nlattr *ha[NFTA_HOOK_MAX + 1]; |
| 831 | struct net *net = sock_net(skb->sk); | 821 | struct net *net = sock_net(skb->sk); |
| 832 | int family = nfmsg->nfgen_family; | 822 | int family = nfmsg->nfgen_family; |
| 823 | u8 policy = NF_ACCEPT; | ||
| 833 | u64 handle = 0; | 824 | u64 handle = 0; |
| 825 | unsigned int i; | ||
| 834 | int err; | 826 | int err; |
| 835 | bool create; | 827 | bool create; |
| 836 | 828 | ||
| @@ -844,9 +836,6 @@ static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb, | |||
| 844 | if (IS_ERR(table)) | 836 | if (IS_ERR(table)) |
| 845 | return PTR_ERR(table); | 837 | return PTR_ERR(table); |
| 846 | 838 | ||
| 847 | if (table->use == UINT_MAX) | ||
| 848 | return -EOVERFLOW; | ||
| 849 | |||
| 850 | chain = NULL; | 839 | chain = NULL; |
| 851 | name = nla[NFTA_CHAIN_NAME]; | 840 | name = nla[NFTA_CHAIN_NAME]; |
| 852 | 841 | ||
| @@ -864,6 +853,22 @@ static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb, | |||
| 864 | } | 853 | } |
| 865 | } | 854 | } |
| 866 | 855 | ||
| 856 | if (nla[NFTA_CHAIN_POLICY]) { | ||
| 857 | if ((chain != NULL && | ||
| 858 | !(chain->flags & NFT_BASE_CHAIN)) || | ||
| 859 | nla[NFTA_CHAIN_HOOK] == NULL) | ||
| 860 | return -EOPNOTSUPP; | ||
| 861 | |||
| 862 | policy = ntohl(nla_get_be32(nla[NFTA_CHAIN_POLICY])); | ||
| 863 | switch (policy) { | ||
| 864 | case NF_DROP: | ||
| 865 | case NF_ACCEPT: | ||
| 866 | break; | ||
| 867 | default: | ||
| 868 | return -EINVAL; | ||
| 869 | } | ||
| 870 | } | ||
| 871 | |||
| 867 | if (chain != NULL) { | 872 | if (chain != NULL) { |
| 868 | if (nlh->nlmsg_flags & NLM_F_EXCL) | 873 | if (nlh->nlmsg_flags & NLM_F_EXCL) |
| 869 | return -EEXIST; | 874 | return -EEXIST; |
| @@ -874,16 +879,6 @@ static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb, | |||
| 874 | !IS_ERR(nf_tables_chain_lookup(table, nla[NFTA_CHAIN_NAME]))) | 879 | !IS_ERR(nf_tables_chain_lookup(table, nla[NFTA_CHAIN_NAME]))) |
| 875 | return -EEXIST; | 880 | return -EEXIST; |
| 876 | 881 | ||
| 877 | if (nla[NFTA_CHAIN_POLICY]) { | ||
| 878 | if (!(chain->flags & NFT_BASE_CHAIN)) | ||
| 879 | return -EOPNOTSUPP; | ||
| 880 | |||
| 881 | err = nf_tables_chain_policy(nft_base_chain(chain), | ||
| 882 | nla[NFTA_CHAIN_POLICY]); | ||
| 883 | if (err < 0) | ||
| 884 | return err; | ||
| 885 | } | ||
| 886 | |||
| 887 | if (nla[NFTA_CHAIN_COUNTERS]) { | 882 | if (nla[NFTA_CHAIN_COUNTERS]) { |
| 888 | if (!(chain->flags & NFT_BASE_CHAIN)) | 883 | if (!(chain->flags & NFT_BASE_CHAIN)) |
| 889 | return -EOPNOTSUPP; | 884 | return -EOPNOTSUPP; |
| @@ -894,24 +889,31 @@ static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb, | |||
| 894 | return err; | 889 | return err; |
| 895 | } | 890 | } |
| 896 | 891 | ||
| 892 | if (nla[NFTA_CHAIN_POLICY]) | ||
| 893 | nft_base_chain(chain)->policy = policy; | ||
| 894 | |||
| 897 | if (nla[NFTA_CHAIN_HANDLE] && name) | 895 | if (nla[NFTA_CHAIN_HANDLE] && name) |
| 898 | nla_strlcpy(chain->name, name, NFT_CHAIN_MAXNAMELEN); | 896 | nla_strlcpy(chain->name, name, NFT_CHAIN_MAXNAMELEN); |
| 899 | 897 | ||
| 900 | goto notify; | 898 | goto notify; |
| 901 | } | 899 | } |
| 902 | 900 | ||
| 901 | if (table->use == UINT_MAX) | ||
| 902 | return -EOVERFLOW; | ||
| 903 | |||
| 903 | if (nla[NFTA_CHAIN_HOOK]) { | 904 | if (nla[NFTA_CHAIN_HOOK]) { |
| 905 | const struct nf_chain_type *type; | ||
| 904 | struct nf_hook_ops *ops; | 906 | struct nf_hook_ops *ops; |
| 905 | nf_hookfn *hookfn; | 907 | nf_hookfn *hookfn; |
| 906 | u32 hooknum; | 908 | u32 hooknum, priority; |
| 907 | int type = NFT_CHAIN_T_DEFAULT; | ||
| 908 | 909 | ||
| 910 | type = chain_type[family][NFT_CHAIN_T_DEFAULT]; | ||
| 909 | if (nla[NFTA_CHAIN_TYPE]) { | 911 | if (nla[NFTA_CHAIN_TYPE]) { |
| 910 | type = nf_tables_chain_type_lookup(afi, | 912 | type = nf_tables_chain_type_lookup(afi, |
| 911 | nla[NFTA_CHAIN_TYPE], | 913 | nla[NFTA_CHAIN_TYPE], |
| 912 | create); | 914 | create); |
| 913 | if (type < 0) | 915 | if (IS_ERR(type)) |
| 914 | return -ENOENT; | 916 | return PTR_ERR(type); |
| 915 | } | 917 | } |
| 916 | 918 | ||
| 917 | err = nla_parse_nested(ha, NFTA_HOOK_MAX, nla[NFTA_CHAIN_HOOK], | 919 | err = nla_parse_nested(ha, NFTA_HOOK_MAX, nla[NFTA_CHAIN_HOOK], |
| @@ -925,46 +927,23 @@ static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb, | |||
| 925 | hooknum = ntohl(nla_get_be32(ha[NFTA_HOOK_HOOKNUM])); | 927 | hooknum = ntohl(nla_get_be32(ha[NFTA_HOOK_HOOKNUM])); |
| 926 | if (hooknum >= afi->nhooks) | 928 | if (hooknum >= afi->nhooks) |
| 927 | return -EINVAL; | 929 | return -EINVAL; |
| 930 | priority = ntohl(nla_get_be32(ha[NFTA_HOOK_PRIORITY])); | ||
| 928 | 931 | ||
| 929 | hookfn = chain_type[family][type]->fn[hooknum]; | 932 | if (!(type->hook_mask & (1 << hooknum))) |
| 930 | if (hookfn == NULL) | ||
| 931 | return -EOPNOTSUPP; | 933 | return -EOPNOTSUPP; |
| 934 | if (!try_module_get(type->owner)) | ||
| 935 | return -ENOENT; | ||
| 936 | hookfn = type->hooks[hooknum]; | ||
| 932 | 937 | ||
| 933 | basechain = kzalloc(sizeof(*basechain), GFP_KERNEL); | 938 | basechain = kzalloc(sizeof(*basechain), GFP_KERNEL); |
| 934 | if (basechain == NULL) | 939 | if (basechain == NULL) |
| 935 | return -ENOMEM; | 940 | return -ENOMEM; |
| 936 | 941 | ||
| 937 | basechain->type = type; | ||
| 938 | chain = &basechain->chain; | ||
| 939 | |||
| 940 | ops = &basechain->ops; | ||
| 941 | ops->pf = family; | ||
| 942 | ops->owner = afi->owner; | ||
| 943 | ops->hooknum = ntohl(nla_get_be32(ha[NFTA_HOOK_HOOKNUM])); | ||
| 944 | ops->priority = ntohl(nla_get_be32(ha[NFTA_HOOK_PRIORITY])); | ||
| 945 | ops->priv = chain; | ||
| 946 | ops->hook = hookfn; | ||
| 947 | if (afi->hooks[ops->hooknum]) | ||
| 948 | ops->hook = afi->hooks[ops->hooknum]; | ||
| 949 | |||
| 950 | chain->flags |= NFT_BASE_CHAIN; | ||
| 951 | |||
| 952 | if (nla[NFTA_CHAIN_POLICY]) { | ||
| 953 | err = nf_tables_chain_policy(basechain, | ||
| 954 | nla[NFTA_CHAIN_POLICY]); | ||
| 955 | if (err < 0) { | ||
| 956 | free_percpu(basechain->stats); | ||
| 957 | kfree(basechain); | ||
| 958 | return err; | ||
| 959 | } | ||
| 960 | } else | ||
| 961 | basechain->policy = NF_ACCEPT; | ||
| 962 | |||
| 963 | if (nla[NFTA_CHAIN_COUNTERS]) { | 942 | if (nla[NFTA_CHAIN_COUNTERS]) { |
| 964 | err = nf_tables_counters(basechain, | 943 | err = nf_tables_counters(basechain, |
| 965 | nla[NFTA_CHAIN_COUNTERS]); | 944 | nla[NFTA_CHAIN_COUNTERS]); |
| 966 | if (err < 0) { | 945 | if (err < 0) { |
| 967 | free_percpu(basechain->stats); | 946 | module_put(type->owner); |
| 968 | kfree(basechain); | 947 | kfree(basechain); |
| 969 | return err; | 948 | return err; |
| 970 | } | 949 | } |
| @@ -972,12 +951,33 @@ static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb, | |||
| 972 | struct nft_stats __percpu *newstats; | 951 | struct nft_stats __percpu *newstats; |
| 973 | 952 | ||
| 974 | newstats = alloc_percpu(struct nft_stats); | 953 | newstats = alloc_percpu(struct nft_stats); |
| 975 | if (newstats == NULL) | 954 | if (newstats == NULL) { |
| 955 | module_put(type->owner); | ||
| 956 | kfree(basechain); | ||
| 976 | return -ENOMEM; | 957 | return -ENOMEM; |
| 958 | } | ||
| 959 | rcu_assign_pointer(basechain->stats, newstats); | ||
| 960 | } | ||
| 961 | |||
| 962 | basechain->type = type; | ||
| 963 | chain = &basechain->chain; | ||
| 977 | 964 | ||
| 978 | rcu_assign_pointer(nft_base_chain(chain)->stats, | 965 | for (i = 0; i < afi->nops; i++) { |
| 979 | newstats); | 966 | ops = &basechain->ops[i]; |
| 967 | ops->pf = family; | ||
| 968 | ops->owner = afi->owner; | ||
| 969 | ops->hooknum = hooknum; | ||
| 970 | ops->priority = priority; | ||
| 971 | ops->priv = chain; | ||
| 972 | ops->hook = afi->hooks[ops->hooknum]; | ||
| 973 | if (hookfn) | ||
| 974 | ops->hook = hookfn; | ||
| 975 | if (afi->hook_ops_init) | ||
| 976 | afi->hook_ops_init(ops, i); | ||
| 980 | } | 977 | } |
| 978 | |||
| 979 | chain->flags |= NFT_BASE_CHAIN; | ||
| 980 | basechain->policy = policy; | ||
| 981 | } else { | 981 | } else { |
| 982 | chain = kzalloc(sizeof(*chain), GFP_KERNEL); | 982 | chain = kzalloc(sizeof(*chain), GFP_KERNEL); |
| 983 | if (chain == NULL) | 983 | if (chain == NULL) |
| @@ -992,8 +992,9 @@ static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb, | |||
| 992 | 992 | ||
| 993 | if (!(table->flags & NFT_TABLE_F_DORMANT) && | 993 | if (!(table->flags & NFT_TABLE_F_DORMANT) && |
| 994 | chain->flags & NFT_BASE_CHAIN) { | 994 | chain->flags & NFT_BASE_CHAIN) { |
| 995 | err = nf_register_hook(&nft_base_chain(chain)->ops); | 995 | err = nf_register_hooks(nft_base_chain(chain)->ops, afi->nops); |
| 996 | if (err < 0) { | 996 | if (err < 0) { |
| 997 | module_put(basechain->type->owner); | ||
| 997 | free_percpu(basechain->stats); | 998 | free_percpu(basechain->stats); |
| 998 | kfree(basechain); | 999 | kfree(basechain); |
| 999 | return err; | 1000 | return err; |
| @@ -1014,6 +1015,7 @@ static void nf_tables_rcu_chain_destroy(struct rcu_head *head) | |||
| 1014 | BUG_ON(chain->use > 0); | 1015 | BUG_ON(chain->use > 0); |
| 1015 | 1016 | ||
| 1016 | if (chain->flags & NFT_BASE_CHAIN) { | 1017 | if (chain->flags & NFT_BASE_CHAIN) { |
| 1018 | module_put(nft_base_chain(chain)->type->owner); | ||
| 1017 | free_percpu(nft_base_chain(chain)->stats); | 1019 | free_percpu(nft_base_chain(chain)->stats); |
| 1018 | kfree(nft_base_chain(chain)); | 1020 | kfree(nft_base_chain(chain)); |
| 1019 | } else | 1021 | } else |
| @@ -1051,7 +1053,7 @@ static int nf_tables_delchain(struct sock *nlsk, struct sk_buff *skb, | |||
| 1051 | 1053 | ||
| 1052 | if (!(table->flags & NFT_TABLE_F_DORMANT) && | 1054 | if (!(table->flags & NFT_TABLE_F_DORMANT) && |
| 1053 | chain->flags & NFT_BASE_CHAIN) | 1055 | chain->flags & NFT_BASE_CHAIN) |
| 1054 | nf_unregister_hook(&nft_base_chain(chain)->ops); | 1056 | nf_unregister_hooks(nft_base_chain(chain)->ops, afi->nops); |
| 1055 | 1057 | ||
| 1056 | nf_tables_chain_notify(skb, nlh, table, chain, NFT_MSG_DELCHAIN, | 1058 | nf_tables_chain_notify(skb, nlh, table, chain, NFT_MSG_DELCHAIN, |
| 1057 | family); | 1059 | family); |
| @@ -1931,12 +1933,14 @@ static int nft_ctx_init_from_setattr(struct nft_ctx *ctx, | |||
| 1931 | { | 1933 | { |
| 1932 | struct net *net = sock_net(skb->sk); | 1934 | struct net *net = sock_net(skb->sk); |
| 1933 | const struct nfgenmsg *nfmsg = nlmsg_data(nlh); | 1935 | const struct nfgenmsg *nfmsg = nlmsg_data(nlh); |
| 1934 | const struct nft_af_info *afi; | 1936 | const struct nft_af_info *afi = NULL; |
| 1935 | const struct nft_table *table = NULL; | 1937 | const struct nft_table *table = NULL; |
| 1936 | 1938 | ||
| 1937 | afi = nf_tables_afinfo_lookup(net, nfmsg->nfgen_family, false); | 1939 | if (nfmsg->nfgen_family != NFPROTO_UNSPEC) { |
| 1938 | if (IS_ERR(afi)) | 1940 | afi = nf_tables_afinfo_lookup(net, nfmsg->nfgen_family, false); |
| 1939 | return PTR_ERR(afi); | 1941 | if (IS_ERR(afi)) |
| 1942 | return PTR_ERR(afi); | ||
| 1943 | } | ||
| 1940 | 1944 | ||
| 1941 | if (nla[NFTA_SET_TABLE] != NULL) { | 1945 | if (nla[NFTA_SET_TABLE] != NULL) { |
| 1942 | table = nf_tables_table_lookup(afi, nla[NFTA_SET_TABLE]); | 1946 | table = nf_tables_table_lookup(afi, nla[NFTA_SET_TABLE]); |
| @@ -1981,11 +1985,14 @@ static int nf_tables_set_alloc_name(struct nft_ctx *ctx, struct nft_set *set, | |||
| 1981 | return -ENOMEM; | 1985 | return -ENOMEM; |
| 1982 | 1986 | ||
| 1983 | list_for_each_entry(i, &ctx->table->sets, list) { | 1987 | list_for_each_entry(i, &ctx->table->sets, list) { |
| 1984 | if (!sscanf(i->name, name, &n)) | 1988 | int tmp; |
| 1989 | |||
| 1990 | if (!sscanf(i->name, name, &tmp)) | ||
| 1985 | continue; | 1991 | continue; |
| 1986 | if (n < 0 || n > BITS_PER_LONG * PAGE_SIZE) | 1992 | if (tmp < 0 || tmp > BITS_PER_LONG * PAGE_SIZE) |
| 1987 | continue; | 1993 | continue; |
| 1988 | set_bit(n, inuse); | 1994 | |
| 1995 | set_bit(tmp, inuse); | ||
| 1989 | } | 1996 | } |
| 1990 | 1997 | ||
| 1991 | n = find_first_zero_bit(inuse, BITS_PER_LONG * PAGE_SIZE); | 1998 | n = find_first_zero_bit(inuse, BITS_PER_LONG * PAGE_SIZE); |
| @@ -2102,8 +2109,8 @@ done: | |||
| 2102 | return skb->len; | 2109 | return skb->len; |
| 2103 | } | 2110 | } |
| 2104 | 2111 | ||
| 2105 | static int nf_tables_dump_sets_all(struct nft_ctx *ctx, struct sk_buff *skb, | 2112 | static int nf_tables_dump_sets_family(struct nft_ctx *ctx, struct sk_buff *skb, |
| 2106 | struct netlink_callback *cb) | 2113 | struct netlink_callback *cb) |
| 2107 | { | 2114 | { |
| 2108 | const struct nft_set *set; | 2115 | const struct nft_set *set; |
| 2109 | unsigned int idx, s_idx = cb->args[0]; | 2116 | unsigned int idx, s_idx = cb->args[0]; |
| @@ -2139,6 +2146,61 @@ done: | |||
| 2139 | return skb->len; | 2146 | return skb->len; |
| 2140 | } | 2147 | } |
| 2141 | 2148 | ||
| 2149 | static int nf_tables_dump_sets_all(struct nft_ctx *ctx, struct sk_buff *skb, | ||
| 2150 | struct netlink_callback *cb) | ||
| 2151 | { | ||
| 2152 | const struct nft_set *set; | ||
| 2153 | unsigned int idx, s_idx = cb->args[0]; | ||
| 2154 | const struct nft_af_info *afi; | ||
| 2155 | struct nft_table *table, *cur_table = (struct nft_table *)cb->args[2]; | ||
| 2156 | struct net *net = sock_net(skb->sk); | ||
| 2157 | int cur_family = cb->args[3]; | ||
| 2158 | |||
| 2159 | if (cb->args[1]) | ||
| 2160 | return skb->len; | ||
| 2161 | |||
| 2162 | list_for_each_entry(afi, &net->nft.af_info, list) { | ||
| 2163 | if (cur_family) { | ||
| 2164 | if (afi->family != cur_family) | ||
| 2165 | continue; | ||
| 2166 | |||
| 2167 | cur_family = 0; | ||
| 2168 | } | ||
| 2169 | |||
| 2170 | list_for_each_entry(table, &afi->tables, list) { | ||
| 2171 | if (cur_table) { | ||
| 2172 | if (cur_table != table) | ||
| 2173 | continue; | ||
| 2174 | |||
| 2175 | cur_table = NULL; | ||
| 2176 | } | ||
| 2177 | |||
| 2178 | ctx->table = table; | ||
| 2179 | ctx->afi = afi; | ||
| 2180 | idx = 0; | ||
| 2181 | list_for_each_entry(set, &ctx->table->sets, list) { | ||
| 2182 | if (idx < s_idx) | ||
| 2183 | goto cont; | ||
| 2184 | if (nf_tables_fill_set(skb, ctx, set, | ||
| 2185 | NFT_MSG_NEWSET, | ||
| 2186 | NLM_F_MULTI) < 0) { | ||
| 2187 | cb->args[0] = idx; | ||
| 2188 | cb->args[2] = (unsigned long) table; | ||
| 2189 | cb->args[3] = afi->family; | ||
| 2190 | goto done; | ||
| 2191 | } | ||
| 2192 | cont: | ||
| 2193 | idx++; | ||
| 2194 | } | ||
| 2195 | if (s_idx) | ||
| 2196 | s_idx = 0; | ||
| 2197 | } | ||
| 2198 | } | ||
| 2199 | cb->args[1] = 1; | ||
| 2200 | done: | ||
| 2201 | return skb->len; | ||
| 2202 | } | ||
| 2203 | |||
| 2142 | static int nf_tables_dump_sets(struct sk_buff *skb, struct netlink_callback *cb) | 2204 | static int nf_tables_dump_sets(struct sk_buff *skb, struct netlink_callback *cb) |
| 2143 | { | 2205 | { |
| 2144 | const struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh); | 2206 | const struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh); |
| @@ -2155,9 +2217,12 @@ static int nf_tables_dump_sets(struct sk_buff *skb, struct netlink_callback *cb) | |||
| 2155 | if (err < 0) | 2217 | if (err < 0) |
| 2156 | return err; | 2218 | return err; |
| 2157 | 2219 | ||
| 2158 | if (ctx.table == NULL) | 2220 | if (ctx.table == NULL) { |
| 2159 | ret = nf_tables_dump_sets_all(&ctx, skb, cb); | 2221 | if (ctx.afi == NULL) |
| 2160 | else | 2222 | ret = nf_tables_dump_sets_all(&ctx, skb, cb); |
| 2223 | else | ||
| 2224 | ret = nf_tables_dump_sets_family(&ctx, skb, cb); | ||
| 2225 | } else | ||
| 2161 | ret = nf_tables_dump_sets_table(&ctx, skb, cb); | 2226 | ret = nf_tables_dump_sets_table(&ctx, skb, cb); |
| 2162 | 2227 | ||
| 2163 | return ret; | 2228 | return ret; |
| @@ -2170,6 +2235,7 @@ static int nf_tables_getset(struct sock *nlsk, struct sk_buff *skb, | |||
| 2170 | const struct nft_set *set; | 2235 | const struct nft_set *set; |
| 2171 | struct nft_ctx ctx; | 2236 | struct nft_ctx ctx; |
| 2172 | struct sk_buff *skb2; | 2237 | struct sk_buff *skb2; |
| 2238 | const struct nfgenmsg *nfmsg = nlmsg_data(nlh); | ||
| 2173 | int err; | 2239 | int err; |
| 2174 | 2240 | ||
| 2175 | /* Verify existance before starting dump */ | 2241 | /* Verify existance before starting dump */ |
| @@ -2184,6 +2250,10 @@ static int nf_tables_getset(struct sock *nlsk, struct sk_buff *skb, | |||
| 2184 | return netlink_dump_start(nlsk, skb, nlh, &c); | 2250 | return netlink_dump_start(nlsk, skb, nlh, &c); |
| 2185 | } | 2251 | } |
| 2186 | 2252 | ||
| 2253 | /* Only accept unspec with dump */ | ||
| 2254 | if (nfmsg->nfgen_family == NFPROTO_UNSPEC) | ||
| 2255 | return -EAFNOSUPPORT; | ||
| 2256 | |||
| 2187 | set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_NAME]); | 2257 | set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_NAME]); |
| 2188 | if (IS_ERR(set)) | 2258 | if (IS_ERR(set)) |
| 2189 | return PTR_ERR(set); | 2259 | return PTR_ERR(set); |
| @@ -2353,6 +2423,7 @@ static int nf_tables_delset(struct sock *nlsk, struct sk_buff *skb, | |||
| 2353 | const struct nlmsghdr *nlh, | 2423 | const struct nlmsghdr *nlh, |
| 2354 | const struct nlattr * const nla[]) | 2424 | const struct nlattr * const nla[]) |
| 2355 | { | 2425 | { |
| 2426 | const struct nfgenmsg *nfmsg = nlmsg_data(nlh); | ||
| 2356 | struct nft_set *set; | 2427 | struct nft_set *set; |
| 2357 | struct nft_ctx ctx; | 2428 | struct nft_ctx ctx; |
| 2358 | int err; | 2429 | int err; |
| @@ -2364,6 +2435,9 @@ static int nf_tables_delset(struct sock *nlsk, struct sk_buff *skb, | |||
| 2364 | if (err < 0) | 2435 | if (err < 0) |
| 2365 | return err; | 2436 | return err; |
| 2366 | 2437 | ||
| 2438 | if (nfmsg->nfgen_family == NFPROTO_UNSPEC) | ||
| 2439 | return -EAFNOSUPPORT; | ||
| 2440 | |||
| 2367 | set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_NAME]); | 2441 | set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_NAME]); |
| 2368 | if (IS_ERR(set)) | 2442 | if (IS_ERR(set)) |
| 2369 | return PTR_ERR(set); | 2443 | return PTR_ERR(set); |
| @@ -2535,9 +2609,8 @@ static int nf_tables_dump_set(struct sk_buff *skb, struct netlink_callback *cb) | |||
| 2535 | u32 portid, seq; | 2609 | u32 portid, seq; |
| 2536 | int event, err; | 2610 | int event, err; |
| 2537 | 2611 | ||
| 2538 | nfmsg = nlmsg_data(cb->nlh); | 2612 | err = nlmsg_parse(cb->nlh, sizeof(struct nfgenmsg), nla, |
| 2539 | err = nlmsg_parse(cb->nlh, sizeof(*nfmsg), nla, NFTA_SET_ELEM_LIST_MAX, | 2613 | NFTA_SET_ELEM_LIST_MAX, nft_set_elem_list_policy); |
| 2540 | nft_set_elem_list_policy); | ||
| 2541 | if (err < 0) | 2614 | if (err < 0) |
| 2542 | return err; | 2615 | return err; |
| 2543 | 2616 | ||
diff --git a/net/netfilter/nf_tables_core.c b/net/netfilter/nf_tables_core.c index cb9e685caae1..0d879fcb8763 100644 --- a/net/netfilter/nf_tables_core.c +++ b/net/netfilter/nf_tables_core.c | |||
| @@ -109,14 +109,14 @@ static inline void nft_trace_packet(const struct nft_pktinfo *pkt, | |||
| 109 | { | 109 | { |
| 110 | struct net *net = dev_net(pkt->in ? pkt->in : pkt->out); | 110 | struct net *net = dev_net(pkt->in ? pkt->in : pkt->out); |
| 111 | 111 | ||
| 112 | nf_log_packet(net, pkt->xt.family, pkt->hooknum, pkt->skb, pkt->in, | 112 | nf_log_packet(net, pkt->xt.family, pkt->ops->hooknum, pkt->skb, pkt->in, |
| 113 | pkt->out, &trace_loginfo, "TRACE: %s:%s:%s:%u ", | 113 | pkt->out, &trace_loginfo, "TRACE: %s:%s:%s:%u ", |
| 114 | chain->table->name, chain->name, comments[type], | 114 | chain->table->name, chain->name, comments[type], |
| 115 | rulenum); | 115 | rulenum); |
| 116 | } | 116 | } |
| 117 | 117 | ||
| 118 | unsigned int | 118 | unsigned int |
| 119 | nft_do_chain_pktinfo(struct nft_pktinfo *pkt, const struct nf_hook_ops *ops) | 119 | nft_do_chain(struct nft_pktinfo *pkt, const struct nf_hook_ops *ops) |
| 120 | { | 120 | { |
| 121 | const struct nft_chain *chain = ops->priv; | 121 | const struct nft_chain *chain = ops->priv; |
| 122 | const struct nft_rule *rule; | 122 | const struct nft_rule *rule; |
| @@ -164,7 +164,7 @@ next_rule: | |||
| 164 | break; | 164 | break; |
| 165 | } | 165 | } |
| 166 | 166 | ||
| 167 | switch (data[NFT_REG_VERDICT].verdict) { | 167 | switch (data[NFT_REG_VERDICT].verdict & NF_VERDICT_MASK) { |
| 168 | case NF_ACCEPT: | 168 | case NF_ACCEPT: |
| 169 | case NF_DROP: | 169 | case NF_DROP: |
| 170 | case NF_QUEUE: | 170 | case NF_QUEUE: |
| @@ -172,6 +172,9 @@ next_rule: | |||
| 172 | nft_trace_packet(pkt, chain, rulenum, NFT_TRACE_RULE); | 172 | nft_trace_packet(pkt, chain, rulenum, NFT_TRACE_RULE); |
| 173 | 173 | ||
| 174 | return data[NFT_REG_VERDICT].verdict; | 174 | return data[NFT_REG_VERDICT].verdict; |
| 175 | } | ||
| 176 | |||
| 177 | switch (data[NFT_REG_VERDICT].verdict) { | ||
| 175 | case NFT_JUMP: | 178 | case NFT_JUMP: |
| 176 | if (unlikely(pkt->skb->nf_trace)) | 179 | if (unlikely(pkt->skb->nf_trace)) |
| 177 | nft_trace_packet(pkt, chain, rulenum, NFT_TRACE_RULE); | 180 | nft_trace_packet(pkt, chain, rulenum, NFT_TRACE_RULE); |
| @@ -213,7 +216,7 @@ next_rule: | |||
| 213 | 216 | ||
| 214 | return nft_base_chain(chain)->policy; | 217 | return nft_base_chain(chain)->policy; |
| 215 | } | 218 | } |
| 216 | EXPORT_SYMBOL_GPL(nft_do_chain_pktinfo); | 219 | EXPORT_SYMBOL_GPL(nft_do_chain); |
| 217 | 220 | ||
| 218 | int __init nf_tables_core_module_init(void) | 221 | int __init nf_tables_core_module_init(void) |
| 219 | { | 222 | { |
diff --git a/net/netfilter/nf_tables_inet.c b/net/netfilter/nf_tables_inet.c new file mode 100644 index 000000000000..9dd2d216cfc1 --- /dev/null +++ b/net/netfilter/nf_tables_inet.c | |||
| @@ -0,0 +1,104 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2012-2014 Patrick McHardy <kaber@trash.net> | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/init.h> | ||
| 10 | #include <linux/module.h> | ||
| 11 | #include <linux/ip.h> | ||
| 12 | #include <linux/netfilter_ipv4.h> | ||
| 13 | #include <linux/netfilter_ipv6.h> | ||
| 14 | #include <net/netfilter/nf_tables.h> | ||
| 15 | #include <net/netfilter/nf_tables_ipv4.h> | ||
| 16 | #include <net/netfilter/nf_tables_ipv6.h> | ||
| 17 | #include <net/ip.h> | ||
| 18 | |||
| 19 | static void nft_inet_hook_ops_init(struct nf_hook_ops *ops, unsigned int n) | ||
| 20 | { | ||
| 21 | struct nft_af_info *afi; | ||
| 22 | |||
| 23 | if (n == 1) | ||
| 24 | afi = &nft_af_ipv4; | ||
| 25 | else | ||
| 26 | afi = &nft_af_ipv6; | ||
| 27 | |||
| 28 | ops->pf = afi->family; | ||
| 29 | if (afi->hooks[ops->hooknum]) | ||
| 30 | ops->hook = afi->hooks[ops->hooknum]; | ||
| 31 | } | ||
| 32 | |||
| 33 | static struct nft_af_info nft_af_inet __read_mostly = { | ||
| 34 | .family = NFPROTO_INET, | ||
| 35 | .nhooks = NF_INET_NUMHOOKS, | ||
| 36 | .owner = THIS_MODULE, | ||
| 37 | .nops = 2, | ||
| 38 | .hook_ops_init = nft_inet_hook_ops_init, | ||
| 39 | }; | ||
| 40 | |||
| 41 | static int __net_init nf_tables_inet_init_net(struct net *net) | ||
| 42 | { | ||
| 43 | net->nft.inet = kmalloc(sizeof(struct nft_af_info), GFP_KERNEL); | ||
| 44 | if (net->nft.inet == NULL) | ||
| 45 | return -ENOMEM; | ||
| 46 | memcpy(net->nft.inet, &nft_af_inet, sizeof(nft_af_inet)); | ||
| 47 | |||
| 48 | if (nft_register_afinfo(net, net->nft.inet) < 0) | ||
| 49 | goto err; | ||
| 50 | |||
| 51 | return 0; | ||
| 52 | |||
| 53 | err: | ||
| 54 | kfree(net->nft.inet); | ||
| 55 | return -ENOMEM; | ||
| 56 | } | ||
| 57 | |||
| 58 | static void __net_exit nf_tables_inet_exit_net(struct net *net) | ||
| 59 | { | ||
| 60 | nft_unregister_afinfo(net->nft.inet); | ||
| 61 | kfree(net->nft.inet); | ||
| 62 | } | ||
| 63 | |||
| 64 | static struct pernet_operations nf_tables_inet_net_ops = { | ||
| 65 | .init = nf_tables_inet_init_net, | ||
| 66 | .exit = nf_tables_inet_exit_net, | ||
| 67 | }; | ||
| 68 | |||
| 69 | static const struct nf_chain_type filter_inet = { | ||
| 70 | .name = "filter", | ||
| 71 | .type = NFT_CHAIN_T_DEFAULT, | ||
| 72 | .family = NFPROTO_INET, | ||
| 73 | .owner = THIS_MODULE, | ||
| 74 | .hook_mask = (1 << NF_INET_LOCAL_IN) | | ||
| 75 | (1 << NF_INET_LOCAL_OUT) | | ||
| 76 | (1 << NF_INET_FORWARD) | | ||
| 77 | (1 << NF_INET_PRE_ROUTING) | | ||
| 78 | (1 << NF_INET_POST_ROUTING), | ||
| 79 | }; | ||
| 80 | |||
| 81 | static int __init nf_tables_inet_init(void) | ||
| 82 | { | ||
| 83 | int ret; | ||
| 84 | |||
| 85 | nft_register_chain_type(&filter_inet); | ||
| 86 | ret = register_pernet_subsys(&nf_tables_inet_net_ops); | ||
| 87 | if (ret < 0) | ||
| 88 | nft_unregister_chain_type(&filter_inet); | ||
| 89 | |||
| 90 | return ret; | ||
| 91 | } | ||
| 92 | |||
| 93 | static void __exit nf_tables_inet_exit(void) | ||
| 94 | { | ||
| 95 | unregister_pernet_subsys(&nf_tables_inet_net_ops); | ||
| 96 | nft_unregister_chain_type(&filter_inet); | ||
| 97 | } | ||
| 98 | |||
| 99 | module_init(nf_tables_inet_init); | ||
| 100 | module_exit(nf_tables_inet_exit); | ||
| 101 | |||
| 102 | MODULE_LICENSE("GPL"); | ||
| 103 | MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>"); | ||
| 104 | MODULE_ALIAS_NFT_FAMILY(1); | ||
diff --git a/net/netfilter/nfnetlink_queue_core.c b/net/netfilter/nfnetlink_queue_core.c index 21258cf70091..f072fe803510 100644 --- a/net/netfilter/nfnetlink_queue_core.c +++ b/net/netfilter/nfnetlink_queue_core.c | |||
| @@ -29,6 +29,7 @@ | |||
| 29 | #include <linux/netfilter/nfnetlink_queue.h> | 29 | #include <linux/netfilter/nfnetlink_queue.h> |
| 30 | #include <linux/list.h> | 30 | #include <linux/list.h> |
| 31 | #include <net/sock.h> | 31 | #include <net/sock.h> |
| 32 | #include <net/tcp_states.h> | ||
| 32 | #include <net/netfilter/nf_queue.h> | 33 | #include <net/netfilter/nf_queue.h> |
| 33 | #include <net/netns/generic.h> | 34 | #include <net/netns/generic.h> |
| 34 | #include <net/netfilter/nfnetlink_queue.h> | 35 | #include <net/netfilter/nfnetlink_queue.h> |
| @@ -235,51 +236,6 @@ nfqnl_flush(struct nfqnl_instance *queue, nfqnl_cmpfn cmpfn, unsigned long data) | |||
| 235 | spin_unlock_bh(&queue->lock); | 236 | spin_unlock_bh(&queue->lock); |
| 236 | } | 237 | } |
| 237 | 238 | ||
| 238 | static void | ||
| 239 | nfqnl_zcopy(struct sk_buff *to, const struct sk_buff *from, int len, int hlen) | ||
| 240 | { | ||
| 241 | int i, j = 0; | ||
| 242 | int plen = 0; /* length of skb->head fragment */ | ||
| 243 | struct page *page; | ||
| 244 | unsigned int offset; | ||
| 245 | |||
| 246 | /* dont bother with small payloads */ | ||
| 247 | if (len <= skb_tailroom(to)) { | ||
| 248 | skb_copy_bits(from, 0, skb_put(to, len), len); | ||
| 249 | return; | ||
| 250 | } | ||
| 251 | |||
| 252 | if (hlen) { | ||
| 253 | skb_copy_bits(from, 0, skb_put(to, hlen), hlen); | ||
| 254 | len -= hlen; | ||
| 255 | } else { | ||
| 256 | plen = min_t(int, skb_headlen(from), len); | ||
| 257 | if (plen) { | ||
| 258 | page = virt_to_head_page(from->head); | ||
| 259 | offset = from->data - (unsigned char *)page_address(page); | ||
| 260 | __skb_fill_page_desc(to, 0, page, offset, plen); | ||
| 261 | get_page(page); | ||
| 262 | j = 1; | ||
| 263 | len -= plen; | ||
| 264 | } | ||
| 265 | } | ||
| 266 | |||
| 267 | to->truesize += len + plen; | ||
| 268 | to->len += len + plen; | ||
| 269 | to->data_len += len + plen; | ||
| 270 | |||
| 271 | for (i = 0; i < skb_shinfo(from)->nr_frags; i++) { | ||
| 272 | if (!len) | ||
| 273 | break; | ||
| 274 | skb_shinfo(to)->frags[j] = skb_shinfo(from)->frags[i]; | ||
| 275 | skb_shinfo(to)->frags[j].size = min_t(int, skb_shinfo(to)->frags[j].size, len); | ||
| 276 | len -= skb_shinfo(to)->frags[j].size; | ||
| 277 | skb_frag_ref(to, j); | ||
| 278 | j++; | ||
| 279 | } | ||
| 280 | skb_shinfo(to)->nr_frags = j; | ||
| 281 | } | ||
| 282 | |||
| 283 | static int | 239 | static int |
| 284 | nfqnl_put_packet_info(struct sk_buff *nlskb, struct sk_buff *packet, | 240 | nfqnl_put_packet_info(struct sk_buff *nlskb, struct sk_buff *packet, |
| 285 | bool csum_verify) | 241 | bool csum_verify) |
| @@ -297,6 +253,31 @@ nfqnl_put_packet_info(struct sk_buff *nlskb, struct sk_buff *packet, | |||
| 297 | return flags ? nla_put_be32(nlskb, NFQA_SKB_INFO, htonl(flags)) : 0; | 253 | return flags ? nla_put_be32(nlskb, NFQA_SKB_INFO, htonl(flags)) : 0; |
| 298 | } | 254 | } |
| 299 | 255 | ||
| 256 | static int nfqnl_put_sk_uidgid(struct sk_buff *skb, struct sock *sk) | ||
| 257 | { | ||
| 258 | const struct cred *cred; | ||
| 259 | |||
| 260 | if (sk->sk_state == TCP_TIME_WAIT) | ||
| 261 | return 0; | ||
| 262 | |||
| 263 | read_lock_bh(&sk->sk_callback_lock); | ||
| 264 | if (sk->sk_socket && sk->sk_socket->file) { | ||
| 265 | cred = sk->sk_socket->file->f_cred; | ||
| 266 | if (nla_put_be32(skb, NFQA_UID, | ||
| 267 | htonl(from_kuid_munged(&init_user_ns, cred->fsuid)))) | ||
| 268 | goto nla_put_failure; | ||
| 269 | if (nla_put_be32(skb, NFQA_GID, | ||
| 270 | htonl(from_kgid_munged(&init_user_ns, cred->fsgid)))) | ||
| 271 | goto nla_put_failure; | ||
| 272 | } | ||
| 273 | read_unlock_bh(&sk->sk_callback_lock); | ||
| 274 | return 0; | ||
| 275 | |||
| 276 | nla_put_failure: | ||
| 277 | read_unlock_bh(&sk->sk_callback_lock); | ||
| 278 | return -1; | ||
| 279 | } | ||
| 280 | |||
| 300 | static struct sk_buff * | 281 | static struct sk_buff * |
| 301 | nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue, | 282 | nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue, |
| 302 | struct nf_queue_entry *entry, | 283 | struct nf_queue_entry *entry, |
| @@ -304,7 +285,7 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue, | |||
| 304 | { | 285 | { |
| 305 | size_t size; | 286 | size_t size; |
| 306 | size_t data_len = 0, cap_len = 0; | 287 | size_t data_len = 0, cap_len = 0; |
| 307 | int hlen = 0; | 288 | unsigned int hlen = 0; |
| 308 | struct sk_buff *skb; | 289 | struct sk_buff *skb; |
| 309 | struct nlattr *nla; | 290 | struct nlattr *nla; |
| 310 | struct nfqnl_msg_packet_hdr *pmsg; | 291 | struct nfqnl_msg_packet_hdr *pmsg; |
| @@ -356,14 +337,8 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue, | |||
| 356 | if (data_len > entskb->len) | 337 | if (data_len > entskb->len) |
| 357 | data_len = entskb->len; | 338 | data_len = entskb->len; |
| 358 | 339 | ||
| 359 | if (!entskb->head_frag || | 340 | hlen = skb_zerocopy_headlen(entskb); |
| 360 | skb_headlen(entskb) < L1_CACHE_BYTES || | 341 | hlen = min_t(unsigned int, hlen, data_len); |
| 361 | skb_shinfo(entskb)->nr_frags >= MAX_SKB_FRAGS) | ||
| 362 | hlen = skb_headlen(entskb); | ||
| 363 | |||
| 364 | if (skb_has_frag_list(entskb)) | ||
| 365 | hlen = entskb->len; | ||
| 366 | hlen = min_t(int, data_len, hlen); | ||
| 367 | size += sizeof(struct nlattr) + hlen; | 342 | size += sizeof(struct nlattr) + hlen; |
| 368 | cap_len = entskb->len; | 343 | cap_len = entskb->len; |
| 369 | break; | 344 | break; |
| @@ -372,6 +347,11 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue, | |||
| 372 | if (queue->flags & NFQA_CFG_F_CONNTRACK) | 347 | if (queue->flags & NFQA_CFG_F_CONNTRACK) |
| 373 | ct = nfqnl_ct_get(entskb, &size, &ctinfo); | 348 | ct = nfqnl_ct_get(entskb, &size, &ctinfo); |
| 374 | 349 | ||
| 350 | if (queue->flags & NFQA_CFG_F_UID_GID) { | ||
| 351 | size += (nla_total_size(sizeof(u_int32_t)) /* uid */ | ||
| 352 | + nla_total_size(sizeof(u_int32_t))); /* gid */ | ||
| 353 | } | ||
| 354 | |||
| 375 | skb = nfnetlink_alloc_skb(net, size, queue->peer_portid, | 355 | skb = nfnetlink_alloc_skb(net, size, queue->peer_portid, |
| 376 | GFP_ATOMIC); | 356 | GFP_ATOMIC); |
| 377 | if (!skb) | 357 | if (!skb) |
| @@ -484,6 +464,10 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue, | |||
| 484 | goto nla_put_failure; | 464 | goto nla_put_failure; |
| 485 | } | 465 | } |
| 486 | 466 | ||
| 467 | if ((queue->flags & NFQA_CFG_F_UID_GID) && entskb->sk && | ||
| 468 | nfqnl_put_sk_uidgid(skb, entskb->sk) < 0) | ||
| 469 | goto nla_put_failure; | ||
| 470 | |||
| 487 | if (ct && nfqnl_ct_put(skb, ct, ctinfo) < 0) | 471 | if (ct && nfqnl_ct_put(skb, ct, ctinfo) < 0) |
| 488 | goto nla_put_failure; | 472 | goto nla_put_failure; |
| 489 | 473 | ||
| @@ -504,7 +488,7 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue, | |||
| 504 | nla->nla_type = NFQA_PAYLOAD; | 488 | nla->nla_type = NFQA_PAYLOAD; |
| 505 | nla->nla_len = nla_attr_size(data_len); | 489 | nla->nla_len = nla_attr_size(data_len); |
| 506 | 490 | ||
| 507 | nfqnl_zcopy(skb, entskb, data_len, hlen); | 491 | skb_zerocopy(skb, entskb, data_len, hlen); |
| 508 | } | 492 | } |
| 509 | 493 | ||
| 510 | nlh->nlmsg_len = skb->len; | 494 | nlh->nlmsg_len = skb->len; |
diff --git a/net/netfilter/nft_compat.c b/net/netfilter/nft_compat.c index da0c1f4ada12..82cb8236f8a1 100644 --- a/net/netfilter/nft_compat.c +++ b/net/netfilter/nft_compat.c | |||
| @@ -92,7 +92,7 @@ nft_target_set_tgchk_param(struct xt_tgchk_param *par, | |||
| 92 | if (ctx->chain->flags & NFT_BASE_CHAIN) { | 92 | if (ctx->chain->flags & NFT_BASE_CHAIN) { |
| 93 | const struct nft_base_chain *basechain = | 93 | const struct nft_base_chain *basechain = |
| 94 | nft_base_chain(ctx->chain); | 94 | nft_base_chain(ctx->chain); |
| 95 | const struct nf_hook_ops *ops = &basechain->ops; | 95 | const struct nf_hook_ops *ops = &basechain->ops[0]; |
| 96 | 96 | ||
| 97 | par->hook_mask = 1 << ops->hooknum; | 97 | par->hook_mask = 1 << ops->hooknum; |
| 98 | } | 98 | } |
| @@ -253,7 +253,7 @@ static int nft_target_validate(const struct nft_ctx *ctx, | |||
| 253 | if (ctx->chain->flags & NFT_BASE_CHAIN) { | 253 | if (ctx->chain->flags & NFT_BASE_CHAIN) { |
| 254 | const struct nft_base_chain *basechain = | 254 | const struct nft_base_chain *basechain = |
| 255 | nft_base_chain(ctx->chain); | 255 | nft_base_chain(ctx->chain); |
| 256 | const struct nf_hook_ops *ops = &basechain->ops; | 256 | const struct nf_hook_ops *ops = &basechain->ops[0]; |
| 257 | 257 | ||
| 258 | hook_mask = 1 << ops->hooknum; | 258 | hook_mask = 1 << ops->hooknum; |
| 259 | if (hook_mask & target->hooks) | 259 | if (hook_mask & target->hooks) |
| @@ -323,7 +323,7 @@ nft_match_set_mtchk_param(struct xt_mtchk_param *par, const struct nft_ctx *ctx, | |||
| 323 | if (ctx->chain->flags & NFT_BASE_CHAIN) { | 323 | if (ctx->chain->flags & NFT_BASE_CHAIN) { |
| 324 | const struct nft_base_chain *basechain = | 324 | const struct nft_base_chain *basechain = |
| 325 | nft_base_chain(ctx->chain); | 325 | nft_base_chain(ctx->chain); |
| 326 | const struct nf_hook_ops *ops = &basechain->ops; | 326 | const struct nf_hook_ops *ops = &basechain->ops[0]; |
| 327 | 327 | ||
| 328 | par->hook_mask = 1 << ops->hooknum; | 328 | par->hook_mask = 1 << ops->hooknum; |
| 329 | } | 329 | } |
| @@ -449,7 +449,7 @@ static int nft_match_validate(const struct nft_ctx *ctx, | |||
| 449 | if (ctx->chain->flags & NFT_BASE_CHAIN) { | 449 | if (ctx->chain->flags & NFT_BASE_CHAIN) { |
| 450 | const struct nft_base_chain *basechain = | 450 | const struct nft_base_chain *basechain = |
| 451 | nft_base_chain(ctx->chain); | 451 | nft_base_chain(ctx->chain); |
| 452 | const struct nf_hook_ops *ops = &basechain->ops; | 452 | const struct nf_hook_ops *ops = &basechain->ops[0]; |
| 453 | 453 | ||
| 454 | hook_mask = 1 << ops->hooknum; | 454 | hook_mask = 1 << ops->hooknum; |
| 455 | if (hook_mask & match->hooks) | 455 | if (hook_mask & match->hooks) |
diff --git a/net/netfilter/nft_ct.c b/net/netfilter/nft_ct.c index 955f4e6e7089..917052e20602 100644 --- a/net/netfilter/nft_ct.c +++ b/net/netfilter/nft_ct.c | |||
| @@ -18,17 +18,21 @@ | |||
| 18 | #include <net/netfilter/nf_conntrack.h> | 18 | #include <net/netfilter/nf_conntrack.h> |
| 19 | #include <net/netfilter/nf_conntrack_tuple.h> | 19 | #include <net/netfilter/nf_conntrack_tuple.h> |
| 20 | #include <net/netfilter/nf_conntrack_helper.h> | 20 | #include <net/netfilter/nf_conntrack_helper.h> |
| 21 | #include <net/netfilter/nf_conntrack_ecache.h> | ||
| 21 | 22 | ||
| 22 | struct nft_ct { | 23 | struct nft_ct { |
| 23 | enum nft_ct_keys key:8; | 24 | enum nft_ct_keys key:8; |
| 24 | enum ip_conntrack_dir dir:8; | 25 | enum ip_conntrack_dir dir:8; |
| 25 | enum nft_registers dreg:8; | 26 | union{ |
| 27 | enum nft_registers dreg:8; | ||
| 28 | enum nft_registers sreg:8; | ||
| 29 | }; | ||
| 26 | uint8_t family; | 30 | uint8_t family; |
| 27 | }; | 31 | }; |
| 28 | 32 | ||
| 29 | static void nft_ct_eval(const struct nft_expr *expr, | 33 | static void nft_ct_get_eval(const struct nft_expr *expr, |
| 30 | struct nft_data data[NFT_REG_MAX + 1], | 34 | struct nft_data data[NFT_REG_MAX + 1], |
| 31 | const struct nft_pktinfo *pkt) | 35 | const struct nft_pktinfo *pkt) |
| 32 | { | 36 | { |
| 33 | const struct nft_ct *priv = nft_expr_priv(expr); | 37 | const struct nft_ct *priv = nft_expr_priv(expr); |
| 34 | struct nft_data *dest = &data[priv->dreg]; | 38 | struct nft_data *dest = &data[priv->dreg]; |
| @@ -123,24 +127,79 @@ err: | |||
| 123 | data[NFT_REG_VERDICT].verdict = NFT_BREAK; | 127 | data[NFT_REG_VERDICT].verdict = NFT_BREAK; |
| 124 | } | 128 | } |
| 125 | 129 | ||
| 130 | static void nft_ct_set_eval(const struct nft_expr *expr, | ||
| 131 | struct nft_data data[NFT_REG_MAX + 1], | ||
| 132 | const struct nft_pktinfo *pkt) | ||
| 133 | { | ||
| 134 | const struct nft_ct *priv = nft_expr_priv(expr); | ||
| 135 | struct sk_buff *skb = pkt->skb; | ||
| 136 | #ifdef CONFIG_NF_CONNTRACK_MARK | ||
| 137 | u32 value = data[priv->sreg].data[0]; | ||
| 138 | #endif | ||
| 139 | enum ip_conntrack_info ctinfo; | ||
| 140 | struct nf_conn *ct; | ||
| 141 | |||
| 142 | ct = nf_ct_get(skb, &ctinfo); | ||
| 143 | if (ct == NULL) | ||
| 144 | return; | ||
| 145 | |||
| 146 | switch (priv->key) { | ||
| 147 | #ifdef CONFIG_NF_CONNTRACK_MARK | ||
| 148 | case NFT_CT_MARK: | ||
| 149 | if (ct->mark != value) { | ||
| 150 | ct->mark = value; | ||
| 151 | nf_conntrack_event_cache(IPCT_MARK, ct); | ||
| 152 | } | ||
| 153 | break; | ||
| 154 | #endif | ||
| 155 | } | ||
| 156 | } | ||
| 157 | |||
| 126 | static const struct nla_policy nft_ct_policy[NFTA_CT_MAX + 1] = { | 158 | static const struct nla_policy nft_ct_policy[NFTA_CT_MAX + 1] = { |
| 127 | [NFTA_CT_DREG] = { .type = NLA_U32 }, | 159 | [NFTA_CT_DREG] = { .type = NLA_U32 }, |
| 128 | [NFTA_CT_KEY] = { .type = NLA_U32 }, | 160 | [NFTA_CT_KEY] = { .type = NLA_U32 }, |
| 129 | [NFTA_CT_DIRECTION] = { .type = NLA_U8 }, | 161 | [NFTA_CT_DIRECTION] = { .type = NLA_U8 }, |
| 162 | [NFTA_CT_SREG] = { .type = NLA_U32 }, | ||
| 130 | }; | 163 | }; |
| 131 | 164 | ||
| 132 | static int nft_ct_init(const struct nft_ctx *ctx, | 165 | static int nft_ct_l3proto_try_module_get(uint8_t family) |
| 133 | const struct nft_expr *expr, | ||
| 134 | const struct nlattr * const tb[]) | ||
| 135 | { | 166 | { |
| 136 | struct nft_ct *priv = nft_expr_priv(expr); | ||
| 137 | int err; | 167 | int err; |
| 138 | 168 | ||
| 139 | if (tb[NFTA_CT_DREG] == NULL || | 169 | if (family == NFPROTO_INET) { |
| 140 | tb[NFTA_CT_KEY] == NULL) | 170 | err = nf_ct_l3proto_try_module_get(NFPROTO_IPV4); |
| 141 | return -EINVAL; | 171 | if (err < 0) |
| 172 | goto err1; | ||
| 173 | err = nf_ct_l3proto_try_module_get(NFPROTO_IPV6); | ||
| 174 | if (err < 0) | ||
| 175 | goto err2; | ||
| 176 | } else { | ||
| 177 | err = nf_ct_l3proto_try_module_get(family); | ||
| 178 | if (err < 0) | ||
| 179 | goto err1; | ||
| 180 | } | ||
| 181 | return 0; | ||
| 182 | |||
| 183 | err2: | ||
| 184 | nf_ct_l3proto_module_put(NFPROTO_IPV4); | ||
| 185 | err1: | ||
| 186 | return err; | ||
| 187 | } | ||
| 188 | |||
| 189 | static void nft_ct_l3proto_module_put(uint8_t family) | ||
| 190 | { | ||
| 191 | if (family == NFPROTO_INET) { | ||
| 192 | nf_ct_l3proto_module_put(NFPROTO_IPV4); | ||
| 193 | nf_ct_l3proto_module_put(NFPROTO_IPV6); | ||
| 194 | } else | ||
| 195 | nf_ct_l3proto_module_put(family); | ||
| 196 | } | ||
| 197 | |||
| 198 | static int nft_ct_init_validate_get(const struct nft_expr *expr, | ||
| 199 | const struct nlattr * const tb[]) | ||
| 200 | { | ||
| 201 | struct nft_ct *priv = nft_expr_priv(expr); | ||
| 142 | 202 | ||
| 143 | priv->key = ntohl(nla_get_be32(tb[NFTA_CT_KEY])); | ||
| 144 | if (tb[NFTA_CT_DIRECTION] != NULL) { | 203 | if (tb[NFTA_CT_DIRECTION] != NULL) { |
| 145 | priv->dir = nla_get_u8(tb[NFTA_CT_DIRECTION]); | 204 | priv->dir = nla_get_u8(tb[NFTA_CT_DIRECTION]); |
| 146 | switch (priv->dir) { | 205 | switch (priv->dir) { |
| @@ -179,34 +238,72 @@ static int nft_ct_init(const struct nft_ctx *ctx, | |||
| 179 | return -EOPNOTSUPP; | 238 | return -EOPNOTSUPP; |
| 180 | } | 239 | } |
| 181 | 240 | ||
| 182 | err = nf_ct_l3proto_try_module_get(ctx->afi->family); | 241 | return 0; |
| 242 | } | ||
| 243 | |||
| 244 | static int nft_ct_init_validate_set(uint32_t key) | ||
| 245 | { | ||
| 246 | switch (key) { | ||
| 247 | case NFT_CT_MARK: | ||
| 248 | break; | ||
| 249 | default: | ||
| 250 | return -EOPNOTSUPP; | ||
| 251 | } | ||
| 252 | |||
| 253 | return 0; | ||
| 254 | } | ||
| 255 | |||
| 256 | static int nft_ct_init(const struct nft_ctx *ctx, | ||
| 257 | const struct nft_expr *expr, | ||
| 258 | const struct nlattr * const tb[]) | ||
| 259 | { | ||
| 260 | struct nft_ct *priv = nft_expr_priv(expr); | ||
| 261 | int err; | ||
| 262 | |||
| 263 | priv->key = ntohl(nla_get_be32(tb[NFTA_CT_KEY])); | ||
| 264 | |||
| 265 | if (tb[NFTA_CT_DREG]) { | ||
| 266 | err = nft_ct_init_validate_get(expr, tb); | ||
| 267 | if (err < 0) | ||
| 268 | return err; | ||
| 269 | |||
| 270 | priv->dreg = ntohl(nla_get_be32(tb[NFTA_CT_DREG])); | ||
| 271 | err = nft_validate_output_register(priv->dreg); | ||
| 272 | if (err < 0) | ||
| 273 | return err; | ||
| 274 | |||
| 275 | err = nft_validate_data_load(ctx, priv->dreg, NULL, | ||
| 276 | NFT_DATA_VALUE); | ||
| 277 | if (err < 0) | ||
| 278 | return err; | ||
| 279 | } else { | ||
| 280 | err = nft_ct_init_validate_set(priv->key); | ||
| 281 | if (err < 0) | ||
| 282 | return err; | ||
| 283 | |||
| 284 | priv->sreg = ntohl(nla_get_be32(tb[NFTA_CT_SREG])); | ||
| 285 | err = nft_validate_input_register(priv->sreg); | ||
| 286 | if (err < 0) | ||
| 287 | return err; | ||
| 288 | } | ||
| 289 | |||
| 290 | err = nft_ct_l3proto_try_module_get(ctx->afi->family); | ||
| 183 | if (err < 0) | 291 | if (err < 0) |
| 184 | return err; | 292 | return err; |
| 185 | priv->family = ctx->afi->family; | ||
| 186 | 293 | ||
| 187 | priv->dreg = ntohl(nla_get_be32(tb[NFTA_CT_DREG])); | 294 | priv->family = ctx->afi->family; |
| 188 | err = nft_validate_output_register(priv->dreg); | ||
| 189 | if (err < 0) | ||
| 190 | goto err1; | ||
| 191 | 295 | ||
| 192 | err = nft_validate_data_load(ctx, priv->dreg, NULL, NFT_DATA_VALUE); | ||
| 193 | if (err < 0) | ||
| 194 | goto err1; | ||
| 195 | return 0; | 296 | return 0; |
| 196 | |||
| 197 | err1: | ||
| 198 | nf_ct_l3proto_module_put(ctx->afi->family); | ||
| 199 | return err; | ||
| 200 | } | 297 | } |
| 201 | 298 | ||
| 202 | static void nft_ct_destroy(const struct nft_expr *expr) | 299 | static void nft_ct_destroy(const struct nft_expr *expr) |
| 203 | { | 300 | { |
| 204 | struct nft_ct *priv = nft_expr_priv(expr); | 301 | struct nft_ct *priv = nft_expr_priv(expr); |
| 205 | 302 | ||
| 206 | nf_ct_l3proto_module_put(priv->family); | 303 | nft_ct_l3proto_module_put(priv->family); |
| 207 | } | 304 | } |
| 208 | 305 | ||
| 209 | static int nft_ct_dump(struct sk_buff *skb, const struct nft_expr *expr) | 306 | static int nft_ct_get_dump(struct sk_buff *skb, const struct nft_expr *expr) |
| 210 | { | 307 | { |
| 211 | const struct nft_ct *priv = nft_expr_priv(expr); | 308 | const struct nft_ct *priv = nft_expr_priv(expr); |
| 212 | 309 | ||
| @@ -222,19 +319,61 @@ nla_put_failure: | |||
| 222 | return -1; | 319 | return -1; |
| 223 | } | 320 | } |
| 224 | 321 | ||
| 322 | static int nft_ct_set_dump(struct sk_buff *skb, const struct nft_expr *expr) | ||
| 323 | { | ||
| 324 | const struct nft_ct *priv = nft_expr_priv(expr); | ||
| 325 | |||
| 326 | if (nla_put_be32(skb, NFTA_CT_SREG, htonl(priv->sreg))) | ||
| 327 | goto nla_put_failure; | ||
| 328 | if (nla_put_be32(skb, NFTA_CT_KEY, htonl(priv->key))) | ||
| 329 | goto nla_put_failure; | ||
| 330 | return 0; | ||
| 331 | |||
| 332 | nla_put_failure: | ||
| 333 | return -1; | ||
| 334 | } | ||
| 335 | |||
| 225 | static struct nft_expr_type nft_ct_type; | 336 | static struct nft_expr_type nft_ct_type; |
| 226 | static const struct nft_expr_ops nft_ct_ops = { | 337 | static const struct nft_expr_ops nft_ct_get_ops = { |
| 227 | .type = &nft_ct_type, | 338 | .type = &nft_ct_type, |
| 228 | .size = NFT_EXPR_SIZE(sizeof(struct nft_ct)), | 339 | .size = NFT_EXPR_SIZE(sizeof(struct nft_ct)), |
| 229 | .eval = nft_ct_eval, | 340 | .eval = nft_ct_get_eval, |
| 230 | .init = nft_ct_init, | 341 | .init = nft_ct_init, |
| 231 | .destroy = nft_ct_destroy, | 342 | .destroy = nft_ct_destroy, |
| 232 | .dump = nft_ct_dump, | 343 | .dump = nft_ct_get_dump, |
| 233 | }; | 344 | }; |
| 234 | 345 | ||
| 346 | static const struct nft_expr_ops nft_ct_set_ops = { | ||
| 347 | .type = &nft_ct_type, | ||
| 348 | .size = NFT_EXPR_SIZE(sizeof(struct nft_ct)), | ||
| 349 | .eval = nft_ct_set_eval, | ||
| 350 | .init = nft_ct_init, | ||
| 351 | .destroy = nft_ct_destroy, | ||
| 352 | .dump = nft_ct_set_dump, | ||
| 353 | }; | ||
| 354 | |||
| 355 | static const struct nft_expr_ops * | ||
| 356 | nft_ct_select_ops(const struct nft_ctx *ctx, | ||
| 357 | const struct nlattr * const tb[]) | ||
| 358 | { | ||
| 359 | if (tb[NFTA_CT_KEY] == NULL) | ||
| 360 | return ERR_PTR(-EINVAL); | ||
| 361 | |||
| 362 | if (tb[NFTA_CT_DREG] && tb[NFTA_CT_SREG]) | ||
| 363 | return ERR_PTR(-EINVAL); | ||
| 364 | |||
| 365 | if (tb[NFTA_CT_DREG]) | ||
| 366 | return &nft_ct_get_ops; | ||
| 367 | |||
| 368 | if (tb[NFTA_CT_SREG]) | ||
| 369 | return &nft_ct_set_ops; | ||
| 370 | |||
| 371 | return ERR_PTR(-EINVAL); | ||
| 372 | } | ||
| 373 | |||
| 235 | static struct nft_expr_type nft_ct_type __read_mostly = { | 374 | static struct nft_expr_type nft_ct_type __read_mostly = { |
| 236 | .name = "ct", | 375 | .name = "ct", |
| 237 | .ops = &nft_ct_ops, | 376 | .select_ops = &nft_ct_select_ops, |
| 238 | .policy = nft_ct_policy, | 377 | .policy = nft_ct_policy, |
| 239 | .maxattr = NFTA_CT_MAX, | 378 | .maxattr = NFTA_CT_MAX, |
| 240 | .owner = THIS_MODULE, | 379 | .owner = THIS_MODULE, |
diff --git a/net/netfilter/nft_log.c b/net/netfilter/nft_log.c index 57cad072a13e..5af790123ad8 100644 --- a/net/netfilter/nft_log.c +++ b/net/netfilter/nft_log.c | |||
| @@ -33,7 +33,7 @@ static void nft_log_eval(const struct nft_expr *expr, | |||
| 33 | const struct nft_log *priv = nft_expr_priv(expr); | 33 | const struct nft_log *priv = nft_expr_priv(expr); |
| 34 | struct net *net = dev_net(pkt->in ? pkt->in : pkt->out); | 34 | struct net *net = dev_net(pkt->in ? pkt->in : pkt->out); |
| 35 | 35 | ||
| 36 | nf_log_packet(net, priv->family, pkt->hooknum, pkt->skb, pkt->in, | 36 | nf_log_packet(net, priv->family, pkt->ops->hooknum, pkt->skb, pkt->in, |
| 37 | pkt->out, &priv->loginfo, "%s", priv->prefix); | 37 | pkt->out, &priv->loginfo, "%s", priv->prefix); |
| 38 | } | 38 | } |
| 39 | 39 | ||
diff --git a/net/netfilter/nft_meta.c b/net/netfilter/nft_meta.c index 8c28220a90b3..e8254ad2e5a9 100644 --- a/net/netfilter/nft_meta.c +++ b/net/netfilter/nft_meta.c | |||
| @@ -21,12 +21,15 @@ | |||
| 21 | 21 | ||
| 22 | struct nft_meta { | 22 | struct nft_meta { |
| 23 | enum nft_meta_keys key:8; | 23 | enum nft_meta_keys key:8; |
| 24 | enum nft_registers dreg:8; | 24 | union { |
| 25 | enum nft_registers dreg:8; | ||
| 26 | enum nft_registers sreg:8; | ||
| 27 | }; | ||
| 25 | }; | 28 | }; |
| 26 | 29 | ||
| 27 | static void nft_meta_eval(const struct nft_expr *expr, | 30 | static void nft_meta_get_eval(const struct nft_expr *expr, |
| 28 | struct nft_data data[NFT_REG_MAX + 1], | 31 | struct nft_data data[NFT_REG_MAX + 1], |
| 29 | const struct nft_pktinfo *pkt) | 32 | const struct nft_pktinfo *pkt) |
| 30 | { | 33 | { |
| 31 | const struct nft_meta *priv = nft_expr_priv(expr); | 34 | const struct nft_meta *priv = nft_expr_priv(expr); |
| 32 | const struct sk_buff *skb = pkt->skb; | 35 | const struct sk_buff *skb = pkt->skb; |
| @@ -40,6 +43,12 @@ static void nft_meta_eval(const struct nft_expr *expr, | |||
| 40 | case NFT_META_PROTOCOL: | 43 | case NFT_META_PROTOCOL: |
| 41 | *(__be16 *)dest->data = skb->protocol; | 44 | *(__be16 *)dest->data = skb->protocol; |
| 42 | break; | 45 | break; |
| 46 | case NFT_META_NFPROTO: | ||
| 47 | dest->data[0] = pkt->ops->pf; | ||
| 48 | break; | ||
| 49 | case NFT_META_L4PROTO: | ||
| 50 | dest->data[0] = pkt->tprot; | ||
| 51 | break; | ||
| 43 | case NFT_META_PRIORITY: | 52 | case NFT_META_PRIORITY: |
| 44 | dest->data[0] = skb->priority; | 53 | dest->data[0] = skb->priority; |
| 45 | break; | 54 | break; |
| @@ -132,25 +141,54 @@ err: | |||
| 132 | data[NFT_REG_VERDICT].verdict = NFT_BREAK; | 141 | data[NFT_REG_VERDICT].verdict = NFT_BREAK; |
| 133 | } | 142 | } |
| 134 | 143 | ||
| 144 | static void nft_meta_set_eval(const struct nft_expr *expr, | ||
| 145 | struct nft_data data[NFT_REG_MAX + 1], | ||
| 146 | const struct nft_pktinfo *pkt) | ||
| 147 | { | ||
| 148 | const struct nft_meta *meta = nft_expr_priv(expr); | ||
| 149 | struct sk_buff *skb = pkt->skb; | ||
| 150 | u32 value = data[meta->sreg].data[0]; | ||
| 151 | |||
| 152 | switch (meta->key) { | ||
| 153 | case NFT_META_MARK: | ||
| 154 | skb->mark = value; | ||
| 155 | break; | ||
| 156 | case NFT_META_PRIORITY: | ||
| 157 | skb->priority = value; | ||
| 158 | break; | ||
| 159 | case NFT_META_NFTRACE: | ||
| 160 | skb->nf_trace = 1; | ||
| 161 | break; | ||
| 162 | default: | ||
| 163 | WARN_ON(1); | ||
| 164 | } | ||
| 165 | } | ||
| 166 | |||
| 135 | static const struct nla_policy nft_meta_policy[NFTA_META_MAX + 1] = { | 167 | static const struct nla_policy nft_meta_policy[NFTA_META_MAX + 1] = { |
| 136 | [NFTA_META_DREG] = { .type = NLA_U32 }, | 168 | [NFTA_META_DREG] = { .type = NLA_U32 }, |
| 137 | [NFTA_META_KEY] = { .type = NLA_U32 }, | 169 | [NFTA_META_KEY] = { .type = NLA_U32 }, |
| 170 | [NFTA_META_SREG] = { .type = NLA_U32 }, | ||
| 138 | }; | 171 | }; |
| 139 | 172 | ||
| 140 | static int nft_meta_init(const struct nft_ctx *ctx, const struct nft_expr *expr, | 173 | static int nft_meta_init_validate_set(uint32_t key) |
| 141 | const struct nlattr * const tb[]) | ||
| 142 | { | 174 | { |
| 143 | struct nft_meta *priv = nft_expr_priv(expr); | 175 | switch (key) { |
| 144 | int err; | 176 | case NFT_META_MARK: |
| 145 | 177 | case NFT_META_PRIORITY: | |
| 146 | if (tb[NFTA_META_DREG] == NULL || | 178 | case NFT_META_NFTRACE: |
| 147 | tb[NFTA_META_KEY] == NULL) | 179 | return 0; |
| 148 | return -EINVAL; | 180 | default: |
| 181 | return -EOPNOTSUPP; | ||
| 182 | } | ||
| 183 | } | ||
| 149 | 184 | ||
| 150 | priv->key = ntohl(nla_get_be32(tb[NFTA_META_KEY])); | 185 | static int nft_meta_init_validate_get(uint32_t key) |
| 151 | switch (priv->key) { | 186 | { |
| 187 | switch (key) { | ||
| 152 | case NFT_META_LEN: | 188 | case NFT_META_LEN: |
| 153 | case NFT_META_PROTOCOL: | 189 | case NFT_META_PROTOCOL: |
| 190 | case NFT_META_NFPROTO: | ||
| 191 | case NFT_META_L4PROTO: | ||
| 154 | case NFT_META_PRIORITY: | 192 | case NFT_META_PRIORITY: |
| 155 | case NFT_META_MARK: | 193 | case NFT_META_MARK: |
| 156 | case NFT_META_IIF: | 194 | case NFT_META_IIF: |
| @@ -167,26 +205,72 @@ static int nft_meta_init(const struct nft_ctx *ctx, const struct nft_expr *expr, | |||
| 167 | #ifdef CONFIG_NETWORK_SECMARK | 205 | #ifdef CONFIG_NETWORK_SECMARK |
| 168 | case NFT_META_SECMARK: | 206 | case NFT_META_SECMARK: |
| 169 | #endif | 207 | #endif |
| 170 | break; | 208 | return 0; |
| 171 | default: | 209 | default: |
| 172 | return -EOPNOTSUPP; | 210 | return -EOPNOTSUPP; |
| 173 | } | 211 | } |
| 174 | 212 | ||
| 175 | priv->dreg = ntohl(nla_get_be32(tb[NFTA_META_DREG])); | 213 | } |
| 176 | err = nft_validate_output_register(priv->dreg); | 214 | |
| 215 | static int nft_meta_init(const struct nft_ctx *ctx, const struct nft_expr *expr, | ||
| 216 | const struct nlattr * const tb[]) | ||
| 217 | { | ||
| 218 | struct nft_meta *priv = nft_expr_priv(expr); | ||
| 219 | int err; | ||
| 220 | |||
| 221 | priv->key = ntohl(nla_get_be32(tb[NFTA_META_KEY])); | ||
| 222 | |||
| 223 | if (tb[NFTA_META_DREG]) { | ||
| 224 | err = nft_meta_init_validate_get(priv->key); | ||
| 225 | if (err < 0) | ||
| 226 | return err; | ||
| 227 | |||
| 228 | priv->dreg = ntohl(nla_get_be32(tb[NFTA_META_DREG])); | ||
| 229 | err = nft_validate_output_register(priv->dreg); | ||
| 230 | if (err < 0) | ||
| 231 | return err; | ||
| 232 | |||
| 233 | return nft_validate_data_load(ctx, priv->dreg, NULL, | ||
| 234 | NFT_DATA_VALUE); | ||
| 235 | } | ||
| 236 | |||
| 237 | err = nft_meta_init_validate_set(priv->key); | ||
| 238 | if (err < 0) | ||
| 239 | return err; | ||
| 240 | |||
| 241 | priv->sreg = ntohl(nla_get_be32(tb[NFTA_META_SREG])); | ||
| 242 | err = nft_validate_input_register(priv->sreg); | ||
| 177 | if (err < 0) | 243 | if (err < 0) |
| 178 | return err; | 244 | return err; |
| 179 | return nft_validate_data_load(ctx, priv->dreg, NULL, NFT_DATA_VALUE); | 245 | |
| 246 | return 0; | ||
| 180 | } | 247 | } |
| 181 | 248 | ||
| 182 | static int nft_meta_dump(struct sk_buff *skb, const struct nft_expr *expr) | 249 | static int nft_meta_get_dump(struct sk_buff *skb, |
| 250 | const struct nft_expr *expr) | ||
| 183 | { | 251 | { |
| 184 | const struct nft_meta *priv = nft_expr_priv(expr); | 252 | const struct nft_meta *priv = nft_expr_priv(expr); |
| 185 | 253 | ||
| 254 | if (nla_put_be32(skb, NFTA_META_KEY, htonl(priv->key))) | ||
| 255 | goto nla_put_failure; | ||
| 186 | if (nla_put_be32(skb, NFTA_META_DREG, htonl(priv->dreg))) | 256 | if (nla_put_be32(skb, NFTA_META_DREG, htonl(priv->dreg))) |
| 187 | goto nla_put_failure; | 257 | goto nla_put_failure; |
| 258 | return 0; | ||
| 259 | |||
| 260 | nla_put_failure: | ||
| 261 | return -1; | ||
| 262 | } | ||
| 263 | |||
| 264 | static int nft_meta_set_dump(struct sk_buff *skb, | ||
| 265 | const struct nft_expr *expr) | ||
| 266 | { | ||
| 267 | const struct nft_meta *priv = nft_expr_priv(expr); | ||
| 268 | |||
| 188 | if (nla_put_be32(skb, NFTA_META_KEY, htonl(priv->key))) | 269 | if (nla_put_be32(skb, NFTA_META_KEY, htonl(priv->key))) |
| 189 | goto nla_put_failure; | 270 | goto nla_put_failure; |
| 271 | if (nla_put_be32(skb, NFTA_META_SREG, htonl(priv->sreg))) | ||
| 272 | goto nla_put_failure; | ||
| 273 | |||
| 190 | return 0; | 274 | return 0; |
| 191 | 275 | ||
| 192 | nla_put_failure: | 276 | nla_put_failure: |
| @@ -194,17 +278,44 @@ nla_put_failure: | |||
| 194 | } | 278 | } |
| 195 | 279 | ||
| 196 | static struct nft_expr_type nft_meta_type; | 280 | static struct nft_expr_type nft_meta_type; |
| 197 | static const struct nft_expr_ops nft_meta_ops = { | 281 | static const struct nft_expr_ops nft_meta_get_ops = { |
| 282 | .type = &nft_meta_type, | ||
| 283 | .size = NFT_EXPR_SIZE(sizeof(struct nft_meta)), | ||
| 284 | .eval = nft_meta_get_eval, | ||
| 285 | .init = nft_meta_init, | ||
| 286 | .dump = nft_meta_get_dump, | ||
| 287 | }; | ||
| 288 | |||
| 289 | static const struct nft_expr_ops nft_meta_set_ops = { | ||
| 198 | .type = &nft_meta_type, | 290 | .type = &nft_meta_type, |
| 199 | .size = NFT_EXPR_SIZE(sizeof(struct nft_meta)), | 291 | .size = NFT_EXPR_SIZE(sizeof(struct nft_meta)), |
| 200 | .eval = nft_meta_eval, | 292 | .eval = nft_meta_set_eval, |
| 201 | .init = nft_meta_init, | 293 | .init = nft_meta_init, |
| 202 | .dump = nft_meta_dump, | 294 | .dump = nft_meta_set_dump, |
| 203 | }; | 295 | }; |
| 204 | 296 | ||
| 297 | static const struct nft_expr_ops * | ||
| 298 | nft_meta_select_ops(const struct nft_ctx *ctx, | ||
| 299 | const struct nlattr * const tb[]) | ||
| 300 | { | ||
| 301 | if (tb[NFTA_META_KEY] == NULL) | ||
| 302 | return ERR_PTR(-EINVAL); | ||
| 303 | |||
| 304 | if (tb[NFTA_META_DREG] && tb[NFTA_META_SREG]) | ||
| 305 | return ERR_PTR(-EINVAL); | ||
| 306 | |||
| 307 | if (tb[NFTA_META_DREG]) | ||
| 308 | return &nft_meta_get_ops; | ||
| 309 | |||
| 310 | if (tb[NFTA_META_SREG]) | ||
| 311 | return &nft_meta_set_ops; | ||
| 312 | |||
| 313 | return ERR_PTR(-EINVAL); | ||
| 314 | } | ||
| 315 | |||
| 205 | static struct nft_expr_type nft_meta_type __read_mostly = { | 316 | static struct nft_expr_type nft_meta_type __read_mostly = { |
| 206 | .name = "meta", | 317 | .name = "meta", |
| 207 | .ops = &nft_meta_ops, | 318 | .select_ops = &nft_meta_select_ops, |
| 208 | .policy = nft_meta_policy, | 319 | .policy = nft_meta_policy, |
| 209 | .maxattr = NFTA_META_MAX, | 320 | .maxattr = NFTA_META_MAX, |
| 210 | .owner = THIS_MODULE, | 321 | .owner = THIS_MODULE, |
diff --git a/net/netfilter/nft_meta_target.c b/net/netfilter/nft_meta_target.c deleted file mode 100644 index 71177df75ffb..000000000000 --- a/net/netfilter/nft_meta_target.c +++ /dev/null | |||
| @@ -1,117 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2008 Patrick McHardy <kaber@trash.net> | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * Development of this code funded by Astaro AG (http://www.astaro.com/) | ||
| 9 | */ | ||
| 10 | |||
| 11 | #include <linux/kernel.h> | ||
| 12 | #include <linux/init.h> | ||
| 13 | #include <linux/list.h> | ||
| 14 | #include <linux/rbtree.h> | ||
| 15 | #include <linux/netlink.h> | ||
| 16 | #include <linux/netfilter.h> | ||
| 17 | #include <linux/netfilter/nf_tables.h> | ||
| 18 | #include <net/netfilter/nf_tables.h> | ||
| 19 | |||
| 20 | struct nft_meta { | ||
| 21 | enum nft_meta_keys key; | ||
| 22 | }; | ||
| 23 | |||
| 24 | static void nft_meta_eval(const struct nft_expr *expr, | ||
| 25 | struct nft_data *nfres, | ||
| 26 | struct nft_data *data, | ||
| 27 | const struct nft_pktinfo *pkt) | ||
| 28 | { | ||
| 29 | const struct nft_meta *meta = nft_expr_priv(expr); | ||
| 30 | struct sk_buff *skb = pkt->skb; | ||
| 31 | u32 val = data->data[0]; | ||
| 32 | |||
| 33 | switch (meta->key) { | ||
| 34 | case NFT_META_MARK: | ||
| 35 | skb->mark = val; | ||
| 36 | break; | ||
| 37 | case NFT_META_PRIORITY: | ||
| 38 | skb->priority = val; | ||
| 39 | break; | ||
| 40 | case NFT_META_NFTRACE: | ||
| 41 | skb->nf_trace = val; | ||
| 42 | break; | ||
| 43 | #ifdef CONFIG_NETWORK_SECMARK | ||
| 44 | case NFT_META_SECMARK: | ||
| 45 | skb->secmark = val; | ||
| 46 | break; | ||
| 47 | #endif | ||
| 48 | default: | ||
| 49 | WARN_ON(1); | ||
| 50 | } | ||
| 51 | } | ||
| 52 | |||
| 53 | static const struct nla_policy nft_meta_policy[NFTA_META_MAX + 1] = { | ||
| 54 | [NFTA_META_KEY] = { .type = NLA_U32 }, | ||
| 55 | }; | ||
| 56 | |||
| 57 | static int nft_meta_init(const struct nft_expr *expr, struct nlattr *tb[]) | ||
| 58 | { | ||
| 59 | struct nft_meta *meta = nft_expr_priv(expr); | ||
| 60 | |||
| 61 | if (tb[NFTA_META_KEY] == NULL) | ||
| 62 | return -EINVAL; | ||
| 63 | |||
| 64 | meta->key = ntohl(nla_get_be32(tb[NFTA_META_KEY])); | ||
| 65 | switch (meta->key) { | ||
| 66 | case NFT_META_MARK: | ||
| 67 | case NFT_META_PRIORITY: | ||
| 68 | case NFT_META_NFTRACE: | ||
| 69 | #ifdef CONFIG_NETWORK_SECMARK | ||
| 70 | case NFT_META_SECMARK: | ||
| 71 | #endif | ||
| 72 | break; | ||
| 73 | default: | ||
| 74 | return -EINVAL; | ||
| 75 | } | ||
| 76 | |||
| 77 | return 0; | ||
| 78 | } | ||
| 79 | |||
| 80 | static int nft_meta_dump(struct sk_buff *skb, const struct nft_expr *expr) | ||
| 81 | { | ||
| 82 | struct nft_meta *meta = nft_expr_priv(expr); | ||
| 83 | |||
| 84 | NLA_PUT_BE32(skb, NFTA_META_KEY, htonl(meta->key)); | ||
| 85 | return 0; | ||
| 86 | |||
| 87 | nla_put_failure: | ||
| 88 | return -1; | ||
| 89 | } | ||
| 90 | |||
| 91 | static struct nft_expr_ops meta_target __read_mostly = { | ||
| 92 | .name = "meta", | ||
| 93 | .size = NFT_EXPR_SIZE(sizeof(struct nft_meta)), | ||
| 94 | .owner = THIS_MODULE, | ||
| 95 | .eval = nft_meta_eval, | ||
| 96 | .init = nft_meta_init, | ||
| 97 | .dump = nft_meta_dump, | ||
| 98 | .policy = nft_meta_policy, | ||
| 99 | .maxattr = NFTA_META_MAX, | ||
| 100 | }; | ||
| 101 | |||
| 102 | static int __init nft_meta_target_init(void) | ||
| 103 | { | ||
| 104 | return nft_register_expr(&meta_target); | ||
| 105 | } | ||
| 106 | |||
| 107 | static void __exit nft_meta_target_exit(void) | ||
| 108 | { | ||
| 109 | nft_unregister_expr(&meta_target); | ||
| 110 | } | ||
| 111 | |||
| 112 | module_init(nft_meta_target_init); | ||
| 113 | module_exit(nft_meta_target_exit); | ||
| 114 | |||
| 115 | MODULE_LICENSE("GPL"); | ||
| 116 | MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>"); | ||
| 117 | MODULE_ALIAS_NFT_EXPR("meta"); | ||
diff --git a/net/netfilter/nft_queue.c b/net/netfilter/nft_queue.c new file mode 100644 index 000000000000..cbea473d69e9 --- /dev/null +++ b/net/netfilter/nft_queue.c | |||
| @@ -0,0 +1,134 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2013 Eric Leblond <eric@regit.org> | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * Development of this code partly funded by OISF | ||
| 9 | * (http://www.openinfosecfoundation.org/) | ||
| 10 | */ | ||
| 11 | |||
| 12 | #include <linux/kernel.h> | ||
| 13 | #include <linux/init.h> | ||
| 14 | #include <linux/module.h> | ||
| 15 | #include <linux/netlink.h> | ||
| 16 | #include <linux/jhash.h> | ||
| 17 | #include <linux/netfilter.h> | ||
| 18 | #include <linux/netfilter/nf_tables.h> | ||
| 19 | #include <net/netfilter/nf_tables.h> | ||
| 20 | #include <net/netfilter/nf_queue.h> | ||
| 21 | |||
| 22 | static u32 jhash_initval __read_mostly; | ||
| 23 | |||
| 24 | struct nft_queue { | ||
| 25 | u16 queuenum; | ||
| 26 | u16 queues_total; | ||
| 27 | u16 flags; | ||
| 28 | u8 family; | ||
| 29 | }; | ||
| 30 | |||
| 31 | static void nft_queue_eval(const struct nft_expr *expr, | ||
| 32 | struct nft_data data[NFT_REG_MAX + 1], | ||
| 33 | const struct nft_pktinfo *pkt) | ||
| 34 | { | ||
| 35 | struct nft_queue *priv = nft_expr_priv(expr); | ||
| 36 | u32 queue = priv->queuenum; | ||
| 37 | u32 ret; | ||
| 38 | |||
| 39 | if (priv->queues_total > 1) { | ||
| 40 | if (priv->flags & NFT_QUEUE_FLAG_CPU_FANOUT) { | ||
| 41 | int cpu = smp_processor_id(); | ||
| 42 | |||
| 43 | queue = priv->queuenum + cpu % priv->queues_total; | ||
| 44 | } else { | ||
| 45 | queue = nfqueue_hash(pkt->skb, queue, | ||
| 46 | priv->queues_total, priv->family, | ||
| 47 | jhash_initval); | ||
| 48 | } | ||
| 49 | } | ||
| 50 | |||
| 51 | ret = NF_QUEUE_NR(queue); | ||
| 52 | if (priv->flags & NFT_QUEUE_FLAG_BYPASS) | ||
| 53 | ret |= NF_VERDICT_FLAG_QUEUE_BYPASS; | ||
| 54 | |||
| 55 | data[NFT_REG_VERDICT].verdict = ret; | ||
| 56 | } | ||
| 57 | |||
| 58 | static const struct nla_policy nft_queue_policy[NFTA_QUEUE_MAX + 1] = { | ||
| 59 | [NFTA_QUEUE_NUM] = { .type = NLA_U16 }, | ||
| 60 | [NFTA_QUEUE_TOTAL] = { .type = NLA_U16 }, | ||
| 61 | [NFTA_QUEUE_FLAGS] = { .type = NLA_U16 }, | ||
| 62 | }; | ||
| 63 | |||
| 64 | static int nft_queue_init(const struct nft_ctx *ctx, | ||
| 65 | const struct nft_expr *expr, | ||
| 66 | const struct nlattr * const tb[]) | ||
| 67 | { | ||
| 68 | struct nft_queue *priv = nft_expr_priv(expr); | ||
| 69 | |||
| 70 | if (tb[NFTA_QUEUE_NUM] == NULL) | ||
| 71 | return -EINVAL; | ||
| 72 | |||
| 73 | init_hashrandom(&jhash_initval); | ||
| 74 | priv->family = ctx->afi->family; | ||
| 75 | priv->queuenum = ntohs(nla_get_be16(tb[NFTA_QUEUE_NUM])); | ||
| 76 | |||
| 77 | if (tb[NFTA_QUEUE_TOTAL] != NULL) | ||
| 78 | priv->queues_total = ntohs(nla_get_be16(tb[NFTA_QUEUE_TOTAL])); | ||
| 79 | if (tb[NFTA_QUEUE_FLAGS] != NULL) { | ||
| 80 | priv->flags = ntohs(nla_get_be16(tb[NFTA_QUEUE_FLAGS])); | ||
| 81 | if (priv->flags & ~NFT_QUEUE_FLAG_MASK) | ||
| 82 | return -EINVAL; | ||
| 83 | } | ||
| 84 | return 0; | ||
| 85 | } | ||
| 86 | |||
| 87 | static int nft_queue_dump(struct sk_buff *skb, const struct nft_expr *expr) | ||
| 88 | { | ||
| 89 | const struct nft_queue *priv = nft_expr_priv(expr); | ||
| 90 | |||
| 91 | if (nla_put_be16(skb, NFTA_QUEUE_NUM, htons(priv->queuenum)) || | ||
| 92 | nla_put_be16(skb, NFTA_QUEUE_TOTAL, htons(priv->queues_total)) || | ||
| 93 | nla_put_be16(skb, NFTA_QUEUE_FLAGS, htons(priv->flags))) | ||
| 94 | goto nla_put_failure; | ||
| 95 | |||
| 96 | return 0; | ||
| 97 | |||
| 98 | nla_put_failure: | ||
| 99 | return -1; | ||
| 100 | } | ||
| 101 | |||
| 102 | static struct nft_expr_type nft_queue_type; | ||
| 103 | static const struct nft_expr_ops nft_queue_ops = { | ||
| 104 | .type = &nft_queue_type, | ||
| 105 | .size = NFT_EXPR_SIZE(sizeof(struct nft_queue)), | ||
| 106 | .eval = nft_queue_eval, | ||
| 107 | .init = nft_queue_init, | ||
| 108 | .dump = nft_queue_dump, | ||
| 109 | }; | ||
| 110 | |||
| 111 | static struct nft_expr_type nft_queue_type __read_mostly = { | ||
| 112 | .name = "queue", | ||
| 113 | .ops = &nft_queue_ops, | ||
| 114 | .policy = nft_queue_policy, | ||
| 115 | .maxattr = NFTA_QUEUE_MAX, | ||
| 116 | .owner = THIS_MODULE, | ||
| 117 | }; | ||
| 118 | |||
| 119 | static int __init nft_queue_module_init(void) | ||
| 120 | { | ||
| 121 | return nft_register_expr(&nft_queue_type); | ||
| 122 | } | ||
| 123 | |||
| 124 | static void __exit nft_queue_module_exit(void) | ||
| 125 | { | ||
| 126 | nft_unregister_expr(&nft_queue_type); | ||
| 127 | } | ||
| 128 | |||
| 129 | module_init(nft_queue_module_init); | ||
| 130 | module_exit(nft_queue_module_exit); | ||
| 131 | |||
| 132 | MODULE_LICENSE("GPL"); | ||
| 133 | MODULE_AUTHOR("Eric Leblond <eric@regit.org>"); | ||
| 134 | MODULE_ALIAS_NFT_EXPR("queue"); | ||
diff --git a/net/ipv4/netfilter/nft_reject_ipv4.c b/net/netfilter/nft_reject.c index 4a5e94ac314a..5e204711d704 100644 --- a/net/ipv4/netfilter/nft_reject_ipv4.c +++ b/net/netfilter/nft_reject.c | |||
| @@ -1,5 +1,6 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net> | 2 | * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net> |
| 3 | * Copyright (c) 2013 Eric Leblond <eric@regit.org> | ||
| 3 | * | 4 | * |
| 4 | * This program is free software; you can redistribute it and/or modify | 5 | * This program is free software; you can redistribute it and/or modify |
| 5 | * it under the terms of the GNU General Public License version 2 as | 6 | * it under the terms of the GNU General Public License version 2 as |
| @@ -16,10 +17,16 @@ | |||
| 16 | #include <linux/netfilter/nf_tables.h> | 17 | #include <linux/netfilter/nf_tables.h> |
| 17 | #include <net/netfilter/nf_tables.h> | 18 | #include <net/netfilter/nf_tables.h> |
| 18 | #include <net/icmp.h> | 19 | #include <net/icmp.h> |
| 20 | #include <net/netfilter/ipv4/nf_reject.h> | ||
| 21 | |||
| 22 | #if IS_ENABLED(CONFIG_NF_TABLES_IPV6) | ||
| 23 | #include <net/netfilter/ipv6/nf_reject.h> | ||
| 24 | #endif | ||
| 19 | 25 | ||
| 20 | struct nft_reject { | 26 | struct nft_reject { |
| 21 | enum nft_reject_types type:8; | 27 | enum nft_reject_types type:8; |
| 22 | u8 icmp_code; | 28 | u8 icmp_code; |
| 29 | u8 family; | ||
| 23 | }; | 30 | }; |
| 24 | 31 | ||
| 25 | static void nft_reject_eval(const struct nft_expr *expr, | 32 | static void nft_reject_eval(const struct nft_expr *expr, |
| @@ -27,12 +34,26 @@ static void nft_reject_eval(const struct nft_expr *expr, | |||
| 27 | const struct nft_pktinfo *pkt) | 34 | const struct nft_pktinfo *pkt) |
| 28 | { | 35 | { |
| 29 | struct nft_reject *priv = nft_expr_priv(expr); | 36 | struct nft_reject *priv = nft_expr_priv(expr); |
| 30 | 37 | #if IS_ENABLED(CONFIG_NF_TABLES_IPV6) | |
| 38 | struct net *net = dev_net((pkt->in != NULL) ? pkt->in : pkt->out); | ||
| 39 | #endif | ||
| 31 | switch (priv->type) { | 40 | switch (priv->type) { |
| 32 | case NFT_REJECT_ICMP_UNREACH: | 41 | case NFT_REJECT_ICMP_UNREACH: |
| 33 | icmp_send(pkt->skb, ICMP_DEST_UNREACH, priv->icmp_code, 0); | 42 | if (priv->family == NFPROTO_IPV4) |
| 43 | nf_send_unreach(pkt->skb, priv->icmp_code); | ||
| 44 | #if IS_ENABLED(CONFIG_NF_TABLES_IPV6) | ||
| 45 | else if (priv->family == NFPROTO_IPV6) | ||
| 46 | nf_send_unreach6(net, pkt->skb, priv->icmp_code, | ||
| 47 | pkt->ops->hooknum); | ||
| 48 | #endif | ||
| 34 | break; | 49 | break; |
| 35 | case NFT_REJECT_TCP_RST: | 50 | case NFT_REJECT_TCP_RST: |
| 51 | if (priv->family == NFPROTO_IPV4) | ||
| 52 | nf_send_reset(pkt->skb, pkt->ops->hooknum); | ||
| 53 | #if IS_ENABLED(CONFIG_NF_TABLES_IPV6) | ||
| 54 | else if (priv->family == NFPROTO_IPV6) | ||
| 55 | nf_send_reset6(net, pkt->skb, pkt->ops->hooknum); | ||
| 56 | #endif | ||
| 36 | break; | 57 | break; |
| 37 | } | 58 | } |
| 38 | 59 | ||
| @@ -53,6 +74,7 @@ static int nft_reject_init(const struct nft_ctx *ctx, | |||
| 53 | if (tb[NFTA_REJECT_TYPE] == NULL) | 74 | if (tb[NFTA_REJECT_TYPE] == NULL) |
| 54 | return -EINVAL; | 75 | return -EINVAL; |
| 55 | 76 | ||
| 77 | priv->family = ctx->afi->family; | ||
| 56 | priv->type = ntohl(nla_get_be32(tb[NFTA_REJECT_TYPE])); | 78 | priv->type = ntohl(nla_get_be32(tb[NFTA_REJECT_TYPE])); |
| 57 | switch (priv->type) { | 79 | switch (priv->type) { |
| 58 | case NFT_REJECT_ICMP_UNREACH: | 80 | case NFT_REJECT_ICMP_UNREACH: |
diff --git a/net/netfilter/xt_CT.c b/net/netfilter/xt_CT.c index da35ac06a975..5929be622c5c 100644 --- a/net/netfilter/xt_CT.c +++ b/net/netfilter/xt_CT.c | |||
| @@ -211,8 +211,10 @@ static int xt_ct_tg_check(const struct xt_tgchk_param *par, | |||
| 211 | ret = 0; | 211 | ret = 0; |
| 212 | if ((info->ct_events || info->exp_events) && | 212 | if ((info->ct_events || info->exp_events) && |
| 213 | !nf_ct_ecache_ext_add(ct, info->ct_events, info->exp_events, | 213 | !nf_ct_ecache_ext_add(ct, info->ct_events, info->exp_events, |
| 214 | GFP_KERNEL)) | 214 | GFP_KERNEL)) { |
| 215 | ret = -EINVAL; | ||
| 215 | goto err3; | 216 | goto err3; |
| 217 | } | ||
| 216 | 218 | ||
| 217 | if (info->helper[0]) { | 219 | if (info->helper[0]) { |
| 218 | ret = xt_ct_set_helper(ct, info->helper, par); | 220 | ret = xt_ct_set_helper(ct, info->helper, par); |
diff --git a/net/netfilter/xt_NFQUEUE.c b/net/netfilter/xt_NFQUEUE.c index ed00fef58996..8f1779ff7e30 100644 --- a/net/netfilter/xt_NFQUEUE.c +++ b/net/netfilter/xt_NFQUEUE.c | |||
| @@ -11,15 +11,13 @@ | |||
| 11 | #include <linux/module.h> | 11 | #include <linux/module.h> |
| 12 | #include <linux/skbuff.h> | 12 | #include <linux/skbuff.h> |
| 13 | 13 | ||
| 14 | #include <linux/ip.h> | ||
| 15 | #include <linux/ipv6.h> | ||
| 16 | #include <linux/jhash.h> | ||
| 17 | |||
| 18 | #include <linux/netfilter.h> | 14 | #include <linux/netfilter.h> |
| 19 | #include <linux/netfilter_arp.h> | 15 | #include <linux/netfilter_arp.h> |
| 20 | #include <linux/netfilter/x_tables.h> | 16 | #include <linux/netfilter/x_tables.h> |
| 21 | #include <linux/netfilter/xt_NFQUEUE.h> | 17 | #include <linux/netfilter/xt_NFQUEUE.h> |
| 22 | 18 | ||
| 19 | #include <net/netfilter/nf_queue.h> | ||
| 20 | |||
| 23 | MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>"); | 21 | MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>"); |
| 24 | MODULE_DESCRIPTION("Xtables: packet forwarding to netlink"); | 22 | MODULE_DESCRIPTION("Xtables: packet forwarding to netlink"); |
| 25 | MODULE_LICENSE("GPL"); | 23 | MODULE_LICENSE("GPL"); |
| @@ -28,7 +26,6 @@ MODULE_ALIAS("ip6t_NFQUEUE"); | |||
| 28 | MODULE_ALIAS("arpt_NFQUEUE"); | 26 | MODULE_ALIAS("arpt_NFQUEUE"); |
| 29 | 27 | ||
| 30 | static u32 jhash_initval __read_mostly; | 28 | static u32 jhash_initval __read_mostly; |
| 31 | static bool rnd_inited __read_mostly; | ||
| 32 | 29 | ||
| 33 | static unsigned int | 30 | static unsigned int |
| 34 | nfqueue_tg(struct sk_buff *skb, const struct xt_action_param *par) | 31 | nfqueue_tg(struct sk_buff *skb, const struct xt_action_param *par) |
| @@ -38,69 +35,16 @@ nfqueue_tg(struct sk_buff *skb, const struct xt_action_param *par) | |||
| 38 | return NF_QUEUE_NR(tinfo->queuenum); | 35 | return NF_QUEUE_NR(tinfo->queuenum); |
| 39 | } | 36 | } |
| 40 | 37 | ||
| 41 | static u32 hash_v4(const struct sk_buff *skb) | ||
| 42 | { | ||
| 43 | const struct iphdr *iph = ip_hdr(skb); | ||
| 44 | |||
| 45 | /* packets in either direction go into same queue */ | ||
| 46 | if ((__force u32)iph->saddr < (__force u32)iph->daddr) | ||
| 47 | return jhash_3words((__force u32)iph->saddr, | ||
| 48 | (__force u32)iph->daddr, iph->protocol, jhash_initval); | ||
| 49 | |||
| 50 | return jhash_3words((__force u32)iph->daddr, | ||
| 51 | (__force u32)iph->saddr, iph->protocol, jhash_initval); | ||
| 52 | } | ||
| 53 | |||
| 54 | #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) | ||
| 55 | static u32 hash_v6(const struct sk_buff *skb) | ||
| 56 | { | ||
| 57 | const struct ipv6hdr *ip6h = ipv6_hdr(skb); | ||
| 58 | u32 a, b, c; | ||
| 59 | |||
| 60 | if ((__force u32)ip6h->saddr.s6_addr32[3] < | ||
| 61 | (__force u32)ip6h->daddr.s6_addr32[3]) { | ||
| 62 | a = (__force u32) ip6h->saddr.s6_addr32[3]; | ||
| 63 | b = (__force u32) ip6h->daddr.s6_addr32[3]; | ||
| 64 | } else { | ||
| 65 | b = (__force u32) ip6h->saddr.s6_addr32[3]; | ||
| 66 | a = (__force u32) ip6h->daddr.s6_addr32[3]; | ||
| 67 | } | ||
| 68 | |||
| 69 | if ((__force u32)ip6h->saddr.s6_addr32[1] < | ||
| 70 | (__force u32)ip6h->daddr.s6_addr32[1]) | ||
| 71 | c = (__force u32) ip6h->saddr.s6_addr32[1]; | ||
| 72 | else | ||
| 73 | c = (__force u32) ip6h->daddr.s6_addr32[1]; | ||
| 74 | |||
| 75 | return jhash_3words(a, b, c, jhash_initval); | ||
| 76 | } | ||
| 77 | #endif | ||
| 78 | |||
| 79 | static u32 | ||
| 80 | nfqueue_hash(const struct sk_buff *skb, const struct xt_action_param *par) | ||
| 81 | { | ||
| 82 | const struct xt_NFQ_info_v1 *info = par->targinfo; | ||
| 83 | u32 queue = info->queuenum; | ||
| 84 | |||
| 85 | if (par->family == NFPROTO_IPV4) | ||
| 86 | queue += ((u64) hash_v4(skb) * info->queues_total) >> 32; | ||
| 87 | #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) | ||
| 88 | else if (par->family == NFPROTO_IPV6) | ||
| 89 | queue += ((u64) hash_v6(skb) * info->queues_total) >> 32; | ||
| 90 | #endif | ||
| 91 | |||
| 92 | return queue; | ||
| 93 | } | ||
| 94 | |||
| 95 | static unsigned int | 38 | static unsigned int |
| 96 | nfqueue_tg_v1(struct sk_buff *skb, const struct xt_action_param *par) | 39 | nfqueue_tg_v1(struct sk_buff *skb, const struct xt_action_param *par) |
| 97 | { | 40 | { |
| 98 | const struct xt_NFQ_info_v1 *info = par->targinfo; | 41 | const struct xt_NFQ_info_v1 *info = par->targinfo; |
| 99 | u32 queue = info->queuenum; | 42 | u32 queue = info->queuenum; |
| 100 | 43 | ||
| 101 | if (info->queues_total > 1) | 44 | if (info->queues_total > 1) { |
| 102 | queue = nfqueue_hash(skb, par); | 45 | queue = nfqueue_hash(skb, queue, info->queues_total, |
| 103 | 46 | par->family, jhash_initval); | |
| 47 | } | ||
| 104 | return NF_QUEUE_NR(queue); | 48 | return NF_QUEUE_NR(queue); |
| 105 | } | 49 | } |
| 106 | 50 | ||
| @@ -120,10 +64,8 @@ static int nfqueue_tg_check(const struct xt_tgchk_param *par) | |||
| 120 | const struct xt_NFQ_info_v3 *info = par->targinfo; | 64 | const struct xt_NFQ_info_v3 *info = par->targinfo; |
| 121 | u32 maxid; | 65 | u32 maxid; |
| 122 | 66 | ||
| 123 | if (unlikely(!rnd_inited)) { | 67 | init_hashrandom(&jhash_initval); |
| 124 | get_random_bytes(&jhash_initval, sizeof(jhash_initval)); | 68 | |
| 125 | rnd_inited = true; | ||
| 126 | } | ||
| 127 | if (info->queues_total == 0) { | 69 | if (info->queues_total == 0) { |
| 128 | pr_err("NFQUEUE: number of total queues is 0\n"); | 70 | pr_err("NFQUEUE: number of total queues is 0\n"); |
| 129 | return -EINVAL; | 71 | return -EINVAL; |
| @@ -154,8 +96,10 @@ nfqueue_tg_v3(struct sk_buff *skb, const struct xt_action_param *par) | |||
| 154 | int cpu = smp_processor_id(); | 96 | int cpu = smp_processor_id(); |
| 155 | 97 | ||
| 156 | queue = info->queuenum + cpu % info->queues_total; | 98 | queue = info->queuenum + cpu % info->queues_total; |
| 157 | } else | 99 | } else { |
| 158 | queue = nfqueue_hash(skb, par); | 100 | queue = nfqueue_hash(skb, queue, info->queues_total, |
| 101 | par->family, jhash_initval); | ||
| 102 | } | ||
| 159 | } | 103 | } |
| 160 | 104 | ||
| 161 | ret = NF_QUEUE_NR(queue); | 105 | ret = NF_QUEUE_NR(queue); |
diff --git a/net/netfilter/xt_cgroup.c b/net/netfilter/xt_cgroup.c new file mode 100644 index 000000000000..9a8e77e7f8d4 --- /dev/null +++ b/net/netfilter/xt_cgroup.c | |||
| @@ -0,0 +1,71 @@ | |||
| 1 | /* | ||
| 2 | * Xtables module to match the process control group. | ||
| 3 | * | ||
| 4 | * Might be used to implement individual "per-application" firewall | ||
| 5 | * policies in contrast to global policies based on control groups. | ||
| 6 | * Matching is based upon processes tagged to net_cls' classid marker. | ||
| 7 | * | ||
| 8 | * (C) 2013 Daniel Borkmann <dborkman@redhat.com> | ||
| 9 | * | ||
| 10 | * This program is free software; you can redistribute it and/or modify | ||
| 11 | * it under the terms of the GNU General Public License version 2 as | ||
| 12 | * published by the Free Software Foundation. | ||
| 13 | */ | ||
| 14 | |||
| 15 | #include <linux/skbuff.h> | ||
| 16 | #include <linux/module.h> | ||
| 17 | #include <linux/netfilter/x_tables.h> | ||
| 18 | #include <linux/netfilter/xt_cgroup.h> | ||
| 19 | #include <net/sock.h> | ||
| 20 | |||
| 21 | MODULE_LICENSE("GPL"); | ||
| 22 | MODULE_AUTHOR("Daniel Borkmann <dborkman@redhat.com>"); | ||
| 23 | MODULE_DESCRIPTION("Xtables: process control group matching"); | ||
| 24 | MODULE_ALIAS("ipt_cgroup"); | ||
| 25 | MODULE_ALIAS("ip6t_cgroup"); | ||
| 26 | |||
| 27 | static int cgroup_mt_check(const struct xt_mtchk_param *par) | ||
| 28 | { | ||
| 29 | struct xt_cgroup_info *info = par->matchinfo; | ||
| 30 | |||
| 31 | if (info->invert & ~1) | ||
| 32 | return -EINVAL; | ||
| 33 | |||
| 34 | return info->id ? 0 : -EINVAL; | ||
| 35 | } | ||
| 36 | |||
| 37 | static bool | ||
| 38 | cgroup_mt(const struct sk_buff *skb, struct xt_action_param *par) | ||
| 39 | { | ||
| 40 | const struct xt_cgroup_info *info = par->matchinfo; | ||
| 41 | |||
| 42 | if (skb->sk == NULL) | ||
| 43 | return false; | ||
| 44 | |||
| 45 | return (info->id == skb->sk->sk_classid) ^ info->invert; | ||
| 46 | } | ||
| 47 | |||
| 48 | static struct xt_match cgroup_mt_reg __read_mostly = { | ||
| 49 | .name = "cgroup", | ||
| 50 | .revision = 0, | ||
| 51 | .family = NFPROTO_UNSPEC, | ||
| 52 | .checkentry = cgroup_mt_check, | ||
| 53 | .match = cgroup_mt, | ||
| 54 | .matchsize = sizeof(struct xt_cgroup_info), | ||
| 55 | .me = THIS_MODULE, | ||
| 56 | .hooks = (1 << NF_INET_LOCAL_OUT) | | ||
| 57 | (1 << NF_INET_POST_ROUTING), | ||
| 58 | }; | ||
| 59 | |||
| 60 | static int __init cgroup_mt_init(void) | ||
| 61 | { | ||
| 62 | return xt_register_match(&cgroup_mt_reg); | ||
| 63 | } | ||
| 64 | |||
| 65 | static void __exit cgroup_mt_exit(void) | ||
| 66 | { | ||
| 67 | xt_unregister_match(&cgroup_mt_reg); | ||
| 68 | } | ||
| 69 | |||
| 70 | module_init(cgroup_mt_init); | ||
| 71 | module_exit(cgroup_mt_exit); | ||
diff --git a/net/netfilter/xt_connmark.c b/net/netfilter/xt_connmark.c index 7278145e6a68..69f78e96fdb4 100644 --- a/net/netfilter/xt_connmark.c +++ b/net/netfilter/xt_connmark.c | |||
| @@ -17,8 +17,7 @@ | |||
| 17 | * GNU General Public License for more details. | 17 | * GNU General Public License for more details. |
| 18 | * | 18 | * |
| 19 | * You should have received a copy of the GNU General Public License | 19 | * You should have received a copy of the GNU General Public License |
| 20 | * along with this program; if not, write to the Free Software | 20 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 22 | */ | 21 | */ |
| 23 | 22 | ||
| 24 | #include <linux/module.h> | 23 | #include <linux/module.h> |
diff --git a/net/netfilter/xt_ipcomp.c b/net/netfilter/xt_ipcomp.c new file mode 100644 index 000000000000..a4c7561698c5 --- /dev/null +++ b/net/netfilter/xt_ipcomp.c | |||
| @@ -0,0 +1,111 @@ | |||
| 1 | /* Kernel module to match IPComp parameters for IPv4 and IPv6 | ||
| 2 | * | ||
| 3 | * Copyright (C) 2013 WindRiver | ||
| 4 | * | ||
| 5 | * Author: | ||
| 6 | * Fan Du <fan.du@windriver.com> | ||
| 7 | * | ||
| 8 | * Based on: | ||
| 9 | * net/netfilter/xt_esp.c | ||
| 10 | * | ||
| 11 | * This program is free software; you can redistribute it and/or | ||
| 12 | * modify it under the terms of the GNU General Public License | ||
| 13 | * as published by the Free Software Foundation; either version | ||
| 14 | * 2 of the License, or (at your option) any later version. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
| 18 | #include <linux/in.h> | ||
| 19 | #include <linux/module.h> | ||
| 20 | #include <linux/skbuff.h> | ||
| 21 | #include <linux/ip.h> | ||
| 22 | |||
| 23 | #include <linux/netfilter/xt_ipcomp.h> | ||
| 24 | #include <linux/netfilter/x_tables.h> | ||
| 25 | |||
| 26 | MODULE_LICENSE("GPL"); | ||
| 27 | MODULE_AUTHOR("Fan Du <fan.du@windriver.com>"); | ||
| 28 | MODULE_DESCRIPTION("Xtables: IPv4/6 IPsec-IPComp SPI match"); | ||
| 29 | |||
| 30 | /* Returns 1 if the spi is matched by the range, 0 otherwise */ | ||
| 31 | static inline bool | ||
| 32 | spi_match(u_int32_t min, u_int32_t max, u_int32_t spi, bool invert) | ||
| 33 | { | ||
| 34 | bool r; | ||
| 35 | pr_debug("spi_match:%c 0x%x <= 0x%x <= 0x%x\n", | ||
| 36 | invert ? '!' : ' ', min, spi, max); | ||
| 37 | r = (spi >= min && spi <= max) ^ invert; | ||
| 38 | pr_debug(" result %s\n", r ? "PASS" : "FAILED"); | ||
| 39 | return r; | ||
| 40 | } | ||
| 41 | |||
| 42 | static bool comp_mt(const struct sk_buff *skb, struct xt_action_param *par) | ||
| 43 | { | ||
| 44 | struct ip_comp_hdr _comphdr; | ||
| 45 | const struct ip_comp_hdr *chdr; | ||
| 46 | const struct xt_ipcomp *compinfo = par->matchinfo; | ||
| 47 | |||
| 48 | /* Must not be a fragment. */ | ||
| 49 | if (par->fragoff != 0) | ||
| 50 | return false; | ||
| 51 | |||
| 52 | chdr = skb_header_pointer(skb, par->thoff, sizeof(_comphdr), &_comphdr); | ||
| 53 | if (chdr == NULL) { | ||
| 54 | /* We've been asked to examine this packet, and we | ||
| 55 | * can't. Hence, no choice but to drop. | ||
| 56 | */ | ||
| 57 | pr_debug("Dropping evil IPComp tinygram.\n"); | ||
| 58 | par->hotdrop = true; | ||
| 59 | return 0; | ||
| 60 | } | ||
| 61 | |||
| 62 | return spi_match(compinfo->spis[0], compinfo->spis[1], | ||
| 63 | ntohl(chdr->cpi << 16), | ||
| 64 | !!(compinfo->invflags & XT_IPCOMP_INV_SPI)); | ||
| 65 | } | ||
| 66 | |||
| 67 | static int comp_mt_check(const struct xt_mtchk_param *par) | ||
| 68 | { | ||
| 69 | const struct xt_ipcomp *compinfo = par->matchinfo; | ||
| 70 | |||
| 71 | /* Must specify no unknown invflags */ | ||
| 72 | if (compinfo->invflags & ~XT_IPCOMP_INV_MASK) { | ||
| 73 | pr_err("unknown flags %X\n", compinfo->invflags); | ||
| 74 | return -EINVAL; | ||
| 75 | } | ||
| 76 | return 0; | ||
| 77 | } | ||
| 78 | |||
| 79 | static struct xt_match comp_mt_reg[] __read_mostly = { | ||
| 80 | { | ||
| 81 | .name = "ipcomp", | ||
| 82 | .family = NFPROTO_IPV4, | ||
| 83 | .match = comp_mt, | ||
| 84 | .matchsize = sizeof(struct xt_ipcomp), | ||
| 85 | .proto = IPPROTO_COMP, | ||
| 86 | .checkentry = comp_mt_check, | ||
| 87 | .me = THIS_MODULE, | ||
| 88 | }, | ||
| 89 | { | ||
| 90 | .name = "ipcomp", | ||
| 91 | .family = NFPROTO_IPV6, | ||
| 92 | .match = comp_mt, | ||
| 93 | .matchsize = sizeof(struct xt_ipcomp), | ||
| 94 | .proto = IPPROTO_COMP, | ||
| 95 | .checkentry = comp_mt_check, | ||
| 96 | .me = THIS_MODULE, | ||
| 97 | }, | ||
| 98 | }; | ||
| 99 | |||
| 100 | static int __init comp_mt_init(void) | ||
| 101 | { | ||
| 102 | return xt_register_matches(comp_mt_reg, ARRAY_SIZE(comp_mt_reg)); | ||
| 103 | } | ||
| 104 | |||
| 105 | static void __exit comp_mt_exit(void) | ||
| 106 | { | ||
| 107 | xt_unregister_matches(comp_mt_reg, ARRAY_SIZE(comp_mt_reg)); | ||
| 108 | } | ||
| 109 | |||
| 110 | module_init(comp_mt_init); | ||
| 111 | module_exit(comp_mt_exit); | ||
diff --git a/net/netfilter/xt_l2tp.c b/net/netfilter/xt_l2tp.c new file mode 100644 index 000000000000..8aee572771f2 --- /dev/null +++ b/net/netfilter/xt_l2tp.c | |||
| @@ -0,0 +1,354 @@ | |||
| 1 | /* Kernel module to match L2TP header parameters. */ | ||
| 2 | |||
| 3 | /* (C) 2013 James Chapman <jchapman@katalix.com> | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify | ||
| 6 | * it under the terms of the GNU General Public License version 2 as | ||
| 7 | * published by the Free Software Foundation. | ||
| 8 | */ | ||
| 9 | |||
| 10 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
| 11 | #include <linux/module.h> | ||
| 12 | #include <linux/skbuff.h> | ||
| 13 | #include <linux/if_ether.h> | ||
| 14 | #include <net/ip.h> | ||
| 15 | #include <linux/ipv6.h> | ||
| 16 | #include <net/ipv6.h> | ||
| 17 | #include <net/udp.h> | ||
| 18 | #include <linux/l2tp.h> | ||
| 19 | |||
| 20 | #include <linux/netfilter_ipv4.h> | ||
| 21 | #include <linux/netfilter_ipv6.h> | ||
| 22 | #include <linux/netfilter_ipv4/ip_tables.h> | ||
| 23 | #include <linux/netfilter_ipv6/ip6_tables.h> | ||
| 24 | #include <linux/netfilter/x_tables.h> | ||
| 25 | #include <linux/netfilter/xt_tcpudp.h> | ||
| 26 | #include <linux/netfilter/xt_l2tp.h> | ||
| 27 | |||
| 28 | /* L2TP header masks */ | ||
| 29 | #define L2TP_HDR_T_BIT 0x8000 | ||
| 30 | #define L2TP_HDR_L_BIT 0x4000 | ||
| 31 | #define L2TP_HDR_VER 0x000f | ||
| 32 | |||
| 33 | MODULE_LICENSE("GPL"); | ||
| 34 | MODULE_AUTHOR("James Chapman <jchapman@katalix.com>"); | ||
| 35 | MODULE_DESCRIPTION("Xtables: L2TP header match"); | ||
| 36 | MODULE_ALIAS("ipt_l2tp"); | ||
| 37 | MODULE_ALIAS("ip6t_l2tp"); | ||
| 38 | |||
| 39 | /* The L2TP fields that can be matched */ | ||
| 40 | struct l2tp_data { | ||
| 41 | u32 tid; | ||
| 42 | u32 sid; | ||
| 43 | u8 type; | ||
| 44 | u8 version; | ||
| 45 | }; | ||
| 46 | |||
| 47 | union l2tp_val { | ||
| 48 | __be16 val16[2]; | ||
| 49 | __be32 val32; | ||
| 50 | }; | ||
| 51 | |||
| 52 | static bool l2tp_match(const struct xt_l2tp_info *info, struct l2tp_data *data) | ||
| 53 | { | ||
| 54 | if ((info->flags & XT_L2TP_TYPE) && (info->type != data->type)) | ||
| 55 | return false; | ||
| 56 | |||
| 57 | if ((info->flags & XT_L2TP_VERSION) && (info->version != data->version)) | ||
| 58 | return false; | ||
| 59 | |||
| 60 | /* Check tid only for L2TPv3 control or any L2TPv2 packets */ | ||
| 61 | if ((info->flags & XT_L2TP_TID) && | ||
| 62 | ((data->type == XT_L2TP_TYPE_CONTROL) || (data->version == 2)) && | ||
| 63 | (info->tid != data->tid)) | ||
| 64 | return false; | ||
| 65 | |||
| 66 | /* Check sid only for L2TP data packets */ | ||
| 67 | if ((info->flags & XT_L2TP_SID) && (data->type == XT_L2TP_TYPE_DATA) && | ||
| 68 | (info->sid != data->sid)) | ||
| 69 | return false; | ||
| 70 | |||
| 71 | return true; | ||
| 72 | } | ||
| 73 | |||
| 74 | /* Parse L2TP header fields when UDP encapsulation is used. Handles | ||
| 75 | * L2TPv2 and L2TPv3. Note the L2TPv3 control and data packets have a | ||
| 76 | * different format. See | ||
| 77 | * RFC2661, Section 3.1, L2TPv2 Header Format | ||
| 78 | * RFC3931, Section 3.2.1, L2TPv3 Control Message Header | ||
| 79 | * RFC3931, Section 3.2.2, L2TPv3 Data Message Header | ||
| 80 | * RFC3931, Section 4.1.2.1, L2TPv3 Session Header over UDP | ||
| 81 | */ | ||
| 82 | static bool l2tp_udp_mt(const struct sk_buff *skb, struct xt_action_param *par, u16 thoff) | ||
| 83 | { | ||
| 84 | const struct xt_l2tp_info *info = par->matchinfo; | ||
| 85 | int uhlen = sizeof(struct udphdr); | ||
| 86 | int offs = thoff + uhlen; | ||
| 87 | union l2tp_val *lh; | ||
| 88 | union l2tp_val lhbuf; | ||
| 89 | u16 flags; | ||
| 90 | struct l2tp_data data = { 0, }; | ||
| 91 | |||
| 92 | if (par->fragoff != 0) | ||
| 93 | return false; | ||
| 94 | |||
| 95 | /* Extract L2TP header fields. The flags in the first 16 bits | ||
| 96 | * tell us where the other fields are. | ||
| 97 | */ | ||
| 98 | lh = skb_header_pointer(skb, offs, 2, &lhbuf); | ||
| 99 | if (lh == NULL) | ||
| 100 | return false; | ||
| 101 | |||
| 102 | flags = ntohs(lh->val16[0]); | ||
| 103 | if (flags & L2TP_HDR_T_BIT) | ||
| 104 | data.type = XT_L2TP_TYPE_CONTROL; | ||
| 105 | else | ||
| 106 | data.type = XT_L2TP_TYPE_DATA; | ||
| 107 | data.version = (u8) flags & L2TP_HDR_VER; | ||
| 108 | |||
| 109 | /* Now extract the L2TP tid/sid. These are in different places | ||
| 110 | * for L2TPv2 (rfc2661) and L2TPv3 (rfc3931). For L2TPv2, we | ||
| 111 | * must also check to see if the length field is present, | ||
| 112 | * since this affects the offsets into the packet of the | ||
| 113 | * tid/sid fields. | ||
| 114 | */ | ||
| 115 | if (data.version == 3) { | ||
| 116 | lh = skb_header_pointer(skb, offs + 4, 4, &lhbuf); | ||
| 117 | if (lh == NULL) | ||
| 118 | return false; | ||
| 119 | if (data.type == XT_L2TP_TYPE_CONTROL) | ||
| 120 | data.tid = ntohl(lh->val32); | ||
| 121 | else | ||
| 122 | data.sid = ntohl(lh->val32); | ||
| 123 | } else if (data.version == 2) { | ||
| 124 | if (flags & L2TP_HDR_L_BIT) | ||
| 125 | offs += 2; | ||
| 126 | lh = skb_header_pointer(skb, offs + 2, 4, &lhbuf); | ||
| 127 | if (lh == NULL) | ||
| 128 | return false; | ||
| 129 | data.tid = (u32) ntohs(lh->val16[0]); | ||
| 130 | data.sid = (u32) ntohs(lh->val16[1]); | ||
| 131 | } else | ||
| 132 | return false; | ||
| 133 | |||
| 134 | return l2tp_match(info, &data); | ||
| 135 | } | ||
| 136 | |||
| 137 | /* Parse L2TP header fields for IP encapsulation (no UDP header). | ||
| 138 | * L2TPv3 data packets have a different form with IP encap. See | ||
| 139 | * RC3931, Section 4.1.1.1, L2TPv3 Session Header over IP. | ||
| 140 | * RC3931, Section 4.1.1.2, L2TPv3 Control and Data Traffic over IP. | ||
| 141 | */ | ||
| 142 | static bool l2tp_ip_mt(const struct sk_buff *skb, struct xt_action_param *par, u16 thoff) | ||
| 143 | { | ||
| 144 | const struct xt_l2tp_info *info = par->matchinfo; | ||
| 145 | union l2tp_val *lh; | ||
| 146 | union l2tp_val lhbuf; | ||
| 147 | struct l2tp_data data = { 0, }; | ||
| 148 | |||
| 149 | /* For IP encap, the L2TP sid is the first 32-bits. */ | ||
| 150 | lh = skb_header_pointer(skb, thoff, sizeof(lhbuf), &lhbuf); | ||
| 151 | if (lh == NULL) | ||
| 152 | return false; | ||
| 153 | if (lh->val32 == 0) { | ||
| 154 | /* Must be a control packet. The L2TP tid is further | ||
| 155 | * into the packet. | ||
| 156 | */ | ||
| 157 | data.type = XT_L2TP_TYPE_CONTROL; | ||
| 158 | lh = skb_header_pointer(skb, thoff + 8, sizeof(lhbuf), | ||
| 159 | &lhbuf); | ||
| 160 | if (lh == NULL) | ||
| 161 | return false; | ||
| 162 | data.tid = ntohl(lh->val32); | ||
| 163 | } else { | ||
| 164 | data.sid = ntohl(lh->val32); | ||
| 165 | data.type = XT_L2TP_TYPE_DATA; | ||
| 166 | } | ||
| 167 | |||
| 168 | data.version = 3; | ||
| 169 | |||
| 170 | return l2tp_match(info, &data); | ||
| 171 | } | ||
| 172 | |||
| 173 | static bool l2tp_mt4(const struct sk_buff *skb, struct xt_action_param *par) | ||
| 174 | { | ||
| 175 | struct iphdr *iph = ip_hdr(skb); | ||
| 176 | u8 ipproto = iph->protocol; | ||
| 177 | |||
| 178 | /* l2tp_mt_check4 already restricts the transport protocol */ | ||
| 179 | switch (ipproto) { | ||
| 180 | case IPPROTO_UDP: | ||
| 181 | return l2tp_udp_mt(skb, par, par->thoff); | ||
| 182 | case IPPROTO_L2TP: | ||
| 183 | return l2tp_ip_mt(skb, par, par->thoff); | ||
| 184 | } | ||
| 185 | |||
| 186 | return false; | ||
| 187 | } | ||
| 188 | |||
| 189 | #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) | ||
| 190 | static bool l2tp_mt6(const struct sk_buff *skb, struct xt_action_param *par) | ||
| 191 | { | ||
| 192 | unsigned int thoff = 0; | ||
| 193 | unsigned short fragoff = 0; | ||
| 194 | int ipproto; | ||
| 195 | |||
| 196 | ipproto = ipv6_find_hdr(skb, &thoff, -1, &fragoff, NULL); | ||
| 197 | if (fragoff != 0) | ||
| 198 | return false; | ||
| 199 | |||
| 200 | /* l2tp_mt_check6 already restricts the transport protocol */ | ||
| 201 | switch (ipproto) { | ||
| 202 | case IPPROTO_UDP: | ||
| 203 | return l2tp_udp_mt(skb, par, thoff); | ||
| 204 | case IPPROTO_L2TP: | ||
| 205 | return l2tp_ip_mt(skb, par, thoff); | ||
| 206 | } | ||
| 207 | |||
| 208 | return false; | ||
| 209 | } | ||
| 210 | #endif | ||
| 211 | |||
| 212 | static int l2tp_mt_check(const struct xt_mtchk_param *par) | ||
| 213 | { | ||
| 214 | const struct xt_l2tp_info *info = par->matchinfo; | ||
| 215 | |||
| 216 | /* Check for invalid flags */ | ||
| 217 | if (info->flags & ~(XT_L2TP_TID | XT_L2TP_SID | XT_L2TP_VERSION | | ||
| 218 | XT_L2TP_TYPE)) { | ||
| 219 | pr_info("unknown flags: %x\n", info->flags); | ||
| 220 | return -EINVAL; | ||
| 221 | } | ||
| 222 | |||
| 223 | /* At least one of tid, sid or type=control must be specified */ | ||
| 224 | if ((!(info->flags & XT_L2TP_TID)) && | ||
| 225 | (!(info->flags & XT_L2TP_SID)) && | ||
| 226 | ((!(info->flags & XT_L2TP_TYPE)) || | ||
| 227 | (info->type != XT_L2TP_TYPE_CONTROL))) { | ||
| 228 | pr_info("invalid flags combination: %x\n", info->flags); | ||
| 229 | return -EINVAL; | ||
| 230 | } | ||
| 231 | |||
| 232 | /* If version 2 is specified, check that incompatible params | ||
| 233 | * are not supplied | ||
| 234 | */ | ||
| 235 | if (info->flags & XT_L2TP_VERSION) { | ||
| 236 | if ((info->version < 2) || (info->version > 3)) { | ||
| 237 | pr_info("wrong L2TP version: %u\n", info->version); | ||
| 238 | return -EINVAL; | ||
| 239 | } | ||
| 240 | |||
| 241 | if (info->version == 2) { | ||
| 242 | if ((info->flags & XT_L2TP_TID) && | ||
| 243 | (info->tid > 0xffff)) { | ||
| 244 | pr_info("v2 tid > 0xffff: %u\n", info->tid); | ||
| 245 | return -EINVAL; | ||
| 246 | } | ||
| 247 | if ((info->flags & XT_L2TP_SID) && | ||
| 248 | (info->sid > 0xffff)) { | ||
| 249 | pr_info("v2 sid > 0xffff: %u\n", info->sid); | ||
| 250 | return -EINVAL; | ||
| 251 | } | ||
| 252 | } | ||
| 253 | } | ||
| 254 | |||
| 255 | return 0; | ||
| 256 | } | ||
| 257 | |||
| 258 | static int l2tp_mt_check4(const struct xt_mtchk_param *par) | ||
| 259 | { | ||
| 260 | const struct xt_l2tp_info *info = par->matchinfo; | ||
| 261 | const struct ipt_entry *e = par->entryinfo; | ||
| 262 | const struct ipt_ip *ip = &e->ip; | ||
| 263 | int ret; | ||
| 264 | |||
| 265 | ret = l2tp_mt_check(par); | ||
| 266 | if (ret != 0) | ||
| 267 | return ret; | ||
| 268 | |||
| 269 | if ((ip->proto != IPPROTO_UDP) && | ||
| 270 | (ip->proto != IPPROTO_L2TP)) { | ||
| 271 | pr_info("missing protocol rule (udp|l2tpip)\n"); | ||
| 272 | return -EINVAL; | ||
| 273 | } | ||
| 274 | |||
| 275 | if ((ip->proto == IPPROTO_L2TP) && | ||
| 276 | (info->version == 2)) { | ||
| 277 | pr_info("v2 doesn't support IP mode\n"); | ||
| 278 | return -EINVAL; | ||
| 279 | } | ||
| 280 | |||
| 281 | return 0; | ||
| 282 | } | ||
| 283 | |||
| 284 | #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) | ||
| 285 | static int l2tp_mt_check6(const struct xt_mtchk_param *par) | ||
| 286 | { | ||
| 287 | const struct xt_l2tp_info *info = par->matchinfo; | ||
| 288 | const struct ip6t_entry *e = par->entryinfo; | ||
| 289 | const struct ip6t_ip6 *ip = &e->ipv6; | ||
| 290 | int ret; | ||
| 291 | |||
| 292 | ret = l2tp_mt_check(par); | ||
| 293 | if (ret != 0) | ||
| 294 | return ret; | ||
| 295 | |||
| 296 | if ((ip->proto != IPPROTO_UDP) && | ||
| 297 | (ip->proto != IPPROTO_L2TP)) { | ||
| 298 | pr_info("missing protocol rule (udp|l2tpip)\n"); | ||
| 299 | return -EINVAL; | ||
| 300 | } | ||
| 301 | |||
| 302 | if ((ip->proto == IPPROTO_L2TP) && | ||
| 303 | (info->version == 2)) { | ||
| 304 | pr_info("v2 doesn't support IP mode\n"); | ||
| 305 | return -EINVAL; | ||
| 306 | } | ||
| 307 | |||
| 308 | return 0; | ||
| 309 | } | ||
| 310 | #endif | ||
| 311 | |||
| 312 | static struct xt_match l2tp_mt_reg[] __read_mostly = { | ||
| 313 | { | ||
| 314 | .name = "l2tp", | ||
| 315 | .revision = 0, | ||
| 316 | .family = NFPROTO_IPV4, | ||
| 317 | .match = l2tp_mt4, | ||
| 318 | .matchsize = XT_ALIGN(sizeof(struct xt_l2tp_info)), | ||
| 319 | .checkentry = l2tp_mt_check4, | ||
| 320 | .hooks = ((1 << NF_INET_PRE_ROUTING) | | ||
| 321 | (1 << NF_INET_LOCAL_IN) | | ||
| 322 | (1 << NF_INET_LOCAL_OUT) | | ||
| 323 | (1 << NF_INET_FORWARD)), | ||
| 324 | .me = THIS_MODULE, | ||
| 325 | }, | ||
| 326 | #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) | ||
| 327 | { | ||
| 328 | .name = "l2tp", | ||
| 329 | .revision = 0, | ||
| 330 | .family = NFPROTO_IPV6, | ||
| 331 | .match = l2tp_mt6, | ||
| 332 | .matchsize = XT_ALIGN(sizeof(struct xt_l2tp_info)), | ||
| 333 | .checkentry = l2tp_mt_check6, | ||
| 334 | .hooks = ((1 << NF_INET_PRE_ROUTING) | | ||
| 335 | (1 << NF_INET_LOCAL_IN) | | ||
| 336 | (1 << NF_INET_LOCAL_OUT) | | ||
| 337 | (1 << NF_INET_FORWARD)), | ||
| 338 | .me = THIS_MODULE, | ||
| 339 | }, | ||
| 340 | #endif | ||
| 341 | }; | ||
| 342 | |||
| 343 | static int __init l2tp_mt_init(void) | ||
| 344 | { | ||
| 345 | return xt_register_matches(&l2tp_mt_reg[0], ARRAY_SIZE(l2tp_mt_reg)); | ||
| 346 | } | ||
| 347 | |||
| 348 | static void __exit l2tp_mt_exit(void) | ||
| 349 | { | ||
| 350 | xt_unregister_matches(&l2tp_mt_reg[0], ARRAY_SIZE(l2tp_mt_reg)); | ||
| 351 | } | ||
| 352 | |||
| 353 | module_init(l2tp_mt_init); | ||
| 354 | module_exit(l2tp_mt_exit); | ||
diff --git a/net/netfilter/xt_osf.c b/net/netfilter/xt_osf.c index 647d989a01e6..7174611bd672 100644 --- a/net/netfilter/xt_osf.c +++ b/net/netfilter/xt_osf.c | |||
| @@ -13,8 +13,7 @@ | |||
| 13 | * GNU General Public License for more details. | 13 | * GNU General Public License for more details. |
| 14 | * | 14 | * |
| 15 | * You should have received a copy of the GNU General Public License | 15 | * You should have received a copy of the GNU General Public License |
| 16 | * along with this program; if not, write to the Free Software | 16 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 18 | */ | 17 | */ |
| 19 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | 18 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
| 20 | #include <linux/module.h> | 19 | #include <linux/module.h> |
diff --git a/net/netfilter/xt_statistic.c b/net/netfilter/xt_statistic.c index 4fe4fb4276d0..11de55e7a868 100644 --- a/net/netfilter/xt_statistic.c +++ b/net/netfilter/xt_statistic.c | |||
| @@ -37,7 +37,7 @@ statistic_mt(const struct sk_buff *skb, struct xt_action_param *par) | |||
| 37 | 37 | ||
| 38 | switch (info->mode) { | 38 | switch (info->mode) { |
| 39 | case XT_STATISTIC_MODE_RANDOM: | 39 | case XT_STATISTIC_MODE_RANDOM: |
| 40 | if ((net_random() & 0x7FFFFFFF) < info->u.random.probability) | 40 | if ((prandom_u32() & 0x7FFFFFFF) < info->u.random.probability) |
| 41 | ret = !ret; | 41 | ret = !ret; |
| 42 | break; | 42 | break; |
| 43 | case XT_STATISTIC_MODE_NTH: | 43 | case XT_STATISTIC_MODE_NTH: |
diff --git a/net/netlabel/netlabel_addrlist.c b/net/netlabel/netlabel_addrlist.c index 6f1701322fb6..d0a3acfa5742 100644 --- a/net/netlabel/netlabel_addrlist.c +++ b/net/netlabel/netlabel_addrlist.c | |||
| @@ -24,8 +24,7 @@ | |||
| 24 | * the GNU General Public License for more details. | 24 | * the GNU General Public License for more details. |
| 25 | * | 25 | * |
| 26 | * You should have received a copy of the GNU General Public License | 26 | * You should have received a copy of the GNU General Public License |
| 27 | * along with this program; if not, write to the Free Software | 27 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 28 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 29 | * | 28 | * |
| 30 | */ | 29 | */ |
| 31 | 30 | ||
diff --git a/net/netlabel/netlabel_addrlist.h b/net/netlabel/netlabel_addrlist.h index a1287ce18130..d0f38bc9af6d 100644 --- a/net/netlabel/netlabel_addrlist.h +++ b/net/netlabel/netlabel_addrlist.h | |||
| @@ -24,8 +24,7 @@ | |||
| 24 | * the GNU General Public License for more details. | 24 | * the GNU General Public License for more details. |
| 25 | * | 25 | * |
| 26 | * You should have received a copy of the GNU General Public License | 26 | * You should have received a copy of the GNU General Public License |
| 27 | * along with this program; if not, write to the Free Software | 27 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 28 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 29 | * | 28 | * |
| 30 | */ | 29 | */ |
| 31 | 30 | ||
diff --git a/net/netlabel/netlabel_cipso_v4.c b/net/netlabel/netlabel_cipso_v4.c index 69345cebe3a3..c2f2a53a4879 100644 --- a/net/netlabel/netlabel_cipso_v4.c +++ b/net/netlabel/netlabel_cipso_v4.c | |||
| @@ -23,8 +23,7 @@ | |||
| 23 | * the GNU General Public License for more details. | 23 | * the GNU General Public License for more details. |
| 24 | * | 24 | * |
| 25 | * You should have received a copy of the GNU General Public License | 25 | * You should have received a copy of the GNU General Public License |
| 26 | * along with this program; if not, write to the Free Software | 26 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 27 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 28 | * | 27 | * |
| 29 | */ | 28 | */ |
| 30 | 29 | ||
diff --git a/net/netlabel/netlabel_cipso_v4.h b/net/netlabel/netlabel_cipso_v4.h index d24d774bfd62..875826808b00 100644 --- a/net/netlabel/netlabel_cipso_v4.h +++ b/net/netlabel/netlabel_cipso_v4.h | |||
| @@ -23,8 +23,7 @@ | |||
| 23 | * the GNU General Public License for more details. | 23 | * the GNU General Public License for more details. |
| 24 | * | 24 | * |
| 25 | * You should have received a copy of the GNU General Public License | 25 | * You should have received a copy of the GNU General Public License |
| 26 | * along with this program; if not, write to the Free Software | 26 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 27 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 28 | * | 27 | * |
| 29 | */ | 28 | */ |
| 30 | 29 | ||
diff --git a/net/netlabel/netlabel_domainhash.c b/net/netlabel/netlabel_domainhash.c index 85d842e6e431..f0cb92f3ddaf 100644 --- a/net/netlabel/netlabel_domainhash.c +++ b/net/netlabel/netlabel_domainhash.c | |||
| @@ -24,8 +24,7 @@ | |||
| 24 | * the GNU General Public License for more details. | 24 | * the GNU General Public License for more details. |
| 25 | * | 25 | * |
| 26 | * You should have received a copy of the GNU General Public License | 26 | * You should have received a copy of the GNU General Public License |
| 27 | * along with this program; if not, write to the Free Software | 27 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 28 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 29 | * | 28 | * |
| 30 | */ | 29 | */ |
| 31 | 30 | ||
diff --git a/net/netlabel/netlabel_domainhash.h b/net/netlabel/netlabel_domainhash.h index b9be0eed8980..680caf4dff56 100644 --- a/net/netlabel/netlabel_domainhash.h +++ b/net/netlabel/netlabel_domainhash.h | |||
| @@ -24,8 +24,7 @@ | |||
| 24 | * the GNU General Public License for more details. | 24 | * the GNU General Public License for more details. |
| 25 | * | 25 | * |
| 26 | * You should have received a copy of the GNU General Public License | 26 | * You should have received a copy of the GNU General Public License |
| 27 | * along with this program; if not, write to the Free Software | 27 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 28 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 29 | * | 28 | * |
| 30 | */ | 29 | */ |
| 31 | 30 | ||
diff --git a/net/netlabel/netlabel_kapi.c b/net/netlabel/netlabel_kapi.c index dce1bebf7aec..3045a964f39c 100644 --- a/net/netlabel/netlabel_kapi.c +++ b/net/netlabel/netlabel_kapi.c | |||
| @@ -23,8 +23,7 @@ | |||
| 23 | * the GNU General Public License for more details. | 23 | * the GNU General Public License for more details. |
| 24 | * | 24 | * |
| 25 | * You should have received a copy of the GNU General Public License | 25 | * You should have received a copy of the GNU General Public License |
| 26 | * along with this program; if not, write to the Free Software | 26 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 27 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 28 | * | 27 | * |
| 29 | */ | 28 | */ |
| 30 | 29 | ||
diff --git a/net/netlabel/netlabel_mgmt.c b/net/netlabel/netlabel_mgmt.c index 8ef83ee97c6a..e66e977ef2fa 100644 --- a/net/netlabel/netlabel_mgmt.c +++ b/net/netlabel/netlabel_mgmt.c | |||
| @@ -23,8 +23,7 @@ | |||
| 23 | * the GNU General Public License for more details. | 23 | * the GNU General Public License for more details. |
| 24 | * | 24 | * |
| 25 | * You should have received a copy of the GNU General Public License | 25 | * You should have received a copy of the GNU General Public License |
| 26 | * along with this program; if not, write to the Free Software | 26 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 27 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 28 | * | 27 | * |
| 29 | */ | 28 | */ |
| 30 | 29 | ||
diff --git a/net/netlabel/netlabel_mgmt.h b/net/netlabel/netlabel_mgmt.h index 5a9f31ce5799..8b6e1ab62b48 100644 --- a/net/netlabel/netlabel_mgmt.h +++ b/net/netlabel/netlabel_mgmt.h | |||
| @@ -23,8 +23,7 @@ | |||
| 23 | * the GNU General Public License for more details. | 23 | * the GNU General Public License for more details. |
| 24 | * | 24 | * |
| 25 | * You should have received a copy of the GNU General Public License | 25 | * You should have received a copy of the GNU General Public License |
| 26 | * along with this program; if not, write to the Free Software | 26 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 27 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 28 | * | 27 | * |
| 29 | */ | 28 | */ |
| 30 | 29 | ||
diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c index 43817d73ccf9..78a63c18779e 100644 --- a/net/netlabel/netlabel_unlabeled.c +++ b/net/netlabel/netlabel_unlabeled.c | |||
| @@ -23,8 +23,7 @@ | |||
| 23 | * the GNU General Public License for more details. | 23 | * the GNU General Public License for more details. |
| 24 | * | 24 | * |
| 25 | * You should have received a copy of the GNU General Public License | 25 | * You should have received a copy of the GNU General Public License |
| 26 | * along with this program; if not, write to the Free Software | 26 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 27 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 28 | * | 27 | * |
| 29 | */ | 28 | */ |
| 30 | 29 | ||
diff --git a/net/netlabel/netlabel_unlabeled.h b/net/netlabel/netlabel_unlabeled.h index 700af49022a0..3a9e5dc9511b 100644 --- a/net/netlabel/netlabel_unlabeled.h +++ b/net/netlabel/netlabel_unlabeled.h | |||
| @@ -23,8 +23,7 @@ | |||
| 23 | * the GNU General Public License for more details. | 23 | * the GNU General Public License for more details. |
| 24 | * | 24 | * |
| 25 | * You should have received a copy of the GNU General Public License | 25 | * You should have received a copy of the GNU General Public License |
| 26 | * along with this program; if not, write to the Free Software | 26 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 27 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 28 | * | 27 | * |
| 29 | */ | 28 | */ |
| 30 | 29 | ||
diff --git a/net/netlabel/netlabel_user.c b/net/netlabel/netlabel_user.c index 9650c4ad5f88..1e779bb7fa43 100644 --- a/net/netlabel/netlabel_user.c +++ b/net/netlabel/netlabel_user.c | |||
| @@ -23,8 +23,7 @@ | |||
| 23 | * the GNU General Public License for more details. | 23 | * the GNU General Public License for more details. |
| 24 | * | 24 | * |
| 25 | * You should have received a copy of the GNU General Public License | 25 | * You should have received a copy of the GNU General Public License |
| 26 | * along with this program; if not, write to the Free Software | 26 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 27 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 28 | * | 27 | * |
| 29 | */ | 28 | */ |
| 30 | 29 | ||
diff --git a/net/netlabel/netlabel_user.h b/net/netlabel/netlabel_user.h index 81969785e279..4a397cde1a48 100644 --- a/net/netlabel/netlabel_user.h +++ b/net/netlabel/netlabel_user.h | |||
| @@ -23,8 +23,7 @@ | |||
| 23 | * the GNU General Public License for more details. | 23 | * the GNU General Public License for more details. |
| 24 | * | 24 | * |
| 25 | * You should have received a copy of the GNU General Public License | 25 | * You should have received a copy of the GNU General Public License |
| 26 | * along with this program; if not, write to the Free Software | 26 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 27 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 28 | * | 27 | * |
| 29 | */ | 28 | */ |
| 30 | 29 | ||
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index bca50b95c182..fdf51353cf78 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c | |||
| @@ -131,7 +131,7 @@ int netlink_add_tap(struct netlink_tap *nt) | |||
| 131 | } | 131 | } |
| 132 | EXPORT_SYMBOL_GPL(netlink_add_tap); | 132 | EXPORT_SYMBOL_GPL(netlink_add_tap); |
| 133 | 133 | ||
| 134 | int __netlink_remove_tap(struct netlink_tap *nt) | 134 | static int __netlink_remove_tap(struct netlink_tap *nt) |
| 135 | { | 135 | { |
| 136 | bool found = false; | 136 | bool found = false; |
| 137 | struct netlink_tap *tmp; | 137 | struct netlink_tap *tmp; |
| @@ -155,7 +155,6 @@ out: | |||
| 155 | 155 | ||
| 156 | return found ? 0 : -ENODEV; | 156 | return found ? 0 : -ENODEV; |
| 157 | } | 157 | } |
| 158 | EXPORT_SYMBOL_GPL(__netlink_remove_tap); | ||
| 159 | 158 | ||
| 160 | int netlink_remove_tap(struct netlink_tap *nt) | 159 | int netlink_remove_tap(struct netlink_tap *nt) |
| 161 | { | 160 | { |
| @@ -204,6 +203,8 @@ static int __netlink_deliver_tap_skb(struct sk_buff *skb, | |||
| 204 | if (nskb) { | 203 | if (nskb) { |
| 205 | nskb->dev = dev; | 204 | nskb->dev = dev; |
| 206 | nskb->protocol = htons((u16) sk->sk_protocol); | 205 | nskb->protocol = htons((u16) sk->sk_protocol); |
| 206 | nskb->pkt_type = netlink_is_kernel(sk) ? | ||
| 207 | PACKET_KERNEL : PACKET_USER; | ||
| 207 | 208 | ||
| 208 | ret = dev_queue_xmit(nskb); | 209 | ret = dev_queue_xmit(nskb); |
| 209 | if (unlikely(ret > 0)) | 210 | if (unlikely(ret > 0)) |
| @@ -239,6 +240,13 @@ static void netlink_deliver_tap(struct sk_buff *skb) | |||
| 239 | rcu_read_unlock(); | 240 | rcu_read_unlock(); |
| 240 | } | 241 | } |
| 241 | 242 | ||
| 243 | static void netlink_deliver_tap_kernel(struct sock *dst, struct sock *src, | ||
| 244 | struct sk_buff *skb) | ||
| 245 | { | ||
| 246 | if (!(netlink_is_kernel(dst) && netlink_is_kernel(src))) | ||
| 247 | netlink_deliver_tap(skb); | ||
| 248 | } | ||
| 249 | |||
| 242 | static void netlink_overrun(struct sock *sk) | 250 | static void netlink_overrun(struct sock *sk) |
| 243 | { | 251 | { |
| 244 | struct netlink_sock *nlk = nlk_sk(sk); | 252 | struct netlink_sock *nlk = nlk_sk(sk); |
| @@ -1697,14 +1705,10 @@ static int netlink_unicast_kernel(struct sock *sk, struct sk_buff *skb, | |||
| 1697 | 1705 | ||
| 1698 | ret = -ECONNREFUSED; | 1706 | ret = -ECONNREFUSED; |
| 1699 | if (nlk->netlink_rcv != NULL) { | 1707 | if (nlk->netlink_rcv != NULL) { |
| 1700 | /* We could do a netlink_deliver_tap(skb) here as well | ||
| 1701 | * but since this is intended for the kernel only, we | ||
| 1702 | * should rather let it stay under the hood. | ||
| 1703 | */ | ||
| 1704 | |||
| 1705 | ret = skb->len; | 1708 | ret = skb->len; |
| 1706 | netlink_skb_set_owner_r(skb, sk); | 1709 | netlink_skb_set_owner_r(skb, sk); |
| 1707 | NETLINK_CB(skb).sk = ssk; | 1710 | NETLINK_CB(skb).sk = ssk; |
| 1711 | netlink_deliver_tap_kernel(sk, ssk, skb); | ||
| 1708 | nlk->netlink_rcv(skb); | 1712 | nlk->netlink_rcv(skb); |
| 1709 | consume_skb(skb); | 1713 | consume_skb(skb); |
| 1710 | } else { | 1714 | } else { |
| @@ -1769,6 +1773,9 @@ struct sk_buff *netlink_alloc_skb(struct sock *ssk, unsigned int size, | |||
| 1769 | if (ring->pg_vec == NULL) | 1773 | if (ring->pg_vec == NULL) |
| 1770 | goto out_put; | 1774 | goto out_put; |
| 1771 | 1775 | ||
| 1776 | if (ring->frame_size - NL_MMAP_HDRLEN < size) | ||
| 1777 | goto out_put; | ||
| 1778 | |||
| 1772 | skb = alloc_skb_head(gfp_mask); | 1779 | skb = alloc_skb_head(gfp_mask); |
| 1773 | if (skb == NULL) | 1780 | if (skb == NULL) |
| 1774 | goto err1; | 1781 | goto err1; |
| @@ -1778,6 +1785,7 @@ struct sk_buff *netlink_alloc_skb(struct sock *ssk, unsigned int size, | |||
| 1778 | if (ring->pg_vec == NULL) | 1785 | if (ring->pg_vec == NULL) |
| 1779 | goto out_free; | 1786 | goto out_free; |
| 1780 | 1787 | ||
| 1788 | /* check again under lock */ | ||
| 1781 | maxlen = ring->frame_size - NL_MMAP_HDRLEN; | 1789 | maxlen = ring->frame_size - NL_MMAP_HDRLEN; |
| 1782 | if (maxlen < size) | 1790 | if (maxlen < size) |
| 1783 | goto out_free; | 1791 | goto out_free; |
| @@ -2214,7 +2222,7 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock, | |||
| 2214 | struct sock_iocb *siocb = kiocb_to_siocb(kiocb); | 2222 | struct sock_iocb *siocb = kiocb_to_siocb(kiocb); |
| 2215 | struct sock *sk = sock->sk; | 2223 | struct sock *sk = sock->sk; |
| 2216 | struct netlink_sock *nlk = nlk_sk(sk); | 2224 | struct netlink_sock *nlk = nlk_sk(sk); |
| 2217 | struct sockaddr_nl *addr = msg->msg_name; | 2225 | DECLARE_SOCKADDR(struct sockaddr_nl *, addr, msg->msg_name); |
| 2218 | u32 dst_portid; | 2226 | u32 dst_portid; |
| 2219 | u32 dst_group; | 2227 | u32 dst_group; |
| 2220 | struct sk_buff *skb; | 2228 | struct sk_buff *skb; |
| @@ -2345,7 +2353,7 @@ static int netlink_recvmsg(struct kiocb *kiocb, struct socket *sock, | |||
| 2345 | err = skb_copy_datagram_iovec(data_skb, 0, msg->msg_iov, copied); | 2353 | err = skb_copy_datagram_iovec(data_skb, 0, msg->msg_iov, copied); |
| 2346 | 2354 | ||
| 2347 | if (msg->msg_name) { | 2355 | if (msg->msg_name) { |
| 2348 | struct sockaddr_nl *addr = (struct sockaddr_nl *)msg->msg_name; | 2356 | DECLARE_SOCKADDR(struct sockaddr_nl *, addr, msg->msg_name); |
| 2349 | addr->nl_family = AF_NETLINK; | 2357 | addr->nl_family = AF_NETLINK; |
| 2350 | addr->nl_pad = 0; | 2358 | addr->nl_pad = 0; |
| 2351 | addr->nl_pid = NETLINK_CB(skb).portid; | 2359 | addr->nl_pid = NETLINK_CB(skb).portid; |
| @@ -2535,21 +2543,6 @@ void __netlink_clear_multicast_users(struct sock *ksk, unsigned int group) | |||
| 2535 | netlink_update_socket_mc(nlk_sk(sk), group, 0); | 2543 | netlink_update_socket_mc(nlk_sk(sk), group, 0); |
| 2536 | } | 2544 | } |
| 2537 | 2545 | ||
| 2538 | /** | ||
| 2539 | * netlink_clear_multicast_users - kick off multicast listeners | ||
| 2540 | * | ||
| 2541 | * This function removes all listeners from the given group. | ||
| 2542 | * @ksk: The kernel netlink socket, as returned by | ||
| 2543 | * netlink_kernel_create(). | ||
| 2544 | * @group: The multicast group to clear. | ||
| 2545 | */ | ||
| 2546 | void netlink_clear_multicast_users(struct sock *ksk, unsigned int group) | ||
| 2547 | { | ||
| 2548 | netlink_table_grab(); | ||
| 2549 | __netlink_clear_multicast_users(ksk, group); | ||
| 2550 | netlink_table_ungrab(); | ||
| 2551 | } | ||
| 2552 | |||
| 2553 | struct nlmsghdr * | 2546 | struct nlmsghdr * |
| 2554 | __nlmsg_put(struct sk_buff *skb, u32 portid, u32 seq, int type, int len, int flags) | 2547 | __nlmsg_put(struct sk_buff *skb, u32 portid, u32 seq, int type, int len, int flags) |
| 2555 | { | 2548 | { |
diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c index 713671ae45af..b1dcdb932a86 100644 --- a/net/netlink/genetlink.c +++ b/net/netlink/genetlink.c | |||
| @@ -461,6 +461,26 @@ int genl_unregister_family(struct genl_family *family) | |||
| 461 | EXPORT_SYMBOL(genl_unregister_family); | 461 | EXPORT_SYMBOL(genl_unregister_family); |
| 462 | 462 | ||
| 463 | /** | 463 | /** |
| 464 | * genlmsg_new_unicast - Allocate generic netlink message for unicast | ||
| 465 | * @payload: size of the message payload | ||
| 466 | * @info: information on destination | ||
| 467 | * @flags: the type of memory to allocate | ||
| 468 | * | ||
| 469 | * Allocates a new sk_buff large enough to cover the specified payload | ||
| 470 | * plus required Netlink headers. Will check receiving socket for | ||
| 471 | * memory mapped i/o capability and use it if enabled. Will fall back | ||
| 472 | * to non-mapped skb if message size exceeds the frame size of the ring. | ||
| 473 | */ | ||
| 474 | struct sk_buff *genlmsg_new_unicast(size_t payload, struct genl_info *info, | ||
| 475 | gfp_t flags) | ||
| 476 | { | ||
| 477 | size_t len = nlmsg_total_size(genlmsg_total_size(payload)); | ||
| 478 | |||
| 479 | return netlink_alloc_skb(info->dst_sk, len, info->snd_portid, flags); | ||
| 480 | } | ||
| 481 | EXPORT_SYMBOL_GPL(genlmsg_new_unicast); | ||
| 482 | |||
| 483 | /** | ||
| 464 | * genlmsg_put - Add generic netlink header to netlink message | 484 | * genlmsg_put - Add generic netlink header to netlink message |
| 465 | * @skb: socket buffer holding the message | 485 | * @skb: socket buffer holding the message |
| 466 | * @portid: netlink portid the message is addressed to | 486 | * @portid: netlink portid the message is addressed to |
| @@ -600,6 +620,7 @@ static int genl_family_rcv_msg(struct genl_family *family, | |||
| 600 | info.genlhdr = nlmsg_data(nlh); | 620 | info.genlhdr = nlmsg_data(nlh); |
| 601 | info.userhdr = nlmsg_data(nlh) + GENL_HDRLEN; | 621 | info.userhdr = nlmsg_data(nlh) + GENL_HDRLEN; |
| 602 | info.attrs = attrbuf; | 622 | info.attrs = attrbuf; |
| 623 | info.dst_sk = skb->sk; | ||
| 603 | genl_info_net_set(&info, net); | 624 | genl_info_net_set(&info, net); |
| 604 | memset(&info.user_ptr, 0, sizeof(info.user_ptr)); | 625 | memset(&info.user_ptr, 0, sizeof(info.user_ptr)); |
| 605 | 626 | ||
diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c index 53c19a35fc6d..b74aa0755521 100644 --- a/net/netrom/af_netrom.c +++ b/net/netrom/af_netrom.c | |||
| @@ -1028,7 +1028,7 @@ static int nr_sendmsg(struct kiocb *iocb, struct socket *sock, | |||
| 1028 | { | 1028 | { |
| 1029 | struct sock *sk = sock->sk; | 1029 | struct sock *sk = sock->sk; |
| 1030 | struct nr_sock *nr = nr_sk(sk); | 1030 | struct nr_sock *nr = nr_sk(sk); |
| 1031 | struct sockaddr_ax25 *usax = (struct sockaddr_ax25 *)msg->msg_name; | 1031 | DECLARE_SOCKADDR(struct sockaddr_ax25 *, usax, msg->msg_name); |
| 1032 | int err; | 1032 | int err; |
| 1033 | struct sockaddr_ax25 sax; | 1033 | struct sockaddr_ax25 sax; |
| 1034 | struct sk_buff *skb; | 1034 | struct sk_buff *skb; |
| @@ -1137,7 +1137,7 @@ static int nr_recvmsg(struct kiocb *iocb, struct socket *sock, | |||
| 1137 | struct msghdr *msg, size_t size, int flags) | 1137 | struct msghdr *msg, size_t size, int flags) |
| 1138 | { | 1138 | { |
| 1139 | struct sock *sk = sock->sk; | 1139 | struct sock *sk = sock->sk; |
| 1140 | struct sockaddr_ax25 *sax = (struct sockaddr_ax25 *)msg->msg_name; | 1140 | DECLARE_SOCKADDR(struct sockaddr_ax25 *, sax, msg->msg_name); |
| 1141 | size_t copied; | 1141 | size_t copied; |
| 1142 | struct sk_buff *skb; | 1142 | struct sk_buff *skb; |
| 1143 | int er; | 1143 | int er; |
diff --git a/net/nfc/af_nfc.c b/net/nfc/af_nfc.c index 9d68441e2a5a..2277276f52bc 100644 --- a/net/nfc/af_nfc.c +++ b/net/nfc/af_nfc.c | |||
| @@ -16,9 +16,7 @@ | |||
| 16 | * GNU General Public License for more details. | 16 | * GNU General Public License for more details. |
| 17 | * | 17 | * |
| 18 | * You should have received a copy of the GNU General Public License | 18 | * You should have received a copy of the GNU General Public License |
| 19 | * along with this program; if not, write to the | 19 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 20 | * Free Software Foundation, Inc., | ||
| 21 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
| 22 | */ | 20 | */ |
| 23 | 21 | ||
| 24 | #include <linux/nfc.h> | 22 | #include <linux/nfc.h> |
diff --git a/net/nfc/core.c b/net/nfc/core.c index 83b9927e7d19..ca1e65f4b133 100644 --- a/net/nfc/core.c +++ b/net/nfc/core.c | |||
| @@ -16,9 +16,7 @@ | |||
| 16 | * GNU General Public License for more details. | 16 | * GNU General Public License for more details. |
| 17 | * | 17 | * |
| 18 | * You should have received a copy of the GNU General Public License | 18 | * You should have received a copy of the GNU General Public License |
| 19 | * along with this program; if not, write to the | 19 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 20 | * Free Software Foundation, Inc., | ||
| 21 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
| 22 | */ | 20 | */ |
| 23 | 21 | ||
| 24 | #define pr_fmt(fmt) KBUILD_MODNAME ": %s: " fmt, __func__ | 22 | #define pr_fmt(fmt) KBUILD_MODNAME ": %s: " fmt, __func__ |
| @@ -135,11 +133,8 @@ int nfc_dev_up(struct nfc_dev *dev) | |||
| 135 | dev->dev_up = true; | 133 | dev->dev_up = true; |
| 136 | 134 | ||
| 137 | /* We have to enable the device before discovering SEs */ | 135 | /* We have to enable the device before discovering SEs */ |
| 138 | if (dev->ops->discover_se) { | 136 | if (dev->ops->discover_se && dev->ops->discover_se(dev)) |
| 139 | rc = dev->ops->discover_se(dev); | 137 | pr_err("SE discovery failed\n"); |
| 140 | if (rc) | ||
| 141 | pr_warn("SE discovery failed\n"); | ||
| 142 | } | ||
| 143 | 138 | ||
| 144 | error: | 139 | error: |
| 145 | device_unlock(&dev->dev); | 140 | device_unlock(&dev->dev); |
diff --git a/net/nfc/digital_core.c b/net/nfc/digital_core.c index 09fc95439955..c129d1571ca6 100644 --- a/net/nfc/digital_core.c +++ b/net/nfc/digital_core.c | |||
| @@ -339,7 +339,6 @@ int digital_target_found(struct nfc_digital_dev *ddev, | |||
| 339 | pr_debug("rf_tech=%d, protocol=%d\n", rf_tech, protocol); | 339 | pr_debug("rf_tech=%d, protocol=%d\n", rf_tech, protocol); |
| 340 | 340 | ||
| 341 | ddev->curr_rf_tech = rf_tech; | 341 | ddev->curr_rf_tech = rf_tech; |
| 342 | ddev->curr_protocol = protocol; | ||
| 343 | 342 | ||
| 344 | if (DIGITAL_DRV_CAPS_IN_CRC(ddev)) { | 343 | if (DIGITAL_DRV_CAPS_IN_CRC(ddev)) { |
| 345 | ddev->skb_add_crc = digital_skb_add_crc_none; | 344 | ddev->skb_add_crc = digital_skb_add_crc_none; |
| @@ -541,8 +540,14 @@ static int digital_dep_link_up(struct nfc_dev *nfc_dev, | |||
| 541 | __u8 comm_mode, __u8 *gb, size_t gb_len) | 540 | __u8 comm_mode, __u8 *gb, size_t gb_len) |
| 542 | { | 541 | { |
| 543 | struct nfc_digital_dev *ddev = nfc_get_drvdata(nfc_dev); | 542 | struct nfc_digital_dev *ddev = nfc_get_drvdata(nfc_dev); |
| 543 | int rc; | ||
| 544 | |||
| 545 | rc = digital_in_send_atr_req(ddev, target, comm_mode, gb, gb_len); | ||
| 544 | 546 | ||
| 545 | return digital_in_send_atr_req(ddev, target, comm_mode, gb, gb_len); | 547 | if (!rc) |
| 548 | ddev->curr_protocol = NFC_PROTO_NFC_DEP; | ||
| 549 | |||
| 550 | return rc; | ||
| 546 | } | 551 | } |
| 547 | 552 | ||
| 548 | static int digital_dep_link_down(struct nfc_dev *nfc_dev) | 553 | static int digital_dep_link_down(struct nfc_dev *nfc_dev) |
| @@ -557,6 +562,20 @@ static int digital_dep_link_down(struct nfc_dev *nfc_dev) | |||
| 557 | static int digital_activate_target(struct nfc_dev *nfc_dev, | 562 | static int digital_activate_target(struct nfc_dev *nfc_dev, |
| 558 | struct nfc_target *target, __u32 protocol) | 563 | struct nfc_target *target, __u32 protocol) |
| 559 | { | 564 | { |
| 565 | struct nfc_digital_dev *ddev = nfc_get_drvdata(nfc_dev); | ||
| 566 | |||
| 567 | if (ddev->poll_tech_count) { | ||
| 568 | pr_err("Can't activate a target while polling\n"); | ||
| 569 | return -EBUSY; | ||
| 570 | } | ||
| 571 | |||
| 572 | if (ddev->curr_protocol) { | ||
| 573 | pr_err("A target is already active\n"); | ||
| 574 | return -EBUSY; | ||
| 575 | } | ||
| 576 | |||
| 577 | ddev->curr_protocol = protocol; | ||
| 578 | |||
| 560 | return 0; | 579 | return 0; |
| 561 | } | 580 | } |
| 562 | 581 | ||
| @@ -565,6 +584,11 @@ static void digital_deactivate_target(struct nfc_dev *nfc_dev, | |||
| 565 | { | 584 | { |
| 566 | struct nfc_digital_dev *ddev = nfc_get_drvdata(nfc_dev); | 585 | struct nfc_digital_dev *ddev = nfc_get_drvdata(nfc_dev); |
| 567 | 586 | ||
| 587 | if (!ddev->curr_protocol) { | ||
| 588 | pr_err("No active target\n"); | ||
| 589 | return; | ||
| 590 | } | ||
| 591 | |||
| 568 | ddev->curr_protocol = 0; | 592 | ddev->curr_protocol = 0; |
| 569 | } | 593 | } |
| 570 | 594 | ||
diff --git a/net/nfc/digital_dep.c b/net/nfc/digital_dep.c index 07bbc24fb4c7..d4ed25ff723f 100644 --- a/net/nfc/digital_dep.c +++ b/net/nfc/digital_dep.c | |||
| @@ -32,7 +32,6 @@ | |||
| 32 | #define DIGITAL_ATR_REQ_MIN_SIZE 16 | 32 | #define DIGITAL_ATR_REQ_MIN_SIZE 16 |
| 33 | #define DIGITAL_ATR_REQ_MAX_SIZE 64 | 33 | #define DIGITAL_ATR_REQ_MAX_SIZE 64 |
| 34 | 34 | ||
| 35 | #define DIGITAL_NFCID3_LEN ((u8)8) | ||
| 36 | #define DIGITAL_LR_BITS_PAYLOAD_SIZE_254B 0x30 | 35 | #define DIGITAL_LR_BITS_PAYLOAD_SIZE_254B 0x30 |
| 37 | #define DIGITAL_GB_BIT 0x02 | 36 | #define DIGITAL_GB_BIT 0x02 |
| 38 | 37 | ||
| @@ -206,10 +205,9 @@ int digital_in_send_atr_req(struct nfc_digital_dev *ddev, | |||
| 206 | atr_req->dir = DIGITAL_NFC_DEP_FRAME_DIR_OUT; | 205 | atr_req->dir = DIGITAL_NFC_DEP_FRAME_DIR_OUT; |
| 207 | atr_req->cmd = DIGITAL_CMD_ATR_REQ; | 206 | atr_req->cmd = DIGITAL_CMD_ATR_REQ; |
| 208 | if (target->nfcid2_len) | 207 | if (target->nfcid2_len) |
| 209 | memcpy(atr_req->nfcid3, target->nfcid2, | 208 | memcpy(atr_req->nfcid3, target->nfcid2, NFC_NFCID2_MAXSIZE); |
| 210 | max(target->nfcid2_len, DIGITAL_NFCID3_LEN)); | ||
| 211 | else | 209 | else |
| 212 | get_random_bytes(atr_req->nfcid3, DIGITAL_NFCID3_LEN); | 210 | get_random_bytes(atr_req->nfcid3, NFC_NFCID3_MAXSIZE); |
| 213 | 211 | ||
| 214 | atr_req->did = 0; | 212 | atr_req->did = 0; |
| 215 | atr_req->bs = 0; | 213 | atr_req->bs = 0; |
| @@ -382,6 +380,33 @@ int digital_in_send_dep_req(struct nfc_digital_dev *ddev, | |||
| 382 | data_exch); | 380 | data_exch); |
| 383 | } | 381 | } |
| 384 | 382 | ||
| 383 | static void digital_tg_set_rf_tech(struct nfc_digital_dev *ddev, u8 rf_tech) | ||
| 384 | { | ||
| 385 | ddev->curr_rf_tech = rf_tech; | ||
| 386 | |||
| 387 | ddev->skb_add_crc = digital_skb_add_crc_none; | ||
| 388 | ddev->skb_check_crc = digital_skb_check_crc_none; | ||
| 389 | |||
| 390 | if (DIGITAL_DRV_CAPS_TG_CRC(ddev)) | ||
| 391 | return; | ||
| 392 | |||
| 393 | switch (ddev->curr_rf_tech) { | ||
| 394 | case NFC_DIGITAL_RF_TECH_106A: | ||
| 395 | ddev->skb_add_crc = digital_skb_add_crc_a; | ||
| 396 | ddev->skb_check_crc = digital_skb_check_crc_a; | ||
| 397 | break; | ||
| 398 | |||
| 399 | case NFC_DIGITAL_RF_TECH_212F: | ||
| 400 | case NFC_DIGITAL_RF_TECH_424F: | ||
| 401 | ddev->skb_add_crc = digital_skb_add_crc_f; | ||
| 402 | ddev->skb_check_crc = digital_skb_check_crc_f; | ||
| 403 | break; | ||
| 404 | |||
| 405 | default: | ||
| 406 | break; | ||
| 407 | } | ||
| 408 | } | ||
| 409 | |||
| 385 | static void digital_tg_recv_dep_req(struct nfc_digital_dev *ddev, void *arg, | 410 | static void digital_tg_recv_dep_req(struct nfc_digital_dev *ddev, void *arg, |
| 386 | struct sk_buff *resp) | 411 | struct sk_buff *resp) |
| 387 | { | 412 | { |
| @@ -472,11 +497,13 @@ int digital_tg_send_dep_res(struct nfc_digital_dev *ddev, struct sk_buff *skb) | |||
| 472 | static void digital_tg_send_psl_res_complete(struct nfc_digital_dev *ddev, | 497 | static void digital_tg_send_psl_res_complete(struct nfc_digital_dev *ddev, |
| 473 | void *arg, struct sk_buff *resp) | 498 | void *arg, struct sk_buff *resp) |
| 474 | { | 499 | { |
| 475 | u8 rf_tech = PTR_ERR(arg); | 500 | u8 rf_tech = (unsigned long)arg; |
| 476 | 501 | ||
| 477 | if (IS_ERR(resp)) | 502 | if (IS_ERR(resp)) |
| 478 | return; | 503 | return; |
| 479 | 504 | ||
| 505 | digital_tg_set_rf_tech(ddev, rf_tech); | ||
| 506 | |||
| 480 | digital_tg_configure_hw(ddev, NFC_DIGITAL_CONFIG_RF_TECH, rf_tech); | 507 | digital_tg_configure_hw(ddev, NFC_DIGITAL_CONFIG_RF_TECH, rf_tech); |
| 481 | 508 | ||
| 482 | digital_tg_listen(ddev, 1500, digital_tg_recv_dep_req, NULL); | 509 | digital_tg_listen(ddev, 1500, digital_tg_recv_dep_req, NULL); |
| @@ -508,7 +535,7 @@ static int digital_tg_send_psl_res(struct nfc_digital_dev *ddev, u8 did, | |||
| 508 | ddev->skb_add_crc(skb); | 535 | ddev->skb_add_crc(skb); |
| 509 | 536 | ||
| 510 | rc = digital_tg_send_cmd(ddev, skb, 0, digital_tg_send_psl_res_complete, | 537 | rc = digital_tg_send_cmd(ddev, skb, 0, digital_tg_send_psl_res_complete, |
| 511 | ERR_PTR(rf_tech)); | 538 | (void *)(unsigned long)rf_tech); |
| 512 | 539 | ||
| 513 | if (rc) | 540 | if (rc) |
| 514 | kfree_skb(skb); | 541 | kfree_skb(skb); |
| @@ -563,7 +590,7 @@ static void digital_tg_recv_psl_req(struct nfc_digital_dev *ddev, void *arg, | |||
| 563 | rf_tech = NFC_DIGITAL_RF_TECH_424F; | 590 | rf_tech = NFC_DIGITAL_RF_TECH_424F; |
| 564 | break; | 591 | break; |
| 565 | default: | 592 | default: |
| 566 | pr_err("Unsuported dsi value %d\n", dsi); | 593 | pr_err("Unsupported dsi value %d\n", dsi); |
| 567 | goto exit; | 594 | goto exit; |
| 568 | } | 595 | } |
| 569 | 596 | ||
| @@ -661,16 +688,10 @@ void digital_tg_recv_atr_req(struct nfc_digital_dev *ddev, void *arg, | |||
| 661 | 688 | ||
| 662 | if (resp->data[0] == DIGITAL_NFC_DEP_NFCA_SOD_SB) { | 689 | if (resp->data[0] == DIGITAL_NFC_DEP_NFCA_SOD_SB) { |
| 663 | min_size = DIGITAL_ATR_REQ_MIN_SIZE + 2; | 690 | min_size = DIGITAL_ATR_REQ_MIN_SIZE + 2; |
| 664 | 691 | digital_tg_set_rf_tech(ddev, NFC_DIGITAL_RF_TECH_106A); | |
| 665 | ddev->curr_rf_tech = NFC_DIGITAL_RF_TECH_106A; | ||
| 666 | ddev->skb_add_crc = digital_skb_add_crc_a; | ||
| 667 | ddev->skb_check_crc = digital_skb_check_crc_a; | ||
| 668 | } else { | 692 | } else { |
| 669 | min_size = DIGITAL_ATR_REQ_MIN_SIZE + 1; | 693 | min_size = DIGITAL_ATR_REQ_MIN_SIZE + 1; |
| 670 | 694 | digital_tg_set_rf_tech(ddev, NFC_DIGITAL_RF_TECH_212F); | |
| 671 | ddev->curr_rf_tech = NFC_DIGITAL_RF_TECH_212F; | ||
| 672 | ddev->skb_add_crc = digital_skb_add_crc_f; | ||
| 673 | ddev->skb_check_crc = digital_skb_check_crc_f; | ||
| 674 | } | 695 | } |
| 675 | 696 | ||
| 676 | if (resp->len < min_size) { | 697 | if (resp->len < min_size) { |
| @@ -678,10 +699,7 @@ void digital_tg_recv_atr_req(struct nfc_digital_dev *ddev, void *arg, | |||
| 678 | goto exit; | 699 | goto exit; |
| 679 | } | 700 | } |
| 680 | 701 | ||
| 681 | if (DIGITAL_DRV_CAPS_TG_CRC(ddev)) { | 702 | ddev->curr_protocol = NFC_PROTO_NFC_DEP_MASK; |
| 682 | ddev->skb_add_crc = digital_skb_add_crc_none; | ||
| 683 | ddev->skb_check_crc = digital_skb_check_crc_none; | ||
| 684 | } | ||
| 685 | 703 | ||
| 686 | rc = ddev->skb_check_crc(resp); | 704 | rc = ddev->skb_check_crc(resp); |
| 687 | if (rc) { | 705 | if (rc) { |
diff --git a/net/nfc/hci/command.c b/net/nfc/hci/command.c index 64f922be9281..a9f4d2e62d8d 100644 --- a/net/nfc/hci/command.c +++ b/net/nfc/hci/command.c | |||
| @@ -12,9 +12,7 @@ | |||
| 12 | * GNU General Public License for more details. | 12 | * GNU General Public License for more details. |
| 13 | * | 13 | * |
| 14 | * You should have received a copy of the GNU General Public License | 14 | * You should have received a copy of the GNU General Public License |
| 15 | * along with this program; if not, write to the | 15 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 16 | * Free Software Foundation, Inc., | ||
| 17 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
| 18 | */ | 16 | */ |
| 19 | 17 | ||
| 20 | #define pr_fmt(fmt) "hci: %s: " fmt, __func__ | 18 | #define pr_fmt(fmt) "hci: %s: " fmt, __func__ |
diff --git a/net/nfc/hci/core.c b/net/nfc/hci/core.c index d07ca4c5cf8c..d45b638e77c7 100644 --- a/net/nfc/hci/core.c +++ b/net/nfc/hci/core.c | |||
| @@ -12,9 +12,7 @@ | |||
| 12 | * GNU General Public License for more details. | 12 | * GNU General Public License for more details. |
| 13 | * | 13 | * |
| 14 | * You should have received a copy of the GNU General Public License | 14 | * You should have received a copy of the GNU General Public License |
| 15 | * along with this program; if not, write to the | 15 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 16 | * Free Software Foundation, Inc., | ||
| 17 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
| 18 | */ | 16 | */ |
| 19 | 17 | ||
| 20 | #define pr_fmt(fmt) "hci: %s: " fmt, __func__ | 18 | #define pr_fmt(fmt) "hci: %s: " fmt, __func__ |
| @@ -337,11 +335,8 @@ exit: | |||
| 337 | kfree_skb(skb); | 335 | kfree_skb(skb); |
| 338 | 336 | ||
| 339 | exit_noskb: | 337 | exit_noskb: |
| 340 | if (r) { | 338 | if (r) |
| 341 | /* TODO: There was an error dispatching the event, | 339 | nfc_hci_driver_failure(hdev, r); |
| 342 | * how to propagate up to nfc core? | ||
| 343 | */ | ||
| 344 | } | ||
| 345 | } | 340 | } |
| 346 | 341 | ||
| 347 | static void nfc_hci_cmd_timeout(unsigned long data) | 342 | static void nfc_hci_cmd_timeout(unsigned long data) |
diff --git a/net/nfc/hci/hci.h b/net/nfc/hci/hci.h index b274d12c18ac..c3d2e2c1394c 100644 --- a/net/nfc/hci/hci.h +++ b/net/nfc/hci/hci.h | |||
| @@ -12,9 +12,7 @@ | |||
| 12 | * GNU General Public License for more details. | 12 | * GNU General Public License for more details. |
| 13 | * | 13 | * |
| 14 | * You should have received a copy of the GNU General Public License | 14 | * You should have received a copy of the GNU General Public License |
| 15 | * along with this program; if not, write to the | 15 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 16 | * Free Software Foundation, Inc., | ||
| 17 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
| 18 | */ | 16 | */ |
| 19 | 17 | ||
| 20 | #ifndef __LOCAL_HCI_H | 18 | #ifndef __LOCAL_HCI_H |
diff --git a/net/nfc/hci/hcp.c b/net/nfc/hci/hcp.c index b6b4109f2343..e9de1514656e 100644 --- a/net/nfc/hci/hcp.c +++ b/net/nfc/hci/hcp.c | |||
| @@ -12,9 +12,7 @@ | |||
| 12 | * GNU General Public License for more details. | 12 | * GNU General Public License for more details. |
| 13 | * | 13 | * |
| 14 | * You should have received a copy of the GNU General Public License | 14 | * You should have received a copy of the GNU General Public License |
| 15 | * along with this program; if not, write to the | 15 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 16 | * Free Software Foundation, Inc., | ||
| 17 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
| 18 | */ | 16 | */ |
| 19 | 17 | ||
| 20 | #define pr_fmt(fmt) "hci: %s: " fmt, __func__ | 18 | #define pr_fmt(fmt) "hci: %s: " fmt, __func__ |
diff --git a/net/nfc/hci/llc.c b/net/nfc/hci/llc.c index fe5e966e5b88..a07d2b818487 100644 --- a/net/nfc/hci/llc.c +++ b/net/nfc/hci/llc.c | |||
| @@ -13,9 +13,7 @@ | |||
| 13 | * GNU General Public License for more details. | 13 | * GNU General Public License for more details. |
| 14 | * | 14 | * |
| 15 | * You should have received a copy of the GNU General Public License | 15 | * You should have received a copy of the GNU General Public License |
| 16 | * along with this program; if not, write to the | 16 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 17 | * Free Software Foundation, Inc., | ||
| 18 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
| 19 | */ | 17 | */ |
| 20 | 18 | ||
| 21 | #include <net/nfc/llc.h> | 19 | #include <net/nfc/llc.h> |
diff --git a/net/nfc/hci/llc.h b/net/nfc/hci/llc.h index 7be0b7f3ceb6..5dad4c57ffb3 100644 --- a/net/nfc/hci/llc.h +++ b/net/nfc/hci/llc.h | |||
| @@ -13,9 +13,7 @@ | |||
| 13 | * GNU General Public License for more details. | 13 | * GNU General Public License for more details. |
| 14 | * | 14 | * |
| 15 | * You should have received a copy of the GNU General Public License | 15 | * You should have received a copy of the GNU General Public License |
| 16 | * along with this program; if not, write to the | 16 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 17 | * Free Software Foundation, Inc., | ||
| 18 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
| 19 | */ | 17 | */ |
| 20 | 18 | ||
| 21 | #ifndef __LOCAL_LLC_H_ | 19 | #ifndef __LOCAL_LLC_H_ |
diff --git a/net/nfc/hci/llc_nop.c b/net/nfc/hci/llc_nop.c index 87b10291b40f..d0435d5a197b 100644 --- a/net/nfc/hci/llc_nop.c +++ b/net/nfc/hci/llc_nop.c | |||
| @@ -13,9 +13,7 @@ | |||
| 13 | * GNU General Public License for more details. | 13 | * GNU General Public License for more details. |
| 14 | * | 14 | * |
| 15 | * You should have received a copy of the GNU General Public License | 15 | * You should have received a copy of the GNU General Public License |
| 16 | * along with this program; if not, write to the | 16 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 17 | * Free Software Foundation, Inc., | ||
| 18 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
| 19 | */ | 17 | */ |
| 20 | 18 | ||
| 21 | #include <linux/types.h> | 19 | #include <linux/types.h> |
diff --git a/net/nfc/hci/llc_shdlc.c b/net/nfc/hci/llc_shdlc.c index 27b313befc35..401c7e255273 100644 --- a/net/nfc/hci/llc_shdlc.c +++ b/net/nfc/hci/llc_shdlc.c | |||
| @@ -13,9 +13,7 @@ | |||
| 13 | * GNU General Public License for more details. | 13 | * GNU General Public License for more details. |
| 14 | * | 14 | * |
| 15 | * You should have received a copy of the GNU General Public License | 15 | * You should have received a copy of the GNU General Public License |
| 16 | * along with this program; if not, write to the | 16 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 17 | * Free Software Foundation, Inc., | ||
| 18 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
| 19 | */ | 17 | */ |
| 20 | 18 | ||
| 21 | #define pr_fmt(fmt) "shdlc: %s: " fmt, __func__ | 19 | #define pr_fmt(fmt) "shdlc: %s: " fmt, __func__ |
| @@ -300,7 +298,7 @@ static void llc_shdlc_rcv_rej(struct llc_shdlc *shdlc, int y_nr) | |||
| 300 | { | 298 | { |
| 301 | struct sk_buff *skb; | 299 | struct sk_buff *skb; |
| 302 | 300 | ||
| 303 | pr_debug("remote asks retransmition from frame %d\n", y_nr); | 301 | pr_debug("remote asks retransmission from frame %d\n", y_nr); |
| 304 | 302 | ||
| 305 | if (llc_shdlc_x_lteq_y_lt_z(shdlc->dnr, y_nr, shdlc->ns)) { | 303 | if (llc_shdlc_x_lteq_y_lt_z(shdlc->dnr, y_nr, shdlc->ns)) { |
| 306 | if (shdlc->t2_active) { | 304 | if (shdlc->t2_active) { |
diff --git a/net/nfc/llcp.h b/net/nfc/llcp.h index f4d48b57ea11..de1789e3cc82 100644 --- a/net/nfc/llcp.h +++ b/net/nfc/llcp.h | |||
| @@ -12,9 +12,7 @@ | |||
| 12 | * GNU General Public License for more details. | 12 | * GNU General Public License for more details. |
| 13 | * | 13 | * |
| 14 | * You should have received a copy of the GNU General Public License | 14 | * You should have received a copy of the GNU General Public License |
| 15 | * along with this program; if not, write to the | 15 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 16 | * Free Software Foundation, Inc., | ||
| 17 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
| 18 | */ | 16 | */ |
| 19 | 17 | ||
| 20 | enum llcp_state { | 18 | enum llcp_state { |
diff --git a/net/nfc/llcp_commands.c b/net/nfc/llcp_commands.c index 1017894807c0..bec6ed15f503 100644 --- a/net/nfc/llcp_commands.c +++ b/net/nfc/llcp_commands.c | |||
| @@ -12,9 +12,7 @@ | |||
| 12 | * GNU General Public License for more details. | 12 | * GNU General Public License for more details. |
| 13 | * | 13 | * |
| 14 | * You should have received a copy of the GNU General Public License | 14 | * You should have received a copy of the GNU General Public License |
| 15 | * along with this program; if not, write to the | 15 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 16 | * Free Software Foundation, Inc., | ||
| 17 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
| 18 | */ | 16 | */ |
| 19 | 17 | ||
| 20 | #define pr_fmt(fmt) "llcp: %s: " fmt, __func__ | 18 | #define pr_fmt(fmt) "llcp: %s: " fmt, __func__ |
| @@ -677,7 +675,7 @@ int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock, | |||
| 677 | 675 | ||
| 678 | do { | 676 | do { |
| 679 | remote_miu = sock->remote_miu > LLCP_MAX_MIU ? | 677 | remote_miu = sock->remote_miu > LLCP_MAX_MIU ? |
| 680 | local->remote_miu : sock->remote_miu; | 678 | LLCP_DEFAULT_MIU : sock->remote_miu; |
| 681 | 679 | ||
| 682 | frag_len = min_t(size_t, remote_miu, remaining_len); | 680 | frag_len = min_t(size_t, remote_miu, remaining_len); |
| 683 | 681 | ||
| @@ -686,8 +684,10 @@ int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock, | |||
| 686 | 684 | ||
| 687 | pdu = llcp_allocate_pdu(sock, LLCP_PDU_I, | 685 | pdu = llcp_allocate_pdu(sock, LLCP_PDU_I, |
| 688 | frag_len + LLCP_SEQUENCE_SIZE); | 686 | frag_len + LLCP_SEQUENCE_SIZE); |
| 689 | if (pdu == NULL) | 687 | if (pdu == NULL) { |
| 688 | kfree(msg_data); | ||
| 690 | return -ENOMEM; | 689 | return -ENOMEM; |
| 690 | } | ||
| 691 | 691 | ||
| 692 | skb_put(pdu, LLCP_SEQUENCE_SIZE); | 692 | skb_put(pdu, LLCP_SEQUENCE_SIZE); |
| 693 | 693 | ||
diff --git a/net/nfc/llcp_core.c b/net/nfc/llcp_core.c index 81cd3416c7d4..6184bd1fba3a 100644 --- a/net/nfc/llcp_core.c +++ b/net/nfc/llcp_core.c | |||
| @@ -12,9 +12,7 @@ | |||
| 12 | * GNU General Public License for more details. | 12 | * GNU General Public License for more details. |
| 13 | * | 13 | * |
| 14 | * You should have received a copy of the GNU General Public License | 14 | * You should have received a copy of the GNU General Public License |
| 15 | * along with this program; if not, write to the | 15 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 16 | * Free Software Foundation, Inc., | ||
| 17 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
| 18 | */ | 16 | */ |
| 19 | 17 | ||
| 20 | #define pr_fmt(fmt) "llcp: %s: " fmt, __func__ | 18 | #define pr_fmt(fmt) "llcp: %s: " fmt, __func__ |
| @@ -945,7 +943,6 @@ static void nfc_llcp_recv_connect(struct nfc_llcp_local *local, | |||
| 945 | new_sock->local = nfc_llcp_local_get(local); | 943 | new_sock->local = nfc_llcp_local_get(local); |
| 946 | new_sock->rw = sock->rw; | 944 | new_sock->rw = sock->rw; |
| 947 | new_sock->miux = sock->miux; | 945 | new_sock->miux = sock->miux; |
| 948 | new_sock->remote_miu = local->remote_miu; | ||
| 949 | new_sock->nfc_protocol = sock->nfc_protocol; | 946 | new_sock->nfc_protocol = sock->nfc_protocol; |
| 950 | new_sock->dsap = ssap; | 947 | new_sock->dsap = ssap; |
| 951 | new_sock->target_idx = local->target_idx; | 948 | new_sock->target_idx = local->target_idx; |
diff --git a/net/nfc/llcp_sock.c b/net/nfc/llcp_sock.c index 824c6056bf82..51f077a92fa9 100644 --- a/net/nfc/llcp_sock.c +++ b/net/nfc/llcp_sock.c | |||
| @@ -12,9 +12,7 @@ | |||
| 12 | * GNU General Public License for more details. | 12 | * GNU General Public License for more details. |
| 13 | * | 13 | * |
| 14 | * You should have received a copy of the GNU General Public License | 14 | * You should have received a copy of the GNU General Public License |
| 15 | * along with this program; if not, write to the | 15 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 16 | * Free Software Foundation, Inc., | ||
| 17 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
| 18 | */ | 16 | */ |
| 19 | 17 | ||
| 20 | #define pr_fmt(fmt) "llcp: %s: " fmt, __func__ | 18 | #define pr_fmt(fmt) "llcp: %s: " fmt, __func__ |
| @@ -702,7 +700,6 @@ static int llcp_sock_connect(struct socket *sock, struct sockaddr *_addr, | |||
| 702 | 700 | ||
| 703 | llcp_sock->dev = dev; | 701 | llcp_sock->dev = dev; |
| 704 | llcp_sock->local = nfc_llcp_local_get(local); | 702 | llcp_sock->local = nfc_llcp_local_get(local); |
| 705 | llcp_sock->remote_miu = llcp_sock->local->remote_miu; | ||
| 706 | llcp_sock->ssap = nfc_llcp_get_local_ssap(local); | 703 | llcp_sock->ssap = nfc_llcp_get_local_ssap(local); |
| 707 | if (llcp_sock->ssap == LLCP_SAP_MAX) { | 704 | if (llcp_sock->ssap == LLCP_SAP_MAX) { |
| 708 | ret = -ENOMEM; | 705 | ret = -ENOMEM; |
| @@ -772,8 +769,8 @@ static int llcp_sock_sendmsg(struct kiocb *iocb, struct socket *sock, | |||
| 772 | lock_sock(sk); | 769 | lock_sock(sk); |
| 773 | 770 | ||
| 774 | if (sk->sk_type == SOCK_DGRAM) { | 771 | if (sk->sk_type == SOCK_DGRAM) { |
| 775 | struct sockaddr_nfc_llcp *addr = | 772 | DECLARE_SOCKADDR(struct sockaddr_nfc_llcp *, addr, |
| 776 | (struct sockaddr_nfc_llcp *)msg->msg_name; | 773 | msg->msg_name); |
| 777 | 774 | ||
| 778 | if (msg->msg_namelen < sizeof(*addr)) { | 775 | if (msg->msg_namelen < sizeof(*addr)) { |
| 779 | release_sock(sk); | 776 | release_sock(sk); |
| @@ -845,8 +842,8 @@ static int llcp_sock_recvmsg(struct kiocb *iocb, struct socket *sock, | |||
| 845 | 842 | ||
| 846 | if (sk->sk_type == SOCK_DGRAM && msg->msg_name) { | 843 | if (sk->sk_type == SOCK_DGRAM && msg->msg_name) { |
| 847 | struct nfc_llcp_ui_cb *ui_cb = nfc_llcp_ui_skb_cb(skb); | 844 | struct nfc_llcp_ui_cb *ui_cb = nfc_llcp_ui_skb_cb(skb); |
| 848 | struct sockaddr_nfc_llcp *sockaddr = | 845 | DECLARE_SOCKADDR(struct sockaddr_nfc_llcp *, sockaddr, |
| 849 | (struct sockaddr_nfc_llcp *) msg->msg_name; | 846 | msg->msg_name); |
| 850 | 847 | ||
| 851 | msg->msg_namelen = sizeof(struct sockaddr_nfc_llcp); | 848 | msg->msg_namelen = sizeof(struct sockaddr_nfc_llcp); |
| 852 | 849 | ||
diff --git a/net/nfc/nci/core.c b/net/nfc/nci/core.c index b943d46a1644..46bda010bf11 100644 --- a/net/nfc/nci/core.c +++ b/net/nfc/nci/core.c | |||
| @@ -20,8 +20,7 @@ | |||
| 20 | * GNU General Public License for more details. | 20 | * GNU General Public License for more details. |
| 21 | * | 21 | * |
| 22 | * You should have received a copy of the GNU General Public License | 22 | * You should have received a copy of the GNU General Public License |
| 23 | * along with this program; if not, write to the Free Software | 23 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 24 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 25 | * | 24 | * |
| 26 | */ | 25 | */ |
| 27 | 26 | ||
| @@ -302,6 +301,9 @@ static int nci_open_device(struct nci_dev *ndev) | |||
| 302 | rc = __nci_request(ndev, nci_reset_req, 0, | 301 | rc = __nci_request(ndev, nci_reset_req, 0, |
| 303 | msecs_to_jiffies(NCI_RESET_TIMEOUT)); | 302 | msecs_to_jiffies(NCI_RESET_TIMEOUT)); |
| 304 | 303 | ||
| 304 | if (ndev->ops->setup(ndev)) | ||
| 305 | ndev->ops->setup(ndev); | ||
| 306 | |||
| 305 | if (!rc) { | 307 | if (!rc) { |
| 306 | rc = __nci_request(ndev, nci_init_req, 0, | 308 | rc = __nci_request(ndev, nci_init_req, 0, |
| 307 | msecs_to_jiffies(NCI_INIT_TIMEOUT)); | 309 | msecs_to_jiffies(NCI_INIT_TIMEOUT)); |
| @@ -362,6 +364,8 @@ static int nci_close_device(struct nci_dev *ndev) | |||
| 362 | msecs_to_jiffies(NCI_RESET_TIMEOUT)); | 364 | msecs_to_jiffies(NCI_RESET_TIMEOUT)); |
| 363 | clear_bit(NCI_INIT, &ndev->flags); | 365 | clear_bit(NCI_INIT, &ndev->flags); |
| 364 | 366 | ||
| 367 | del_timer_sync(&ndev->cmd_timer); | ||
| 368 | |||
| 365 | /* Flush cmd wq */ | 369 | /* Flush cmd wq */ |
| 366 | flush_workqueue(ndev->cmd_wq); | 370 | flush_workqueue(ndev->cmd_wq); |
| 367 | 371 | ||
| @@ -409,12 +413,26 @@ static int nci_dev_down(struct nfc_dev *nfc_dev) | |||
| 409 | return nci_close_device(ndev); | 413 | return nci_close_device(ndev); |
| 410 | } | 414 | } |
| 411 | 415 | ||
| 416 | int nci_set_config(struct nci_dev *ndev, __u8 id, size_t len, __u8 *val) | ||
| 417 | { | ||
| 418 | struct nci_set_config_param param; | ||
| 419 | |||
| 420 | if (!val || !len) | ||
| 421 | return 0; | ||
| 422 | |||
| 423 | param.id = id; | ||
| 424 | param.len = len; | ||
| 425 | param.val = val; | ||
| 426 | |||
| 427 | return __nci_request(ndev, nci_set_config_req, (unsigned long)¶m, | ||
| 428 | msecs_to_jiffies(NCI_SET_CONFIG_TIMEOUT)); | ||
| 429 | } | ||
| 430 | EXPORT_SYMBOL(nci_set_config); | ||
| 431 | |||
| 412 | static int nci_set_local_general_bytes(struct nfc_dev *nfc_dev) | 432 | static int nci_set_local_general_bytes(struct nfc_dev *nfc_dev) |
| 413 | { | 433 | { |
| 414 | struct nci_dev *ndev = nfc_get_drvdata(nfc_dev); | 434 | struct nci_dev *ndev = nfc_get_drvdata(nfc_dev); |
| 415 | struct nci_set_config_param param; | 435 | struct nci_set_config_param param; |
| 416 | __u8 local_gb[NFC_MAX_GT_LEN]; | ||
| 417 | int i; | ||
| 418 | 436 | ||
| 419 | param.val = nfc_get_local_general_bytes(nfc_dev, ¶m.len); | 437 | param.val = nfc_get_local_general_bytes(nfc_dev, ¶m.len); |
| 420 | if ((param.val == NULL) || (param.len == 0)) | 438 | if ((param.val == NULL) || (param.len == 0)) |
| @@ -423,11 +441,7 @@ static int nci_set_local_general_bytes(struct nfc_dev *nfc_dev) | |||
| 423 | if (param.len > NFC_MAX_GT_LEN) | 441 | if (param.len > NFC_MAX_GT_LEN) |
| 424 | return -EINVAL; | 442 | return -EINVAL; |
| 425 | 443 | ||
| 426 | for (i = 0; i < param.len; i++) | ||
| 427 | local_gb[param.len-1-i] = param.val[i]; | ||
| 428 | |||
| 429 | param.id = NCI_PN_ATR_REQ_GEN_BYTES; | 444 | param.id = NCI_PN_ATR_REQ_GEN_BYTES; |
| 430 | param.val = local_gb; | ||
| 431 | 445 | ||
| 432 | return nci_request(ndev, nci_set_config_req, (unsigned long)¶m, | 446 | return nci_request(ndev, nci_set_config_req, (unsigned long)¶m, |
| 433 | msecs_to_jiffies(NCI_SET_CONFIG_TIMEOUT)); | 447 | msecs_to_jiffies(NCI_SET_CONFIG_TIMEOUT)); |
diff --git a/net/nfc/nci/data.c b/net/nfc/nci/data.c index 2a9399dd6c68..6c3aef852876 100644 --- a/net/nfc/nci/data.c +++ b/net/nfc/nci/data.c | |||
| @@ -16,8 +16,7 @@ | |||
| 16 | * GNU General Public License for more details. | 16 | * GNU General Public License for more details. |
| 17 | * | 17 | * |
| 18 | * You should have received a copy of the GNU General Public License | 18 | * You should have received a copy of the GNU General Public License |
| 19 | * along with this program; if not, write to the Free Software | 19 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 21 | * | 20 | * |
| 22 | */ | 21 | */ |
| 23 | 22 | ||
diff --git a/net/nfc/nci/lib.c b/net/nfc/nci/lib.c index 6b7fd26c68d9..ed774a2e989a 100644 --- a/net/nfc/nci/lib.c +++ b/net/nfc/nci/lib.c | |||
| @@ -20,8 +20,7 @@ | |||
| 20 | * GNU General Public License for more details. | 20 | * GNU General Public License for more details. |
| 21 | * | 21 | * |
| 22 | * You should have received a copy of the GNU General Public License | 22 | * You should have received a copy of the GNU General Public License |
| 23 | * along with this program; if not, write to the Free Software | 23 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 24 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 25 | * | 24 | * |
| 26 | */ | 25 | */ |
| 27 | 26 | ||
diff --git a/net/nfc/nci/ntf.c b/net/nfc/nci/ntf.c index b2aa98ef0927..1e905097456b 100644 --- a/net/nfc/nci/ntf.c +++ b/net/nfc/nci/ntf.c | |||
| @@ -20,8 +20,7 @@ | |||
| 20 | * GNU General Public License for more details. | 20 | * GNU General Public License for more details. |
| 21 | * | 21 | * |
| 22 | * You should have received a copy of the GNU General Public License | 22 | * You should have received a copy of the GNU General Public License |
| 23 | * along with this program; if not, write to the Free Software | 23 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 24 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 25 | * | 24 | * |
| 26 | */ | 25 | */ |
| 27 | 26 | ||
diff --git a/net/nfc/nci/rsp.c b/net/nfc/nci/rsp.c index dd072f38ad00..041de51ccdbe 100644 --- a/net/nfc/nci/rsp.c +++ b/net/nfc/nci/rsp.c | |||
| @@ -20,8 +20,7 @@ | |||
| 20 | * GNU General Public License for more details. | 20 | * GNU General Public License for more details. |
| 21 | * | 21 | * |
| 22 | * You should have received a copy of the GNU General Public License | 22 | * You should have received a copy of the GNU General Public License |
| 23 | * along with this program; if not, write to the Free Software | 23 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 24 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 25 | * | 24 | * |
| 26 | */ | 25 | */ |
| 27 | 26 | ||
diff --git a/net/nfc/netlink.c b/net/nfc/netlink.c index a9b2342d5253..ebbf6fb88b35 100644 --- a/net/nfc/netlink.c +++ b/net/nfc/netlink.c | |||
| @@ -16,9 +16,7 @@ | |||
| 16 | * GNU General Public License for more details. | 16 | * GNU General Public License for more details. |
| 17 | * | 17 | * |
| 18 | * You should have received a copy of the GNU General Public License | 18 | * You should have received a copy of the GNU General Public License |
| 19 | * along with this program; if not, write to the | 19 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 20 | * Free Software Foundation, Inc., | ||
| 21 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
| 22 | */ | 20 | */ |
| 23 | 21 | ||
| 24 | #define pr_fmt(fmt) KBUILD_MODNAME ": %s: " fmt, __func__ | 22 | #define pr_fmt(fmt) KBUILD_MODNAME ": %s: " fmt, __func__ |
diff --git a/net/nfc/nfc.h b/net/nfc/nfc.h index aaf606fc1faa..9d6e74f7e6b3 100644 --- a/net/nfc/nfc.h +++ b/net/nfc/nfc.h | |||
| @@ -16,9 +16,7 @@ | |||
| 16 | * GNU General Public License for more details. | 16 | * GNU General Public License for more details. |
| 17 | * | 17 | * |
| 18 | * You should have received a copy of the GNU General Public License | 18 | * You should have received a copy of the GNU General Public License |
| 19 | * along with this program; if not, write to the | 19 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 20 | * Free Software Foundation, Inc., | ||
| 21 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
| 22 | */ | 20 | */ |
| 23 | 21 | ||
| 24 | #ifndef __LOCAL_NFC_H | 22 | #ifndef __LOCAL_NFC_H |
diff --git a/net/nfc/rawsock.c b/net/nfc/rawsock.c index 66bcd2eb5773..c27a6e86cae4 100644 --- a/net/nfc/rawsock.c +++ b/net/nfc/rawsock.c | |||
| @@ -16,9 +16,7 @@ | |||
| 16 | * GNU General Public License for more details. | 16 | * GNU General Public License for more details. |
| 17 | * | 17 | * |
| 18 | * You should have received a copy of the GNU General Public License | 18 | * You should have received a copy of the GNU General Public License |
| 19 | * along with this program; if not, write to the | 19 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 20 | * Free Software Foundation, Inc., | ||
| 21 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
| 22 | */ | 20 | */ |
| 23 | 21 | ||
| 24 | #define pr_fmt(fmt) KBUILD_MODNAME ": %s: " fmt, __func__ | 22 | #define pr_fmt(fmt) KBUILD_MODNAME ": %s: " fmt, __func__ |
diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c index 65cfaa816075..2c77e7b1a913 100644 --- a/net/openvswitch/actions.c +++ b/net/openvswitch/actions.c | |||
| @@ -165,7 +165,7 @@ static void set_ip_addr(struct sk_buff *skb, struct iphdr *nh, | |||
| 165 | } | 165 | } |
| 166 | 166 | ||
| 167 | csum_replace4(&nh->check, *addr, new_addr); | 167 | csum_replace4(&nh->check, *addr, new_addr); |
| 168 | skb->rxhash = 0; | 168 | skb_clear_hash(skb); |
| 169 | *addr = new_addr; | 169 | *addr = new_addr; |
| 170 | } | 170 | } |
| 171 | 171 | ||
| @@ -199,7 +199,7 @@ static void set_ipv6_addr(struct sk_buff *skb, u8 l4_proto, | |||
| 199 | if (recalculate_csum) | 199 | if (recalculate_csum) |
| 200 | update_ipv6_checksum(skb, l4_proto, addr, new_addr); | 200 | update_ipv6_checksum(skb, l4_proto, addr, new_addr); |
| 201 | 201 | ||
| 202 | skb->rxhash = 0; | 202 | skb_clear_hash(skb); |
| 203 | memcpy(addr, new_addr, sizeof(__be32[4])); | 203 | memcpy(addr, new_addr, sizeof(__be32[4])); |
| 204 | } | 204 | } |
| 205 | 205 | ||
| @@ -296,7 +296,7 @@ static void set_tp_port(struct sk_buff *skb, __be16 *port, | |||
| 296 | { | 296 | { |
| 297 | inet_proto_csum_replace2(check, skb, *port, new_port, 0); | 297 | inet_proto_csum_replace2(check, skb, *port, new_port, 0); |
| 298 | *port = new_port; | 298 | *port = new_port; |
| 299 | skb->rxhash = 0; | 299 | skb_clear_hash(skb); |
| 300 | } | 300 | } |
| 301 | 301 | ||
| 302 | static void set_udp_port(struct sk_buff *skb, __be16 *port, __be16 new_port) | 302 | static void set_udp_port(struct sk_buff *skb, __be16 *port, __be16 new_port) |
| @@ -310,7 +310,7 @@ static void set_udp_port(struct sk_buff *skb, __be16 *port, __be16 new_port) | |||
| 310 | uh->check = CSUM_MANGLED_0; | 310 | uh->check = CSUM_MANGLED_0; |
| 311 | } else { | 311 | } else { |
| 312 | *port = new_port; | 312 | *port = new_port; |
| 313 | skb->rxhash = 0; | 313 | skb_clear_hash(skb); |
| 314 | } | 314 | } |
| 315 | } | 315 | } |
| 316 | 316 | ||
| @@ -381,7 +381,7 @@ static int set_sctp(struct sk_buff *skb, | |||
| 381 | /* Carry any checksum errors through. */ | 381 | /* Carry any checksum errors through. */ |
| 382 | sh->checksum = old_csum ^ old_correct_csum ^ new_csum; | 382 | sh->checksum = old_csum ^ old_correct_csum ^ new_csum; |
| 383 | 383 | ||
| 384 | skb->rxhash = 0; | 384 | skb_clear_hash(skb); |
| 385 | } | 385 | } |
| 386 | 386 | ||
| 387 | return 0; | 387 | return 0; |
| @@ -445,7 +445,7 @@ static int sample(struct datapath *dp, struct sk_buff *skb, | |||
| 445 | a = nla_next(a, &rem)) { | 445 | a = nla_next(a, &rem)) { |
| 446 | switch (nla_type(a)) { | 446 | switch (nla_type(a)) { |
| 447 | case OVS_SAMPLE_ATTR_PROBABILITY: | 447 | case OVS_SAMPLE_ATTR_PROBABILITY: |
| 448 | if (net_random() >= nla_get_u32(a)) | 448 | if (prandom_u32() >= nla_get_u32(a)) |
| 449 | return 0; | 449 | return 0; |
| 450 | break; | 450 | break; |
| 451 | 451 | ||
diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c index 6f5e1dd3be2d..df4692826ead 100644 --- a/net/openvswitch/datapath.c +++ b/net/openvswitch/datapath.c | |||
| @@ -108,10 +108,9 @@ int lockdep_ovsl_is_held(void) | |||
| 108 | #endif | 108 | #endif |
| 109 | 109 | ||
| 110 | static struct vport *new_vport(const struct vport_parms *); | 110 | static struct vport *new_vport(const struct vport_parms *); |
| 111 | static int queue_gso_packets(struct net *, int dp_ifindex, struct sk_buff *, | 111 | static int queue_gso_packets(struct datapath *dp, struct sk_buff *, |
| 112 | const struct dp_upcall_info *); | 112 | const struct dp_upcall_info *); |
| 113 | static int queue_userspace_packet(struct net *, int dp_ifindex, | 113 | static int queue_userspace_packet(struct datapath *dp, struct sk_buff *, |
| 114 | struct sk_buff *, | ||
| 115 | const struct dp_upcall_info *); | 114 | const struct dp_upcall_info *); |
| 116 | 115 | ||
| 117 | /* Must be called with rcu_read_lock or ovs_mutex. */ | 116 | /* Must be called with rcu_read_lock or ovs_mutex. */ |
| @@ -133,7 +132,7 @@ static struct datapath *get_dp(struct net *net, int dp_ifindex) | |||
| 133 | } | 132 | } |
| 134 | 133 | ||
| 135 | /* Must be called with rcu_read_lock or ovs_mutex. */ | 134 | /* Must be called with rcu_read_lock or ovs_mutex. */ |
| 136 | const char *ovs_dp_name(const struct datapath *dp) | 135 | static const char *ovs_dp_name(const struct datapath *dp) |
| 137 | { | 136 | { |
| 138 | struct vport *vport = ovs_vport_ovsl_rcu(dp, OVSP_LOCAL); | 137 | struct vport *vport = ovs_vport_ovsl_rcu(dp, OVSP_LOCAL); |
| 139 | return vport->ops->get_name(vport); | 138 | return vport->ops->get_name(vport); |
| @@ -234,7 +233,7 @@ void ovs_dp_process_received_packet(struct vport *p, struct sk_buff *skb) | |||
| 234 | } | 233 | } |
| 235 | 234 | ||
| 236 | /* Look up flow. */ | 235 | /* Look up flow. */ |
| 237 | flow = ovs_flow_tbl_lookup(&dp->table, &key, &n_mask_hit); | 236 | flow = ovs_flow_tbl_lookup_stats(&dp->table, &key, &n_mask_hit); |
| 238 | if (unlikely(!flow)) { | 237 | if (unlikely(!flow)) { |
| 239 | struct dp_upcall_info upcall; | 238 | struct dp_upcall_info upcall; |
| 240 | 239 | ||
| @@ -251,9 +250,9 @@ void ovs_dp_process_received_packet(struct vport *p, struct sk_buff *skb) | |||
| 251 | OVS_CB(skb)->flow = flow; | 250 | OVS_CB(skb)->flow = flow; |
| 252 | OVS_CB(skb)->pkt_key = &key; | 251 | OVS_CB(skb)->pkt_key = &key; |
| 253 | 252 | ||
| 254 | stats_counter = &stats->n_hit; | 253 | ovs_flow_stats_update(OVS_CB(skb)->flow, skb); |
| 255 | ovs_flow_used(OVS_CB(skb)->flow, skb); | ||
| 256 | ovs_execute_actions(dp, skb); | 254 | ovs_execute_actions(dp, skb); |
| 255 | stats_counter = &stats->n_hit; | ||
| 257 | 256 | ||
| 258 | out: | 257 | out: |
| 259 | /* Update datapath statistics. */ | 258 | /* Update datapath statistics. */ |
| @@ -277,7 +276,6 @@ int ovs_dp_upcall(struct datapath *dp, struct sk_buff *skb, | |||
| 277 | const struct dp_upcall_info *upcall_info) | 276 | const struct dp_upcall_info *upcall_info) |
| 278 | { | 277 | { |
| 279 | struct dp_stats_percpu *stats; | 278 | struct dp_stats_percpu *stats; |
| 280 | int dp_ifindex; | ||
| 281 | int err; | 279 | int err; |
| 282 | 280 | ||
| 283 | if (upcall_info->portid == 0) { | 281 | if (upcall_info->portid == 0) { |
| @@ -285,16 +283,10 @@ int ovs_dp_upcall(struct datapath *dp, struct sk_buff *skb, | |||
| 285 | goto err; | 283 | goto err; |
| 286 | } | 284 | } |
| 287 | 285 | ||
| 288 | dp_ifindex = get_dpifindex(dp); | ||
| 289 | if (!dp_ifindex) { | ||
| 290 | err = -ENODEV; | ||
| 291 | goto err; | ||
| 292 | } | ||
| 293 | |||
| 294 | if (!skb_is_gso(skb)) | 286 | if (!skb_is_gso(skb)) |
| 295 | err = queue_userspace_packet(ovs_dp_get_net(dp), dp_ifindex, skb, upcall_info); | 287 | err = queue_userspace_packet(dp, skb, upcall_info); |
| 296 | else | 288 | else |
| 297 | err = queue_gso_packets(ovs_dp_get_net(dp), dp_ifindex, skb, upcall_info); | 289 | err = queue_gso_packets(dp, skb, upcall_info); |
| 298 | if (err) | 290 | if (err) |
| 299 | goto err; | 291 | goto err; |
| 300 | 292 | ||
| @@ -310,8 +302,7 @@ err: | |||
| 310 | return err; | 302 | return err; |
| 311 | } | 303 | } |
| 312 | 304 | ||
| 313 | static int queue_gso_packets(struct net *net, int dp_ifindex, | 305 | static int queue_gso_packets(struct datapath *dp, struct sk_buff *skb, |
| 314 | struct sk_buff *skb, | ||
| 315 | const struct dp_upcall_info *upcall_info) | 306 | const struct dp_upcall_info *upcall_info) |
| 316 | { | 307 | { |
| 317 | unsigned short gso_type = skb_shinfo(skb)->gso_type; | 308 | unsigned short gso_type = skb_shinfo(skb)->gso_type; |
| @@ -320,14 +311,14 @@ static int queue_gso_packets(struct net *net, int dp_ifindex, | |||
| 320 | struct sk_buff *segs, *nskb; | 311 | struct sk_buff *segs, *nskb; |
| 321 | int err; | 312 | int err; |
| 322 | 313 | ||
| 323 | segs = __skb_gso_segment(skb, NETIF_F_SG | NETIF_F_HW_CSUM, false); | 314 | segs = __skb_gso_segment(skb, NETIF_F_SG, false); |
| 324 | if (IS_ERR(segs)) | 315 | if (IS_ERR(segs)) |
| 325 | return PTR_ERR(segs); | 316 | return PTR_ERR(segs); |
| 326 | 317 | ||
| 327 | /* Queue all of the segments. */ | 318 | /* Queue all of the segments. */ |
| 328 | skb = segs; | 319 | skb = segs; |
| 329 | do { | 320 | do { |
| 330 | err = queue_userspace_packet(net, dp_ifindex, skb, upcall_info); | 321 | err = queue_userspace_packet(dp, skb, upcall_info); |
| 331 | if (err) | 322 | if (err) |
| 332 | break; | 323 | break; |
| 333 | 324 | ||
| @@ -380,11 +371,11 @@ static size_t key_attr_size(void) | |||
| 380 | + nla_total_size(28); /* OVS_KEY_ATTR_ND */ | 371 | + nla_total_size(28); /* OVS_KEY_ATTR_ND */ |
| 381 | } | 372 | } |
| 382 | 373 | ||
| 383 | static size_t upcall_msg_size(const struct sk_buff *skb, | 374 | static size_t upcall_msg_size(const struct nlattr *userdata, |
| 384 | const struct nlattr *userdata) | 375 | unsigned int hdrlen) |
| 385 | { | 376 | { |
| 386 | size_t size = NLMSG_ALIGN(sizeof(struct ovs_header)) | 377 | size_t size = NLMSG_ALIGN(sizeof(struct ovs_header)) |
| 387 | + nla_total_size(skb->len) /* OVS_PACKET_ATTR_PACKET */ | 378 | + nla_total_size(hdrlen) /* OVS_PACKET_ATTR_PACKET */ |
| 388 | + nla_total_size(key_attr_size()); /* OVS_PACKET_ATTR_KEY */ | 379 | + nla_total_size(key_attr_size()); /* OVS_PACKET_ATTR_KEY */ |
| 389 | 380 | ||
| 390 | /* OVS_PACKET_ATTR_USERDATA */ | 381 | /* OVS_PACKET_ATTR_USERDATA */ |
| @@ -394,15 +385,24 @@ static size_t upcall_msg_size(const struct sk_buff *skb, | |||
| 394 | return size; | 385 | return size; |
| 395 | } | 386 | } |
| 396 | 387 | ||
| 397 | static int queue_userspace_packet(struct net *net, int dp_ifindex, | 388 | static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb, |
| 398 | struct sk_buff *skb, | ||
| 399 | const struct dp_upcall_info *upcall_info) | 389 | const struct dp_upcall_info *upcall_info) |
| 400 | { | 390 | { |
| 401 | struct ovs_header *upcall; | 391 | struct ovs_header *upcall; |
| 402 | struct sk_buff *nskb = NULL; | 392 | struct sk_buff *nskb = NULL; |
| 403 | struct sk_buff *user_skb; /* to be queued to userspace */ | 393 | struct sk_buff *user_skb; /* to be queued to userspace */ |
| 404 | struct nlattr *nla; | 394 | struct nlattr *nla; |
| 405 | int err; | 395 | struct genl_info info = { |
| 396 | .dst_sk = ovs_dp_get_net(dp)->genl_sock, | ||
| 397 | .snd_portid = upcall_info->portid, | ||
| 398 | }; | ||
| 399 | size_t len; | ||
| 400 | unsigned int hlen; | ||
| 401 | int err, dp_ifindex; | ||
| 402 | |||
| 403 | dp_ifindex = get_dpifindex(dp); | ||
| 404 | if (!dp_ifindex) | ||
| 405 | return -ENODEV; | ||
| 406 | 406 | ||
| 407 | if (vlan_tx_tag_present(skb)) { | 407 | if (vlan_tx_tag_present(skb)) { |
| 408 | nskb = skb_clone(skb, GFP_ATOMIC); | 408 | nskb = skb_clone(skb, GFP_ATOMIC); |
| @@ -422,7 +422,22 @@ static int queue_userspace_packet(struct net *net, int dp_ifindex, | |||
| 422 | goto out; | 422 | goto out; |
| 423 | } | 423 | } |
| 424 | 424 | ||
| 425 | user_skb = genlmsg_new(upcall_msg_size(skb, upcall_info->userdata), GFP_ATOMIC); | 425 | /* Complete checksum if needed */ |
| 426 | if (skb->ip_summed == CHECKSUM_PARTIAL && | ||
| 427 | (err = skb_checksum_help(skb))) | ||
| 428 | goto out; | ||
| 429 | |||
| 430 | /* Older versions of OVS user space enforce alignment of the last | ||
| 431 | * Netlink attribute to NLA_ALIGNTO which would require extensive | ||
| 432 | * padding logic. Only perform zerocopy if padding is not required. | ||
| 433 | */ | ||
| 434 | if (dp->user_features & OVS_DP_F_UNALIGNED) | ||
| 435 | hlen = skb_zerocopy_headlen(skb); | ||
| 436 | else | ||
| 437 | hlen = skb->len; | ||
| 438 | |||
| 439 | len = upcall_msg_size(upcall_info->userdata, hlen); | ||
| 440 | user_skb = genlmsg_new_unicast(len, &info, GFP_ATOMIC); | ||
| 426 | if (!user_skb) { | 441 | if (!user_skb) { |
| 427 | err = -ENOMEM; | 442 | err = -ENOMEM; |
| 428 | goto out; | 443 | goto out; |
| @@ -441,26 +456,24 @@ static int queue_userspace_packet(struct net *net, int dp_ifindex, | |||
| 441 | nla_len(upcall_info->userdata), | 456 | nla_len(upcall_info->userdata), |
| 442 | nla_data(upcall_info->userdata)); | 457 | nla_data(upcall_info->userdata)); |
| 443 | 458 | ||
| 444 | nla = __nla_reserve(user_skb, OVS_PACKET_ATTR_PACKET, skb->len); | 459 | /* Only reserve room for attribute header, packet data is added |
| 460 | * in skb_zerocopy() */ | ||
| 461 | if (!(nla = nla_reserve(user_skb, OVS_PACKET_ATTR_PACKET, 0))) { | ||
| 462 | err = -ENOBUFS; | ||
| 463 | goto out; | ||
| 464 | } | ||
| 465 | nla->nla_len = nla_attr_size(skb->len); | ||
| 445 | 466 | ||
| 446 | skb_copy_and_csum_dev(skb, nla_data(nla)); | 467 | skb_zerocopy(user_skb, skb, skb->len, hlen); |
| 447 | 468 | ||
| 448 | genlmsg_end(user_skb, upcall); | 469 | ((struct nlmsghdr *) user_skb->data)->nlmsg_len = user_skb->len; |
| 449 | err = genlmsg_unicast(net, user_skb, upcall_info->portid); | ||
| 450 | 470 | ||
| 471 | err = genlmsg_unicast(ovs_dp_get_net(dp), user_skb, upcall_info->portid); | ||
| 451 | out: | 472 | out: |
| 452 | kfree_skb(nskb); | 473 | kfree_skb(nskb); |
| 453 | return err; | 474 | return err; |
| 454 | } | 475 | } |
| 455 | 476 | ||
| 456 | static void clear_stats(struct sw_flow *flow) | ||
| 457 | { | ||
| 458 | flow->used = 0; | ||
| 459 | flow->tcp_flags = 0; | ||
| 460 | flow->packet_count = 0; | ||
| 461 | flow->byte_count = 0; | ||
| 462 | } | ||
| 463 | |||
| 464 | static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info) | 477 | static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info) |
| 465 | { | 478 | { |
| 466 | struct ovs_header *ovs_header = info->userhdr; | 479 | struct ovs_header *ovs_header = info->userhdr; |
| @@ -499,7 +512,7 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info) | |||
| 499 | packet->protocol = htons(ETH_P_802_2); | 512 | packet->protocol = htons(ETH_P_802_2); |
| 500 | 513 | ||
| 501 | /* Build an sw_flow for sending this packet. */ | 514 | /* Build an sw_flow for sending this packet. */ |
| 502 | flow = ovs_flow_alloc(); | 515 | flow = ovs_flow_alloc(false); |
| 503 | err = PTR_ERR(flow); | 516 | err = PTR_ERR(flow); |
| 504 | if (IS_ERR(flow)) | 517 | if (IS_ERR(flow)) |
| 505 | goto err_kfree_skb; | 518 | goto err_kfree_skb; |
| @@ -635,10 +648,10 @@ static int ovs_flow_cmd_fill_info(struct sw_flow *flow, struct datapath *dp, | |||
| 635 | const int skb_orig_len = skb->len; | 648 | const int skb_orig_len = skb->len; |
| 636 | struct nlattr *start; | 649 | struct nlattr *start; |
| 637 | struct ovs_flow_stats stats; | 650 | struct ovs_flow_stats stats; |
| 651 | __be16 tcp_flags; | ||
| 652 | unsigned long used; | ||
| 638 | struct ovs_header *ovs_header; | 653 | struct ovs_header *ovs_header; |
| 639 | struct nlattr *nla; | 654 | struct nlattr *nla; |
| 640 | unsigned long used; | ||
| 641 | u8 tcp_flags; | ||
| 642 | int err; | 655 | int err; |
| 643 | 656 | ||
| 644 | ovs_header = genlmsg_put(skb, portid, seq, &dp_flow_genl_family, flags, cmd); | 657 | ovs_header = genlmsg_put(skb, portid, seq, &dp_flow_genl_family, flags, cmd); |
| @@ -667,24 +680,17 @@ static int ovs_flow_cmd_fill_info(struct sw_flow *flow, struct datapath *dp, | |||
| 667 | 680 | ||
| 668 | nla_nest_end(skb, nla); | 681 | nla_nest_end(skb, nla); |
| 669 | 682 | ||
| 670 | spin_lock_bh(&flow->lock); | 683 | ovs_flow_stats_get(flow, &stats, &used, &tcp_flags); |
| 671 | used = flow->used; | ||
| 672 | stats.n_packets = flow->packet_count; | ||
| 673 | stats.n_bytes = flow->byte_count; | ||
| 674 | tcp_flags = (u8)ntohs(flow->tcp_flags); | ||
| 675 | spin_unlock_bh(&flow->lock); | ||
| 676 | |||
| 677 | if (used && | 684 | if (used && |
| 678 | nla_put_u64(skb, OVS_FLOW_ATTR_USED, ovs_flow_used_time(used))) | 685 | nla_put_u64(skb, OVS_FLOW_ATTR_USED, ovs_flow_used_time(used))) |
| 679 | goto nla_put_failure; | 686 | goto nla_put_failure; |
| 680 | 687 | ||
| 681 | if (stats.n_packets && | 688 | if (stats.n_packets && |
| 682 | nla_put(skb, OVS_FLOW_ATTR_STATS, | 689 | nla_put(skb, OVS_FLOW_ATTR_STATS, sizeof(struct ovs_flow_stats), &stats)) |
| 683 | sizeof(struct ovs_flow_stats), &stats)) | ||
| 684 | goto nla_put_failure; | 690 | goto nla_put_failure; |
| 685 | 691 | ||
| 686 | if (tcp_flags && | 692 | if ((u8)ntohs(tcp_flags) && |
| 687 | nla_put_u8(skb, OVS_FLOW_ATTR_TCP_FLAGS, tcp_flags)) | 693 | nla_put_u8(skb, OVS_FLOW_ATTR_TCP_FLAGS, (u8)ntohs(tcp_flags))) |
| 688 | goto nla_put_failure; | 694 | goto nla_put_failure; |
| 689 | 695 | ||
| 690 | /* If OVS_FLOW_ATTR_ACTIONS doesn't fit, skip dumping the actions if | 696 | /* If OVS_FLOW_ATTR_ACTIONS doesn't fit, skip dumping the actions if |
| @@ -701,8 +707,7 @@ static int ovs_flow_cmd_fill_info(struct sw_flow *flow, struct datapath *dp, | |||
| 701 | if (start) { | 707 | if (start) { |
| 702 | const struct sw_flow_actions *sf_acts; | 708 | const struct sw_flow_actions *sf_acts; |
| 703 | 709 | ||
| 704 | sf_acts = rcu_dereference_check(flow->sf_acts, | 710 | sf_acts = rcu_dereference_ovsl(flow->sf_acts); |
| 705 | lockdep_ovsl_is_held()); | ||
| 706 | 711 | ||
| 707 | err = ovs_nla_put_actions(sf_acts->actions, | 712 | err = ovs_nla_put_actions(sf_acts->actions, |
| 708 | sf_acts->actions_len, skb); | 713 | sf_acts->actions_len, skb); |
| @@ -726,39 +731,34 @@ error: | |||
| 726 | return err; | 731 | return err; |
| 727 | } | 732 | } |
| 728 | 733 | ||
| 729 | static struct sk_buff *ovs_flow_cmd_alloc_info(struct sw_flow *flow) | 734 | static struct sk_buff *ovs_flow_cmd_alloc_info(struct sw_flow *flow, |
| 735 | struct genl_info *info) | ||
| 730 | { | 736 | { |
| 731 | const struct sw_flow_actions *sf_acts; | 737 | size_t len; |
| 732 | 738 | ||
| 733 | sf_acts = ovsl_dereference(flow->sf_acts); | 739 | len = ovs_flow_cmd_msg_size(ovsl_dereference(flow->sf_acts)); |
| 734 | 740 | ||
| 735 | return genlmsg_new(ovs_flow_cmd_msg_size(sf_acts), GFP_KERNEL); | 741 | return genlmsg_new_unicast(len, info, GFP_KERNEL); |
| 736 | } | 742 | } |
| 737 | 743 | ||
| 738 | static struct sk_buff *ovs_flow_cmd_build_info(struct sw_flow *flow, | 744 | static struct sk_buff *ovs_flow_cmd_build_info(struct sw_flow *flow, |
| 739 | struct datapath *dp, | 745 | struct datapath *dp, |
| 740 | u32 portid, u32 seq, u8 cmd) | 746 | struct genl_info *info, |
| 747 | u8 cmd) | ||
| 741 | { | 748 | { |
| 742 | struct sk_buff *skb; | 749 | struct sk_buff *skb; |
| 743 | int retval; | 750 | int retval; |
| 744 | 751 | ||
| 745 | skb = ovs_flow_cmd_alloc_info(flow); | 752 | skb = ovs_flow_cmd_alloc_info(flow, info); |
| 746 | if (!skb) | 753 | if (!skb) |
| 747 | return ERR_PTR(-ENOMEM); | 754 | return ERR_PTR(-ENOMEM); |
| 748 | 755 | ||
| 749 | retval = ovs_flow_cmd_fill_info(flow, dp, skb, portid, seq, 0, cmd); | 756 | retval = ovs_flow_cmd_fill_info(flow, dp, skb, info->snd_portid, |
| 757 | info->snd_seq, 0, cmd); | ||
| 750 | BUG_ON(retval < 0); | 758 | BUG_ON(retval < 0); |
| 751 | return skb; | 759 | return skb; |
| 752 | } | 760 | } |
| 753 | 761 | ||
| 754 | static struct sw_flow *__ovs_flow_tbl_lookup(struct flow_table *tbl, | ||
| 755 | const struct sw_flow_key *key) | ||
| 756 | { | ||
| 757 | u32 __always_unused n_mask_hit; | ||
| 758 | |||
| 759 | return ovs_flow_tbl_lookup(tbl, key, &n_mask_hit); | ||
| 760 | } | ||
| 761 | |||
| 762 | static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info) | 762 | static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info) |
| 763 | { | 763 | { |
| 764 | struct nlattr **a = info->attrs; | 764 | struct nlattr **a = info->attrs; |
| @@ -770,6 +770,7 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info) | |||
| 770 | struct datapath *dp; | 770 | struct datapath *dp; |
| 771 | struct sw_flow_actions *acts = NULL; | 771 | struct sw_flow_actions *acts = NULL; |
| 772 | struct sw_flow_match match; | 772 | struct sw_flow_match match; |
| 773 | bool exact_5tuple; | ||
| 773 | int error; | 774 | int error; |
| 774 | 775 | ||
| 775 | /* Extract key. */ | 776 | /* Extract key. */ |
| @@ -778,7 +779,7 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info) | |||
| 778 | goto error; | 779 | goto error; |
| 779 | 780 | ||
| 780 | ovs_match_init(&match, &key, &mask); | 781 | ovs_match_init(&match, &key, &mask); |
| 781 | error = ovs_nla_get_match(&match, | 782 | error = ovs_nla_get_match(&match, &exact_5tuple, |
| 782 | a[OVS_FLOW_ATTR_KEY], a[OVS_FLOW_ATTR_MASK]); | 783 | a[OVS_FLOW_ATTR_KEY], a[OVS_FLOW_ATTR_MASK]); |
| 783 | if (error) | 784 | if (error) |
| 784 | goto error; | 785 | goto error; |
| @@ -809,7 +810,7 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info) | |||
| 809 | goto err_unlock_ovs; | 810 | goto err_unlock_ovs; |
| 810 | 811 | ||
| 811 | /* Check if this is a duplicate flow */ | 812 | /* Check if this is a duplicate flow */ |
| 812 | flow = __ovs_flow_tbl_lookup(&dp->table, &key); | 813 | flow = ovs_flow_tbl_lookup(&dp->table, &key); |
| 813 | if (!flow) { | 814 | if (!flow) { |
| 814 | /* Bail out if we're not allowed to create a new flow. */ | 815 | /* Bail out if we're not allowed to create a new flow. */ |
| 815 | error = -ENOENT; | 816 | error = -ENOENT; |
| @@ -817,12 +818,11 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info) | |||
| 817 | goto err_unlock_ovs; | 818 | goto err_unlock_ovs; |
| 818 | 819 | ||
| 819 | /* Allocate flow. */ | 820 | /* Allocate flow. */ |
| 820 | flow = ovs_flow_alloc(); | 821 | flow = ovs_flow_alloc(!exact_5tuple); |
| 821 | if (IS_ERR(flow)) { | 822 | if (IS_ERR(flow)) { |
| 822 | error = PTR_ERR(flow); | 823 | error = PTR_ERR(flow); |
| 823 | goto err_unlock_ovs; | 824 | goto err_unlock_ovs; |
| 824 | } | 825 | } |
| 825 | clear_stats(flow); | ||
| 826 | 826 | ||
| 827 | flow->key = masked_key; | 827 | flow->key = masked_key; |
| 828 | flow->unmasked_key = key; | 828 | flow->unmasked_key = key; |
| @@ -835,8 +835,7 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info) | |||
| 835 | goto err_flow_free; | 835 | goto err_flow_free; |
| 836 | } | 836 | } |
| 837 | 837 | ||
| 838 | reply = ovs_flow_cmd_build_info(flow, dp, info->snd_portid, | 838 | reply = ovs_flow_cmd_build_info(flow, dp, info, OVS_FLOW_CMD_NEW); |
| 839 | info->snd_seq, OVS_FLOW_CMD_NEW); | ||
| 840 | } else { | 839 | } else { |
| 841 | /* We found a matching flow. */ | 840 | /* We found a matching flow. */ |
| 842 | struct sw_flow_actions *old_acts; | 841 | struct sw_flow_actions *old_acts; |
| @@ -864,15 +863,11 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info) | |||
| 864 | rcu_assign_pointer(flow->sf_acts, acts); | 863 | rcu_assign_pointer(flow->sf_acts, acts); |
| 865 | ovs_nla_free_flow_actions(old_acts); | 864 | ovs_nla_free_flow_actions(old_acts); |
| 866 | 865 | ||
| 867 | reply = ovs_flow_cmd_build_info(flow, dp, info->snd_portid, | 866 | reply = ovs_flow_cmd_build_info(flow, dp, info, OVS_FLOW_CMD_NEW); |
| 868 | info->snd_seq, OVS_FLOW_CMD_NEW); | ||
| 869 | 867 | ||
| 870 | /* Clear stats. */ | 868 | /* Clear stats. */ |
| 871 | if (a[OVS_FLOW_ATTR_CLEAR]) { | 869 | if (a[OVS_FLOW_ATTR_CLEAR]) |
| 872 | spin_lock_bh(&flow->lock); | 870 | ovs_flow_stats_clear(flow); |
| 873 | clear_stats(flow); | ||
| 874 | spin_unlock_bh(&flow->lock); | ||
| 875 | } | ||
| 876 | } | 871 | } |
| 877 | ovs_unlock(); | 872 | ovs_unlock(); |
| 878 | 873 | ||
| @@ -910,7 +905,7 @@ static int ovs_flow_cmd_get(struct sk_buff *skb, struct genl_info *info) | |||
| 910 | } | 905 | } |
| 911 | 906 | ||
| 912 | ovs_match_init(&match, &key, NULL); | 907 | ovs_match_init(&match, &key, NULL); |
| 913 | err = ovs_nla_get_match(&match, a[OVS_FLOW_ATTR_KEY], NULL); | 908 | err = ovs_nla_get_match(&match, NULL, a[OVS_FLOW_ATTR_KEY], NULL); |
| 914 | if (err) | 909 | if (err) |
| 915 | return err; | 910 | return err; |
| 916 | 911 | ||
| @@ -921,14 +916,13 @@ static int ovs_flow_cmd_get(struct sk_buff *skb, struct genl_info *info) | |||
| 921 | goto unlock; | 916 | goto unlock; |
| 922 | } | 917 | } |
| 923 | 918 | ||
| 924 | flow = __ovs_flow_tbl_lookup(&dp->table, &key); | 919 | flow = ovs_flow_tbl_lookup(&dp->table, &key); |
| 925 | if (!flow || !ovs_flow_cmp_unmasked_key(flow, &match)) { | 920 | if (!flow || !ovs_flow_cmp_unmasked_key(flow, &match)) { |
| 926 | err = -ENOENT; | 921 | err = -ENOENT; |
| 927 | goto unlock; | 922 | goto unlock; |
| 928 | } | 923 | } |
| 929 | 924 | ||
| 930 | reply = ovs_flow_cmd_build_info(flow, dp, info->snd_portid, | 925 | reply = ovs_flow_cmd_build_info(flow, dp, info, OVS_FLOW_CMD_NEW); |
| 931 | info->snd_seq, OVS_FLOW_CMD_NEW); | ||
| 932 | if (IS_ERR(reply)) { | 926 | if (IS_ERR(reply)) { |
| 933 | err = PTR_ERR(reply); | 927 | err = PTR_ERR(reply); |
| 934 | goto unlock; | 928 | goto unlock; |
| @@ -965,17 +959,17 @@ static int ovs_flow_cmd_del(struct sk_buff *skb, struct genl_info *info) | |||
| 965 | } | 959 | } |
| 966 | 960 | ||
| 967 | ovs_match_init(&match, &key, NULL); | 961 | ovs_match_init(&match, &key, NULL); |
| 968 | err = ovs_nla_get_match(&match, a[OVS_FLOW_ATTR_KEY], NULL); | 962 | err = ovs_nla_get_match(&match, NULL, a[OVS_FLOW_ATTR_KEY], NULL); |
| 969 | if (err) | 963 | if (err) |
| 970 | goto unlock; | 964 | goto unlock; |
| 971 | 965 | ||
| 972 | flow = __ovs_flow_tbl_lookup(&dp->table, &key); | 966 | flow = ovs_flow_tbl_lookup(&dp->table, &key); |
| 973 | if (!flow || !ovs_flow_cmp_unmasked_key(flow, &match)) { | 967 | if (!flow || !ovs_flow_cmp_unmasked_key(flow, &match)) { |
| 974 | err = -ENOENT; | 968 | err = -ENOENT; |
| 975 | goto unlock; | 969 | goto unlock; |
| 976 | } | 970 | } |
| 977 | 971 | ||
| 978 | reply = ovs_flow_cmd_alloc_info(flow); | 972 | reply = ovs_flow_cmd_alloc_info(flow, info); |
| 979 | if (!reply) { | 973 | if (!reply) { |
| 980 | err = -ENOMEM; | 974 | err = -ENOMEM; |
| 981 | goto unlock; | 975 | goto unlock; |
| @@ -1061,6 +1055,7 @@ static const struct genl_ops dp_flow_genl_ops[] = { | |||
| 1061 | static const struct nla_policy datapath_policy[OVS_DP_ATTR_MAX + 1] = { | 1055 | static const struct nla_policy datapath_policy[OVS_DP_ATTR_MAX + 1] = { |
| 1062 | [OVS_DP_ATTR_NAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ - 1 }, | 1056 | [OVS_DP_ATTR_NAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ - 1 }, |
| 1063 | [OVS_DP_ATTR_UPCALL_PID] = { .type = NLA_U32 }, | 1057 | [OVS_DP_ATTR_UPCALL_PID] = { .type = NLA_U32 }, |
| 1058 | [OVS_DP_ATTR_USER_FEATURES] = { .type = NLA_U32 }, | ||
| 1064 | }; | 1059 | }; |
| 1065 | 1060 | ||
| 1066 | static struct genl_family dp_datapath_genl_family = { | 1061 | static struct genl_family dp_datapath_genl_family = { |
| @@ -1119,6 +1114,9 @@ static int ovs_dp_cmd_fill_info(struct datapath *dp, struct sk_buff *skb, | |||
| 1119 | &dp_megaflow_stats)) | 1114 | &dp_megaflow_stats)) |
| 1120 | goto nla_put_failure; | 1115 | goto nla_put_failure; |
| 1121 | 1116 | ||
| 1117 | if (nla_put_u32(skb, OVS_DP_ATTR_USER_FEATURES, dp->user_features)) | ||
| 1118 | goto nla_put_failure; | ||
| 1119 | |||
| 1122 | return genlmsg_end(skb, ovs_header); | 1120 | return genlmsg_end(skb, ovs_header); |
| 1123 | 1121 | ||
| 1124 | nla_put_failure: | 1122 | nla_put_failure: |
| @@ -1127,17 +1125,17 @@ error: | |||
| 1127 | return -EMSGSIZE; | 1125 | return -EMSGSIZE; |
| 1128 | } | 1126 | } |
| 1129 | 1127 | ||
| 1130 | static struct sk_buff *ovs_dp_cmd_build_info(struct datapath *dp, u32 portid, | 1128 | static struct sk_buff *ovs_dp_cmd_build_info(struct datapath *dp, |
| 1131 | u32 seq, u8 cmd) | 1129 | struct genl_info *info, u8 cmd) |
| 1132 | { | 1130 | { |
| 1133 | struct sk_buff *skb; | 1131 | struct sk_buff *skb; |
| 1134 | int retval; | 1132 | int retval; |
| 1135 | 1133 | ||
| 1136 | skb = genlmsg_new(ovs_dp_cmd_msg_size(), GFP_KERNEL); | 1134 | skb = genlmsg_new_unicast(ovs_dp_cmd_msg_size(), info, GFP_KERNEL); |
| 1137 | if (!skb) | 1135 | if (!skb) |
| 1138 | return ERR_PTR(-ENOMEM); | 1136 | return ERR_PTR(-ENOMEM); |
| 1139 | 1137 | ||
| 1140 | retval = ovs_dp_cmd_fill_info(dp, skb, portid, seq, 0, cmd); | 1138 | retval = ovs_dp_cmd_fill_info(dp, skb, info->snd_portid, info->snd_seq, 0, cmd); |
| 1141 | if (retval < 0) { | 1139 | if (retval < 0) { |
| 1142 | kfree_skb(skb); | 1140 | kfree_skb(skb); |
| 1143 | return ERR_PTR(retval); | 1141 | return ERR_PTR(retval); |
| @@ -1165,6 +1163,24 @@ static struct datapath *lookup_datapath(struct net *net, | |||
| 1165 | return dp ? dp : ERR_PTR(-ENODEV); | 1163 | return dp ? dp : ERR_PTR(-ENODEV); |
| 1166 | } | 1164 | } |
| 1167 | 1165 | ||
| 1166 | static void ovs_dp_reset_user_features(struct sk_buff *skb, struct genl_info *info) | ||
| 1167 | { | ||
| 1168 | struct datapath *dp; | ||
| 1169 | |||
| 1170 | dp = lookup_datapath(sock_net(skb->sk), info->userhdr, info->attrs); | ||
| 1171 | if (!dp) | ||
| 1172 | return; | ||
| 1173 | |||
| 1174 | WARN(dp->user_features, "Dropping previously announced user features\n"); | ||
| 1175 | dp->user_features = 0; | ||
| 1176 | } | ||
| 1177 | |||
| 1178 | static void ovs_dp_change(struct datapath *dp, struct nlattr **a) | ||
| 1179 | { | ||
| 1180 | if (a[OVS_DP_ATTR_USER_FEATURES]) | ||
| 1181 | dp->user_features = nla_get_u32(a[OVS_DP_ATTR_USER_FEATURES]); | ||
| 1182 | } | ||
| 1183 | |||
| 1168 | static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info) | 1184 | static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info) |
| 1169 | { | 1185 | { |
| 1170 | struct nlattr **a = info->attrs; | 1186 | struct nlattr **a = info->attrs; |
| @@ -1223,17 +1239,27 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info) | |||
| 1223 | parms.port_no = OVSP_LOCAL; | 1239 | parms.port_no = OVSP_LOCAL; |
| 1224 | parms.upcall_portid = nla_get_u32(a[OVS_DP_ATTR_UPCALL_PID]); | 1240 | parms.upcall_portid = nla_get_u32(a[OVS_DP_ATTR_UPCALL_PID]); |
| 1225 | 1241 | ||
| 1242 | ovs_dp_change(dp, a); | ||
| 1243 | |||
| 1226 | vport = new_vport(&parms); | 1244 | vport = new_vport(&parms); |
| 1227 | if (IS_ERR(vport)) { | 1245 | if (IS_ERR(vport)) { |
| 1228 | err = PTR_ERR(vport); | 1246 | err = PTR_ERR(vport); |
| 1229 | if (err == -EBUSY) | 1247 | if (err == -EBUSY) |
| 1230 | err = -EEXIST; | 1248 | err = -EEXIST; |
| 1231 | 1249 | ||
| 1250 | if (err == -EEXIST) { | ||
| 1251 | /* An outdated user space instance that does not understand | ||
| 1252 | * the concept of user_features has attempted to create a new | ||
| 1253 | * datapath and is likely to reuse it. Drop all user features. | ||
| 1254 | */ | ||
| 1255 | if (info->genlhdr->version < OVS_DP_VER_FEATURES) | ||
| 1256 | ovs_dp_reset_user_features(skb, info); | ||
| 1257 | } | ||
| 1258 | |||
| 1232 | goto err_destroy_ports_array; | 1259 | goto err_destroy_ports_array; |
| 1233 | } | 1260 | } |
| 1234 | 1261 | ||
| 1235 | reply = ovs_dp_cmd_build_info(dp, info->snd_portid, | 1262 | reply = ovs_dp_cmd_build_info(dp, info, OVS_DP_CMD_NEW); |
| 1236 | info->snd_seq, OVS_DP_CMD_NEW); | ||
| 1237 | err = PTR_ERR(reply); | 1263 | err = PTR_ERR(reply); |
| 1238 | if (IS_ERR(reply)) | 1264 | if (IS_ERR(reply)) |
| 1239 | goto err_destroy_local_port; | 1265 | goto err_destroy_local_port; |
| @@ -1299,8 +1325,7 @@ static int ovs_dp_cmd_del(struct sk_buff *skb, struct genl_info *info) | |||
| 1299 | if (IS_ERR(dp)) | 1325 | if (IS_ERR(dp)) |
| 1300 | goto unlock; | 1326 | goto unlock; |
| 1301 | 1327 | ||
| 1302 | reply = ovs_dp_cmd_build_info(dp, info->snd_portid, | 1328 | reply = ovs_dp_cmd_build_info(dp, info, OVS_DP_CMD_DEL); |
| 1303 | info->snd_seq, OVS_DP_CMD_DEL); | ||
| 1304 | err = PTR_ERR(reply); | 1329 | err = PTR_ERR(reply); |
| 1305 | if (IS_ERR(reply)) | 1330 | if (IS_ERR(reply)) |
| 1306 | goto unlock; | 1331 | goto unlock; |
| @@ -1328,8 +1353,9 @@ static int ovs_dp_cmd_set(struct sk_buff *skb, struct genl_info *info) | |||
| 1328 | if (IS_ERR(dp)) | 1353 | if (IS_ERR(dp)) |
| 1329 | goto unlock; | 1354 | goto unlock; |
| 1330 | 1355 | ||
| 1331 | reply = ovs_dp_cmd_build_info(dp, info->snd_portid, | 1356 | ovs_dp_change(dp, info->attrs); |
| 1332 | info->snd_seq, OVS_DP_CMD_NEW); | 1357 | |
| 1358 | reply = ovs_dp_cmd_build_info(dp, info, OVS_DP_CMD_NEW); | ||
| 1333 | if (IS_ERR(reply)) { | 1359 | if (IS_ERR(reply)) { |
| 1334 | err = PTR_ERR(reply); | 1360 | err = PTR_ERR(reply); |
| 1335 | genl_set_err(&dp_datapath_genl_family, sock_net(skb->sk), 0, | 1361 | genl_set_err(&dp_datapath_genl_family, sock_net(skb->sk), 0, |
| @@ -1360,8 +1386,7 @@ static int ovs_dp_cmd_get(struct sk_buff *skb, struct genl_info *info) | |||
| 1360 | goto unlock; | 1386 | goto unlock; |
| 1361 | } | 1387 | } |
| 1362 | 1388 | ||
| 1363 | reply = ovs_dp_cmd_build_info(dp, info->snd_portid, | 1389 | reply = ovs_dp_cmd_build_info(dp, info, OVS_DP_CMD_NEW); |
| 1364 | info->snd_seq, OVS_DP_CMD_NEW); | ||
| 1365 | if (IS_ERR(reply)) { | 1390 | if (IS_ERR(reply)) { |
| 1366 | err = PTR_ERR(reply); | 1391 | err = PTR_ERR(reply); |
| 1367 | goto unlock; | 1392 | goto unlock; |
| @@ -1441,7 +1466,7 @@ struct genl_family dp_vport_genl_family = { | |||
| 1441 | .parallel_ops = true, | 1466 | .parallel_ops = true, |
| 1442 | }; | 1467 | }; |
| 1443 | 1468 | ||
| 1444 | struct genl_multicast_group ovs_dp_vport_multicast_group = { | 1469 | static struct genl_multicast_group ovs_dp_vport_multicast_group = { |
| 1445 | .name = OVS_VPORT_MCGROUP | 1470 | .name = OVS_VPORT_MCGROUP |
| 1446 | }; | 1471 | }; |
| 1447 | 1472 | ||
diff --git a/net/openvswitch/datapath.h b/net/openvswitch/datapath.h index 4067ea41be28..6be9fbb5e9cb 100644 --- a/net/openvswitch/datapath.h +++ b/net/openvswitch/datapath.h | |||
| @@ -88,6 +88,8 @@ struct datapath { | |||
| 88 | /* Network namespace ref. */ | 88 | /* Network namespace ref. */ |
| 89 | struct net *net; | 89 | struct net *net; |
| 90 | #endif | 90 | #endif |
| 91 | |||
| 92 | u32 user_features; | ||
| 91 | }; | 93 | }; |
| 92 | 94 | ||
| 93 | /** | 95 | /** |
| @@ -145,6 +147,8 @@ int lockdep_ovsl_is_held(void); | |||
| 145 | #define ASSERT_OVSL() WARN_ON(unlikely(!lockdep_ovsl_is_held())) | 147 | #define ASSERT_OVSL() WARN_ON(unlikely(!lockdep_ovsl_is_held())) |
| 146 | #define ovsl_dereference(p) \ | 148 | #define ovsl_dereference(p) \ |
| 147 | rcu_dereference_protected(p, lockdep_ovsl_is_held()) | 149 | rcu_dereference_protected(p, lockdep_ovsl_is_held()) |
| 150 | #define rcu_dereference_ovsl(p) \ | ||
| 151 | rcu_dereference_check(p, lockdep_ovsl_is_held()) | ||
| 148 | 152 | ||
| 149 | static inline struct net *ovs_dp_get_net(struct datapath *dp) | 153 | static inline struct net *ovs_dp_get_net(struct datapath *dp) |
| 150 | { | 154 | { |
| @@ -178,14 +182,12 @@ static inline struct vport *ovs_vport_ovsl(const struct datapath *dp, int port_n | |||
| 178 | 182 | ||
| 179 | extern struct notifier_block ovs_dp_device_notifier; | 183 | extern struct notifier_block ovs_dp_device_notifier; |
| 180 | extern struct genl_family dp_vport_genl_family; | 184 | extern struct genl_family dp_vport_genl_family; |
| 181 | extern struct genl_multicast_group ovs_dp_vport_multicast_group; | ||
| 182 | 185 | ||
| 183 | void ovs_dp_process_received_packet(struct vport *, struct sk_buff *); | 186 | void ovs_dp_process_received_packet(struct vport *, struct sk_buff *); |
| 184 | void ovs_dp_detach_port(struct vport *); | 187 | void ovs_dp_detach_port(struct vport *); |
| 185 | int ovs_dp_upcall(struct datapath *, struct sk_buff *, | 188 | int ovs_dp_upcall(struct datapath *, struct sk_buff *, |
| 186 | const struct dp_upcall_info *); | 189 | const struct dp_upcall_info *); |
| 187 | 190 | ||
| 188 | const char *ovs_dp_name(const struct datapath *dp); | ||
| 189 | struct sk_buff *ovs_vport_cmd_build_info(struct vport *, u32 pid, u32 seq, | 191 | struct sk_buff *ovs_vport_cmd_build_info(struct vport *, u32 pid, u32 seq, |
| 190 | u8 cmd); | 192 | u8 cmd); |
| 191 | 193 | ||
diff --git a/net/openvswitch/flow.c b/net/openvswitch/flow.c index b409f5279601..16f4b46161d4 100644 --- a/net/openvswitch/flow.c +++ b/net/openvswitch/flow.c | |||
| @@ -35,6 +35,7 @@ | |||
| 35 | #include <linux/ip.h> | 35 | #include <linux/ip.h> |
| 36 | #include <linux/ipv6.h> | 36 | #include <linux/ipv6.h> |
| 37 | #include <linux/sctp.h> | 37 | #include <linux/sctp.h> |
| 38 | #include <linux/smp.h> | ||
| 38 | #include <linux/tcp.h> | 39 | #include <linux/tcp.h> |
| 39 | #include <linux/udp.h> | 40 | #include <linux/udp.h> |
| 40 | #include <linux/icmp.h> | 41 | #include <linux/icmp.h> |
| @@ -60,10 +61,16 @@ u64 ovs_flow_used_time(unsigned long flow_jiffies) | |||
| 60 | 61 | ||
| 61 | #define TCP_FLAGS_BE16(tp) (*(__be16 *)&tcp_flag_word(tp) & htons(0x0FFF)) | 62 | #define TCP_FLAGS_BE16(tp) (*(__be16 *)&tcp_flag_word(tp) & htons(0x0FFF)) |
| 62 | 63 | ||
| 63 | void ovs_flow_used(struct sw_flow *flow, struct sk_buff *skb) | 64 | void ovs_flow_stats_update(struct sw_flow *flow, struct sk_buff *skb) |
| 64 | { | 65 | { |
| 66 | struct flow_stats *stats; | ||
| 65 | __be16 tcp_flags = 0; | 67 | __be16 tcp_flags = 0; |
| 66 | 68 | ||
| 69 | if (!flow->stats.is_percpu) | ||
| 70 | stats = flow->stats.stat; | ||
| 71 | else | ||
| 72 | stats = this_cpu_ptr(flow->stats.cpu_stats); | ||
| 73 | |||
| 67 | if ((flow->key.eth.type == htons(ETH_P_IP) || | 74 | if ((flow->key.eth.type == htons(ETH_P_IP) || |
| 68 | flow->key.eth.type == htons(ETH_P_IPV6)) && | 75 | flow->key.eth.type == htons(ETH_P_IPV6)) && |
| 69 | flow->key.ip.proto == IPPROTO_TCP && | 76 | flow->key.ip.proto == IPPROTO_TCP && |
| @@ -71,12 +78,87 @@ void ovs_flow_used(struct sw_flow *flow, struct sk_buff *skb) | |||
| 71 | tcp_flags = TCP_FLAGS_BE16(tcp_hdr(skb)); | 78 | tcp_flags = TCP_FLAGS_BE16(tcp_hdr(skb)); |
| 72 | } | 79 | } |
| 73 | 80 | ||
| 74 | spin_lock(&flow->lock); | 81 | spin_lock(&stats->lock); |
| 75 | flow->used = jiffies; | 82 | stats->used = jiffies; |
| 76 | flow->packet_count++; | 83 | stats->packet_count++; |
| 77 | flow->byte_count += skb->len; | 84 | stats->byte_count += skb->len; |
| 78 | flow->tcp_flags |= tcp_flags; | 85 | stats->tcp_flags |= tcp_flags; |
| 79 | spin_unlock(&flow->lock); | 86 | spin_unlock(&stats->lock); |
| 87 | } | ||
| 88 | |||
| 89 | static void stats_read(struct flow_stats *stats, | ||
| 90 | struct ovs_flow_stats *ovs_stats, | ||
| 91 | unsigned long *used, __be16 *tcp_flags) | ||
| 92 | { | ||
| 93 | spin_lock(&stats->lock); | ||
| 94 | if (time_after(stats->used, *used)) | ||
| 95 | *used = stats->used; | ||
| 96 | *tcp_flags |= stats->tcp_flags; | ||
| 97 | ovs_stats->n_packets += stats->packet_count; | ||
| 98 | ovs_stats->n_bytes += stats->byte_count; | ||
| 99 | spin_unlock(&stats->lock); | ||
| 100 | } | ||
| 101 | |||
| 102 | void ovs_flow_stats_get(struct sw_flow *flow, struct ovs_flow_stats *ovs_stats, | ||
| 103 | unsigned long *used, __be16 *tcp_flags) | ||
| 104 | { | ||
| 105 | int cpu, cur_cpu; | ||
| 106 | |||
| 107 | *used = 0; | ||
| 108 | *tcp_flags = 0; | ||
| 109 | memset(ovs_stats, 0, sizeof(*ovs_stats)); | ||
| 110 | |||
| 111 | if (!flow->stats.is_percpu) { | ||
| 112 | stats_read(flow->stats.stat, ovs_stats, used, tcp_flags); | ||
| 113 | } else { | ||
| 114 | cur_cpu = get_cpu(); | ||
| 115 | for_each_possible_cpu(cpu) { | ||
| 116 | struct flow_stats *stats; | ||
| 117 | |||
| 118 | if (cpu == cur_cpu) | ||
| 119 | local_bh_disable(); | ||
| 120 | |||
| 121 | stats = per_cpu_ptr(flow->stats.cpu_stats, cpu); | ||
| 122 | stats_read(stats, ovs_stats, used, tcp_flags); | ||
| 123 | |||
| 124 | if (cpu == cur_cpu) | ||
| 125 | local_bh_enable(); | ||
| 126 | } | ||
| 127 | put_cpu(); | ||
| 128 | } | ||
| 129 | } | ||
| 130 | |||
| 131 | static void stats_reset(struct flow_stats *stats) | ||
| 132 | { | ||
| 133 | spin_lock(&stats->lock); | ||
| 134 | stats->used = 0; | ||
| 135 | stats->packet_count = 0; | ||
| 136 | stats->byte_count = 0; | ||
| 137 | stats->tcp_flags = 0; | ||
| 138 | spin_unlock(&stats->lock); | ||
| 139 | } | ||
| 140 | |||
| 141 | void ovs_flow_stats_clear(struct sw_flow *flow) | ||
| 142 | { | ||
| 143 | int cpu, cur_cpu; | ||
| 144 | |||
| 145 | if (!flow->stats.is_percpu) { | ||
| 146 | stats_reset(flow->stats.stat); | ||
| 147 | } else { | ||
| 148 | cur_cpu = get_cpu(); | ||
| 149 | |||
| 150 | for_each_possible_cpu(cpu) { | ||
| 151 | |||
| 152 | if (cpu == cur_cpu) | ||
| 153 | local_bh_disable(); | ||
| 154 | |||
| 155 | stats_reset(per_cpu_ptr(flow->stats.cpu_stats, cpu)); | ||
| 156 | |||
| 157 | if (cpu == cur_cpu) | ||
| 158 | local_bh_enable(); | ||
| 159 | } | ||
| 160 | put_cpu(); | ||
| 161 | } | ||
| 80 | } | 162 | } |
| 81 | 163 | ||
| 82 | static int check_header(struct sk_buff *skb, int len) | 164 | static int check_header(struct sk_buff *skb, int len) |
diff --git a/net/openvswitch/flow.h b/net/openvswitch/flow.h index 1510f51dbf74..2d770e28a3a3 100644 --- a/net/openvswitch/flow.h +++ b/net/openvswitch/flow.h | |||
| @@ -19,6 +19,7 @@ | |||
| 19 | #ifndef FLOW_H | 19 | #ifndef FLOW_H |
| 20 | #define FLOW_H 1 | 20 | #define FLOW_H 1 |
| 21 | 21 | ||
| 22 | #include <linux/cache.h> | ||
| 22 | #include <linux/kernel.h> | 23 | #include <linux/kernel.h> |
| 23 | #include <linux/netlink.h> | 24 | #include <linux/netlink.h> |
| 24 | #include <linux/openvswitch.h> | 25 | #include <linux/openvswitch.h> |
| @@ -122,8 +123,8 @@ struct sw_flow_key { | |||
| 122 | } __aligned(BITS_PER_LONG/8); /* Ensure that we can do comparisons as longs. */ | 123 | } __aligned(BITS_PER_LONG/8); /* Ensure that we can do comparisons as longs. */ |
| 123 | 124 | ||
| 124 | struct sw_flow_key_range { | 125 | struct sw_flow_key_range { |
| 125 | size_t start; | 126 | unsigned short int start; |
| 126 | size_t end; | 127 | unsigned short int end; |
| 127 | }; | 128 | }; |
| 128 | 129 | ||
| 129 | struct sw_flow_mask { | 130 | struct sw_flow_mask { |
| @@ -146,6 +147,22 @@ struct sw_flow_actions { | |||
| 146 | struct nlattr actions[]; | 147 | struct nlattr actions[]; |
| 147 | }; | 148 | }; |
| 148 | 149 | ||
| 150 | struct flow_stats { | ||
| 151 | u64 packet_count; /* Number of packets matched. */ | ||
| 152 | u64 byte_count; /* Number of bytes matched. */ | ||
| 153 | unsigned long used; /* Last used time (in jiffies). */ | ||
| 154 | spinlock_t lock; /* Lock for atomic stats update. */ | ||
| 155 | __be16 tcp_flags; /* Union of seen TCP flags. */ | ||
| 156 | }; | ||
| 157 | |||
| 158 | struct sw_flow_stats { | ||
| 159 | bool is_percpu; | ||
| 160 | union { | ||
| 161 | struct flow_stats *stat; | ||
| 162 | struct flow_stats __percpu *cpu_stats; | ||
| 163 | }; | ||
| 164 | }; | ||
| 165 | |||
| 149 | struct sw_flow { | 166 | struct sw_flow { |
| 150 | struct rcu_head rcu; | 167 | struct rcu_head rcu; |
| 151 | struct hlist_node hash_node[2]; | 168 | struct hlist_node hash_node[2]; |
| @@ -155,12 +172,7 @@ struct sw_flow { | |||
| 155 | struct sw_flow_key unmasked_key; | 172 | struct sw_flow_key unmasked_key; |
| 156 | struct sw_flow_mask *mask; | 173 | struct sw_flow_mask *mask; |
| 157 | struct sw_flow_actions __rcu *sf_acts; | 174 | struct sw_flow_actions __rcu *sf_acts; |
| 158 | 175 | struct sw_flow_stats stats; | |
| 159 | spinlock_t lock; /* Lock for values below. */ | ||
| 160 | unsigned long used; /* Last used time (in jiffies). */ | ||
| 161 | u64 packet_count; /* Number of packets matched. */ | ||
| 162 | u64 byte_count; /* Number of bytes matched. */ | ||
| 163 | __be16 tcp_flags; /* Union of seen TCP flags. */ | ||
| 164 | }; | 176 | }; |
| 165 | 177 | ||
| 166 | struct arp_eth_header { | 178 | struct arp_eth_header { |
| @@ -177,7 +189,10 @@ struct arp_eth_header { | |||
| 177 | unsigned char ar_tip[4]; /* target IP address */ | 189 | unsigned char ar_tip[4]; /* target IP address */ |
| 178 | } __packed; | 190 | } __packed; |
| 179 | 191 | ||
| 180 | void ovs_flow_used(struct sw_flow *, struct sk_buff *); | 192 | void ovs_flow_stats_update(struct sw_flow *flow, struct sk_buff *skb); |
| 193 | void ovs_flow_stats_get(struct sw_flow *flow, struct ovs_flow_stats *stats, | ||
| 194 | unsigned long *used, __be16 *tcp_flags); | ||
| 195 | void ovs_flow_stats_clear(struct sw_flow *flow); | ||
| 181 | u64 ovs_flow_used_time(unsigned long flow_jiffies); | 196 | u64 ovs_flow_used_time(unsigned long flow_jiffies); |
| 182 | 197 | ||
| 183 | int ovs_flow_extract(struct sk_buff *, u16 in_port, struct sw_flow_key *); | 198 | int ovs_flow_extract(struct sk_buff *, u16 in_port, struct sw_flow_key *); |
diff --git a/net/openvswitch/flow_netlink.c b/net/openvswitch/flow_netlink.c index 2bc1bc1aca3b..4d000acaed0d 100644 --- a/net/openvswitch/flow_netlink.c +++ b/net/openvswitch/flow_netlink.c | |||
| @@ -266,6 +266,20 @@ static bool is_all_zero(const u8 *fp, size_t size) | |||
| 266 | return true; | 266 | return true; |
| 267 | } | 267 | } |
| 268 | 268 | ||
| 269 | static bool is_all_set(const u8 *fp, size_t size) | ||
| 270 | { | ||
| 271 | int i; | ||
| 272 | |||
| 273 | if (!fp) | ||
| 274 | return false; | ||
| 275 | |||
| 276 | for (i = 0; i < size; i++) | ||
| 277 | if (fp[i] != 0xff) | ||
| 278 | return false; | ||
| 279 | |||
| 280 | return true; | ||
| 281 | } | ||
| 282 | |||
| 269 | static int __parse_flow_nlattrs(const struct nlattr *attr, | 283 | static int __parse_flow_nlattrs(const struct nlattr *attr, |
| 270 | const struct nlattr *a[], | 284 | const struct nlattr *a[], |
| 271 | u64 *attrsp, bool nz) | 285 | u64 *attrsp, bool nz) |
| @@ -487,8 +501,9 @@ static int metadata_from_nlattrs(struct sw_flow_match *match, u64 *attrs, | |||
| 487 | return 0; | 501 | return 0; |
| 488 | } | 502 | } |
| 489 | 503 | ||
| 490 | static int ovs_key_from_nlattrs(struct sw_flow_match *match, u64 attrs, | 504 | static int ovs_key_from_nlattrs(struct sw_flow_match *match, bool *exact_5tuple, |
| 491 | const struct nlattr **a, bool is_mask) | 505 | u64 attrs, const struct nlattr **a, |
| 506 | bool is_mask) | ||
| 492 | { | 507 | { |
| 493 | int err; | 508 | int err; |
| 494 | u64 orig_attrs = attrs; | 509 | u64 orig_attrs = attrs; |
| @@ -545,6 +560,11 @@ static int ovs_key_from_nlattrs(struct sw_flow_match *match, u64 attrs, | |||
| 545 | SW_FLOW_KEY_PUT(match, eth.type, htons(ETH_P_802_2), is_mask); | 560 | SW_FLOW_KEY_PUT(match, eth.type, htons(ETH_P_802_2), is_mask); |
| 546 | } | 561 | } |
| 547 | 562 | ||
| 563 | if (is_mask && exact_5tuple) { | ||
| 564 | if (match->mask->key.eth.type != htons(0xffff)) | ||
| 565 | *exact_5tuple = false; | ||
| 566 | } | ||
| 567 | |||
| 548 | if (attrs & (1 << OVS_KEY_ATTR_IPV4)) { | 568 | if (attrs & (1 << OVS_KEY_ATTR_IPV4)) { |
| 549 | const struct ovs_key_ipv4 *ipv4_key; | 569 | const struct ovs_key_ipv4 *ipv4_key; |
| 550 | 570 | ||
| @@ -567,6 +587,13 @@ static int ovs_key_from_nlattrs(struct sw_flow_match *match, u64 attrs, | |||
| 567 | SW_FLOW_KEY_PUT(match, ipv4.addr.dst, | 587 | SW_FLOW_KEY_PUT(match, ipv4.addr.dst, |
| 568 | ipv4_key->ipv4_dst, is_mask); | 588 | ipv4_key->ipv4_dst, is_mask); |
| 569 | attrs &= ~(1 << OVS_KEY_ATTR_IPV4); | 589 | attrs &= ~(1 << OVS_KEY_ATTR_IPV4); |
| 590 | |||
| 591 | if (is_mask && exact_5tuple && *exact_5tuple) { | ||
| 592 | if (ipv4_key->ipv4_proto != 0xff || | ||
| 593 | ipv4_key->ipv4_src != htonl(0xffffffff) || | ||
| 594 | ipv4_key->ipv4_dst != htonl(0xffffffff)) | ||
| 595 | *exact_5tuple = false; | ||
| 596 | } | ||
| 570 | } | 597 | } |
| 571 | 598 | ||
| 572 | if (attrs & (1 << OVS_KEY_ATTR_IPV6)) { | 599 | if (attrs & (1 << OVS_KEY_ATTR_IPV6)) { |
| @@ -598,6 +625,13 @@ static int ovs_key_from_nlattrs(struct sw_flow_match *match, u64 attrs, | |||
| 598 | is_mask); | 625 | is_mask); |
| 599 | 626 | ||
| 600 | attrs &= ~(1 << OVS_KEY_ATTR_IPV6); | 627 | attrs &= ~(1 << OVS_KEY_ATTR_IPV6); |
| 628 | |||
| 629 | if (is_mask && exact_5tuple && *exact_5tuple) { | ||
| 630 | if (ipv6_key->ipv6_proto != 0xff || | ||
| 631 | !is_all_set((u8 *)ipv6_key->ipv6_src, sizeof(match->key->ipv6.addr.src)) || | ||
| 632 | !is_all_set((u8 *)ipv6_key->ipv6_dst, sizeof(match->key->ipv6.addr.dst))) | ||
| 633 | *exact_5tuple = false; | ||
| 634 | } | ||
| 601 | } | 635 | } |
| 602 | 636 | ||
| 603 | if (attrs & (1 << OVS_KEY_ATTR_ARP)) { | 637 | if (attrs & (1 << OVS_KEY_ATTR_ARP)) { |
| @@ -640,6 +674,11 @@ static int ovs_key_from_nlattrs(struct sw_flow_match *match, u64 attrs, | |||
| 640 | tcp_key->tcp_dst, is_mask); | 674 | tcp_key->tcp_dst, is_mask); |
| 641 | } | 675 | } |
| 642 | attrs &= ~(1 << OVS_KEY_ATTR_TCP); | 676 | attrs &= ~(1 << OVS_KEY_ATTR_TCP); |
| 677 | |||
| 678 | if (is_mask && exact_5tuple && *exact_5tuple && | ||
| 679 | (tcp_key->tcp_src != htons(0xffff) || | ||
| 680 | tcp_key->tcp_dst != htons(0xffff))) | ||
| 681 | *exact_5tuple = false; | ||
| 643 | } | 682 | } |
| 644 | 683 | ||
| 645 | if (attrs & (1 << OVS_KEY_ATTR_TCP_FLAGS)) { | 684 | if (attrs & (1 << OVS_KEY_ATTR_TCP_FLAGS)) { |
| @@ -671,6 +710,11 @@ static int ovs_key_from_nlattrs(struct sw_flow_match *match, u64 attrs, | |||
| 671 | udp_key->udp_dst, is_mask); | 710 | udp_key->udp_dst, is_mask); |
| 672 | } | 711 | } |
| 673 | attrs &= ~(1 << OVS_KEY_ATTR_UDP); | 712 | attrs &= ~(1 << OVS_KEY_ATTR_UDP); |
| 713 | |||
| 714 | if (is_mask && exact_5tuple && *exact_5tuple && | ||
| 715 | (udp_key->udp_src != htons(0xffff) || | ||
| 716 | udp_key->udp_dst != htons(0xffff))) | ||
| 717 | *exact_5tuple = false; | ||
| 674 | } | 718 | } |
| 675 | 719 | ||
| 676 | if (attrs & (1 << OVS_KEY_ATTR_SCTP)) { | 720 | if (attrs & (1 << OVS_KEY_ATTR_SCTP)) { |
| @@ -756,6 +800,7 @@ static void sw_flow_mask_set(struct sw_flow_mask *mask, | |||
| 756 | * attribute specifies the mask field of the wildcarded flow. | 800 | * attribute specifies the mask field of the wildcarded flow. |
| 757 | */ | 801 | */ |
| 758 | int ovs_nla_get_match(struct sw_flow_match *match, | 802 | int ovs_nla_get_match(struct sw_flow_match *match, |
| 803 | bool *exact_5tuple, | ||
| 759 | const struct nlattr *key, | 804 | const struct nlattr *key, |
| 760 | const struct nlattr *mask) | 805 | const struct nlattr *mask) |
| 761 | { | 806 | { |
| @@ -803,10 +848,13 @@ int ovs_nla_get_match(struct sw_flow_match *match, | |||
| 803 | } | 848 | } |
| 804 | } | 849 | } |
| 805 | 850 | ||
| 806 | err = ovs_key_from_nlattrs(match, key_attrs, a, false); | 851 | err = ovs_key_from_nlattrs(match, NULL, key_attrs, a, false); |
| 807 | if (err) | 852 | if (err) |
| 808 | return err; | 853 | return err; |
| 809 | 854 | ||
| 855 | if (exact_5tuple) | ||
| 856 | *exact_5tuple = true; | ||
| 857 | |||
| 810 | if (mask) { | 858 | if (mask) { |
| 811 | err = parse_flow_mask_nlattrs(mask, a, &mask_attrs); | 859 | err = parse_flow_mask_nlattrs(mask, a, &mask_attrs); |
| 812 | if (err) | 860 | if (err) |
| @@ -844,7 +892,7 @@ int ovs_nla_get_match(struct sw_flow_match *match, | |||
| 844 | } | 892 | } |
| 845 | } | 893 | } |
| 846 | 894 | ||
| 847 | err = ovs_key_from_nlattrs(match, mask_attrs, a, true); | 895 | err = ovs_key_from_nlattrs(match, exact_5tuple, mask_attrs, a, true); |
| 848 | if (err) | 896 | if (err) |
| 849 | return err; | 897 | return err; |
| 850 | } else { | 898 | } else { |
| @@ -1128,19 +1176,11 @@ struct sw_flow_actions *ovs_nla_alloc_flow_actions(int size) | |||
| 1128 | return sfa; | 1176 | return sfa; |
| 1129 | } | 1177 | } |
| 1130 | 1178 | ||
| 1131 | /* RCU callback used by ovs_nla_free_flow_actions. */ | ||
| 1132 | static void rcu_free_acts_callback(struct rcu_head *rcu) | ||
| 1133 | { | ||
| 1134 | struct sw_flow_actions *sf_acts = container_of(rcu, | ||
| 1135 | struct sw_flow_actions, rcu); | ||
| 1136 | kfree(sf_acts); | ||
| 1137 | } | ||
| 1138 | |||
| 1139 | /* Schedules 'sf_acts' to be freed after the next RCU grace period. | 1179 | /* Schedules 'sf_acts' to be freed after the next RCU grace period. |
| 1140 | * The caller must hold rcu_read_lock for this to be sensible. */ | 1180 | * The caller must hold rcu_read_lock for this to be sensible. */ |
| 1141 | void ovs_nla_free_flow_actions(struct sw_flow_actions *sf_acts) | 1181 | void ovs_nla_free_flow_actions(struct sw_flow_actions *sf_acts) |
| 1142 | { | 1182 | { |
| 1143 | call_rcu(&sf_acts->rcu, rcu_free_acts_callback); | 1183 | kfree_rcu(sf_acts, rcu); |
| 1144 | } | 1184 | } |
| 1145 | 1185 | ||
| 1146 | static struct nlattr *reserve_sfa_size(struct sw_flow_actions **sfa, | 1186 | static struct nlattr *reserve_sfa_size(struct sw_flow_actions **sfa, |
diff --git a/net/openvswitch/flow_netlink.h b/net/openvswitch/flow_netlink.h index 440151045d39..b31fbe28bc7a 100644 --- a/net/openvswitch/flow_netlink.h +++ b/net/openvswitch/flow_netlink.h | |||
| @@ -45,6 +45,7 @@ int ovs_nla_put_flow(const struct sw_flow_key *, | |||
| 45 | int ovs_nla_get_flow_metadata(struct sw_flow *flow, | 45 | int ovs_nla_get_flow_metadata(struct sw_flow *flow, |
| 46 | const struct nlattr *attr); | 46 | const struct nlattr *attr); |
| 47 | int ovs_nla_get_match(struct sw_flow_match *match, | 47 | int ovs_nla_get_match(struct sw_flow_match *match, |
| 48 | bool *exact_5tuple, | ||
| 48 | const struct nlattr *, | 49 | const struct nlattr *, |
| 49 | const struct nlattr *); | 50 | const struct nlattr *); |
| 50 | 51 | ||
diff --git a/net/openvswitch/flow_table.c b/net/openvswitch/flow_table.c index e42542706087..c58a0fe3c889 100644 --- a/net/openvswitch/flow_table.c +++ b/net/openvswitch/flow_table.c | |||
| @@ -25,7 +25,7 @@ | |||
| 25 | #include <linux/if_vlan.h> | 25 | #include <linux/if_vlan.h> |
| 26 | #include <net/llc_pdu.h> | 26 | #include <net/llc_pdu.h> |
| 27 | #include <linux/kernel.h> | 27 | #include <linux/kernel.h> |
| 28 | #include <linux/jhash.h> | 28 | #include <linux/hash.h> |
| 29 | #include <linux/jiffies.h> | 29 | #include <linux/jiffies.h> |
| 30 | #include <linux/llc.h> | 30 | #include <linux/llc.h> |
| 31 | #include <linux/module.h> | 31 | #include <linux/module.h> |
| @@ -44,8 +44,6 @@ | |||
| 44 | #include <net/ipv6.h> | 44 | #include <net/ipv6.h> |
| 45 | #include <net/ndisc.h> | 45 | #include <net/ndisc.h> |
| 46 | 46 | ||
| 47 | #include "datapath.h" | ||
| 48 | |||
| 49 | #define TBL_MIN_BUCKETS 1024 | 47 | #define TBL_MIN_BUCKETS 1024 |
| 50 | #define REHASH_INTERVAL (10 * 60 * HZ) | 48 | #define REHASH_INTERVAL (10 * 60 * HZ) |
| 51 | 49 | ||
| @@ -72,19 +70,42 @@ void ovs_flow_mask_key(struct sw_flow_key *dst, const struct sw_flow_key *src, | |||
| 72 | *d++ = *s++ & *m++; | 70 | *d++ = *s++ & *m++; |
| 73 | } | 71 | } |
| 74 | 72 | ||
| 75 | struct sw_flow *ovs_flow_alloc(void) | 73 | struct sw_flow *ovs_flow_alloc(bool percpu_stats) |
| 76 | { | 74 | { |
| 77 | struct sw_flow *flow; | 75 | struct sw_flow *flow; |
| 76 | int cpu; | ||
| 78 | 77 | ||
| 79 | flow = kmem_cache_alloc(flow_cache, GFP_KERNEL); | 78 | flow = kmem_cache_alloc(flow_cache, GFP_KERNEL); |
| 80 | if (!flow) | 79 | if (!flow) |
| 81 | return ERR_PTR(-ENOMEM); | 80 | return ERR_PTR(-ENOMEM); |
| 82 | 81 | ||
| 83 | spin_lock_init(&flow->lock); | ||
| 84 | flow->sf_acts = NULL; | 82 | flow->sf_acts = NULL; |
| 85 | flow->mask = NULL; | 83 | flow->mask = NULL; |
| 86 | 84 | ||
| 85 | flow->stats.is_percpu = percpu_stats; | ||
| 86 | |||
| 87 | if (!percpu_stats) { | ||
| 88 | flow->stats.stat = kzalloc(sizeof(*flow->stats.stat), GFP_KERNEL); | ||
| 89 | if (!flow->stats.stat) | ||
| 90 | goto err; | ||
| 91 | |||
| 92 | spin_lock_init(&flow->stats.stat->lock); | ||
| 93 | } else { | ||
| 94 | flow->stats.cpu_stats = alloc_percpu(struct flow_stats); | ||
| 95 | if (!flow->stats.cpu_stats) | ||
| 96 | goto err; | ||
| 97 | |||
| 98 | for_each_possible_cpu(cpu) { | ||
| 99 | struct flow_stats *cpu_stats; | ||
| 100 | |||
| 101 | cpu_stats = per_cpu_ptr(flow->stats.cpu_stats, cpu); | ||
| 102 | spin_lock_init(&cpu_stats->lock); | ||
| 103 | } | ||
| 104 | } | ||
| 87 | return flow; | 105 | return flow; |
| 106 | err: | ||
| 107 | kmem_cache_free(flow_cache, flow); | ||
| 108 | return ERR_PTR(-ENOMEM); | ||
| 88 | } | 109 | } |
| 89 | 110 | ||
| 90 | int ovs_flow_tbl_count(struct flow_table *table) | 111 | int ovs_flow_tbl_count(struct flow_table *table) |
| @@ -118,6 +139,10 @@ static struct flex_array *alloc_buckets(unsigned int n_buckets) | |||
| 118 | static void flow_free(struct sw_flow *flow) | 139 | static void flow_free(struct sw_flow *flow) |
| 119 | { | 140 | { |
| 120 | kfree((struct sf_flow_acts __force *)flow->sf_acts); | 141 | kfree((struct sf_flow_acts __force *)flow->sf_acts); |
| 142 | if (flow->stats.is_percpu) | ||
| 143 | free_percpu(flow->stats.cpu_stats); | ||
| 144 | else | ||
| 145 | kfree(flow->stats.stat); | ||
| 121 | kmem_cache_free(flow_cache, flow); | 146 | kmem_cache_free(flow_cache, flow); |
| 122 | } | 147 | } |
| 123 | 148 | ||
| @@ -128,13 +153,6 @@ static void rcu_free_flow_callback(struct rcu_head *rcu) | |||
| 128 | flow_free(flow); | 153 | flow_free(flow); |
| 129 | } | 154 | } |
| 130 | 155 | ||
| 131 | static void rcu_free_sw_flow_mask_cb(struct rcu_head *rcu) | ||
| 132 | { | ||
| 133 | struct sw_flow_mask *mask = container_of(rcu, struct sw_flow_mask, rcu); | ||
| 134 | |||
| 135 | kfree(mask); | ||
| 136 | } | ||
| 137 | |||
| 138 | static void flow_mask_del_ref(struct sw_flow_mask *mask, bool deferred) | 156 | static void flow_mask_del_ref(struct sw_flow_mask *mask, bool deferred) |
| 139 | { | 157 | { |
| 140 | if (!mask) | 158 | if (!mask) |
| @@ -146,7 +164,7 @@ static void flow_mask_del_ref(struct sw_flow_mask *mask, bool deferred) | |||
| 146 | if (!mask->ref_count) { | 164 | if (!mask->ref_count) { |
| 147 | list_del_rcu(&mask->list); | 165 | list_del_rcu(&mask->list); |
| 148 | if (deferred) | 166 | if (deferred) |
| 149 | call_rcu(&mask->rcu, rcu_free_sw_flow_mask_cb); | 167 | kfree_rcu(mask, rcu); |
| 150 | else | 168 | else |
| 151 | kfree(mask); | 169 | kfree(mask); |
| 152 | } | 170 | } |
| @@ -362,7 +380,7 @@ static u32 flow_hash(const struct sw_flow_key *key, int key_start, | |||
| 362 | /* Make sure number of hash bytes are multiple of u32. */ | 380 | /* Make sure number of hash bytes are multiple of u32. */ |
| 363 | BUILD_BUG_ON(sizeof(long) % sizeof(u32)); | 381 | BUILD_BUG_ON(sizeof(long) % sizeof(u32)); |
| 364 | 382 | ||
| 365 | return jhash2(hash_key, hash_u32s, 0); | 383 | return arch_fast_hash2(hash_key, hash_u32s, 0); |
| 366 | } | 384 | } |
| 367 | 385 | ||
| 368 | static int flow_key_start(const struct sw_flow_key *key) | 386 | static int flow_key_start(const struct sw_flow_key *key) |
| @@ -429,11 +447,11 @@ static struct sw_flow *masked_flow_lookup(struct table_instance *ti, | |||
| 429 | return NULL; | 447 | return NULL; |
| 430 | } | 448 | } |
| 431 | 449 | ||
| 432 | struct sw_flow *ovs_flow_tbl_lookup(struct flow_table *tbl, | 450 | struct sw_flow *ovs_flow_tbl_lookup_stats(struct flow_table *tbl, |
| 433 | const struct sw_flow_key *key, | 451 | const struct sw_flow_key *key, |
| 434 | u32 *n_mask_hit) | 452 | u32 *n_mask_hit) |
| 435 | { | 453 | { |
| 436 | struct table_instance *ti = rcu_dereference(tbl->ti); | 454 | struct table_instance *ti = rcu_dereference_ovsl(tbl->ti); |
| 437 | struct sw_flow_mask *mask; | 455 | struct sw_flow_mask *mask; |
| 438 | struct sw_flow *flow; | 456 | struct sw_flow *flow; |
| 439 | 457 | ||
| @@ -447,6 +465,14 @@ struct sw_flow *ovs_flow_tbl_lookup(struct flow_table *tbl, | |||
| 447 | return NULL; | 465 | return NULL; |
| 448 | } | 466 | } |
| 449 | 467 | ||
| 468 | struct sw_flow *ovs_flow_tbl_lookup(struct flow_table *tbl, | ||
| 469 | const struct sw_flow_key *key) | ||
| 470 | { | ||
| 471 | u32 __always_unused n_mask_hit; | ||
| 472 | |||
| 473 | return ovs_flow_tbl_lookup_stats(tbl, key, &n_mask_hit); | ||
| 474 | } | ||
| 475 | |||
| 450 | int ovs_flow_tbl_num_masks(const struct flow_table *table) | 476 | int ovs_flow_tbl_num_masks(const struct flow_table *table) |
| 451 | { | 477 | { |
| 452 | struct sw_flow_mask *mask; | 478 | struct sw_flow_mask *mask; |
| @@ -514,11 +540,7 @@ static struct sw_flow_mask *flow_mask_find(const struct flow_table *tbl, | |||
| 514 | return NULL; | 540 | return NULL; |
| 515 | } | 541 | } |
| 516 | 542 | ||
| 517 | /** | 543 | /* Add 'mask' into the mask list, if it is not already there. */ |
| 518 | * add a new mask into the mask list. | ||
| 519 | * The caller needs to make sure that 'mask' is not the same | ||
| 520 | * as any masks that are already on the list. | ||
| 521 | */ | ||
| 522 | static int flow_mask_insert(struct flow_table *tbl, struct sw_flow *flow, | 544 | static int flow_mask_insert(struct flow_table *tbl, struct sw_flow *flow, |
| 523 | struct sw_flow_mask *new) | 545 | struct sw_flow_mask *new) |
| 524 | { | 546 | { |
diff --git a/net/openvswitch/flow_table.h b/net/openvswitch/flow_table.h index fbe45d5ad07d..1996e34c0fd8 100644 --- a/net/openvswitch/flow_table.h +++ b/net/openvswitch/flow_table.h | |||
| @@ -55,7 +55,7 @@ struct flow_table { | |||
| 55 | int ovs_flow_init(void); | 55 | int ovs_flow_init(void); |
| 56 | void ovs_flow_exit(void); | 56 | void ovs_flow_exit(void); |
| 57 | 57 | ||
| 58 | struct sw_flow *ovs_flow_alloc(void); | 58 | struct sw_flow *ovs_flow_alloc(bool percpu_stats); |
| 59 | void ovs_flow_free(struct sw_flow *, bool deferred); | 59 | void ovs_flow_free(struct sw_flow *, bool deferred); |
| 60 | 60 | ||
| 61 | int ovs_flow_tbl_init(struct flow_table *); | 61 | int ovs_flow_tbl_init(struct flow_table *); |
| @@ -69,9 +69,11 @@ void ovs_flow_tbl_remove(struct flow_table *table, struct sw_flow *flow); | |||
| 69 | int ovs_flow_tbl_num_masks(const struct flow_table *table); | 69 | int ovs_flow_tbl_num_masks(const struct flow_table *table); |
| 70 | struct sw_flow *ovs_flow_tbl_dump_next(struct table_instance *table, | 70 | struct sw_flow *ovs_flow_tbl_dump_next(struct table_instance *table, |
| 71 | u32 *bucket, u32 *idx); | 71 | u32 *bucket, u32 *idx); |
| 72 | struct sw_flow *ovs_flow_tbl_lookup(struct flow_table *, | 72 | struct sw_flow *ovs_flow_tbl_lookup_stats(struct flow_table *, |
| 73 | const struct sw_flow_key *, | 73 | const struct sw_flow_key *, |
| 74 | u32 *n_mask_hit); | 74 | u32 *n_mask_hit); |
| 75 | struct sw_flow *ovs_flow_tbl_lookup(struct flow_table *, | ||
| 76 | const struct sw_flow_key *); | ||
| 75 | 77 | ||
| 76 | bool ovs_flow_cmp_unmasked_key(const struct sw_flow *flow, | 78 | bool ovs_flow_cmp_unmasked_key(const struct sw_flow *flow, |
| 77 | struct sw_flow_match *match); | 79 | struct sw_flow_match *match); |
diff --git a/net/openvswitch/vport.c b/net/openvswitch/vport.c index d830a95f03a4..208dd9a26dd1 100644 --- a/net/openvswitch/vport.c +++ b/net/openvswitch/vport.c | |||
| @@ -33,6 +33,9 @@ | |||
| 33 | #include "vport.h" | 33 | #include "vport.h" |
| 34 | #include "vport-internal_dev.h" | 34 | #include "vport-internal_dev.h" |
| 35 | 35 | ||
| 36 | static void ovs_vport_record_error(struct vport *, | ||
| 37 | enum vport_err_type err_type); | ||
| 38 | |||
| 36 | /* List of statically compiled vport implementations. Don't forget to also | 39 | /* List of statically compiled vport implementations. Don't forget to also |
| 37 | * add yours to the list at the bottom of vport.h. */ | 40 | * add yours to the list at the bottom of vport.h. */ |
| 38 | static const struct vport_ops *vport_ops_list[] = { | 41 | static const struct vport_ops *vport_ops_list[] = { |
| @@ -136,14 +139,14 @@ struct vport *ovs_vport_alloc(int priv_size, const struct vport_ops *ops, | |||
| 136 | vport->ops = ops; | 139 | vport->ops = ops; |
| 137 | INIT_HLIST_NODE(&vport->dp_hash_node); | 140 | INIT_HLIST_NODE(&vport->dp_hash_node); |
| 138 | 141 | ||
| 139 | vport->percpu_stats = alloc_percpu(struct pcpu_tstats); | 142 | vport->percpu_stats = alloc_percpu(struct pcpu_sw_netstats); |
| 140 | if (!vport->percpu_stats) { | 143 | if (!vport->percpu_stats) { |
| 141 | kfree(vport); | 144 | kfree(vport); |
| 142 | return ERR_PTR(-ENOMEM); | 145 | return ERR_PTR(-ENOMEM); |
| 143 | } | 146 | } |
| 144 | 147 | ||
| 145 | for_each_possible_cpu(i) { | 148 | for_each_possible_cpu(i) { |
| 146 | struct pcpu_tstats *vport_stats; | 149 | struct pcpu_sw_netstats *vport_stats; |
| 147 | vport_stats = per_cpu_ptr(vport->percpu_stats, i); | 150 | vport_stats = per_cpu_ptr(vport->percpu_stats, i); |
| 148 | u64_stats_init(&vport_stats->syncp); | 151 | u64_stats_init(&vport_stats->syncp); |
| 149 | } | 152 | } |
| @@ -275,8 +278,8 @@ void ovs_vport_get_stats(struct vport *vport, struct ovs_vport_stats *stats) | |||
| 275 | spin_unlock_bh(&vport->stats_lock); | 278 | spin_unlock_bh(&vport->stats_lock); |
| 276 | 279 | ||
| 277 | for_each_possible_cpu(i) { | 280 | for_each_possible_cpu(i) { |
| 278 | const struct pcpu_tstats *percpu_stats; | 281 | const struct pcpu_sw_netstats *percpu_stats; |
| 279 | struct pcpu_tstats local_stats; | 282 | struct pcpu_sw_netstats local_stats; |
| 280 | unsigned int start; | 283 | unsigned int start; |
| 281 | 284 | ||
| 282 | percpu_stats = per_cpu_ptr(vport->percpu_stats, i); | 285 | percpu_stats = per_cpu_ptr(vport->percpu_stats, i); |
| @@ -344,7 +347,7 @@ int ovs_vport_get_options(const struct vport *vport, struct sk_buff *skb) | |||
| 344 | void ovs_vport_receive(struct vport *vport, struct sk_buff *skb, | 347 | void ovs_vport_receive(struct vport *vport, struct sk_buff *skb, |
| 345 | struct ovs_key_ipv4_tunnel *tun_key) | 348 | struct ovs_key_ipv4_tunnel *tun_key) |
| 346 | { | 349 | { |
| 347 | struct pcpu_tstats *stats; | 350 | struct pcpu_sw_netstats *stats; |
| 348 | 351 | ||
| 349 | stats = this_cpu_ptr(vport->percpu_stats); | 352 | stats = this_cpu_ptr(vport->percpu_stats); |
| 350 | u64_stats_update_begin(&stats->syncp); | 353 | u64_stats_update_begin(&stats->syncp); |
| @@ -370,7 +373,7 @@ int ovs_vport_send(struct vport *vport, struct sk_buff *skb) | |||
| 370 | int sent = vport->ops->send(vport, skb); | 373 | int sent = vport->ops->send(vport, skb); |
| 371 | 374 | ||
| 372 | if (likely(sent > 0)) { | 375 | if (likely(sent > 0)) { |
| 373 | struct pcpu_tstats *stats; | 376 | struct pcpu_sw_netstats *stats; |
| 374 | 377 | ||
| 375 | stats = this_cpu_ptr(vport->percpu_stats); | 378 | stats = this_cpu_ptr(vport->percpu_stats); |
| 376 | 379 | ||
| @@ -396,7 +399,8 @@ int ovs_vport_send(struct vport *vport, struct sk_buff *skb) | |||
| 396 | * If using the vport generic stats layer indicate that an error of the given | 399 | * If using the vport generic stats layer indicate that an error of the given |
| 397 | * type has occurred. | 400 | * type has occurred. |
| 398 | */ | 401 | */ |
| 399 | void ovs_vport_record_error(struct vport *vport, enum vport_err_type err_type) | 402 | static void ovs_vport_record_error(struct vport *vport, |
| 403 | enum vport_err_type err_type) | ||
| 400 | { | 404 | { |
| 401 | spin_lock(&vport->stats_lock); | 405 | spin_lock(&vport->stats_lock); |
| 402 | 406 | ||
diff --git a/net/openvswitch/vport.h b/net/openvswitch/vport.h index 1a9fbcec6e1b..d7e50a17396c 100644 --- a/net/openvswitch/vport.h +++ b/net/openvswitch/vport.h | |||
| @@ -87,7 +87,7 @@ struct vport { | |||
| 87 | struct hlist_node dp_hash_node; | 87 | struct hlist_node dp_hash_node; |
| 88 | const struct vport_ops *ops; | 88 | const struct vport_ops *ops; |
| 89 | 89 | ||
| 90 | struct pcpu_tstats __percpu *percpu_stats; | 90 | struct pcpu_sw_netstats __percpu *percpu_stats; |
| 91 | 91 | ||
| 92 | spinlock_t stats_lock; | 92 | spinlock_t stats_lock; |
| 93 | struct vport_err_stats err_stats; | 93 | struct vport_err_stats err_stats; |
| @@ -192,7 +192,6 @@ static inline struct vport *vport_from_priv(const void *priv) | |||
| 192 | 192 | ||
| 193 | void ovs_vport_receive(struct vport *, struct sk_buff *, | 193 | void ovs_vport_receive(struct vport *, struct sk_buff *, |
| 194 | struct ovs_key_ipv4_tunnel *); | 194 | struct ovs_key_ipv4_tunnel *); |
| 195 | void ovs_vport_record_error(struct vport *, enum vport_err_type err_type); | ||
| 196 | 195 | ||
| 197 | /* List of statically compiled vport implementations. Don't forget to also | 196 | /* List of statically compiled vport implementations. Don't forget to also |
| 198 | * add yours to the list at the top of vport.c. */ | 197 | * add yours to the list at the top of vport.c. */ |
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 88cfbc189558..6a2bb37506c5 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c | |||
| @@ -88,7 +88,7 @@ | |||
| 88 | #include <linux/virtio_net.h> | 88 | #include <linux/virtio_net.h> |
| 89 | #include <linux/errqueue.h> | 89 | #include <linux/errqueue.h> |
| 90 | #include <linux/net_tstamp.h> | 90 | #include <linux/net_tstamp.h> |
| 91 | #include <linux/reciprocal_div.h> | 91 | #include <linux/percpu.h> |
| 92 | #ifdef CONFIG_INET | 92 | #ifdef CONFIG_INET |
| 93 | #include <net/inet_common.h> | 93 | #include <net/inet_common.h> |
| 94 | #endif | 94 | #endif |
| @@ -237,6 +237,48 @@ struct packet_skb_cb { | |||
| 237 | static void __fanout_unlink(struct sock *sk, struct packet_sock *po); | 237 | static void __fanout_unlink(struct sock *sk, struct packet_sock *po); |
| 238 | static void __fanout_link(struct sock *sk, struct packet_sock *po); | 238 | static void __fanout_link(struct sock *sk, struct packet_sock *po); |
| 239 | 239 | ||
| 240 | static int packet_direct_xmit(struct sk_buff *skb) | ||
| 241 | { | ||
| 242 | struct net_device *dev = skb->dev; | ||
| 243 | const struct net_device_ops *ops = dev->netdev_ops; | ||
| 244 | netdev_features_t features; | ||
| 245 | struct netdev_queue *txq; | ||
| 246 | u16 queue_map; | ||
| 247 | int ret; | ||
| 248 | |||
| 249 | if (unlikely(!netif_running(dev) || | ||
| 250 | !netif_carrier_ok(dev))) { | ||
| 251 | kfree_skb(skb); | ||
| 252 | return NET_XMIT_DROP; | ||
| 253 | } | ||
| 254 | |||
| 255 | features = netif_skb_features(skb); | ||
| 256 | if (skb_needs_linearize(skb, features) && | ||
| 257 | __skb_linearize(skb)) { | ||
| 258 | kfree_skb(skb); | ||
| 259 | return NET_XMIT_DROP; | ||
| 260 | } | ||
| 261 | |||
| 262 | queue_map = skb_get_queue_mapping(skb); | ||
| 263 | txq = netdev_get_tx_queue(dev, queue_map); | ||
| 264 | |||
| 265 | __netif_tx_lock_bh(txq); | ||
| 266 | if (unlikely(netif_xmit_frozen_or_stopped(txq))) { | ||
| 267 | ret = NETDEV_TX_BUSY; | ||
| 268 | kfree_skb(skb); | ||
| 269 | goto out; | ||
| 270 | } | ||
| 271 | |||
| 272 | ret = ops->ndo_start_xmit(skb, dev); | ||
| 273 | if (likely(dev_xmit_complete(ret))) | ||
| 274 | txq_trans_update(txq); | ||
| 275 | else | ||
| 276 | kfree_skb(skb); | ||
| 277 | out: | ||
| 278 | __netif_tx_unlock_bh(txq); | ||
| 279 | return ret; | ||
| 280 | } | ||
| 281 | |||
| 240 | static struct net_device *packet_cached_dev_get(struct packet_sock *po) | 282 | static struct net_device *packet_cached_dev_get(struct packet_sock *po) |
| 241 | { | 283 | { |
| 242 | struct net_device *dev; | 284 | struct net_device *dev; |
| @@ -261,6 +303,16 @@ static void packet_cached_dev_reset(struct packet_sock *po) | |||
| 261 | RCU_INIT_POINTER(po->cached_dev, NULL); | 303 | RCU_INIT_POINTER(po->cached_dev, NULL); |
| 262 | } | 304 | } |
| 263 | 305 | ||
| 306 | static bool packet_use_direct_xmit(const struct packet_sock *po) | ||
| 307 | { | ||
| 308 | return po->xmit == packet_direct_xmit; | ||
| 309 | } | ||
| 310 | |||
| 311 | static u16 packet_pick_tx_queue(struct net_device *dev) | ||
| 312 | { | ||
| 313 | return (u16) raw_smp_processor_id() % dev->real_num_tx_queues; | ||
| 314 | } | ||
| 315 | |||
| 264 | /* register_prot_hook must be invoked with the po->bind_lock held, | 316 | /* register_prot_hook must be invoked with the po->bind_lock held, |
| 265 | * or from a context in which asynchronous accesses to the packet | 317 | * or from a context in which asynchronous accesses to the packet |
| 266 | * socket is not possible (packet_create()). | 318 | * socket is not possible (packet_create()). |
| @@ -458,7 +510,8 @@ static void prb_shutdown_retire_blk_timer(struct packet_sock *po, | |||
| 458 | { | 510 | { |
| 459 | struct tpacket_kbdq_core *pkc; | 511 | struct tpacket_kbdq_core *pkc; |
| 460 | 512 | ||
| 461 | pkc = tx_ring ? &po->tx_ring.prb_bdqc : &po->rx_ring.prb_bdqc; | 513 | pkc = tx_ring ? GET_PBDQC_FROM_RB(&po->tx_ring) : |
| 514 | GET_PBDQC_FROM_RB(&po->rx_ring); | ||
| 462 | 515 | ||
| 463 | spin_lock_bh(&rb_queue->lock); | 516 | spin_lock_bh(&rb_queue->lock); |
| 464 | pkc->delete_blk_timer = 1; | 517 | pkc->delete_blk_timer = 1; |
| @@ -484,7 +537,8 @@ static void prb_setup_retire_blk_timer(struct packet_sock *po, int tx_ring) | |||
| 484 | if (tx_ring) | 537 | if (tx_ring) |
| 485 | BUG(); | 538 | BUG(); |
| 486 | 539 | ||
| 487 | pkc = tx_ring ? &po->tx_ring.prb_bdqc : &po->rx_ring.prb_bdqc; | 540 | pkc = tx_ring ? GET_PBDQC_FROM_RB(&po->tx_ring) : |
| 541 | GET_PBDQC_FROM_RB(&po->rx_ring); | ||
| 488 | prb_init_blk_timer(po, pkc, prb_retire_rx_blk_timer_expired); | 542 | prb_init_blk_timer(po, pkc, prb_retire_rx_blk_timer_expired); |
| 489 | } | 543 | } |
| 490 | 544 | ||
| @@ -542,7 +596,7 @@ static void init_prb_bdqc(struct packet_sock *po, | |||
| 542 | struct pgv *pg_vec, | 596 | struct pgv *pg_vec, |
| 543 | union tpacket_req_u *req_u, int tx_ring) | 597 | union tpacket_req_u *req_u, int tx_ring) |
| 544 | { | 598 | { |
| 545 | struct tpacket_kbdq_core *p1 = &rb->prb_bdqc; | 599 | struct tpacket_kbdq_core *p1 = GET_PBDQC_FROM_RB(rb); |
| 546 | struct tpacket_block_desc *pbd; | 600 | struct tpacket_block_desc *pbd; |
| 547 | 601 | ||
| 548 | memset(p1, 0x0, sizeof(*p1)); | 602 | memset(p1, 0x0, sizeof(*p1)); |
| @@ -606,7 +660,7 @@ static void _prb_refresh_rx_retire_blk_timer(struct tpacket_kbdq_core *pkc) | |||
| 606 | static void prb_retire_rx_blk_timer_expired(unsigned long data) | 660 | static void prb_retire_rx_blk_timer_expired(unsigned long data) |
| 607 | { | 661 | { |
| 608 | struct packet_sock *po = (struct packet_sock *)data; | 662 | struct packet_sock *po = (struct packet_sock *)data; |
| 609 | struct tpacket_kbdq_core *pkc = &po->rx_ring.prb_bdqc; | 663 | struct tpacket_kbdq_core *pkc = GET_PBDQC_FROM_RB(&po->rx_ring); |
| 610 | unsigned int frozen; | 664 | unsigned int frozen; |
| 611 | struct tpacket_block_desc *pbd; | 665 | struct tpacket_block_desc *pbd; |
| 612 | 666 | ||
| @@ -909,7 +963,7 @@ static void prb_clear_blk_fill_status(struct packet_ring_buffer *rb) | |||
| 909 | static void prb_fill_rxhash(struct tpacket_kbdq_core *pkc, | 963 | static void prb_fill_rxhash(struct tpacket_kbdq_core *pkc, |
| 910 | struct tpacket3_hdr *ppd) | 964 | struct tpacket3_hdr *ppd) |
| 911 | { | 965 | { |
| 912 | ppd->hv1.tp_rxhash = skb_get_rxhash(pkc->skb); | 966 | ppd->hv1.tp_rxhash = skb_get_hash(pkc->skb); |
| 913 | } | 967 | } |
| 914 | 968 | ||
| 915 | static void prb_clear_rxhash(struct tpacket_kbdq_core *pkc, | 969 | static void prb_clear_rxhash(struct tpacket_kbdq_core *pkc, |
| @@ -923,9 +977,11 @@ static void prb_fill_vlan_info(struct tpacket_kbdq_core *pkc, | |||
| 923 | { | 977 | { |
| 924 | if (vlan_tx_tag_present(pkc->skb)) { | 978 | if (vlan_tx_tag_present(pkc->skb)) { |
| 925 | ppd->hv1.tp_vlan_tci = vlan_tx_tag_get(pkc->skb); | 979 | ppd->hv1.tp_vlan_tci = vlan_tx_tag_get(pkc->skb); |
| 926 | ppd->tp_status = TP_STATUS_VLAN_VALID; | 980 | ppd->hv1.tp_vlan_tpid = ntohs(pkc->skb->vlan_proto); |
| 981 | ppd->tp_status = TP_STATUS_VLAN_VALID | TP_STATUS_VLAN_TPID_VALID; | ||
| 927 | } else { | 982 | } else { |
| 928 | ppd->hv1.tp_vlan_tci = 0; | 983 | ppd->hv1.tp_vlan_tci = 0; |
| 984 | ppd->hv1.tp_vlan_tpid = 0; | ||
| 929 | ppd->tp_status = TP_STATUS_AVAILABLE; | 985 | ppd->tp_status = TP_STATUS_AVAILABLE; |
| 930 | } | 986 | } |
| 931 | } | 987 | } |
| @@ -933,6 +989,7 @@ static void prb_fill_vlan_info(struct tpacket_kbdq_core *pkc, | |||
| 933 | static void prb_run_all_ft_ops(struct tpacket_kbdq_core *pkc, | 989 | static void prb_run_all_ft_ops(struct tpacket_kbdq_core *pkc, |
| 934 | struct tpacket3_hdr *ppd) | 990 | struct tpacket3_hdr *ppd) |
| 935 | { | 991 | { |
| 992 | ppd->hv1.tp_padding = 0; | ||
| 936 | prb_fill_vlan_info(pkc, ppd); | 993 | prb_fill_vlan_info(pkc, ppd); |
| 937 | 994 | ||
| 938 | if (pkc->feature_req_word & TP_FT_REQ_FILL_RXHASH) | 995 | if (pkc->feature_req_word & TP_FT_REQ_FILL_RXHASH) |
| @@ -1111,6 +1168,47 @@ static void packet_increment_head(struct packet_ring_buffer *buff) | |||
| 1111 | buff->head = buff->head != buff->frame_max ? buff->head+1 : 0; | 1168 | buff->head = buff->head != buff->frame_max ? buff->head+1 : 0; |
| 1112 | } | 1169 | } |
| 1113 | 1170 | ||
| 1171 | static void packet_inc_pending(struct packet_ring_buffer *rb) | ||
| 1172 | { | ||
| 1173 | this_cpu_inc(*rb->pending_refcnt); | ||
| 1174 | } | ||
| 1175 | |||
| 1176 | static void packet_dec_pending(struct packet_ring_buffer *rb) | ||
| 1177 | { | ||
| 1178 | this_cpu_dec(*rb->pending_refcnt); | ||
| 1179 | } | ||
| 1180 | |||
| 1181 | static unsigned int packet_read_pending(const struct packet_ring_buffer *rb) | ||
| 1182 | { | ||
| 1183 | unsigned int refcnt = 0; | ||
| 1184 | int cpu; | ||
| 1185 | |||
| 1186 | /* We don't use pending refcount in rx_ring. */ | ||
| 1187 | if (rb->pending_refcnt == NULL) | ||
| 1188 | return 0; | ||
| 1189 | |||
| 1190 | for_each_possible_cpu(cpu) | ||
| 1191 | refcnt += *per_cpu_ptr(rb->pending_refcnt, cpu); | ||
| 1192 | |||
| 1193 | return refcnt; | ||
| 1194 | } | ||
| 1195 | |||
| 1196 | static int packet_alloc_pending(struct packet_sock *po) | ||
| 1197 | { | ||
| 1198 | po->rx_ring.pending_refcnt = NULL; | ||
| 1199 | |||
| 1200 | po->tx_ring.pending_refcnt = alloc_percpu(unsigned int); | ||
| 1201 | if (unlikely(po->tx_ring.pending_refcnt == NULL)) | ||
| 1202 | return -ENOBUFS; | ||
| 1203 | |||
| 1204 | return 0; | ||
| 1205 | } | ||
| 1206 | |||
| 1207 | static void packet_free_pending(struct packet_sock *po) | ||
| 1208 | { | ||
| 1209 | free_percpu(po->tx_ring.pending_refcnt); | ||
| 1210 | } | ||
| 1211 | |||
| 1114 | static bool packet_rcv_has_room(struct packet_sock *po, struct sk_buff *skb) | 1212 | static bool packet_rcv_has_room(struct packet_sock *po, struct sk_buff *skb) |
| 1115 | { | 1213 | { |
| 1116 | struct sock *sk = &po->sk; | 1214 | struct sock *sk = &po->sk; |
| @@ -1163,7 +1261,7 @@ static unsigned int fanout_demux_hash(struct packet_fanout *f, | |||
| 1163 | struct sk_buff *skb, | 1261 | struct sk_buff *skb, |
| 1164 | unsigned int num) | 1262 | unsigned int num) |
| 1165 | { | 1263 | { |
| 1166 | return reciprocal_divide(skb->rxhash, num); | 1264 | return reciprocal_scale(skb->rxhash, num); |
| 1167 | } | 1265 | } |
| 1168 | 1266 | ||
| 1169 | static unsigned int fanout_demux_lb(struct packet_fanout *f, | 1267 | static unsigned int fanout_demux_lb(struct packet_fanout *f, |
| @@ -1190,7 +1288,7 @@ static unsigned int fanout_demux_rnd(struct packet_fanout *f, | |||
| 1190 | struct sk_buff *skb, | 1288 | struct sk_buff *skb, |
| 1191 | unsigned int num) | 1289 | unsigned int num) |
| 1192 | { | 1290 | { |
| 1193 | return reciprocal_divide(prandom_u32(), num); | 1291 | return prandom_u32_max(num); |
| 1194 | } | 1292 | } |
| 1195 | 1293 | ||
| 1196 | static unsigned int fanout_demux_rollover(struct packet_fanout *f, | 1294 | static unsigned int fanout_demux_rollover(struct packet_fanout *f, |
| @@ -1214,6 +1312,13 @@ static unsigned int fanout_demux_rollover(struct packet_fanout *f, | |||
| 1214 | return idx; | 1312 | return idx; |
| 1215 | } | 1313 | } |
| 1216 | 1314 | ||
| 1315 | static unsigned int fanout_demux_qm(struct packet_fanout *f, | ||
| 1316 | struct sk_buff *skb, | ||
| 1317 | unsigned int num) | ||
| 1318 | { | ||
| 1319 | return skb_get_queue_mapping(skb) % num; | ||
| 1320 | } | ||
| 1321 | |||
| 1217 | static bool fanout_has_flag(struct packet_fanout *f, u16 flag) | 1322 | static bool fanout_has_flag(struct packet_fanout *f, u16 flag) |
| 1218 | { | 1323 | { |
| 1219 | return f->flags & (flag >> 8); | 1324 | return f->flags & (flag >> 8); |
| @@ -1241,7 +1346,7 @@ static int packet_rcv_fanout(struct sk_buff *skb, struct net_device *dev, | |||
| 1241 | if (!skb) | 1346 | if (!skb) |
| 1242 | return 0; | 1347 | return 0; |
| 1243 | } | 1348 | } |
| 1244 | skb_get_rxhash(skb); | 1349 | skb_get_hash(skb); |
| 1245 | idx = fanout_demux_hash(f, skb, num); | 1350 | idx = fanout_demux_hash(f, skb, num); |
| 1246 | break; | 1351 | break; |
| 1247 | case PACKET_FANOUT_LB: | 1352 | case PACKET_FANOUT_LB: |
| @@ -1253,6 +1358,9 @@ static int packet_rcv_fanout(struct sk_buff *skb, struct net_device *dev, | |||
| 1253 | case PACKET_FANOUT_RND: | 1358 | case PACKET_FANOUT_RND: |
| 1254 | idx = fanout_demux_rnd(f, skb, num); | 1359 | idx = fanout_demux_rnd(f, skb, num); |
| 1255 | break; | 1360 | break; |
| 1361 | case PACKET_FANOUT_QM: | ||
| 1362 | idx = fanout_demux_qm(f, skb, num); | ||
| 1363 | break; | ||
| 1256 | case PACKET_FANOUT_ROLLOVER: | 1364 | case PACKET_FANOUT_ROLLOVER: |
| 1257 | idx = fanout_demux_rollover(f, skb, 0, (unsigned int) -1, num); | 1365 | idx = fanout_demux_rollover(f, skb, 0, (unsigned int) -1, num); |
| 1258 | break; | 1366 | break; |
| @@ -1299,9 +1407,9 @@ static void __fanout_unlink(struct sock *sk, struct packet_sock *po) | |||
| 1299 | spin_unlock(&f->lock); | 1407 | spin_unlock(&f->lock); |
| 1300 | } | 1408 | } |
| 1301 | 1409 | ||
| 1302 | static bool match_fanout_group(struct packet_type *ptype, struct sock * sk) | 1410 | static bool match_fanout_group(struct packet_type *ptype, struct sock *sk) |
| 1303 | { | 1411 | { |
| 1304 | if (ptype->af_packet_priv == (void*)((struct packet_sock *)sk)->fanout) | 1412 | if (ptype->af_packet_priv == (void *)((struct packet_sock *)sk)->fanout) |
| 1305 | return true; | 1413 | return true; |
| 1306 | 1414 | ||
| 1307 | return false; | 1415 | return false; |
| @@ -1323,6 +1431,7 @@ static int fanout_add(struct sock *sk, u16 id, u16 type_flags) | |||
| 1323 | case PACKET_FANOUT_LB: | 1431 | case PACKET_FANOUT_LB: |
| 1324 | case PACKET_FANOUT_CPU: | 1432 | case PACKET_FANOUT_CPU: |
| 1325 | case PACKET_FANOUT_RND: | 1433 | case PACKET_FANOUT_RND: |
| 1434 | case PACKET_FANOUT_QM: | ||
| 1326 | break; | 1435 | break; |
| 1327 | default: | 1436 | default: |
| 1328 | return -EINVAL; | 1437 | return -EINVAL; |
| @@ -1485,7 +1594,7 @@ static int packet_sendmsg_spkt(struct kiocb *iocb, struct socket *sock, | |||
| 1485 | struct msghdr *msg, size_t len) | 1594 | struct msghdr *msg, size_t len) |
| 1486 | { | 1595 | { |
| 1487 | struct sock *sk = sock->sk; | 1596 | struct sock *sk = sock->sk; |
| 1488 | struct sockaddr_pkt *saddr = (struct sockaddr_pkt *)msg->msg_name; | 1597 | DECLARE_SOCKADDR(struct sockaddr_pkt *, saddr, msg->msg_name); |
| 1489 | struct sk_buff *skb = NULL; | 1598 | struct sk_buff *skb = NULL; |
| 1490 | struct net_device *dev; | 1599 | struct net_device *dev; |
| 1491 | __be16 proto = 0; | 1600 | __be16 proto = 0; |
| @@ -1758,6 +1867,13 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, | |||
| 1758 | struct timespec ts; | 1867 | struct timespec ts; |
| 1759 | __u32 ts_status; | 1868 | __u32 ts_status; |
| 1760 | 1869 | ||
| 1870 | /* struct tpacket{2,3}_hdr is aligned to a multiple of TPACKET_ALIGNMENT. | ||
| 1871 | * We may add members to them until current aligned size without forcing | ||
| 1872 | * userspace to call getsockopt(..., PACKET_HDRLEN, ...). | ||
| 1873 | */ | ||
| 1874 | BUILD_BUG_ON(TPACKET_ALIGN(sizeof(*h.h2)) != 32); | ||
| 1875 | BUILD_BUG_ON(TPACKET_ALIGN(sizeof(*h.h3)) != 48); | ||
| 1876 | |||
| 1761 | if (skb->pkt_type == PACKET_LOOPBACK) | 1877 | if (skb->pkt_type == PACKET_LOOPBACK) |
| 1762 | goto drop; | 1878 | goto drop; |
| 1763 | 1879 | ||
| @@ -1864,11 +1980,13 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, | |||
| 1864 | h.h2->tp_nsec = ts.tv_nsec; | 1980 | h.h2->tp_nsec = ts.tv_nsec; |
| 1865 | if (vlan_tx_tag_present(skb)) { | 1981 | if (vlan_tx_tag_present(skb)) { |
| 1866 | h.h2->tp_vlan_tci = vlan_tx_tag_get(skb); | 1982 | h.h2->tp_vlan_tci = vlan_tx_tag_get(skb); |
| 1867 | status |= TP_STATUS_VLAN_VALID; | 1983 | h.h2->tp_vlan_tpid = ntohs(skb->vlan_proto); |
| 1984 | status |= TP_STATUS_VLAN_VALID | TP_STATUS_VLAN_TPID_VALID; | ||
| 1868 | } else { | 1985 | } else { |
| 1869 | h.h2->tp_vlan_tci = 0; | 1986 | h.h2->tp_vlan_tci = 0; |
| 1987 | h.h2->tp_vlan_tpid = 0; | ||
| 1870 | } | 1988 | } |
| 1871 | h.h2->tp_padding = 0; | 1989 | memset(h.h2->tp_padding, 0, sizeof(h.h2->tp_padding)); |
| 1872 | hdrlen = sizeof(*h.h2); | 1990 | hdrlen = sizeof(*h.h2); |
| 1873 | break; | 1991 | break; |
| 1874 | case TPACKET_V3: | 1992 | case TPACKET_V3: |
| @@ -1882,6 +2000,7 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, | |||
| 1882 | h.h3->tp_net = netoff; | 2000 | h.h3->tp_net = netoff; |
| 1883 | h.h3->tp_sec = ts.tv_sec; | 2001 | h.h3->tp_sec = ts.tv_sec; |
| 1884 | h.h3->tp_nsec = ts.tv_nsec; | 2002 | h.h3->tp_nsec = ts.tv_nsec; |
| 2003 | memset(h.h3->tp_padding, 0, sizeof(h.h3->tp_padding)); | ||
| 1885 | hdrlen = sizeof(*h.h3); | 2004 | hdrlen = sizeof(*h.h3); |
| 1886 | break; | 2005 | break; |
| 1887 | default: | 2006 | default: |
| @@ -1900,19 +2019,20 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, | |||
| 1900 | sll->sll_ifindex = dev->ifindex; | 2019 | sll->sll_ifindex = dev->ifindex; |
| 1901 | 2020 | ||
| 1902 | smp_mb(); | 2021 | smp_mb(); |
| 2022 | |||
| 1903 | #if ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE == 1 | 2023 | #if ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE == 1 |
| 1904 | { | 2024 | if (po->tp_version <= TPACKET_V2) { |
| 1905 | u8 *start, *end; | 2025 | u8 *start, *end; |
| 1906 | 2026 | ||
| 1907 | if (po->tp_version <= TPACKET_V2) { | 2027 | end = (u8 *) PAGE_ALIGN((unsigned long) h.raw + |
| 1908 | end = (u8 *)PAGE_ALIGN((unsigned long)h.raw | 2028 | macoff + snaplen); |
| 1909 | + macoff + snaplen); | 2029 | |
| 1910 | for (start = h.raw; start < end; start += PAGE_SIZE) | 2030 | for (start = h.raw; start < end; start += PAGE_SIZE) |
| 1911 | flush_dcache_page(pgv_to_page(start)); | 2031 | flush_dcache_page(pgv_to_page(start)); |
| 1912 | } | ||
| 1913 | smp_wmb(); | ||
| 1914 | } | 2032 | } |
| 2033 | smp_wmb(); | ||
| 1915 | #endif | 2034 | #endif |
| 2035 | |||
| 1916 | if (po->tp_version <= TPACKET_V2) | 2036 | if (po->tp_version <= TPACKET_V2) |
| 1917 | __packet_set_status(po, h.raw, status); | 2037 | __packet_set_status(po, h.raw, status); |
| 1918 | else | 2038 | else |
| @@ -1941,14 +2061,13 @@ ring_is_full: | |||
| 1941 | static void tpacket_destruct_skb(struct sk_buff *skb) | 2061 | static void tpacket_destruct_skb(struct sk_buff *skb) |
| 1942 | { | 2062 | { |
| 1943 | struct packet_sock *po = pkt_sk(skb->sk); | 2063 | struct packet_sock *po = pkt_sk(skb->sk); |
| 1944 | void *ph; | ||
| 1945 | 2064 | ||
| 1946 | if (likely(po->tx_ring.pg_vec)) { | 2065 | if (likely(po->tx_ring.pg_vec)) { |
| 2066 | void *ph; | ||
| 1947 | __u32 ts; | 2067 | __u32 ts; |
| 1948 | 2068 | ||
| 1949 | ph = skb_shinfo(skb)->destructor_arg; | 2069 | ph = skb_shinfo(skb)->destructor_arg; |
| 1950 | BUG_ON(atomic_read(&po->tx_ring.pending) == 0); | 2070 | packet_dec_pending(&po->tx_ring); |
| 1951 | atomic_dec(&po->tx_ring.pending); | ||
| 1952 | 2071 | ||
| 1953 | ts = __packet_set_timestamp(po, ph, skb); | 2072 | ts = __packet_set_timestamp(po, ph, skb); |
| 1954 | __packet_set_status(po, ph, TP_STATUS_AVAILABLE | ts); | 2073 | __packet_set_status(po, ph, TP_STATUS_AVAILABLE | ts); |
| @@ -1992,9 +2111,10 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb, | |||
| 1992 | 2111 | ||
| 1993 | skb_reserve(skb, hlen); | 2112 | skb_reserve(skb, hlen); |
| 1994 | skb_reset_network_header(skb); | 2113 | skb_reset_network_header(skb); |
| 1995 | skb_probe_transport_header(skb, 0); | ||
| 1996 | 2114 | ||
| 1997 | if (po->tp_tx_has_off) { | 2115 | if (!packet_use_direct_xmit(po)) |
| 2116 | skb_probe_transport_header(skb, 0); | ||
| 2117 | if (unlikely(po->tp_tx_has_off)) { | ||
| 1998 | int off_min, off_max, off; | 2118 | int off_min, off_max, off; |
| 1999 | off_min = po->tp_hdrlen - sizeof(struct sockaddr_ll); | 2119 | off_min = po->tp_hdrlen - sizeof(struct sockaddr_ll); |
| 2000 | off_max = po->tx_ring.frame_size - tp_len; | 2120 | off_max = po->tx_ring.frame_size - tp_len; |
| @@ -2087,7 +2207,8 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg) | |||
| 2087 | __be16 proto; | 2207 | __be16 proto; |
| 2088 | int err, reserve = 0; | 2208 | int err, reserve = 0; |
| 2089 | void *ph; | 2209 | void *ph; |
| 2090 | struct sockaddr_ll *saddr = (struct sockaddr_ll *)msg->msg_name; | 2210 | DECLARE_SOCKADDR(struct sockaddr_ll *, saddr, msg->msg_name); |
| 2211 | bool need_wait = !(msg->msg_flags & MSG_DONTWAIT); | ||
| 2091 | int tp_len, size_max; | 2212 | int tp_len, size_max; |
| 2092 | unsigned char *addr; | 2213 | unsigned char *addr; |
| 2093 | int len_sum = 0; | 2214 | int len_sum = 0; |
| @@ -2130,10 +2251,10 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg) | |||
| 2130 | 2251 | ||
| 2131 | do { | 2252 | do { |
| 2132 | ph = packet_current_frame(po, &po->tx_ring, | 2253 | ph = packet_current_frame(po, &po->tx_ring, |
| 2133 | TP_STATUS_SEND_REQUEST); | 2254 | TP_STATUS_SEND_REQUEST); |
| 2134 | |||
| 2135 | if (unlikely(ph == NULL)) { | 2255 | if (unlikely(ph == NULL)) { |
| 2136 | schedule(); | 2256 | if (need_wait && need_resched()) |
| 2257 | schedule(); | ||
| 2137 | continue; | 2258 | continue; |
| 2138 | } | 2259 | } |
| 2139 | 2260 | ||
| @@ -2164,12 +2285,13 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg) | |||
| 2164 | } | 2285 | } |
| 2165 | } | 2286 | } |
| 2166 | 2287 | ||
| 2288 | skb_set_queue_mapping(skb, packet_pick_tx_queue(dev)); | ||
| 2167 | skb->destructor = tpacket_destruct_skb; | 2289 | skb->destructor = tpacket_destruct_skb; |
| 2168 | __packet_set_status(po, ph, TP_STATUS_SENDING); | 2290 | __packet_set_status(po, ph, TP_STATUS_SENDING); |
| 2169 | atomic_inc(&po->tx_ring.pending); | 2291 | packet_inc_pending(&po->tx_ring); |
| 2170 | 2292 | ||
| 2171 | status = TP_STATUS_SEND_REQUEST; | 2293 | status = TP_STATUS_SEND_REQUEST; |
| 2172 | err = dev_queue_xmit(skb); | 2294 | err = po->xmit(skb); |
| 2173 | if (unlikely(err > 0)) { | 2295 | if (unlikely(err > 0)) { |
| 2174 | err = net_xmit_errno(err); | 2296 | err = net_xmit_errno(err); |
| 2175 | if (err && __packet_get_status(po, ph) == | 2297 | if (err && __packet_get_status(po, ph) == |
| @@ -2187,9 +2309,13 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg) | |||
| 2187 | packet_increment_head(&po->tx_ring); | 2309 | packet_increment_head(&po->tx_ring); |
| 2188 | len_sum += tp_len; | 2310 | len_sum += tp_len; |
| 2189 | } while (likely((ph != NULL) || | 2311 | } while (likely((ph != NULL) || |
| 2190 | ((!(msg->msg_flags & MSG_DONTWAIT)) && | 2312 | /* Note: packet_read_pending() might be slow if we have |
| 2191 | (atomic_read(&po->tx_ring.pending)))) | 2313 | * to call it as it's per_cpu variable, but in fast-path |
| 2192 | ); | 2314 | * we already short-circuit the loop with the first |
| 2315 | * condition, and luckily don't have to go that path | ||
| 2316 | * anyway. | ||
| 2317 | */ | ||
| 2318 | (need_wait && packet_read_pending(&po->tx_ring)))); | ||
| 2193 | 2319 | ||
| 2194 | err = len_sum; | 2320 | err = len_sum; |
| 2195 | goto out_put; | 2321 | goto out_put; |
| @@ -2228,11 +2354,10 @@ static struct sk_buff *packet_alloc_skb(struct sock *sk, size_t prepad, | |||
| 2228 | return skb; | 2354 | return skb; |
| 2229 | } | 2355 | } |
| 2230 | 2356 | ||
| 2231 | static int packet_snd(struct socket *sock, | 2357 | static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len) |
| 2232 | struct msghdr *msg, size_t len) | ||
| 2233 | { | 2358 | { |
| 2234 | struct sock *sk = sock->sk; | 2359 | struct sock *sk = sock->sk; |
| 2235 | struct sockaddr_ll *saddr = (struct sockaddr_ll *)msg->msg_name; | 2360 | DECLARE_SOCKADDR(struct sockaddr_ll *, saddr, msg->msg_name); |
| 2236 | struct sk_buff *skb; | 2361 | struct sk_buff *skb; |
| 2237 | struct net_device *dev; | 2362 | struct net_device *dev; |
| 2238 | __be16 proto; | 2363 | __be16 proto; |
| @@ -2374,6 +2499,7 @@ static int packet_snd(struct socket *sock, | |||
| 2374 | skb->dev = dev; | 2499 | skb->dev = dev; |
| 2375 | skb->priority = sk->sk_priority; | 2500 | skb->priority = sk->sk_priority; |
| 2376 | skb->mark = sk->sk_mark; | 2501 | skb->mark = sk->sk_mark; |
| 2502 | skb_set_queue_mapping(skb, packet_pick_tx_queue(dev)); | ||
| 2377 | 2503 | ||
| 2378 | if (po->has_vnet_hdr) { | 2504 | if (po->has_vnet_hdr) { |
| 2379 | if (vnet_hdr.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) { | 2505 | if (vnet_hdr.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) { |
| @@ -2394,16 +2520,12 @@ static int packet_snd(struct socket *sock, | |||
| 2394 | len += vnet_hdr_len; | 2520 | len += vnet_hdr_len; |
| 2395 | } | 2521 | } |
| 2396 | 2522 | ||
| 2397 | skb_probe_transport_header(skb, reserve); | 2523 | if (!packet_use_direct_xmit(po)) |
| 2398 | 2524 | skb_probe_transport_header(skb, reserve); | |
| 2399 | if (unlikely(extra_len == 4)) | 2525 | if (unlikely(extra_len == 4)) |
| 2400 | skb->no_fcs = 1; | 2526 | skb->no_fcs = 1; |
| 2401 | 2527 | ||
| 2402 | /* | 2528 | err = po->xmit(skb); |
| 2403 | * Now send it | ||
| 2404 | */ | ||
| 2405 | |||
| 2406 | err = dev_queue_xmit(skb); | ||
| 2407 | if (err > 0 && (err = net_xmit_errno(err)) != 0) | 2529 | if (err > 0 && (err = net_xmit_errno(err)) != 0) |
| 2408 | goto out_unlock; | 2530 | goto out_unlock; |
| 2409 | 2531 | ||
| @@ -2425,6 +2547,7 @@ static int packet_sendmsg(struct kiocb *iocb, struct socket *sock, | |||
| 2425 | { | 2547 | { |
| 2426 | struct sock *sk = sock->sk; | 2548 | struct sock *sk = sock->sk; |
| 2427 | struct packet_sock *po = pkt_sk(sk); | 2549 | struct packet_sock *po = pkt_sk(sk); |
| 2550 | |||
| 2428 | if (po->tx_ring.pg_vec) | 2551 | if (po->tx_ring.pg_vec) |
| 2429 | return tpacket_snd(po, msg); | 2552 | return tpacket_snd(po, msg); |
| 2430 | else | 2553 | else |
| @@ -2491,6 +2614,7 @@ static int packet_release(struct socket *sock) | |||
| 2491 | /* Purge queues */ | 2614 | /* Purge queues */ |
| 2492 | 2615 | ||
| 2493 | skb_queue_purge(&sk->sk_receive_queue); | 2616 | skb_queue_purge(&sk->sk_receive_queue); |
| 2617 | packet_free_pending(po); | ||
| 2494 | sk_refcnt_debug_release(sk); | 2618 | sk_refcnt_debug_release(sk); |
| 2495 | 2619 | ||
| 2496 | sock_put(sk); | 2620 | sock_put(sk); |
| @@ -2501,9 +2625,12 @@ static int packet_release(struct socket *sock) | |||
| 2501 | * Attach a packet hook. | 2625 | * Attach a packet hook. |
| 2502 | */ | 2626 | */ |
| 2503 | 2627 | ||
| 2504 | static int packet_do_bind(struct sock *sk, struct net_device *dev, __be16 protocol) | 2628 | static int packet_do_bind(struct sock *sk, struct net_device *dev, __be16 proto) |
| 2505 | { | 2629 | { |
| 2506 | struct packet_sock *po = pkt_sk(sk); | 2630 | struct packet_sock *po = pkt_sk(sk); |
| 2631 | const struct net_device *dev_curr; | ||
| 2632 | __be16 proto_curr; | ||
| 2633 | bool need_rehook; | ||
| 2507 | 2634 | ||
| 2508 | if (po->fanout) { | 2635 | if (po->fanout) { |
| 2509 | if (dev) | 2636 | if (dev) |
| @@ -2513,21 +2640,29 @@ static int packet_do_bind(struct sock *sk, struct net_device *dev, __be16 protoc | |||
| 2513 | } | 2640 | } |
| 2514 | 2641 | ||
| 2515 | lock_sock(sk); | 2642 | lock_sock(sk); |
| 2516 | |||
| 2517 | spin_lock(&po->bind_lock); | 2643 | spin_lock(&po->bind_lock); |
| 2518 | unregister_prot_hook(sk, true); | ||
| 2519 | 2644 | ||
| 2520 | po->num = protocol; | 2645 | proto_curr = po->prot_hook.type; |
| 2521 | po->prot_hook.type = protocol; | 2646 | dev_curr = po->prot_hook.dev; |
| 2522 | if (po->prot_hook.dev) | 2647 | |
| 2523 | dev_put(po->prot_hook.dev); | 2648 | need_rehook = proto_curr != proto || dev_curr != dev; |
| 2649 | |||
| 2650 | if (need_rehook) { | ||
| 2651 | unregister_prot_hook(sk, true); | ||
| 2652 | |||
| 2653 | po->num = proto; | ||
| 2654 | po->prot_hook.type = proto; | ||
| 2655 | |||
| 2656 | if (po->prot_hook.dev) | ||
| 2657 | dev_put(po->prot_hook.dev); | ||
| 2524 | 2658 | ||
| 2525 | po->prot_hook.dev = dev; | 2659 | po->prot_hook.dev = dev; |
| 2526 | po->ifindex = dev ? dev->ifindex : 0; | ||
| 2527 | 2660 | ||
| 2528 | packet_cached_dev_assign(po, dev); | 2661 | po->ifindex = dev ? dev->ifindex : 0; |
| 2662 | packet_cached_dev_assign(po, dev); | ||
| 2663 | } | ||
| 2529 | 2664 | ||
| 2530 | if (protocol == 0) | 2665 | if (proto == 0 || !need_rehook) |
| 2531 | goto out_unlock; | 2666 | goto out_unlock; |
| 2532 | 2667 | ||
| 2533 | if (!dev || (dev->flags & IFF_UP)) { | 2668 | if (!dev || (dev->flags & IFF_UP)) { |
| @@ -2639,6 +2774,11 @@ static int packet_create(struct net *net, struct socket *sock, int protocol, | |||
| 2639 | po = pkt_sk(sk); | 2774 | po = pkt_sk(sk); |
| 2640 | sk->sk_family = PF_PACKET; | 2775 | sk->sk_family = PF_PACKET; |
| 2641 | po->num = proto; | 2776 | po->num = proto; |
| 2777 | po->xmit = dev_queue_xmit; | ||
| 2778 | |||
| 2779 | err = packet_alloc_pending(po); | ||
| 2780 | if (err) | ||
| 2781 | goto out2; | ||
| 2642 | 2782 | ||
| 2643 | packet_cached_dev_reset(po); | 2783 | packet_cached_dev_reset(po); |
| 2644 | 2784 | ||
| @@ -2672,6 +2812,8 @@ static int packet_create(struct net *net, struct socket *sock, int protocol, | |||
| 2672 | preempt_enable(); | 2812 | preempt_enable(); |
| 2673 | 2813 | ||
| 2674 | return 0; | 2814 | return 0; |
| 2815 | out2: | ||
| 2816 | sk_free(sk); | ||
| 2675 | out: | 2817 | out: |
| 2676 | return err; | 2818 | return err; |
| 2677 | } | 2819 | } |
| @@ -2791,6 +2933,7 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock, | |||
| 2791 | * in, we fill it in now. | 2933 | * in, we fill it in now. |
| 2792 | */ | 2934 | */ |
| 2793 | if (sock->type == SOCK_PACKET) { | 2935 | if (sock->type == SOCK_PACKET) { |
| 2936 | __sockaddr_check_size(sizeof(struct sockaddr_pkt)); | ||
| 2794 | msg->msg_namelen = sizeof(struct sockaddr_pkt); | 2937 | msg->msg_namelen = sizeof(struct sockaddr_pkt); |
| 2795 | } else { | 2938 | } else { |
| 2796 | struct sockaddr_ll *sll = &PACKET_SKB_CB(skb)->sa.ll; | 2939 | struct sockaddr_ll *sll = &PACKET_SKB_CB(skb)->sa.ll; |
| @@ -2813,11 +2956,12 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock, | |||
| 2813 | aux.tp_net = skb_network_offset(skb); | 2956 | aux.tp_net = skb_network_offset(skb); |
| 2814 | if (vlan_tx_tag_present(skb)) { | 2957 | if (vlan_tx_tag_present(skb)) { |
| 2815 | aux.tp_vlan_tci = vlan_tx_tag_get(skb); | 2958 | aux.tp_vlan_tci = vlan_tx_tag_get(skb); |
| 2816 | aux.tp_status |= TP_STATUS_VLAN_VALID; | 2959 | aux.tp_vlan_tpid = ntohs(skb->vlan_proto); |
| 2960 | aux.tp_status |= TP_STATUS_VLAN_VALID | TP_STATUS_VLAN_TPID_VALID; | ||
| 2817 | } else { | 2961 | } else { |
| 2818 | aux.tp_vlan_tci = 0; | 2962 | aux.tp_vlan_tci = 0; |
| 2963 | aux.tp_vlan_tpid = 0; | ||
| 2819 | } | 2964 | } |
| 2820 | aux.tp_padding = 0; | ||
| 2821 | put_cmsg(msg, SOL_PACKET, PACKET_AUXDATA, sizeof(aux), &aux); | 2965 | put_cmsg(msg, SOL_PACKET, PACKET_AUXDATA, sizeof(aux), &aux); |
| 2822 | } | 2966 | } |
| 2823 | 2967 | ||
| @@ -3218,6 +3362,18 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv | |||
| 3218 | po->tp_tx_has_off = !!val; | 3362 | po->tp_tx_has_off = !!val; |
| 3219 | return 0; | 3363 | return 0; |
| 3220 | } | 3364 | } |
| 3365 | case PACKET_QDISC_BYPASS: | ||
| 3366 | { | ||
| 3367 | int val; | ||
| 3368 | |||
| 3369 | if (optlen != sizeof(val)) | ||
| 3370 | return -EINVAL; | ||
| 3371 | if (copy_from_user(&val, optval, sizeof(val))) | ||
| 3372 | return -EFAULT; | ||
| 3373 | |||
| 3374 | po->xmit = val ? packet_direct_xmit : dev_queue_xmit; | ||
| 3375 | return 0; | ||
| 3376 | } | ||
| 3221 | default: | 3377 | default: |
| 3222 | return -ENOPROTOOPT; | 3378 | return -ENOPROTOOPT; |
| 3223 | } | 3379 | } |
| @@ -3310,6 +3466,9 @@ static int packet_getsockopt(struct socket *sock, int level, int optname, | |||
| 3310 | case PACKET_TX_HAS_OFF: | 3466 | case PACKET_TX_HAS_OFF: |
| 3311 | val = po->tp_tx_has_off; | 3467 | val = po->tp_tx_has_off; |
| 3312 | break; | 3468 | break; |
| 3469 | case PACKET_QDISC_BYPASS: | ||
| 3470 | val = packet_use_direct_xmit(po); | ||
| 3471 | break; | ||
| 3313 | default: | 3472 | default: |
| 3314 | return -ENOPROTOOPT; | 3473 | return -ENOPROTOOPT; |
| 3315 | } | 3474 | } |
| @@ -3501,34 +3660,26 @@ static void free_pg_vec(struct pgv *pg_vec, unsigned int order, | |||
| 3501 | 3660 | ||
| 3502 | static char *alloc_one_pg_vec_page(unsigned long order) | 3661 | static char *alloc_one_pg_vec_page(unsigned long order) |
| 3503 | { | 3662 | { |
| 3504 | char *buffer = NULL; | 3663 | char *buffer; |
| 3505 | gfp_t gfp_flags = GFP_KERNEL | __GFP_COMP | | 3664 | gfp_t gfp_flags = GFP_KERNEL | __GFP_COMP | |
| 3506 | __GFP_ZERO | __GFP_NOWARN | __GFP_NORETRY; | 3665 | __GFP_ZERO | __GFP_NOWARN | __GFP_NORETRY; |
| 3507 | 3666 | ||
| 3508 | buffer = (char *) __get_free_pages(gfp_flags, order); | 3667 | buffer = (char *) __get_free_pages(gfp_flags, order); |
| 3509 | |||
| 3510 | if (buffer) | 3668 | if (buffer) |
| 3511 | return buffer; | 3669 | return buffer; |
| 3512 | 3670 | ||
| 3513 | /* | 3671 | /* __get_free_pages failed, fall back to vmalloc */ |
| 3514 | * __get_free_pages failed, fall back to vmalloc | ||
| 3515 | */ | ||
| 3516 | buffer = vzalloc((1 << order) * PAGE_SIZE); | 3672 | buffer = vzalloc((1 << order) * PAGE_SIZE); |
| 3517 | |||
| 3518 | if (buffer) | 3673 | if (buffer) |
| 3519 | return buffer; | 3674 | return buffer; |
| 3520 | 3675 | ||
| 3521 | /* | 3676 | /* vmalloc failed, lets dig into swap here */ |
| 3522 | * vmalloc failed, lets dig into swap here | ||
| 3523 | */ | ||
| 3524 | gfp_flags &= ~__GFP_NORETRY; | 3677 | gfp_flags &= ~__GFP_NORETRY; |
| 3525 | buffer = (char *)__get_free_pages(gfp_flags, order); | 3678 | buffer = (char *) __get_free_pages(gfp_flags, order); |
| 3526 | if (buffer) | 3679 | if (buffer) |
| 3527 | return buffer; | 3680 | return buffer; |
| 3528 | 3681 | ||
| 3529 | /* | 3682 | /* complete and utter failure */ |
| 3530 | * complete and utter failure | ||
| 3531 | */ | ||
| 3532 | return NULL; | 3683 | return NULL; |
| 3533 | } | 3684 | } |
| 3534 | 3685 | ||
| @@ -3583,7 +3734,7 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u, | |||
| 3583 | if (!closing) { | 3734 | if (!closing) { |
| 3584 | if (atomic_read(&po->mapped)) | 3735 | if (atomic_read(&po->mapped)) |
| 3585 | goto out; | 3736 | goto out; |
| 3586 | if (atomic_read(&rb->pending)) | 3737 | if (packet_read_pending(rb)) |
| 3587 | goto out; | 3738 | goto out; |
| 3588 | } | 3739 | } |
| 3589 | 3740 | ||
diff --git a/net/packet/diag.c b/net/packet/diag.c index a9584a2f6d69..533ce4ff108a 100644 --- a/net/packet/diag.c +++ b/net/packet/diag.c | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | #include <linux/net.h> | 3 | #include <linux/net.h> |
| 4 | #include <linux/netdevice.h> | 4 | #include <linux/netdevice.h> |
| 5 | #include <linux/packet_diag.h> | 5 | #include <linux/packet_diag.h> |
| 6 | #include <linux/percpu.h> | ||
| 6 | #include <net/net_namespace.h> | 7 | #include <net/net_namespace.h> |
| 7 | #include <net/sock.h> | 8 | #include <net/sock.h> |
| 8 | 9 | ||
diff --git a/net/packet/internal.h b/net/packet/internal.h index 1035fa2d909c..eb9580a6b25f 100644 --- a/net/packet/internal.h +++ b/net/packet/internal.h | |||
| @@ -64,7 +64,7 @@ struct packet_ring_buffer { | |||
| 64 | unsigned int pg_vec_pages; | 64 | unsigned int pg_vec_pages; |
| 65 | unsigned int pg_vec_len; | 65 | unsigned int pg_vec_len; |
| 66 | 66 | ||
| 67 | atomic_t pending; | 67 | unsigned int __percpu *pending_refcnt; |
| 68 | 68 | ||
| 69 | struct tpacket_kbdq_core prb_bdqc; | 69 | struct tpacket_kbdq_core prb_bdqc; |
| 70 | }; | 70 | }; |
| @@ -114,6 +114,7 @@ struct packet_sock { | |||
| 114 | unsigned int tp_tx_has_off:1; | 114 | unsigned int tp_tx_has_off:1; |
| 115 | unsigned int tp_tstamp; | 115 | unsigned int tp_tstamp; |
| 116 | struct net_device __rcu *cached_dev; | 116 | struct net_device __rcu *cached_dev; |
| 117 | int (*xmit)(struct sk_buff *skb); | ||
| 117 | struct packet_type prot_hook ____cacheline_aligned_in_smp; | 118 | struct packet_type prot_hook ____cacheline_aligned_in_smp; |
| 118 | }; | 119 | }; |
| 119 | 120 | ||
diff --git a/net/phonet/datagram.c b/net/phonet/datagram.c index 38946b26e471..290352c0e6b4 100644 --- a/net/phonet/datagram.c +++ b/net/phonet/datagram.c | |||
| @@ -86,7 +86,7 @@ static int pn_init(struct sock *sk) | |||
| 86 | static int pn_sendmsg(struct kiocb *iocb, struct sock *sk, | 86 | static int pn_sendmsg(struct kiocb *iocb, struct sock *sk, |
| 87 | struct msghdr *msg, size_t len) | 87 | struct msghdr *msg, size_t len) |
| 88 | { | 88 | { |
| 89 | struct sockaddr_pn *target; | 89 | DECLARE_SOCKADDR(struct sockaddr_pn *, target, msg->msg_name); |
| 90 | struct sk_buff *skb; | 90 | struct sk_buff *skb; |
| 91 | int err; | 91 | int err; |
| 92 | 92 | ||
| @@ -94,13 +94,12 @@ static int pn_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
| 94 | MSG_CMSG_COMPAT)) | 94 | MSG_CMSG_COMPAT)) |
| 95 | return -EOPNOTSUPP; | 95 | return -EOPNOTSUPP; |
| 96 | 96 | ||
| 97 | if (msg->msg_name == NULL) | 97 | if (target == NULL) |
| 98 | return -EDESTADDRREQ; | 98 | return -EDESTADDRREQ; |
| 99 | 99 | ||
| 100 | if (msg->msg_namelen < sizeof(struct sockaddr_pn)) | 100 | if (msg->msg_namelen < sizeof(struct sockaddr_pn)) |
| 101 | return -EINVAL; | 101 | return -EINVAL; |
| 102 | 102 | ||
| 103 | target = (struct sockaddr_pn *)msg->msg_name; | ||
| 104 | if (target->spn_family != AF_PHONET) | 103 | if (target->spn_family != AF_PHONET) |
| 105 | return -EAFNOSUPPORT; | 104 | return -EAFNOSUPPORT; |
| 106 | 105 | ||
| @@ -160,6 +159,7 @@ static int pn_recvmsg(struct kiocb *iocb, struct sock *sk, | |||
| 160 | rval = (flags & MSG_TRUNC) ? skb->len : copylen; | 159 | rval = (flags & MSG_TRUNC) ? skb->len : copylen; |
| 161 | 160 | ||
| 162 | if (msg->msg_name != NULL) { | 161 | if (msg->msg_name != NULL) { |
| 162 | __sockaddr_check_size(sizeof(sa)); | ||
| 163 | memcpy(msg->msg_name, &sa, sizeof(sa)); | 163 | memcpy(msg->msg_name, &sa, sizeof(sa)); |
| 164 | *addr_len = sizeof(sa); | 164 | *addr_len = sizeof(sa); |
| 165 | } | 165 | } |
diff --git a/net/rds/bind.c b/net/rds/bind.c index b5ad65a0067e..a2e6562da751 100644 --- a/net/rds/bind.c +++ b/net/rds/bind.c | |||
| @@ -117,7 +117,7 @@ static int rds_add_bound(struct rds_sock *rs, __be32 addr, __be16 *port) | |||
| 117 | rover = be16_to_cpu(*port); | 117 | rover = be16_to_cpu(*port); |
| 118 | last = rover; | 118 | last = rover; |
| 119 | } else { | 119 | } else { |
| 120 | rover = max_t(u16, net_random(), 2); | 120 | rover = max_t(u16, prandom_u32(), 2); |
| 121 | last = rover - 1; | 121 | last = rover - 1; |
| 122 | } | 122 | } |
| 123 | 123 | ||
diff --git a/net/rds/recv.c b/net/rds/recv.c index de339b24ca14..bd82522534fc 100644 --- a/net/rds/recv.c +++ b/net/rds/recv.c | |||
| @@ -402,7 +402,7 @@ int rds_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, | |||
| 402 | struct rds_sock *rs = rds_sk_to_rs(sk); | 402 | struct rds_sock *rs = rds_sk_to_rs(sk); |
| 403 | long timeo; | 403 | long timeo; |
| 404 | int ret = 0, nonblock = msg_flags & MSG_DONTWAIT; | 404 | int ret = 0, nonblock = msg_flags & MSG_DONTWAIT; |
| 405 | struct sockaddr_in *sin; | 405 | DECLARE_SOCKADDR(struct sockaddr_in *, sin, msg->msg_name); |
| 406 | struct rds_incoming *inc = NULL; | 406 | struct rds_incoming *inc = NULL; |
| 407 | 407 | ||
| 408 | /* udp_recvmsg()->sock_recvtimeo() gets away without locking too.. */ | 408 | /* udp_recvmsg()->sock_recvtimeo() gets away without locking too.. */ |
| @@ -479,7 +479,6 @@ int rds_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, | |||
| 479 | 479 | ||
| 480 | rds_stats_inc(s_recv_delivered); | 480 | rds_stats_inc(s_recv_delivered); |
| 481 | 481 | ||
| 482 | sin = (struct sockaddr_in *)msg->msg_name; | ||
| 483 | if (sin) { | 482 | if (sin) { |
| 484 | sin->sin_family = AF_INET; | 483 | sin->sin_family = AF_INET; |
| 485 | sin->sin_port = inc->i_hdr.h_sport; | 484 | sin->sin_port = inc->i_hdr.h_sport; |
diff --git a/net/rds/send.c b/net/rds/send.c index 88eace57dd6b..a82fb660ec00 100644 --- a/net/rds/send.c +++ b/net/rds/send.c | |||
| @@ -922,7 +922,7 @@ int rds_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, | |||
| 922 | { | 922 | { |
| 923 | struct sock *sk = sock->sk; | 923 | struct sock *sk = sock->sk; |
| 924 | struct rds_sock *rs = rds_sk_to_rs(sk); | 924 | struct rds_sock *rs = rds_sk_to_rs(sk); |
| 925 | struct sockaddr_in *usin = (struct sockaddr_in *)msg->msg_name; | 925 | DECLARE_SOCKADDR(struct sockaddr_in *, usin, msg->msg_name); |
| 926 | __be32 daddr; | 926 | __be32 daddr; |
| 927 | __be16 dport; | 927 | __be16 dport; |
| 928 | struct rds_message *rm = NULL; | 928 | struct rds_message *rm = NULL; |
diff --git a/net/rfkill/core.c b/net/rfkill/core.c index 1bacc1079942..ed7e0b4e7f90 100644 --- a/net/rfkill/core.c +++ b/net/rfkill/core.c | |||
| @@ -14,9 +14,7 @@ | |||
| 14 | * GNU General Public License for more details. | 14 | * GNU General Public License for more details. |
| 15 | * | 15 | * |
| 16 | * You should have received a copy of the GNU General Public License | 16 | * You should have received a copy of the GNU General Public License |
| 17 | * along with this program; if not, write to the | 17 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 18 | * Free Software Foundation, Inc., | ||
| 19 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
| 20 | */ | 18 | */ |
| 21 | 19 | ||
| 22 | #include <linux/kernel.h> | 20 | #include <linux/kernel.h> |
diff --git a/net/rfkill/rfkill-gpio.c b/net/rfkill/rfkill-gpio.c index 5620d3c07479..bd2a5b90400c 100644 --- a/net/rfkill/rfkill-gpio.c +++ b/net/rfkill/rfkill-gpio.c | |||
| @@ -25,15 +25,15 @@ | |||
| 25 | #include <linux/clk.h> | 25 | #include <linux/clk.h> |
| 26 | #include <linux/slab.h> | 26 | #include <linux/slab.h> |
| 27 | #include <linux/acpi.h> | 27 | #include <linux/acpi.h> |
| 28 | #include <linux/acpi_gpio.h> | 28 | #include <linux/gpio/consumer.h> |
| 29 | 29 | ||
| 30 | #include <linux/rfkill-gpio.h> | 30 | #include <linux/rfkill-gpio.h> |
| 31 | 31 | ||
| 32 | struct rfkill_gpio_data { | 32 | struct rfkill_gpio_data { |
| 33 | const char *name; | 33 | const char *name; |
| 34 | enum rfkill_type type; | 34 | enum rfkill_type type; |
| 35 | int reset_gpio; | 35 | struct gpio_desc *reset_gpio; |
| 36 | int shutdown_gpio; | 36 | struct gpio_desc *shutdown_gpio; |
| 37 | 37 | ||
| 38 | struct rfkill *rfkill_dev; | 38 | struct rfkill *rfkill_dev; |
| 39 | char *reset_name; | 39 | char *reset_name; |
| @@ -48,19 +48,15 @@ static int rfkill_gpio_set_power(void *data, bool blocked) | |||
| 48 | struct rfkill_gpio_data *rfkill = data; | 48 | struct rfkill_gpio_data *rfkill = data; |
| 49 | 49 | ||
| 50 | if (blocked) { | 50 | if (blocked) { |
| 51 | if (gpio_is_valid(rfkill->shutdown_gpio)) | 51 | gpiod_set_value(rfkill->shutdown_gpio, 0); |
| 52 | gpio_set_value(rfkill->shutdown_gpio, 0); | 52 | gpiod_set_value(rfkill->reset_gpio, 0); |
| 53 | if (gpio_is_valid(rfkill->reset_gpio)) | ||
| 54 | gpio_set_value(rfkill->reset_gpio, 0); | ||
| 55 | if (!IS_ERR(rfkill->clk) && rfkill->clk_enabled) | 53 | if (!IS_ERR(rfkill->clk) && rfkill->clk_enabled) |
| 56 | clk_disable(rfkill->clk); | 54 | clk_disable(rfkill->clk); |
| 57 | } else { | 55 | } else { |
| 58 | if (!IS_ERR(rfkill->clk) && !rfkill->clk_enabled) | 56 | if (!IS_ERR(rfkill->clk) && !rfkill->clk_enabled) |
| 59 | clk_enable(rfkill->clk); | 57 | clk_enable(rfkill->clk); |
| 60 | if (gpio_is_valid(rfkill->reset_gpio)) | 58 | gpiod_set_value(rfkill->reset_gpio, 1); |
| 61 | gpio_set_value(rfkill->reset_gpio, 1); | 59 | gpiod_set_value(rfkill->shutdown_gpio, 1); |
| 62 | if (gpio_is_valid(rfkill->shutdown_gpio)) | ||
| 63 | gpio_set_value(rfkill->shutdown_gpio, 1); | ||
| 64 | } | 60 | } |
| 65 | 61 | ||
| 66 | rfkill->clk_enabled = blocked; | 62 | rfkill->clk_enabled = blocked; |
| @@ -83,8 +79,6 @@ static int rfkill_gpio_acpi_probe(struct device *dev, | |||
| 83 | 79 | ||
| 84 | rfkill->name = dev_name(dev); | 80 | rfkill->name = dev_name(dev); |
| 85 | rfkill->type = (unsigned)id->driver_data; | 81 | rfkill->type = (unsigned)id->driver_data; |
| 86 | rfkill->reset_gpio = acpi_get_gpio_by_index(dev, 0, NULL); | ||
| 87 | rfkill->shutdown_gpio = acpi_get_gpio_by_index(dev, 1, NULL); | ||
| 88 | 82 | ||
| 89 | return 0; | 83 | return 0; |
| 90 | } | 84 | } |
| @@ -94,8 +88,9 @@ static int rfkill_gpio_probe(struct platform_device *pdev) | |||
| 94 | struct rfkill_gpio_platform_data *pdata = pdev->dev.platform_data; | 88 | struct rfkill_gpio_platform_data *pdata = pdev->dev.platform_data; |
| 95 | struct rfkill_gpio_data *rfkill; | 89 | struct rfkill_gpio_data *rfkill; |
| 96 | const char *clk_name = NULL; | 90 | const char *clk_name = NULL; |
| 97 | int ret = 0; | 91 | struct gpio_desc *gpio; |
| 98 | int len = 0; | 92 | int ret; |
| 93 | int len; | ||
| 99 | 94 | ||
| 100 | rfkill = devm_kzalloc(&pdev->dev, sizeof(*rfkill), GFP_KERNEL); | 95 | rfkill = devm_kzalloc(&pdev->dev, sizeof(*rfkill), GFP_KERNEL); |
| 101 | if (!rfkill) | 96 | if (!rfkill) |
| @@ -109,28 +104,10 @@ static int rfkill_gpio_probe(struct platform_device *pdev) | |||
| 109 | clk_name = pdata->power_clk_name; | 104 | clk_name = pdata->power_clk_name; |
| 110 | rfkill->name = pdata->name; | 105 | rfkill->name = pdata->name; |
| 111 | rfkill->type = pdata->type; | 106 | rfkill->type = pdata->type; |
| 112 | rfkill->reset_gpio = pdata->reset_gpio; | ||
| 113 | rfkill->shutdown_gpio = pdata->shutdown_gpio; | ||
| 114 | } else { | 107 | } else { |
| 115 | return -ENODEV; | 108 | return -ENODEV; |
| 116 | } | 109 | } |
| 117 | 110 | ||
| 118 | /* make sure at-least one of the GPIO is defined and that | ||
| 119 | * a name is specified for this instance */ | ||
| 120 | if ((!gpio_is_valid(rfkill->reset_gpio) && | ||
| 121 | !gpio_is_valid(rfkill->shutdown_gpio)) || !rfkill->name) { | ||
| 122 | pr_warn("%s: invalid platform data\n", __func__); | ||
| 123 | return -EINVAL; | ||
| 124 | } | ||
| 125 | |||
| 126 | if (pdata && pdata->gpio_runtime_setup) { | ||
| 127 | ret = pdata->gpio_runtime_setup(pdev); | ||
| 128 | if (ret) { | ||
| 129 | pr_warn("%s: can't set up gpio\n", __func__); | ||
| 130 | return ret; | ||
| 131 | } | ||
| 132 | } | ||
| 133 | |||
| 134 | len = strlen(rfkill->name); | 111 | len = strlen(rfkill->name); |
| 135 | rfkill->reset_name = devm_kzalloc(&pdev->dev, len + 7, GFP_KERNEL); | 112 | rfkill->reset_name = devm_kzalloc(&pdev->dev, len + 7, GFP_KERNEL); |
| 136 | if (!rfkill->reset_name) | 113 | if (!rfkill->reset_name) |
| @@ -145,20 +122,34 @@ static int rfkill_gpio_probe(struct platform_device *pdev) | |||
| 145 | 122 | ||
| 146 | rfkill->clk = devm_clk_get(&pdev->dev, clk_name); | 123 | rfkill->clk = devm_clk_get(&pdev->dev, clk_name); |
| 147 | 124 | ||
| 148 | if (gpio_is_valid(rfkill->reset_gpio)) { | 125 | gpio = devm_gpiod_get_index(&pdev->dev, rfkill->reset_name, 0); |
| 149 | ret = devm_gpio_request_one(&pdev->dev, rfkill->reset_gpio, | 126 | if (!IS_ERR(gpio)) { |
| 150 | 0, rfkill->reset_name); | 127 | ret = gpiod_direction_output(gpio, 0); |
| 151 | if (ret) { | 128 | if (ret) |
| 152 | pr_warn("%s: failed to get reset gpio.\n", __func__); | ||
| 153 | return ret; | 129 | return ret; |
| 154 | } | 130 | rfkill->reset_gpio = gpio; |
| 131 | } | ||
| 132 | |||
| 133 | gpio = devm_gpiod_get_index(&pdev->dev, rfkill->shutdown_name, 1); | ||
| 134 | if (!IS_ERR(gpio)) { | ||
| 135 | ret = gpiod_direction_output(gpio, 0); | ||
| 136 | if (ret) | ||
| 137 | return ret; | ||
| 138 | rfkill->shutdown_gpio = gpio; | ||
| 155 | } | 139 | } |
| 156 | 140 | ||
| 157 | if (gpio_is_valid(rfkill->shutdown_gpio)) { | 141 | /* Make sure at-least one of the GPIO is defined and that |
| 158 | ret = devm_gpio_request_one(&pdev->dev, rfkill->shutdown_gpio, | 142 | * a name is specified for this instance |
| 159 | 0, rfkill->shutdown_name); | 143 | */ |
| 144 | if ((!rfkill->reset_gpio && !rfkill->shutdown_gpio) || !rfkill->name) { | ||
| 145 | dev_err(&pdev->dev, "invalid platform data\n"); | ||
| 146 | return -EINVAL; | ||
| 147 | } | ||
| 148 | |||
| 149 | if (pdata && pdata->gpio_runtime_setup) { | ||
| 150 | ret = pdata->gpio_runtime_setup(pdev); | ||
| 160 | if (ret) { | 151 | if (ret) { |
| 161 | pr_warn("%s: failed to get shutdown gpio.\n", __func__); | 152 | dev_err(&pdev->dev, "can't set up gpio\n"); |
| 162 | return ret; | 153 | return ret; |
| 163 | } | 154 | } |
| 164 | } | 155 | } |
diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c index 62ced6516c58..c2cca2ee6aef 100644 --- a/net/rose/af_rose.c +++ b/net/rose/af_rose.c | |||
| @@ -1012,7 +1012,7 @@ int rose_rx_call_request(struct sk_buff *skb, struct net_device *dev, struct ros | |||
| 1012 | make_rose->source_call = facilities.source_call; | 1012 | make_rose->source_call = facilities.source_call; |
| 1013 | make_rose->source_ndigis = facilities.source_ndigis; | 1013 | make_rose->source_ndigis = facilities.source_ndigis; |
| 1014 | for (n = 0 ; n < facilities.source_ndigis ; n++) | 1014 | for (n = 0 ; n < facilities.source_ndigis ; n++) |
| 1015 | make_rose->source_digis[n]= facilities.source_digis[n]; | 1015 | make_rose->source_digis[n] = facilities.source_digis[n]; |
| 1016 | make_rose->neighbour = neigh; | 1016 | make_rose->neighbour = neigh; |
| 1017 | make_rose->device = dev; | 1017 | make_rose->device = dev; |
| 1018 | make_rose->facilities = facilities; | 1018 | make_rose->facilities = facilities; |
| @@ -1051,7 +1051,7 @@ static int rose_sendmsg(struct kiocb *iocb, struct socket *sock, | |||
| 1051 | { | 1051 | { |
| 1052 | struct sock *sk = sock->sk; | 1052 | struct sock *sk = sock->sk; |
| 1053 | struct rose_sock *rose = rose_sk(sk); | 1053 | struct rose_sock *rose = rose_sk(sk); |
| 1054 | struct sockaddr_rose *usrose = (struct sockaddr_rose *)msg->msg_name; | 1054 | DECLARE_SOCKADDR(struct sockaddr_rose *, usrose, msg->msg_name); |
| 1055 | int err; | 1055 | int err; |
| 1056 | struct full_sockaddr_rose srose; | 1056 | struct full_sockaddr_rose srose; |
| 1057 | struct sk_buff *skb; | 1057 | struct sk_buff *skb; |
| @@ -1253,7 +1253,8 @@ static int rose_recvmsg(struct kiocb *iocb, struct socket *sock, | |||
| 1253 | 1253 | ||
| 1254 | if (msg->msg_name) { | 1254 | if (msg->msg_name) { |
| 1255 | struct sockaddr_rose *srose; | 1255 | struct sockaddr_rose *srose; |
| 1256 | struct full_sockaddr_rose *full_srose = msg->msg_name; | 1256 | DECLARE_SOCKADDR(struct full_sockaddr_rose *, full_srose, |
| 1257 | msg->msg_name); | ||
| 1257 | 1258 | ||
| 1258 | memset(msg->msg_name, 0, sizeof(struct full_sockaddr_rose)); | 1259 | memset(msg->msg_name, 0, sizeof(struct full_sockaddr_rose)); |
| 1259 | srose = msg->msg_name; | 1260 | srose = msg->msg_name; |
diff --git a/net/rose/rose_dev.c b/net/rose/rose_dev.c index 28dbdb911b85..50005888be57 100644 --- a/net/rose/rose_dev.c +++ b/net/rose/rose_dev.c | |||
| @@ -146,7 +146,7 @@ static netdev_tx_t rose_xmit(struct sk_buff *skb, struct net_device *dev) | |||
| 146 | 146 | ||
| 147 | static const struct header_ops rose_header_ops = { | 147 | static const struct header_ops rose_header_ops = { |
| 148 | .create = rose_header, | 148 | .create = rose_header, |
| 149 | .rebuild= rose_rebuild_header, | 149 | .rebuild = rose_rebuild_header, |
| 150 | }; | 150 | }; |
| 151 | 151 | ||
| 152 | static const struct net_device_ops rose_netdev_ops = { | 152 | static const struct net_device_ops rose_netdev_ops = { |
diff --git a/net/rxrpc/ar-ack.c b/net/rxrpc/ar-ack.c index e4d9cbcff402..cd97a0ce48d8 100644 --- a/net/rxrpc/ar-ack.c +++ b/net/rxrpc/ar-ack.c | |||
| @@ -21,10 +21,17 @@ | |||
| 21 | 21 | ||
| 22 | static unsigned int rxrpc_ack_defer = 1; | 22 | static unsigned int rxrpc_ack_defer = 1; |
| 23 | 23 | ||
| 24 | static const char *const rxrpc_acks[] = { | 24 | static const char *rxrpc_acks(u8 reason) |
| 25 | "---", "REQ", "DUP", "OOS", "WIN", "MEM", "PNG", "PNR", "DLY", "IDL", | 25 | { |
| 26 | "-?-" | 26 | static const char *const str[] = { |
| 27 | }; | 27 | "---", "REQ", "DUP", "OOS", "WIN", "MEM", "PNG", "PNR", "DLY", |
| 28 | "IDL", "-?-" | ||
| 29 | }; | ||
| 30 | |||
| 31 | if (reason >= ARRAY_SIZE(str)) | ||
| 32 | reason = ARRAY_SIZE(str) - 1; | ||
| 33 | return str[reason]; | ||
| 34 | } | ||
| 28 | 35 | ||
| 29 | static const s8 rxrpc_ack_priority[] = { | 36 | static const s8 rxrpc_ack_priority[] = { |
| 30 | [0] = 0, | 37 | [0] = 0, |
| @@ -50,7 +57,7 @@ void __rxrpc_propose_ACK(struct rxrpc_call *call, u8 ack_reason, | |||
| 50 | ASSERTCMP(prior, >, 0); | 57 | ASSERTCMP(prior, >, 0); |
| 51 | 58 | ||
| 52 | _enter("{%d},%s,%%%x,%u", | 59 | _enter("{%d},%s,%%%x,%u", |
| 53 | call->debug_id, rxrpc_acks[ack_reason], ntohl(serial), | 60 | call->debug_id, rxrpc_acks(ack_reason), ntohl(serial), |
| 54 | immediate); | 61 | immediate); |
| 55 | 62 | ||
| 56 | if (prior < rxrpc_ack_priority[call->ackr_reason]) { | 63 | if (prior < rxrpc_ack_priority[call->ackr_reason]) { |
| @@ -637,7 +644,7 @@ process_further: | |||
| 637 | hard, | 644 | hard, |
| 638 | ntohl(ack.previousPacket), | 645 | ntohl(ack.previousPacket), |
| 639 | ntohl(ack.serial), | 646 | ntohl(ack.serial), |
| 640 | rxrpc_acks[ack.reason], | 647 | rxrpc_acks(ack.reason), |
| 641 | ack.nAcks); | 648 | ack.nAcks); |
| 642 | 649 | ||
| 643 | rxrpc_extract_ackinfo(call, skb, latest, ack.nAcks); | 650 | rxrpc_extract_ackinfo(call, skb, latest, ack.nAcks); |
| @@ -1180,7 +1187,7 @@ send_ACK: | |||
| 1180 | ntohl(ack.firstPacket), | 1187 | ntohl(ack.firstPacket), |
| 1181 | ntohl(ack.previousPacket), | 1188 | ntohl(ack.previousPacket), |
| 1182 | ntohl(ack.serial), | 1189 | ntohl(ack.serial), |
| 1183 | rxrpc_acks[ack.reason], | 1190 | rxrpc_acks(ack.reason), |
| 1184 | ack.nAcks); | 1191 | ack.nAcks); |
| 1185 | 1192 | ||
| 1186 | del_timer_sync(&call->ack_timer); | 1193 | del_timer_sync(&call->ack_timer); |
diff --git a/net/rxrpc/ar-connection.c b/net/rxrpc/ar-connection.c index 4106ca95ec86..7bf5b5b9e8b9 100644 --- a/net/rxrpc/ar-connection.c +++ b/net/rxrpc/ar-connection.c | |||
| @@ -381,6 +381,8 @@ static int rxrpc_connect_exclusive(struct rxrpc_sock *rx, | |||
| 381 | 381 | ||
| 382 | rxrpc_assign_connection_id(conn); | 382 | rxrpc_assign_connection_id(conn); |
| 383 | rx->conn = conn; | 383 | rx->conn = conn; |
| 384 | } else { | ||
| 385 | spin_lock(&trans->client_lock); | ||
| 384 | } | 386 | } |
| 385 | 387 | ||
| 386 | /* we've got a connection with a free channel and we can now attach the | 388 | /* we've got a connection with a free channel and we can now attach the |
diff --git a/net/rxrpc/ar-output.c b/net/rxrpc/ar-output.c index e1ac183d50bb..d0e8f1c1898a 100644 --- a/net/rxrpc/ar-output.c +++ b/net/rxrpc/ar-output.c | |||
| @@ -152,8 +152,8 @@ int rxrpc_client_sendmsg(struct kiocb *iocb, struct rxrpc_sock *rx, | |||
| 152 | if (trans) { | 152 | if (trans) { |
| 153 | service_id = rx->service_id; | 153 | service_id = rx->service_id; |
| 154 | if (msg->msg_name) { | 154 | if (msg->msg_name) { |
| 155 | struct sockaddr_rxrpc *srx = | 155 | DECLARE_SOCKADDR(struct sockaddr_rxrpc *, srx, |
| 156 | (struct sockaddr_rxrpc *) msg->msg_name; | 156 | msg->msg_name); |
| 157 | service_id = htons(srx->srx_service); | 157 | service_id = htons(srx->srx_service); |
| 158 | } | 158 | } |
| 159 | key = rx->key; | 159 | key = rx->key; |
diff --git a/net/rxrpc/ar-recvmsg.c b/net/rxrpc/ar-recvmsg.c index 898492a8d61b..34b5490dde65 100644 --- a/net/rxrpc/ar-recvmsg.c +++ b/net/rxrpc/ar-recvmsg.c | |||
| @@ -180,7 +180,8 @@ int rxrpc_recvmsg(struct kiocb *iocb, struct socket *sock, | |||
| 180 | if (copy > len - copied) | 180 | if (copy > len - copied) |
| 181 | copy = len - copied; | 181 | copy = len - copied; |
| 182 | 182 | ||
| 183 | if (skb->ip_summed == CHECKSUM_UNNECESSARY) { | 183 | if (skb->ip_summed == CHECKSUM_UNNECESSARY || |
| 184 | skb->ip_summed == CHECKSUM_PARTIAL) { | ||
| 184 | ret = skb_copy_datagram_iovec(skb, offset, | 185 | ret = skb_copy_datagram_iovec(skb, offset, |
| 185 | msg->msg_iov, copy); | 186 | msg->msg_iov, copy); |
| 186 | } else { | 187 | } else { |
| @@ -353,6 +354,10 @@ csum_copy_error: | |||
| 353 | if (continue_call) | 354 | if (continue_call) |
| 354 | rxrpc_put_call(continue_call); | 355 | rxrpc_put_call(continue_call); |
| 355 | rxrpc_kill_skb(skb); | 356 | rxrpc_kill_skb(skb); |
| 357 | if (!(flags & MSG_PEEK)) { | ||
| 358 | if (skb_dequeue(&rx->sk.sk_receive_queue) != skb) | ||
| 359 | BUG(); | ||
| 360 | } | ||
| 356 | skb_kill_datagram(&rx->sk, skb, flags); | 361 | skb_kill_datagram(&rx->sk, skb, flags); |
| 357 | rxrpc_put_call(call); | 362 | rxrpc_put_call(call); |
| 358 | return -EAGAIN; | 363 | return -EAGAIN; |
diff --git a/net/sched/Kconfig b/net/sched/Kconfig index ad1f1d819203..a1a8e29e5fc9 100644 --- a/net/sched/Kconfig +++ b/net/sched/Kconfig | |||
| @@ -286,6 +286,28 @@ config NET_SCH_FQ | |||
| 286 | 286 | ||
| 287 | If unsure, say N. | 287 | If unsure, say N. |
| 288 | 288 | ||
| 289 | config NET_SCH_HHF | ||
| 290 | tristate "Heavy-Hitter Filter (HHF)" | ||
| 291 | help | ||
| 292 | Say Y here if you want to use the Heavy-Hitter Filter (HHF) | ||
| 293 | packet scheduling algorithm. | ||
| 294 | |||
| 295 | To compile this driver as a module, choose M here: the module | ||
| 296 | will be called sch_hhf. | ||
| 297 | |||
| 298 | config NET_SCH_PIE | ||
| 299 | tristate "Proportional Integral controller Enhanced (PIE) scheduler" | ||
| 300 | help | ||
| 301 | Say Y here if you want to use the Proportional Integral controller | ||
| 302 | Enhanced scheduler packet scheduling algorithm. | ||
| 303 | For more information, please see | ||
| 304 | http://tools.ietf.org/html/draft-pan-tsvwg-pie-00 | ||
| 305 | |||
| 306 | To compile this driver as a module, choose M here: the module | ||
| 307 | will be called sch_pie. | ||
| 308 | |||
| 309 | If unsure, say N. | ||
| 310 | |||
| 289 | config NET_SCH_INGRESS | 311 | config NET_SCH_INGRESS |
| 290 | tristate "Ingress Qdisc" | 312 | tristate "Ingress Qdisc" |
| 291 | depends on NET_CLS_ACT | 313 | depends on NET_CLS_ACT |
| @@ -435,6 +457,7 @@ config NET_CLS_FLOW | |||
| 435 | config NET_CLS_CGROUP | 457 | config NET_CLS_CGROUP |
| 436 | tristate "Control Group Classifier" | 458 | tristate "Control Group Classifier" |
| 437 | select NET_CLS | 459 | select NET_CLS |
| 460 | select CGROUP_NET_CLASSID | ||
| 438 | depends on CGROUPS | 461 | depends on CGROUPS |
| 439 | ---help--- | 462 | ---help--- |
| 440 | Say Y here if you want to classify packets based on the control | 463 | Say Y here if you want to classify packets based on the control |
diff --git a/net/sched/Makefile b/net/sched/Makefile index 35fa47a494ab..0a869a11f3e6 100644 --- a/net/sched/Makefile +++ b/net/sched/Makefile | |||
| @@ -40,6 +40,8 @@ obj-$(CONFIG_NET_SCH_QFQ) += sch_qfq.o | |||
| 40 | obj-$(CONFIG_NET_SCH_CODEL) += sch_codel.o | 40 | obj-$(CONFIG_NET_SCH_CODEL) += sch_codel.o |
| 41 | obj-$(CONFIG_NET_SCH_FQ_CODEL) += sch_fq_codel.o | 41 | obj-$(CONFIG_NET_SCH_FQ_CODEL) += sch_fq_codel.o |
| 42 | obj-$(CONFIG_NET_SCH_FQ) += sch_fq.o | 42 | obj-$(CONFIG_NET_SCH_FQ) += sch_fq.o |
| 43 | obj-$(CONFIG_NET_SCH_HHF) += sch_hhf.o | ||
| 44 | obj-$(CONFIG_NET_SCH_PIE) += sch_pie.o | ||
| 43 | 45 | ||
| 44 | obj-$(CONFIG_NET_CLS_U32) += cls_u32.o | 46 | obj-$(CONFIG_NET_CLS_U32) += cls_u32.o |
| 45 | obj-$(CONFIG_NET_CLS_ROUTE4) += cls_route.o | 47 | obj-$(CONFIG_NET_CLS_ROUTE4) += cls_route.o |
diff --git a/net/sched/act_api.c b/net/sched/act_api.c index 69cb848e8345..72bdc7166345 100644 --- a/net/sched/act_api.c +++ b/net/sched/act_api.c | |||
| @@ -29,25 +29,16 @@ | |||
| 29 | 29 | ||
| 30 | void tcf_hash_destroy(struct tcf_common *p, struct tcf_hashinfo *hinfo) | 30 | void tcf_hash_destroy(struct tcf_common *p, struct tcf_hashinfo *hinfo) |
| 31 | { | 31 | { |
| 32 | unsigned int h = tcf_hash(p->tcfc_index, hinfo->hmask); | 32 | spin_lock_bh(&hinfo->lock); |
| 33 | struct tcf_common **p1p; | 33 | hlist_del(&p->tcfc_head); |
| 34 | 34 | spin_unlock_bh(&hinfo->lock); | |
| 35 | for (p1p = &hinfo->htab[h]; *p1p; p1p = &(*p1p)->tcfc_next) { | 35 | gen_kill_estimator(&p->tcfc_bstats, |
| 36 | if (*p1p == p) { | 36 | &p->tcfc_rate_est); |
| 37 | write_lock_bh(hinfo->lock); | 37 | /* |
| 38 | *p1p = p->tcfc_next; | 38 | * gen_estimator est_timer() might access p->tcfc_lock |
| 39 | write_unlock_bh(hinfo->lock); | 39 | * or bstats, wait a RCU grace period before freeing p |
| 40 | gen_kill_estimator(&p->tcfc_bstats, | 40 | */ |
| 41 | &p->tcfc_rate_est); | 41 | kfree_rcu(p, tcfc_rcu); |
| 42 | /* | ||
| 43 | * gen_estimator est_timer() might access p->tcfc_lock | ||
| 44 | * or bstats, wait a RCU grace period before freeing p | ||
| 45 | */ | ||
| 46 | kfree_rcu(p, tcfc_rcu); | ||
| 47 | return; | ||
| 48 | } | ||
| 49 | } | ||
| 50 | WARN_ON(1); | ||
| 51 | } | 42 | } |
| 52 | EXPORT_SYMBOL(tcf_hash_destroy); | 43 | EXPORT_SYMBOL(tcf_hash_destroy); |
| 53 | 44 | ||
| @@ -71,20 +62,22 @@ int tcf_hash_release(struct tcf_common *p, int bind, | |||
| 71 | EXPORT_SYMBOL(tcf_hash_release); | 62 | EXPORT_SYMBOL(tcf_hash_release); |
| 72 | 63 | ||
| 73 | static int tcf_dump_walker(struct sk_buff *skb, struct netlink_callback *cb, | 64 | static int tcf_dump_walker(struct sk_buff *skb, struct netlink_callback *cb, |
| 74 | struct tc_action *a, struct tcf_hashinfo *hinfo) | 65 | struct tc_action *a) |
| 75 | { | 66 | { |
| 67 | struct tcf_hashinfo *hinfo = a->ops->hinfo; | ||
| 68 | struct hlist_head *head; | ||
| 76 | struct tcf_common *p; | 69 | struct tcf_common *p; |
| 77 | int err = 0, index = -1, i = 0, s_i = 0, n_i = 0; | 70 | int err = 0, index = -1, i = 0, s_i = 0, n_i = 0; |
| 78 | struct nlattr *nest; | 71 | struct nlattr *nest; |
| 79 | 72 | ||
| 80 | read_lock_bh(hinfo->lock); | 73 | spin_lock_bh(&hinfo->lock); |
| 81 | 74 | ||
| 82 | s_i = cb->args[0]; | 75 | s_i = cb->args[0]; |
| 83 | 76 | ||
| 84 | for (i = 0; i < (hinfo->hmask + 1); i++) { | 77 | for (i = 0; i < (hinfo->hmask + 1); i++) { |
| 85 | p = hinfo->htab[tcf_hash(i, hinfo->hmask)]; | 78 | head = &hinfo->htab[tcf_hash(i, hinfo->hmask)]; |
| 86 | 79 | ||
| 87 | for (; p; p = p->tcfc_next) { | 80 | hlist_for_each_entry_rcu(p, head, tcfc_head) { |
| 88 | index++; | 81 | index++; |
| 89 | if (index < s_i) | 82 | if (index < s_i) |
| 90 | continue; | 83 | continue; |
| @@ -107,7 +100,7 @@ static int tcf_dump_walker(struct sk_buff *skb, struct netlink_callback *cb, | |||
| 107 | } | 100 | } |
| 108 | } | 101 | } |
| 109 | done: | 102 | done: |
| 110 | read_unlock_bh(hinfo->lock); | 103 | spin_unlock_bh(&hinfo->lock); |
| 111 | if (n_i) | 104 | if (n_i) |
| 112 | cb->args[0] += n_i; | 105 | cb->args[0] += n_i; |
| 113 | return n_i; | 106 | return n_i; |
| @@ -117,10 +110,12 @@ nla_put_failure: | |||
| 117 | goto done; | 110 | goto done; |
| 118 | } | 111 | } |
| 119 | 112 | ||
| 120 | static int tcf_del_walker(struct sk_buff *skb, struct tc_action *a, | 113 | static int tcf_del_walker(struct sk_buff *skb, struct tc_action *a) |
| 121 | struct tcf_hashinfo *hinfo) | ||
| 122 | { | 114 | { |
| 123 | struct tcf_common *p, *s_p; | 115 | struct tcf_hashinfo *hinfo = a->ops->hinfo; |
| 116 | struct hlist_head *head; | ||
| 117 | struct hlist_node *n; | ||
| 118 | struct tcf_common *p; | ||
| 124 | struct nlattr *nest; | 119 | struct nlattr *nest; |
| 125 | int i = 0, n_i = 0; | 120 | int i = 0, n_i = 0; |
| 126 | 121 | ||
| @@ -130,14 +125,12 @@ static int tcf_del_walker(struct sk_buff *skb, struct tc_action *a, | |||
| 130 | if (nla_put_string(skb, TCA_KIND, a->ops->kind)) | 125 | if (nla_put_string(skb, TCA_KIND, a->ops->kind)) |
| 131 | goto nla_put_failure; | 126 | goto nla_put_failure; |
| 132 | for (i = 0; i < (hinfo->hmask + 1); i++) { | 127 | for (i = 0; i < (hinfo->hmask + 1); i++) { |
| 133 | p = hinfo->htab[tcf_hash(i, hinfo->hmask)]; | 128 | head = &hinfo->htab[tcf_hash(i, hinfo->hmask)]; |
| 134 | 129 | hlist_for_each_entry_safe(p, n, head, tcfc_head) { | |
| 135 | while (p != NULL) { | 130 | if (ACT_P_DELETED == tcf_hash_release(p, 0, hinfo)) { |
| 136 | s_p = p->tcfc_next; | ||
| 137 | if (ACT_P_DELETED == tcf_hash_release(p, 0, hinfo)) | ||
| 138 | module_put(a->ops->owner); | 131 | module_put(a->ops->owner); |
| 139 | n_i++; | 132 | n_i++; |
| 140 | p = s_p; | 133 | } |
| 141 | } | 134 | } |
| 142 | } | 135 | } |
| 143 | if (nla_put_u32(skb, TCA_FCNT, n_i)) | 136 | if (nla_put_u32(skb, TCA_FCNT, n_i)) |
| @@ -150,48 +143,45 @@ nla_put_failure: | |||
| 150 | return -EINVAL; | 143 | return -EINVAL; |
| 151 | } | 144 | } |
| 152 | 145 | ||
| 153 | int tcf_generic_walker(struct sk_buff *skb, struct netlink_callback *cb, | 146 | static int tcf_generic_walker(struct sk_buff *skb, struct netlink_callback *cb, |
| 154 | int type, struct tc_action *a) | 147 | int type, struct tc_action *a) |
| 155 | { | 148 | { |
| 156 | struct tcf_hashinfo *hinfo = a->ops->hinfo; | ||
| 157 | |||
| 158 | if (type == RTM_DELACTION) { | 149 | if (type == RTM_DELACTION) { |
| 159 | return tcf_del_walker(skb, a, hinfo); | 150 | return tcf_del_walker(skb, a); |
| 160 | } else if (type == RTM_GETACTION) { | 151 | } else if (type == RTM_GETACTION) { |
| 161 | return tcf_dump_walker(skb, cb, a, hinfo); | 152 | return tcf_dump_walker(skb, cb, a); |
| 162 | } else { | 153 | } else { |
| 163 | WARN(1, "tcf_generic_walker: unknown action %d\n", type); | 154 | WARN(1, "tcf_generic_walker: unknown action %d\n", type); |
| 164 | return -EINVAL; | 155 | return -EINVAL; |
| 165 | } | 156 | } |
| 166 | } | 157 | } |
| 167 | EXPORT_SYMBOL(tcf_generic_walker); | ||
| 168 | 158 | ||
| 169 | struct tcf_common *tcf_hash_lookup(u32 index, struct tcf_hashinfo *hinfo) | 159 | static struct tcf_common *tcf_hash_lookup(u32 index, struct tcf_hashinfo *hinfo) |
| 170 | { | 160 | { |
| 171 | struct tcf_common *p; | 161 | struct tcf_common *p = NULL; |
| 162 | struct hlist_head *head; | ||
| 172 | 163 | ||
| 173 | read_lock_bh(hinfo->lock); | 164 | spin_lock_bh(&hinfo->lock); |
| 174 | for (p = hinfo->htab[tcf_hash(index, hinfo->hmask)]; p; | 165 | head = &hinfo->htab[tcf_hash(index, hinfo->hmask)]; |
| 175 | p = p->tcfc_next) { | 166 | hlist_for_each_entry_rcu(p, head, tcfc_head) |
| 176 | if (p->tcfc_index == index) | 167 | if (p->tcfc_index == index) |
| 177 | break; | 168 | break; |
| 178 | } | 169 | spin_unlock_bh(&hinfo->lock); |
| 179 | read_unlock_bh(hinfo->lock); | ||
| 180 | 170 | ||
| 181 | return p; | 171 | return p; |
| 182 | } | 172 | } |
| 183 | EXPORT_SYMBOL(tcf_hash_lookup); | ||
| 184 | 173 | ||
| 185 | u32 tcf_hash_new_index(u32 *idx_gen, struct tcf_hashinfo *hinfo) | 174 | u32 tcf_hash_new_index(struct tcf_hashinfo *hinfo) |
| 186 | { | 175 | { |
| 187 | u32 val = *idx_gen; | 176 | u32 val = hinfo->index; |
| 188 | 177 | ||
| 189 | do { | 178 | do { |
| 190 | if (++val == 0) | 179 | if (++val == 0) |
| 191 | val = 1; | 180 | val = 1; |
| 192 | } while (tcf_hash_lookup(val, hinfo)); | 181 | } while (tcf_hash_lookup(val, hinfo)); |
| 193 | 182 | ||
| 194 | return (*idx_gen = val); | 183 | hinfo->index = val; |
| 184 | return val; | ||
| 195 | } | 185 | } |
| 196 | EXPORT_SYMBOL(tcf_hash_new_index); | 186 | EXPORT_SYMBOL(tcf_hash_new_index); |
| 197 | 187 | ||
| @@ -208,9 +198,9 @@ int tcf_hash_search(struct tc_action *a, u32 index) | |||
| 208 | } | 198 | } |
| 209 | EXPORT_SYMBOL(tcf_hash_search); | 199 | EXPORT_SYMBOL(tcf_hash_search); |
| 210 | 200 | ||
| 211 | struct tcf_common *tcf_hash_check(u32 index, struct tc_action *a, int bind, | 201 | struct tcf_common *tcf_hash_check(u32 index, struct tc_action *a, int bind) |
| 212 | struct tcf_hashinfo *hinfo) | ||
| 213 | { | 202 | { |
| 203 | struct tcf_hashinfo *hinfo = a->ops->hinfo; | ||
| 214 | struct tcf_common *p = NULL; | 204 | struct tcf_common *p = NULL; |
| 215 | if (index && (p = tcf_hash_lookup(index, hinfo)) != NULL) { | 205 | if (index && (p = tcf_hash_lookup(index, hinfo)) != NULL) { |
| 216 | if (bind) | 206 | if (bind) |
| @@ -223,9 +213,9 @@ struct tcf_common *tcf_hash_check(u32 index, struct tc_action *a, int bind, | |||
| 223 | EXPORT_SYMBOL(tcf_hash_check); | 213 | EXPORT_SYMBOL(tcf_hash_check); |
| 224 | 214 | ||
| 225 | struct tcf_common *tcf_hash_create(u32 index, struct nlattr *est, | 215 | struct tcf_common *tcf_hash_create(u32 index, struct nlattr *est, |
| 226 | struct tc_action *a, int size, int bind, | 216 | struct tc_action *a, int size, int bind) |
| 227 | u32 *idx_gen, struct tcf_hashinfo *hinfo) | ||
| 228 | { | 217 | { |
| 218 | struct tcf_hashinfo *hinfo = a->ops->hinfo; | ||
| 229 | struct tcf_common *p = kzalloc(size, GFP_KERNEL); | 219 | struct tcf_common *p = kzalloc(size, GFP_KERNEL); |
| 230 | 220 | ||
| 231 | if (unlikely(!p)) | 221 | if (unlikely(!p)) |
| @@ -235,7 +225,8 @@ struct tcf_common *tcf_hash_create(u32 index, struct nlattr *est, | |||
| 235 | p->tcfc_bindcnt = 1; | 225 | p->tcfc_bindcnt = 1; |
| 236 | 226 | ||
| 237 | spin_lock_init(&p->tcfc_lock); | 227 | spin_lock_init(&p->tcfc_lock); |
| 238 | p->tcfc_index = index ? index : tcf_hash_new_index(idx_gen, hinfo); | 228 | INIT_HLIST_NODE(&p->tcfc_head); |
| 229 | p->tcfc_index = index ? index : tcf_hash_new_index(hinfo); | ||
| 239 | p->tcfc_tm.install = jiffies; | 230 | p->tcfc_tm.install = jiffies; |
| 240 | p->tcfc_tm.lastuse = jiffies; | 231 | p->tcfc_tm.lastuse = jiffies; |
| 241 | if (est) { | 232 | if (est) { |
| @@ -256,19 +247,18 @@ void tcf_hash_insert(struct tcf_common *p, struct tcf_hashinfo *hinfo) | |||
| 256 | { | 247 | { |
| 257 | unsigned int h = tcf_hash(p->tcfc_index, hinfo->hmask); | 248 | unsigned int h = tcf_hash(p->tcfc_index, hinfo->hmask); |
| 258 | 249 | ||
| 259 | write_lock_bh(hinfo->lock); | 250 | spin_lock_bh(&hinfo->lock); |
| 260 | p->tcfc_next = hinfo->htab[h]; | 251 | hlist_add_head(&p->tcfc_head, &hinfo->htab[h]); |
| 261 | hinfo->htab[h] = p; | 252 | spin_unlock_bh(&hinfo->lock); |
| 262 | write_unlock_bh(hinfo->lock); | ||
| 263 | } | 253 | } |
| 264 | EXPORT_SYMBOL(tcf_hash_insert); | 254 | EXPORT_SYMBOL(tcf_hash_insert); |
| 265 | 255 | ||
| 266 | static struct tc_action_ops *act_base = NULL; | 256 | static LIST_HEAD(act_base); |
| 267 | static DEFINE_RWLOCK(act_mod_lock); | 257 | static DEFINE_RWLOCK(act_mod_lock); |
| 268 | 258 | ||
| 269 | int tcf_register_action(struct tc_action_ops *act) | 259 | int tcf_register_action(struct tc_action_ops *act) |
| 270 | { | 260 | { |
| 271 | struct tc_action_ops *a, **ap; | 261 | struct tc_action_ops *a; |
| 272 | 262 | ||
| 273 | /* Must supply act, dump, cleanup and init */ | 263 | /* Must supply act, dump, cleanup and init */ |
| 274 | if (!act->act || !act->dump || !act->cleanup || !act->init) | 264 | if (!act->act || !act->dump || !act->cleanup || !act->init) |
| @@ -281,14 +271,13 @@ int tcf_register_action(struct tc_action_ops *act) | |||
| 281 | act->walk = tcf_generic_walker; | 271 | act->walk = tcf_generic_walker; |
| 282 | 272 | ||
| 283 | write_lock(&act_mod_lock); | 273 | write_lock(&act_mod_lock); |
| 284 | for (ap = &act_base; (a = *ap) != NULL; ap = &a->next) { | 274 | list_for_each_entry(a, &act_base, head) { |
| 285 | if (act->type == a->type || (strcmp(act->kind, a->kind) == 0)) { | 275 | if (act->type == a->type || (strcmp(act->kind, a->kind) == 0)) { |
| 286 | write_unlock(&act_mod_lock); | 276 | write_unlock(&act_mod_lock); |
| 287 | return -EEXIST; | 277 | return -EEXIST; |
| 288 | } | 278 | } |
| 289 | } | 279 | } |
| 290 | act->next = NULL; | 280 | list_add_tail(&act->head, &act_base); |
| 291 | *ap = act; | ||
| 292 | write_unlock(&act_mod_lock); | 281 | write_unlock(&act_mod_lock); |
| 293 | return 0; | 282 | return 0; |
| 294 | } | 283 | } |
| @@ -296,17 +285,16 @@ EXPORT_SYMBOL(tcf_register_action); | |||
| 296 | 285 | ||
| 297 | int tcf_unregister_action(struct tc_action_ops *act) | 286 | int tcf_unregister_action(struct tc_action_ops *act) |
| 298 | { | 287 | { |
| 299 | struct tc_action_ops *a, **ap; | 288 | struct tc_action_ops *a; |
| 300 | int err = -ENOENT; | 289 | int err = -ENOENT; |
| 301 | 290 | ||
| 302 | write_lock(&act_mod_lock); | 291 | write_lock(&act_mod_lock); |
| 303 | for (ap = &act_base; (a = *ap) != NULL; ap = &a->next) | 292 | list_for_each_entry(a, &act_base, head) { |
| 304 | if (a == act) | 293 | if (a == act) { |
| 294 | list_del(&act->head); | ||
| 295 | err = 0; | ||
| 305 | break; | 296 | break; |
| 306 | if (a) { | 297 | } |
| 307 | *ap = a->next; | ||
| 308 | a->next = NULL; | ||
| 309 | err = 0; | ||
| 310 | } | 298 | } |
| 311 | write_unlock(&act_mod_lock); | 299 | write_unlock(&act_mod_lock); |
| 312 | return err; | 300 | return err; |
| @@ -316,69 +304,42 @@ EXPORT_SYMBOL(tcf_unregister_action); | |||
| 316 | /* lookup by name */ | 304 | /* lookup by name */ |
| 317 | static struct tc_action_ops *tc_lookup_action_n(char *kind) | 305 | static struct tc_action_ops *tc_lookup_action_n(char *kind) |
| 318 | { | 306 | { |
| 319 | struct tc_action_ops *a = NULL; | 307 | struct tc_action_ops *a, *res = NULL; |
| 320 | 308 | ||
| 321 | if (kind) { | 309 | if (kind) { |
| 322 | read_lock(&act_mod_lock); | 310 | read_lock(&act_mod_lock); |
| 323 | for (a = act_base; a; a = a->next) { | 311 | list_for_each_entry(a, &act_base, head) { |
| 324 | if (strcmp(kind, a->kind) == 0) { | 312 | if (strcmp(kind, a->kind) == 0) { |
| 325 | if (!try_module_get(a->owner)) { | 313 | if (try_module_get(a->owner)) |
| 326 | read_unlock(&act_mod_lock); | 314 | res = a; |
| 327 | return NULL; | ||
| 328 | } | ||
| 329 | break; | 315 | break; |
| 330 | } | 316 | } |
| 331 | } | 317 | } |
| 332 | read_unlock(&act_mod_lock); | 318 | read_unlock(&act_mod_lock); |
| 333 | } | 319 | } |
| 334 | return a; | 320 | return res; |
| 335 | } | 321 | } |
| 336 | 322 | ||
| 337 | /* lookup by nlattr */ | 323 | /* lookup by nlattr */ |
| 338 | static struct tc_action_ops *tc_lookup_action(struct nlattr *kind) | 324 | static struct tc_action_ops *tc_lookup_action(struct nlattr *kind) |
| 339 | { | 325 | { |
| 340 | struct tc_action_ops *a = NULL; | 326 | struct tc_action_ops *a, *res = NULL; |
| 341 | 327 | ||
| 342 | if (kind) { | 328 | if (kind) { |
| 343 | read_lock(&act_mod_lock); | 329 | read_lock(&act_mod_lock); |
| 344 | for (a = act_base; a; a = a->next) { | 330 | list_for_each_entry(a, &act_base, head) { |
| 345 | if (nla_strcmp(kind, a->kind) == 0) { | 331 | if (nla_strcmp(kind, a->kind) == 0) { |
| 346 | if (!try_module_get(a->owner)) { | 332 | if (try_module_get(a->owner)) |
| 347 | read_unlock(&act_mod_lock); | 333 | res = a; |
| 348 | return NULL; | ||
| 349 | } | ||
| 350 | break; | 334 | break; |
| 351 | } | 335 | } |
| 352 | } | 336 | } |
| 353 | read_unlock(&act_mod_lock); | 337 | read_unlock(&act_mod_lock); |
| 354 | } | 338 | } |
| 355 | return a; | 339 | return res; |
| 356 | } | 340 | } |
| 357 | 341 | ||
| 358 | #if 0 | 342 | int tcf_action_exec(struct sk_buff *skb, const struct list_head *actions, |
| 359 | /* lookup by id */ | ||
| 360 | static struct tc_action_ops *tc_lookup_action_id(u32 type) | ||
| 361 | { | ||
| 362 | struct tc_action_ops *a = NULL; | ||
| 363 | |||
| 364 | if (type) { | ||
| 365 | read_lock(&act_mod_lock); | ||
| 366 | for (a = act_base; a; a = a->next) { | ||
| 367 | if (a->type == type) { | ||
| 368 | if (!try_module_get(a->owner)) { | ||
| 369 | read_unlock(&act_mod_lock); | ||
| 370 | return NULL; | ||
| 371 | } | ||
| 372 | break; | ||
| 373 | } | ||
| 374 | } | ||
| 375 | read_unlock(&act_mod_lock); | ||
| 376 | } | ||
| 377 | return a; | ||
| 378 | } | ||
| 379 | #endif | ||
| 380 | |||
| 381 | int tcf_action_exec(struct sk_buff *skb, const struct tc_action *act, | ||
| 382 | struct tcf_result *res) | 343 | struct tcf_result *res) |
| 383 | { | 344 | { |
| 384 | const struct tc_action *a; | 345 | const struct tc_action *a; |
| @@ -389,53 +350,39 @@ int tcf_action_exec(struct sk_buff *skb, const struct tc_action *act, | |||
| 389 | ret = TC_ACT_OK; | 350 | ret = TC_ACT_OK; |
| 390 | goto exec_done; | 351 | goto exec_done; |
| 391 | } | 352 | } |
| 392 | while ((a = act) != NULL) { | 353 | list_for_each_entry(a, actions, list) { |
| 393 | repeat: | 354 | repeat: |
| 394 | if (a->ops) { | 355 | ret = a->ops->act(skb, a, res); |
| 395 | ret = a->ops->act(skb, a, res); | 356 | if (TC_MUNGED & skb->tc_verd) { |
| 396 | if (TC_MUNGED & skb->tc_verd) { | 357 | /* copied already, allow trampling */ |
| 397 | /* copied already, allow trampling */ | 358 | skb->tc_verd = SET_TC_OK2MUNGE(skb->tc_verd); |
| 398 | skb->tc_verd = SET_TC_OK2MUNGE(skb->tc_verd); | 359 | skb->tc_verd = CLR_TC_MUNGED(skb->tc_verd); |
| 399 | skb->tc_verd = CLR_TC_MUNGED(skb->tc_verd); | ||
| 400 | } | ||
| 401 | if (ret == TC_ACT_REPEAT) | ||
| 402 | goto repeat; /* we need a ttl - JHS */ | ||
| 403 | if (ret != TC_ACT_PIPE) | ||
| 404 | goto exec_done; | ||
| 405 | } | 360 | } |
| 406 | act = a->next; | 361 | if (ret == TC_ACT_REPEAT) |
| 362 | goto repeat; /* we need a ttl - JHS */ | ||
| 363 | if (ret != TC_ACT_PIPE) | ||
| 364 | goto exec_done; | ||
| 407 | } | 365 | } |
| 408 | exec_done: | 366 | exec_done: |
| 409 | return ret; | 367 | return ret; |
| 410 | } | 368 | } |
| 411 | EXPORT_SYMBOL(tcf_action_exec); | 369 | EXPORT_SYMBOL(tcf_action_exec); |
| 412 | 370 | ||
| 413 | void tcf_action_destroy(struct tc_action *act, int bind) | 371 | void tcf_action_destroy(struct list_head *actions, int bind) |
| 414 | { | 372 | { |
| 415 | struct tc_action *a; | 373 | struct tc_action *a, *tmp; |
| 416 | 374 | ||
| 417 | for (a = act; a; a = act) { | 375 | list_for_each_entry_safe(a, tmp, actions, list) { |
| 418 | if (a->ops) { | 376 | if (a->ops->cleanup(a, bind) == ACT_P_DELETED) |
| 419 | if (a->ops->cleanup(a, bind) == ACT_P_DELETED) | 377 | module_put(a->ops->owner); |
| 420 | module_put(a->ops->owner); | 378 | list_del(&a->list); |
| 421 | act = act->next; | 379 | kfree(a); |
| 422 | kfree(a); | ||
| 423 | } else { | ||
| 424 | /*FIXME: Remove later - catch insertion bugs*/ | ||
| 425 | WARN(1, "tcf_action_destroy: BUG? destroying NULL ops\n"); | ||
| 426 | act = act->next; | ||
| 427 | kfree(a); | ||
| 428 | } | ||
| 429 | } | 380 | } |
| 430 | } | 381 | } |
| 431 | 382 | ||
| 432 | int | 383 | int |
| 433 | tcf_action_dump_old(struct sk_buff *skb, struct tc_action *a, int bind, int ref) | 384 | tcf_action_dump_old(struct sk_buff *skb, struct tc_action *a, int bind, int ref) |
| 434 | { | 385 | { |
| 435 | int err = -EINVAL; | ||
| 436 | |||
| 437 | if (a->ops == NULL) | ||
| 438 | return err; | ||
| 439 | return a->ops->dump(skb, a, bind, ref); | 386 | return a->ops->dump(skb, a, bind, ref); |
| 440 | } | 387 | } |
| 441 | 388 | ||
| @@ -446,9 +393,6 @@ tcf_action_dump_1(struct sk_buff *skb, struct tc_action *a, int bind, int ref) | |||
| 446 | unsigned char *b = skb_tail_pointer(skb); | 393 | unsigned char *b = skb_tail_pointer(skb); |
| 447 | struct nlattr *nest; | 394 | struct nlattr *nest; |
| 448 | 395 | ||
| 449 | if (a->ops == NULL) | ||
| 450 | return err; | ||
| 451 | |||
| 452 | if (nla_put_string(skb, TCA_KIND, a->ops->kind)) | 396 | if (nla_put_string(skb, TCA_KIND, a->ops->kind)) |
| 453 | goto nla_put_failure; | 397 | goto nla_put_failure; |
| 454 | if (tcf_action_copy_stats(skb, a, 0)) | 398 | if (tcf_action_copy_stats(skb, a, 0)) |
| @@ -469,14 +413,13 @@ nla_put_failure: | |||
| 469 | EXPORT_SYMBOL(tcf_action_dump_1); | 413 | EXPORT_SYMBOL(tcf_action_dump_1); |
| 470 | 414 | ||
| 471 | int | 415 | int |
| 472 | tcf_action_dump(struct sk_buff *skb, struct tc_action *act, int bind, int ref) | 416 | tcf_action_dump(struct sk_buff *skb, struct list_head *actions, int bind, int ref) |
| 473 | { | 417 | { |
| 474 | struct tc_action *a; | 418 | struct tc_action *a; |
| 475 | int err = -EINVAL; | 419 | int err = -EINVAL; |
| 476 | struct nlattr *nest; | 420 | struct nlattr *nest; |
| 477 | 421 | ||
| 478 | while ((a = act) != NULL) { | 422 | list_for_each_entry(a, actions, list) { |
| 479 | act = a->next; | ||
| 480 | nest = nla_nest_start(skb, a->order); | 423 | nest = nla_nest_start(skb, a->order); |
| 481 | if (nest == NULL) | 424 | if (nest == NULL) |
| 482 | goto nla_put_failure; | 425 | goto nla_put_failure; |
| @@ -551,6 +494,8 @@ struct tc_action *tcf_action_init_1(struct net *net, struct nlattr *nla, | |||
| 551 | if (a == NULL) | 494 | if (a == NULL) |
| 552 | goto err_mod; | 495 | goto err_mod; |
| 553 | 496 | ||
| 497 | a->ops = a_o; | ||
| 498 | INIT_LIST_HEAD(&a->list); | ||
| 554 | /* backward compatibility for policer */ | 499 | /* backward compatibility for policer */ |
| 555 | if (name == NULL) | 500 | if (name == NULL) |
| 556 | err = a_o->init(net, tb[TCA_ACT_OPTIONS], est, a, ovr, bind); | 501 | err = a_o->init(net, tb[TCA_ACT_OPTIONS], est, a, ovr, bind); |
| @@ -565,7 +510,6 @@ struct tc_action *tcf_action_init_1(struct net *net, struct nlattr *nla, | |||
| 565 | */ | 510 | */ |
| 566 | if (err != ACT_P_CREATED) | 511 | if (err != ACT_P_CREATED) |
| 567 | module_put(a_o->owner); | 512 | module_put(a_o->owner); |
| 568 | a->ops = a_o; | ||
| 569 | 513 | ||
| 570 | return a; | 514 | return a; |
| 571 | 515 | ||
| @@ -577,37 +521,33 @@ err_out: | |||
| 577 | return ERR_PTR(err); | 521 | return ERR_PTR(err); |
| 578 | } | 522 | } |
| 579 | 523 | ||
| 580 | struct tc_action *tcf_action_init(struct net *net, struct nlattr *nla, | 524 | int tcf_action_init(struct net *net, struct nlattr *nla, |
| 581 | struct nlattr *est, char *name, int ovr, | 525 | struct nlattr *est, char *name, int ovr, |
| 582 | int bind) | 526 | int bind, struct list_head *actions) |
| 583 | { | 527 | { |
| 584 | struct nlattr *tb[TCA_ACT_MAX_PRIO + 1]; | 528 | struct nlattr *tb[TCA_ACT_MAX_PRIO + 1]; |
| 585 | struct tc_action *head = NULL, *act, *act_prev = NULL; | 529 | struct tc_action *act; |
| 586 | int err; | 530 | int err; |
| 587 | int i; | 531 | int i; |
| 588 | 532 | ||
| 589 | err = nla_parse_nested(tb, TCA_ACT_MAX_PRIO, nla, NULL); | 533 | err = nla_parse_nested(tb, TCA_ACT_MAX_PRIO, nla, NULL); |
| 590 | if (err < 0) | 534 | if (err < 0) |
| 591 | return ERR_PTR(err); | 535 | return err; |
| 592 | 536 | ||
| 593 | for (i = 1; i <= TCA_ACT_MAX_PRIO && tb[i]; i++) { | 537 | for (i = 1; i <= TCA_ACT_MAX_PRIO && tb[i]; i++) { |
| 594 | act = tcf_action_init_1(net, tb[i], est, name, ovr, bind); | 538 | act = tcf_action_init_1(net, tb[i], est, name, ovr, bind); |
| 595 | if (IS_ERR(act)) | 539 | if (IS_ERR(act)) { |
| 540 | err = PTR_ERR(act); | ||
| 596 | goto err; | 541 | goto err; |
| 542 | } | ||
| 597 | act->order = i; | 543 | act->order = i; |
| 598 | 544 | list_add_tail(&act->list, actions); | |
| 599 | if (head == NULL) | ||
| 600 | head = act; | ||
| 601 | else | ||
| 602 | act_prev->next = act; | ||
| 603 | act_prev = act; | ||
| 604 | } | 545 | } |
| 605 | return head; | 546 | return 0; |
| 606 | 547 | ||
| 607 | err: | 548 | err: |
| 608 | if (head != NULL) | 549 | tcf_action_destroy(actions, bind); |
| 609 | tcf_action_destroy(head, bind); | 550 | return err; |
| 610 | return act; | ||
| 611 | } | 551 | } |
| 612 | 552 | ||
| 613 | int tcf_action_copy_stats(struct sk_buff *skb, struct tc_action *a, | 553 | int tcf_action_copy_stats(struct sk_buff *skb, struct tc_action *a, |
| @@ -615,9 +555,9 @@ int tcf_action_copy_stats(struct sk_buff *skb, struct tc_action *a, | |||
| 615 | { | 555 | { |
| 616 | int err = 0; | 556 | int err = 0; |
| 617 | struct gnet_dump d; | 557 | struct gnet_dump d; |
| 618 | struct tcf_act_hdr *h = a->priv; | 558 | struct tcf_common *p = a->priv; |
| 619 | 559 | ||
| 620 | if (h == NULL) | 560 | if (p == NULL) |
| 621 | goto errout; | 561 | goto errout; |
| 622 | 562 | ||
| 623 | /* compat_mode being true specifies a call that is supposed | 563 | /* compat_mode being true specifies a call that is supposed |
| @@ -626,24 +566,20 @@ int tcf_action_copy_stats(struct sk_buff *skb, struct tc_action *a, | |||
| 626 | if (compat_mode) { | 566 | if (compat_mode) { |
| 627 | if (a->type == TCA_OLD_COMPAT) | 567 | if (a->type == TCA_OLD_COMPAT) |
| 628 | err = gnet_stats_start_copy_compat(skb, 0, | 568 | err = gnet_stats_start_copy_compat(skb, 0, |
| 629 | TCA_STATS, TCA_XSTATS, &h->tcf_lock, &d); | 569 | TCA_STATS, TCA_XSTATS, &p->tcfc_lock, &d); |
| 630 | else | 570 | else |
| 631 | return 0; | 571 | return 0; |
| 632 | } else | 572 | } else |
| 633 | err = gnet_stats_start_copy(skb, TCA_ACT_STATS, | 573 | err = gnet_stats_start_copy(skb, TCA_ACT_STATS, |
| 634 | &h->tcf_lock, &d); | 574 | &p->tcfc_lock, &d); |
| 635 | 575 | ||
| 636 | if (err < 0) | 576 | if (err < 0) |
| 637 | goto errout; | 577 | goto errout; |
| 638 | 578 | ||
| 639 | if (a->ops != NULL && a->ops->get_stats != NULL) | 579 | if (gnet_stats_copy_basic(&d, &p->tcfc_bstats) < 0 || |
| 640 | if (a->ops->get_stats(skb, a) < 0) | 580 | gnet_stats_copy_rate_est(&d, &p->tcfc_bstats, |
| 641 | goto errout; | 581 | &p->tcfc_rate_est) < 0 || |
| 642 | 582 | gnet_stats_copy_queue(&d, &p->tcfc_qstats) < 0) | |
| 643 | if (gnet_stats_copy_basic(&d, &h->tcf_bstats) < 0 || | ||
| 644 | gnet_stats_copy_rate_est(&d, &h->tcf_bstats, | ||
| 645 | &h->tcf_rate_est) < 0 || | ||
| 646 | gnet_stats_copy_queue(&d, &h->tcf_qstats) < 0) | ||
| 647 | goto errout; | 583 | goto errout; |
| 648 | 584 | ||
| 649 | if (gnet_stats_finish_copy(&d) < 0) | 585 | if (gnet_stats_finish_copy(&d) < 0) |
| @@ -656,7 +592,7 @@ errout: | |||
| 656 | } | 592 | } |
| 657 | 593 | ||
| 658 | static int | 594 | static int |
| 659 | tca_get_fill(struct sk_buff *skb, struct tc_action *a, u32 portid, u32 seq, | 595 | tca_get_fill(struct sk_buff *skb, struct list_head *actions, u32 portid, u32 seq, |
| 660 | u16 flags, int event, int bind, int ref) | 596 | u16 flags, int event, int bind, int ref) |
| 661 | { | 597 | { |
| 662 | struct tcamsg *t; | 598 | struct tcamsg *t; |
| @@ -676,7 +612,7 @@ tca_get_fill(struct sk_buff *skb, struct tc_action *a, u32 portid, u32 seq, | |||
| 676 | if (nest == NULL) | 612 | if (nest == NULL) |
| 677 | goto out_nlmsg_trim; | 613 | goto out_nlmsg_trim; |
| 678 | 614 | ||
| 679 | if (tcf_action_dump(skb, a, bind, ref) < 0) | 615 | if (tcf_action_dump(skb, actions, bind, ref) < 0) |
| 680 | goto out_nlmsg_trim; | 616 | goto out_nlmsg_trim; |
| 681 | 617 | ||
| 682 | nla_nest_end(skb, nest); | 618 | nla_nest_end(skb, nest); |
| @@ -691,14 +627,14 @@ out_nlmsg_trim: | |||
| 691 | 627 | ||
| 692 | static int | 628 | static int |
| 693 | act_get_notify(struct net *net, u32 portid, struct nlmsghdr *n, | 629 | act_get_notify(struct net *net, u32 portid, struct nlmsghdr *n, |
| 694 | struct tc_action *a, int event) | 630 | struct list_head *actions, int event) |
| 695 | { | 631 | { |
| 696 | struct sk_buff *skb; | 632 | struct sk_buff *skb; |
| 697 | 633 | ||
| 698 | skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); | 634 | skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); |
| 699 | if (!skb) | 635 | if (!skb) |
| 700 | return -ENOBUFS; | 636 | return -ENOBUFS; |
| 701 | if (tca_get_fill(skb, a, portid, n->nlmsg_seq, 0, event, 0, 0) <= 0) { | 637 | if (tca_get_fill(skb, actions, portid, n->nlmsg_seq, 0, event, 0, 0) <= 0) { |
| 702 | kfree_skb(skb); | 638 | kfree_skb(skb); |
| 703 | return -EINVAL; | 639 | return -EINVAL; |
| 704 | } | 640 | } |
| @@ -729,9 +665,10 @@ tcf_action_get_1(struct nlattr *nla, struct nlmsghdr *n, u32 portid) | |||
| 729 | if (a == NULL) | 665 | if (a == NULL) |
| 730 | goto err_out; | 666 | goto err_out; |
| 731 | 667 | ||
| 668 | INIT_LIST_HEAD(&a->list); | ||
| 732 | err = -EINVAL; | 669 | err = -EINVAL; |
| 733 | a->ops = tc_lookup_action(tb[TCA_ACT_KIND]); | 670 | a->ops = tc_lookup_action(tb[TCA_ACT_KIND]); |
| 734 | if (a->ops == NULL) | 671 | if (a->ops == NULL) /* could happen in batch of actions */ |
| 735 | goto err_free; | 672 | goto err_free; |
| 736 | err = -ENOENT; | 673 | err = -ENOENT; |
| 737 | if (a->ops->lookup(a, index) == 0) | 674 | if (a->ops->lookup(a, index) == 0) |
| @@ -748,12 +685,12 @@ err_out: | |||
| 748 | return ERR_PTR(err); | 685 | return ERR_PTR(err); |
| 749 | } | 686 | } |
| 750 | 687 | ||
| 751 | static void cleanup_a(struct tc_action *act) | 688 | static void cleanup_a(struct list_head *actions) |
| 752 | { | 689 | { |
| 753 | struct tc_action *a; | 690 | struct tc_action *a, *tmp; |
| 754 | 691 | ||
| 755 | for (a = act; a; a = act) { | 692 | list_for_each_entry_safe(a, tmp, actions, list) { |
| 756 | act = a->next; | 693 | list_del(&a->list); |
| 757 | kfree(a); | 694 | kfree(a); |
| 758 | } | 695 | } |
| 759 | } | 696 | } |
| @@ -768,6 +705,7 @@ static struct tc_action *create_a(int i) | |||
| 768 | return NULL; | 705 | return NULL; |
| 769 | } | 706 | } |
| 770 | act->order = i; | 707 | act->order = i; |
| 708 | INIT_LIST_HEAD(&act->list); | ||
| 771 | return act; | 709 | return act; |
| 772 | } | 710 | } |
| 773 | 711 | ||
| @@ -806,7 +744,7 @@ static int tca_action_flush(struct net *net, struct nlattr *nla, | |||
| 806 | err = -EINVAL; | 744 | err = -EINVAL; |
| 807 | kind = tb[TCA_ACT_KIND]; | 745 | kind = tb[TCA_ACT_KIND]; |
| 808 | a->ops = tc_lookup_action(kind); | 746 | a->ops = tc_lookup_action(kind); |
| 809 | if (a->ops == NULL) | 747 | if (a->ops == NULL) /*some idjot trying to flush unknown action */ |
| 810 | goto err_out; | 748 | goto err_out; |
| 811 | 749 | ||
| 812 | nlh = nlmsg_put(skb, portid, n->nlmsg_seq, RTM_DELACTION, sizeof(*t), 0); | 750 | nlh = nlmsg_put(skb, portid, n->nlmsg_seq, RTM_DELACTION, sizeof(*t), 0); |
| @@ -850,12 +788,40 @@ noflush_out: | |||
| 850 | } | 788 | } |
| 851 | 789 | ||
| 852 | static int | 790 | static int |
| 791 | tcf_del_notify(struct net *net, struct nlmsghdr *n, struct list_head *actions, | ||
| 792 | u32 portid) | ||
| 793 | { | ||
| 794 | int ret; | ||
| 795 | struct sk_buff *skb; | ||
| 796 | |||
| 797 | skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); | ||
| 798 | if (!skb) | ||
| 799 | return -ENOBUFS; | ||
| 800 | |||
| 801 | if (tca_get_fill(skb, actions, portid, n->nlmsg_seq, 0, RTM_DELACTION, | ||
| 802 | 0, 1) <= 0) { | ||
| 803 | kfree_skb(skb); | ||
| 804 | return -EINVAL; | ||
| 805 | } | ||
| 806 | |||
| 807 | /* now do the delete */ | ||
| 808 | tcf_action_destroy(actions, 0); | ||
| 809 | |||
| 810 | ret = rtnetlink_send(skb, net, portid, RTNLGRP_TC, | ||
| 811 | n->nlmsg_flags & NLM_F_ECHO); | ||
| 812 | if (ret > 0) | ||
| 813 | return 0; | ||
| 814 | return ret; | ||
| 815 | } | ||
| 816 | |||
| 817 | static int | ||
| 853 | tca_action_gd(struct net *net, struct nlattr *nla, struct nlmsghdr *n, | 818 | tca_action_gd(struct net *net, struct nlattr *nla, struct nlmsghdr *n, |
| 854 | u32 portid, int event) | 819 | u32 portid, int event) |
| 855 | { | 820 | { |
| 856 | int i, ret; | 821 | int i, ret; |
| 857 | struct nlattr *tb[TCA_ACT_MAX_PRIO + 1]; | 822 | struct nlattr *tb[TCA_ACT_MAX_PRIO + 1]; |
| 858 | struct tc_action *head = NULL, *act, *act_prev = NULL; | 823 | struct tc_action *act; |
| 824 | LIST_HEAD(actions); | ||
| 859 | 825 | ||
| 860 | ret = nla_parse_nested(tb, TCA_ACT_MAX_PRIO, nla, NULL); | 826 | ret = nla_parse_nested(tb, TCA_ACT_MAX_PRIO, nla, NULL); |
| 861 | if (ret < 0) | 827 | if (ret < 0) |
| @@ -875,117 +841,62 @@ tca_action_gd(struct net *net, struct nlattr *nla, struct nlmsghdr *n, | |||
| 875 | goto err; | 841 | goto err; |
| 876 | } | 842 | } |
| 877 | act->order = i; | 843 | act->order = i; |
| 878 | 844 | list_add_tail(&act->list, &actions); | |
| 879 | if (head == NULL) | ||
| 880 | head = act; | ||
| 881 | else | ||
| 882 | act_prev->next = act; | ||
| 883 | act_prev = act; | ||
| 884 | } | 845 | } |
| 885 | 846 | ||
| 886 | if (event == RTM_GETACTION) | 847 | if (event == RTM_GETACTION) |
| 887 | ret = act_get_notify(net, portid, n, head, event); | 848 | ret = act_get_notify(net, portid, n, &actions, event); |
| 888 | else { /* delete */ | 849 | else { /* delete */ |
| 889 | struct sk_buff *skb; | 850 | ret = tcf_del_notify(net, n, &actions, portid); |
| 890 | 851 | if (ret) | |
| 891 | skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); | ||
| 892 | if (!skb) { | ||
| 893 | ret = -ENOBUFS; | ||
| 894 | goto err; | ||
| 895 | } | ||
| 896 | |||
| 897 | if (tca_get_fill(skb, head, portid, n->nlmsg_seq, 0, event, | ||
| 898 | 0, 1) <= 0) { | ||
| 899 | kfree_skb(skb); | ||
| 900 | ret = -EINVAL; | ||
| 901 | goto err; | 852 | goto err; |
| 902 | } | ||
| 903 | |||
| 904 | /* now do the delete */ | ||
| 905 | tcf_action_destroy(head, 0); | ||
| 906 | ret = rtnetlink_send(skb, net, portid, RTNLGRP_TC, | ||
| 907 | n->nlmsg_flags & NLM_F_ECHO); | ||
| 908 | if (ret > 0) | ||
| 909 | return 0; | ||
| 910 | return ret; | 853 | return ret; |
| 911 | } | 854 | } |
| 912 | err: | 855 | err: |
| 913 | cleanup_a(head); | 856 | cleanup_a(&actions); |
| 914 | return ret; | 857 | return ret; |
| 915 | } | 858 | } |
| 916 | 859 | ||
| 917 | static int tcf_add_notify(struct net *net, struct tc_action *a, | 860 | static int |
| 918 | u32 portid, u32 seq, int event, u16 flags) | 861 | tcf_add_notify(struct net *net, struct nlmsghdr *n, struct list_head *actions, |
| 862 | u32 portid) | ||
| 919 | { | 863 | { |
| 920 | struct tcamsg *t; | ||
| 921 | struct nlmsghdr *nlh; | ||
| 922 | struct sk_buff *skb; | 864 | struct sk_buff *skb; |
| 923 | struct nlattr *nest; | ||
| 924 | unsigned char *b; | ||
| 925 | int err = 0; | 865 | int err = 0; |
| 926 | 866 | ||
| 927 | skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); | 867 | skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); |
| 928 | if (!skb) | 868 | if (!skb) |
| 929 | return -ENOBUFS; | 869 | return -ENOBUFS; |
| 930 | 870 | ||
| 931 | b = skb_tail_pointer(skb); | 871 | if (tca_get_fill(skb, actions, portid, n->nlmsg_seq, n->nlmsg_flags, |
| 932 | 872 | RTM_NEWACTION, 0, 0) <= 0) { | |
| 933 | nlh = nlmsg_put(skb, portid, seq, event, sizeof(*t), flags); | 873 | kfree_skb(skb); |
| 934 | if (!nlh) | 874 | return -EINVAL; |
| 935 | goto out_kfree_skb; | 875 | } |
| 936 | t = nlmsg_data(nlh); | ||
| 937 | t->tca_family = AF_UNSPEC; | ||
| 938 | t->tca__pad1 = 0; | ||
| 939 | t->tca__pad2 = 0; | ||
| 940 | |||
| 941 | nest = nla_nest_start(skb, TCA_ACT_TAB); | ||
| 942 | if (nest == NULL) | ||
| 943 | goto out_kfree_skb; | ||
| 944 | |||
| 945 | if (tcf_action_dump(skb, a, 0, 0) < 0) | ||
| 946 | goto out_kfree_skb; | ||
| 947 | |||
| 948 | nla_nest_end(skb, nest); | ||
| 949 | |||
| 950 | nlh->nlmsg_len = skb_tail_pointer(skb) - b; | ||
| 951 | NETLINK_CB(skb).dst_group = RTNLGRP_TC; | ||
| 952 | 876 | ||
| 953 | err = rtnetlink_send(skb, net, portid, RTNLGRP_TC, flags & NLM_F_ECHO); | 877 | err = rtnetlink_send(skb, net, portid, RTNLGRP_TC, |
| 878 | n->nlmsg_flags & NLM_F_ECHO); | ||
| 954 | if (err > 0) | 879 | if (err > 0) |
| 955 | err = 0; | 880 | err = 0; |
| 956 | return err; | 881 | return err; |
| 957 | |||
| 958 | out_kfree_skb: | ||
| 959 | kfree_skb(skb); | ||
| 960 | return -1; | ||
| 961 | } | 882 | } |
| 962 | 883 | ||
| 963 | |||
| 964 | static int | 884 | static int |
| 965 | tcf_action_add(struct net *net, struct nlattr *nla, struct nlmsghdr *n, | 885 | tcf_action_add(struct net *net, struct nlattr *nla, struct nlmsghdr *n, |
| 966 | u32 portid, int ovr) | 886 | u32 portid, int ovr) |
| 967 | { | 887 | { |
| 968 | int ret = 0; | 888 | int ret = 0; |
| 969 | struct tc_action *act; | 889 | LIST_HEAD(actions); |
| 970 | struct tc_action *a; | ||
| 971 | u32 seq = n->nlmsg_seq; | ||
| 972 | 890 | ||
| 973 | act = tcf_action_init(net, nla, NULL, NULL, ovr, 0); | 891 | ret = tcf_action_init(net, nla, NULL, NULL, ovr, 0, &actions); |
| 974 | if (act == NULL) | 892 | if (ret) |
| 975 | goto done; | ||
| 976 | if (IS_ERR(act)) { | ||
| 977 | ret = PTR_ERR(act); | ||
| 978 | goto done; | 893 | goto done; |
| 979 | } | ||
| 980 | 894 | ||
| 981 | /* dump then free all the actions after update; inserted policy | 895 | /* dump then free all the actions after update; inserted policy |
| 982 | * stays intact | 896 | * stays intact |
| 983 | */ | 897 | */ |
| 984 | ret = tcf_add_notify(net, act, portid, seq, RTM_NEWACTION, n->nlmsg_flags); | 898 | ret = tcf_add_notify(net, n, &actions, portid); |
| 985 | for (a = act; a; a = act) { | 899 | cleanup_a(&actions); |
| 986 | act = a->next; | ||
| 987 | kfree(a); | ||
| 988 | } | ||
| 989 | done: | 900 | done: |
| 990 | return ret; | 901 | return ret; |
| 991 | } | 902 | } |
diff --git a/net/sched/act_csum.c b/net/sched/act_csum.c index 11fe1a416433..2210187c45c2 100644 --- a/net/sched/act_csum.c +++ b/net/sched/act_csum.c | |||
| @@ -37,15 +37,7 @@ | |||
| 37 | #include <net/tc_act/tc_csum.h> | 37 | #include <net/tc_act/tc_csum.h> |
| 38 | 38 | ||
| 39 | #define CSUM_TAB_MASK 15 | 39 | #define CSUM_TAB_MASK 15 |
| 40 | static struct tcf_common *tcf_csum_ht[CSUM_TAB_MASK + 1]; | 40 | static struct tcf_hashinfo csum_hash_info; |
| 41 | static u32 csum_idx_gen; | ||
| 42 | static DEFINE_RWLOCK(csum_lock); | ||
| 43 | |||
| 44 | static struct tcf_hashinfo csum_hash_info = { | ||
| 45 | .htab = tcf_csum_ht, | ||
| 46 | .hmask = CSUM_TAB_MASK, | ||
| 47 | .lock = &csum_lock, | ||
| 48 | }; | ||
| 49 | 41 | ||
| 50 | static const struct nla_policy csum_policy[TCA_CSUM_MAX + 1] = { | 42 | static const struct nla_policy csum_policy[TCA_CSUM_MAX + 1] = { |
| 51 | [TCA_CSUM_PARMS] = { .len = sizeof(struct tc_csum), }, | 43 | [TCA_CSUM_PARMS] = { .len = sizeof(struct tc_csum), }, |
| @@ -71,17 +63,16 @@ static int tcf_csum_init(struct net *n, struct nlattr *nla, struct nlattr *est, | |||
| 71 | return -EINVAL; | 63 | return -EINVAL; |
| 72 | parm = nla_data(tb[TCA_CSUM_PARMS]); | 64 | parm = nla_data(tb[TCA_CSUM_PARMS]); |
| 73 | 65 | ||
| 74 | pc = tcf_hash_check(parm->index, a, bind, &csum_hash_info); | 66 | pc = tcf_hash_check(parm->index, a, bind); |
| 75 | if (!pc) { | 67 | if (!pc) { |
| 76 | pc = tcf_hash_create(parm->index, est, a, sizeof(*p), bind, | 68 | pc = tcf_hash_create(parm->index, est, a, sizeof(*p), bind); |
| 77 | &csum_idx_gen, &csum_hash_info); | ||
| 78 | if (IS_ERR(pc)) | 69 | if (IS_ERR(pc)) |
| 79 | return PTR_ERR(pc); | 70 | return PTR_ERR(pc); |
| 80 | ret = ACT_P_CREATED; | 71 | ret = ACT_P_CREATED; |
| 81 | } else { | 72 | } else { |
| 82 | if (bind)/* dont override defaults */ | 73 | if (bind)/* dont override defaults */ |
| 83 | return 0; | 74 | return 0; |
| 84 | tcf_hash_release(pc, bind, &csum_hash_info); | 75 | tcf_hash_release(pc, bind, a->ops->hinfo); |
| 85 | if (!ovr) | 76 | if (!ovr) |
| 86 | return -EEXIST; | 77 | return -EEXIST; |
| 87 | } | 78 | } |
| @@ -93,7 +84,7 @@ static int tcf_csum_init(struct net *n, struct nlattr *nla, struct nlattr *est, | |||
| 93 | spin_unlock_bh(&p->tcf_lock); | 84 | spin_unlock_bh(&p->tcf_lock); |
| 94 | 85 | ||
| 95 | if (ret == ACT_P_CREATED) | 86 | if (ret == ACT_P_CREATED) |
| 96 | tcf_hash_insert(pc, &csum_hash_info); | 87 | tcf_hash_insert(pc, a->ops->hinfo); |
| 97 | 88 | ||
| 98 | return ret; | 89 | return ret; |
| 99 | } | 90 | } |
| @@ -580,7 +571,6 @@ static struct tc_action_ops act_csum_ops = { | |||
| 580 | .kind = "csum", | 571 | .kind = "csum", |
| 581 | .hinfo = &csum_hash_info, | 572 | .hinfo = &csum_hash_info, |
| 582 | .type = TCA_ACT_CSUM, | 573 | .type = TCA_ACT_CSUM, |
| 583 | .capab = TCA_CAP_NONE, | ||
| 584 | .owner = THIS_MODULE, | 574 | .owner = THIS_MODULE, |
| 585 | .act = tcf_csum, | 575 | .act = tcf_csum, |
| 586 | .dump = tcf_csum_dump, | 576 | .dump = tcf_csum_dump, |
| @@ -593,6 +583,10 @@ MODULE_LICENSE("GPL"); | |||
| 593 | 583 | ||
| 594 | static int __init csum_init_module(void) | 584 | static int __init csum_init_module(void) |
| 595 | { | 585 | { |
| 586 | int err = tcf_hashinfo_init(&csum_hash_info, CSUM_TAB_MASK); | ||
| 587 | if (err) | ||
| 588 | return err; | ||
| 589 | |||
| 596 | return tcf_register_action(&act_csum_ops); | 590 | return tcf_register_action(&act_csum_ops); |
| 597 | } | 591 | } |
| 598 | 592 | ||
diff --git a/net/sched/act_gact.c b/net/sched/act_gact.c index eb9ba60ebab4..a0eed30d5811 100644 --- a/net/sched/act_gact.c +++ b/net/sched/act_gact.c | |||
| @@ -24,20 +24,12 @@ | |||
| 24 | #include <net/tc_act/tc_gact.h> | 24 | #include <net/tc_act/tc_gact.h> |
| 25 | 25 | ||
| 26 | #define GACT_TAB_MASK 15 | 26 | #define GACT_TAB_MASK 15 |
| 27 | static struct tcf_common *tcf_gact_ht[GACT_TAB_MASK + 1]; | 27 | static struct tcf_hashinfo gact_hash_info; |
| 28 | static u32 gact_idx_gen; | ||
| 29 | static DEFINE_RWLOCK(gact_lock); | ||
| 30 | |||
| 31 | static struct tcf_hashinfo gact_hash_info = { | ||
| 32 | .htab = tcf_gact_ht, | ||
| 33 | .hmask = GACT_TAB_MASK, | ||
| 34 | .lock = &gact_lock, | ||
| 35 | }; | ||
| 36 | 28 | ||
| 37 | #ifdef CONFIG_GACT_PROB | 29 | #ifdef CONFIG_GACT_PROB |
| 38 | static int gact_net_rand(struct tcf_gact *gact) | 30 | static int gact_net_rand(struct tcf_gact *gact) |
| 39 | { | 31 | { |
| 40 | if (!gact->tcfg_pval || net_random() % gact->tcfg_pval) | 32 | if (!gact->tcfg_pval || prandom_u32() % gact->tcfg_pval) |
| 41 | return gact->tcf_action; | 33 | return gact->tcf_action; |
| 42 | return gact->tcfg_paction; | 34 | return gact->tcfg_paction; |
| 43 | } | 35 | } |
| @@ -94,17 +86,16 @@ static int tcf_gact_init(struct net *net, struct nlattr *nla, | |||
| 94 | } | 86 | } |
| 95 | #endif | 87 | #endif |
| 96 | 88 | ||
| 97 | pc = tcf_hash_check(parm->index, a, bind, &gact_hash_info); | 89 | pc = tcf_hash_check(parm->index, a, bind); |
| 98 | if (!pc) { | 90 | if (!pc) { |
| 99 | pc = tcf_hash_create(parm->index, est, a, sizeof(*gact), | 91 | pc = tcf_hash_create(parm->index, est, a, sizeof(*gact), bind); |
| 100 | bind, &gact_idx_gen, &gact_hash_info); | ||
| 101 | if (IS_ERR(pc)) | 92 | if (IS_ERR(pc)) |
| 102 | return PTR_ERR(pc); | 93 | return PTR_ERR(pc); |
| 103 | ret = ACT_P_CREATED; | 94 | ret = ACT_P_CREATED; |
| 104 | } else { | 95 | } else { |
| 105 | if (bind)/* dont override defaults */ | 96 | if (bind)/* dont override defaults */ |
| 106 | return 0; | 97 | return 0; |
| 107 | tcf_hash_release(pc, bind, &gact_hash_info); | 98 | tcf_hash_release(pc, bind, a->ops->hinfo); |
| 108 | if (!ovr) | 99 | if (!ovr) |
| 109 | return -EEXIST; | 100 | return -EEXIST; |
| 110 | } | 101 | } |
| @@ -122,7 +113,7 @@ static int tcf_gact_init(struct net *net, struct nlattr *nla, | |||
| 122 | #endif | 113 | #endif |
| 123 | spin_unlock_bh(&gact->tcf_lock); | 114 | spin_unlock_bh(&gact->tcf_lock); |
| 124 | if (ret == ACT_P_CREATED) | 115 | if (ret == ACT_P_CREATED) |
| 125 | tcf_hash_insert(pc, &gact_hash_info); | 116 | tcf_hash_insert(pc, a->ops->hinfo); |
| 126 | return ret; | 117 | return ret; |
| 127 | } | 118 | } |
| 128 | 119 | ||
| @@ -131,7 +122,7 @@ static int tcf_gact_cleanup(struct tc_action *a, int bind) | |||
| 131 | struct tcf_gact *gact = a->priv; | 122 | struct tcf_gact *gact = a->priv; |
| 132 | 123 | ||
| 133 | if (gact) | 124 | if (gact) |
| 134 | return tcf_hash_release(&gact->common, bind, &gact_hash_info); | 125 | return tcf_hash_release(&gact->common, bind, a->ops->hinfo); |
| 135 | return 0; | 126 | return 0; |
| 136 | } | 127 | } |
| 137 | 128 | ||
| @@ -202,7 +193,6 @@ static struct tc_action_ops act_gact_ops = { | |||
| 202 | .kind = "gact", | 193 | .kind = "gact", |
| 203 | .hinfo = &gact_hash_info, | 194 | .hinfo = &gact_hash_info, |
| 204 | .type = TCA_ACT_GACT, | 195 | .type = TCA_ACT_GACT, |
| 205 | .capab = TCA_CAP_NONE, | ||
| 206 | .owner = THIS_MODULE, | 196 | .owner = THIS_MODULE, |
| 207 | .act = tcf_gact, | 197 | .act = tcf_gact, |
| 208 | .dump = tcf_gact_dump, | 198 | .dump = tcf_gact_dump, |
| @@ -216,6 +206,9 @@ MODULE_LICENSE("GPL"); | |||
| 216 | 206 | ||
| 217 | static int __init gact_init_module(void) | 207 | static int __init gact_init_module(void) |
| 218 | { | 208 | { |
| 209 | int err = tcf_hashinfo_init(&gact_hash_info, GACT_TAB_MASK); | ||
| 210 | if (err) | ||
| 211 | return err; | ||
| 219 | #ifdef CONFIG_GACT_PROB | 212 | #ifdef CONFIG_GACT_PROB |
| 220 | pr_info("GACT probability on\n"); | 213 | pr_info("GACT probability on\n"); |
| 221 | #else | 214 | #else |
| @@ -227,6 +220,7 @@ static int __init gact_init_module(void) | |||
| 227 | static void __exit gact_cleanup_module(void) | 220 | static void __exit gact_cleanup_module(void) |
| 228 | { | 221 | { |
| 229 | tcf_unregister_action(&act_gact_ops); | 222 | tcf_unregister_action(&act_gact_ops); |
| 223 | tcf_hashinfo_destroy(&gact_hash_info); | ||
| 230 | } | 224 | } |
| 231 | 225 | ||
| 232 | module_init(gact_init_module); | 226 | module_init(gact_init_module); |
diff --git a/net/sched/act_ipt.c b/net/sched/act_ipt.c index dcbfe8ce04a6..0a6d62174027 100644 --- a/net/sched/act_ipt.c +++ b/net/sched/act_ipt.c | |||
| @@ -29,15 +29,7 @@ | |||
| 29 | 29 | ||
| 30 | 30 | ||
| 31 | #define IPT_TAB_MASK 15 | 31 | #define IPT_TAB_MASK 15 |
| 32 | static struct tcf_common *tcf_ipt_ht[IPT_TAB_MASK + 1]; | 32 | static struct tcf_hashinfo ipt_hash_info; |
| 33 | static u32 ipt_idx_gen; | ||
| 34 | static DEFINE_RWLOCK(ipt_lock); | ||
| 35 | |||
| 36 | static struct tcf_hashinfo ipt_hash_info = { | ||
| 37 | .htab = tcf_ipt_ht, | ||
| 38 | .hmask = IPT_TAB_MASK, | ||
| 39 | .lock = &ipt_lock, | ||
| 40 | }; | ||
| 41 | 33 | ||
| 42 | static int ipt_init_target(struct xt_entry_target *t, char *table, unsigned int hook) | 34 | static int ipt_init_target(struct xt_entry_target *t, char *table, unsigned int hook) |
| 43 | { | 35 | { |
| @@ -133,10 +125,9 @@ static int tcf_ipt_init(struct net *net, struct nlattr *nla, struct nlattr *est, | |||
| 133 | if (tb[TCA_IPT_INDEX] != NULL) | 125 | if (tb[TCA_IPT_INDEX] != NULL) |
| 134 | index = nla_get_u32(tb[TCA_IPT_INDEX]); | 126 | index = nla_get_u32(tb[TCA_IPT_INDEX]); |
| 135 | 127 | ||
| 136 | pc = tcf_hash_check(index, a, bind, &ipt_hash_info); | 128 | pc = tcf_hash_check(index, a, bind); |
| 137 | if (!pc) { | 129 | if (!pc) { |
| 138 | pc = tcf_hash_create(index, est, a, sizeof(*ipt), bind, | 130 | pc = tcf_hash_create(index, est, a, sizeof(*ipt), bind); |
| 139 | &ipt_idx_gen, &ipt_hash_info); | ||
| 140 | if (IS_ERR(pc)) | 131 | if (IS_ERR(pc)) |
| 141 | return PTR_ERR(pc); | 132 | return PTR_ERR(pc); |
| 142 | ret = ACT_P_CREATED; | 133 | ret = ACT_P_CREATED; |
| @@ -179,7 +170,7 @@ static int tcf_ipt_init(struct net *net, struct nlattr *nla, struct nlattr *est, | |||
| 179 | ipt->tcfi_hook = hook; | 170 | ipt->tcfi_hook = hook; |
| 180 | spin_unlock_bh(&ipt->tcf_lock); | 171 | spin_unlock_bh(&ipt->tcf_lock); |
| 181 | if (ret == ACT_P_CREATED) | 172 | if (ret == ACT_P_CREATED) |
| 182 | tcf_hash_insert(pc, &ipt_hash_info); | 173 | tcf_hash_insert(pc, a->ops->hinfo); |
| 183 | return ret; | 174 | return ret; |
| 184 | 175 | ||
| 185 | err3: | 176 | err3: |
| @@ -295,7 +286,6 @@ static struct tc_action_ops act_ipt_ops = { | |||
| 295 | .kind = "ipt", | 286 | .kind = "ipt", |
| 296 | .hinfo = &ipt_hash_info, | 287 | .hinfo = &ipt_hash_info, |
| 297 | .type = TCA_ACT_IPT, | 288 | .type = TCA_ACT_IPT, |
| 298 | .capab = TCA_CAP_NONE, | ||
| 299 | .owner = THIS_MODULE, | 289 | .owner = THIS_MODULE, |
| 300 | .act = tcf_ipt, | 290 | .act = tcf_ipt, |
| 301 | .dump = tcf_ipt_dump, | 291 | .dump = tcf_ipt_dump, |
| @@ -306,8 +296,7 @@ static struct tc_action_ops act_ipt_ops = { | |||
| 306 | static struct tc_action_ops act_xt_ops = { | 296 | static struct tc_action_ops act_xt_ops = { |
| 307 | .kind = "xt", | 297 | .kind = "xt", |
| 308 | .hinfo = &ipt_hash_info, | 298 | .hinfo = &ipt_hash_info, |
| 309 | .type = TCA_ACT_IPT, | 299 | .type = TCA_ACT_XT, |
| 310 | .capab = TCA_CAP_NONE, | ||
| 311 | .owner = THIS_MODULE, | 300 | .owner = THIS_MODULE, |
| 312 | .act = tcf_ipt, | 301 | .act = tcf_ipt, |
| 313 | .dump = tcf_ipt_dump, | 302 | .dump = tcf_ipt_dump, |
| @@ -322,7 +311,11 @@ MODULE_ALIAS("act_xt"); | |||
| 322 | 311 | ||
| 323 | static int __init ipt_init_module(void) | 312 | static int __init ipt_init_module(void) |
| 324 | { | 313 | { |
| 325 | int ret1, ret2; | 314 | int ret1, ret2, err; |
| 315 | err = tcf_hashinfo_init(&ipt_hash_info, IPT_TAB_MASK); | ||
| 316 | if (err) | ||
| 317 | return err; | ||
| 318 | |||
| 326 | ret1 = tcf_register_action(&act_xt_ops); | 319 | ret1 = tcf_register_action(&act_xt_ops); |
| 327 | if (ret1 < 0) | 320 | if (ret1 < 0) |
| 328 | printk("Failed to load xt action\n"); | 321 | printk("Failed to load xt action\n"); |
| @@ -330,9 +323,10 @@ static int __init ipt_init_module(void) | |||
| 330 | if (ret2 < 0) | 323 | if (ret2 < 0) |
| 331 | printk("Failed to load ipt action\n"); | 324 | printk("Failed to load ipt action\n"); |
| 332 | 325 | ||
| 333 | if (ret1 < 0 && ret2 < 0) | 326 | if (ret1 < 0 && ret2 < 0) { |
| 327 | tcf_hashinfo_destroy(&ipt_hash_info); | ||
| 334 | return ret1; | 328 | return ret1; |
| 335 | else | 329 | } else |
| 336 | return 0; | 330 | return 0; |
| 337 | } | 331 | } |
| 338 | 332 | ||
| @@ -340,6 +334,7 @@ static void __exit ipt_cleanup_module(void) | |||
| 340 | { | 334 | { |
| 341 | tcf_unregister_action(&act_xt_ops); | 335 | tcf_unregister_action(&act_xt_ops); |
| 342 | tcf_unregister_action(&act_ipt_ops); | 336 | tcf_unregister_action(&act_ipt_ops); |
| 337 | tcf_hashinfo_destroy(&ipt_hash_info); | ||
| 343 | } | 338 | } |
| 344 | 339 | ||
| 345 | module_init(ipt_init_module); | 340 | module_init(ipt_init_module); |
diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c index 252378121ce7..0b2c6d39d396 100644 --- a/net/sched/act_mirred.c +++ b/net/sched/act_mirred.c | |||
| @@ -30,16 +30,8 @@ | |||
| 30 | #include <linux/if_arp.h> | 30 | #include <linux/if_arp.h> |
| 31 | 31 | ||
| 32 | #define MIRRED_TAB_MASK 7 | 32 | #define MIRRED_TAB_MASK 7 |
| 33 | static struct tcf_common *tcf_mirred_ht[MIRRED_TAB_MASK + 1]; | ||
| 34 | static u32 mirred_idx_gen; | ||
| 35 | static DEFINE_RWLOCK(mirred_lock); | ||
| 36 | static LIST_HEAD(mirred_list); | 33 | static LIST_HEAD(mirred_list); |
| 37 | 34 | static struct tcf_hashinfo mirred_hash_info; | |
| 38 | static struct tcf_hashinfo mirred_hash_info = { | ||
| 39 | .htab = tcf_mirred_ht, | ||
| 40 | .hmask = MIRRED_TAB_MASK, | ||
| 41 | .lock = &mirred_lock, | ||
| 42 | }; | ||
| 43 | 35 | ||
| 44 | static int tcf_mirred_release(struct tcf_mirred *m, int bind) | 36 | static int tcf_mirred_release(struct tcf_mirred *m, int bind) |
| 45 | { | 37 | { |
| @@ -109,12 +101,11 @@ static int tcf_mirred_init(struct net *net, struct nlattr *nla, | |||
| 109 | dev = NULL; | 101 | dev = NULL; |
| 110 | } | 102 | } |
| 111 | 103 | ||
| 112 | pc = tcf_hash_check(parm->index, a, bind, &mirred_hash_info); | 104 | pc = tcf_hash_check(parm->index, a, bind); |
| 113 | if (!pc) { | 105 | if (!pc) { |
| 114 | if (dev == NULL) | 106 | if (dev == NULL) |
| 115 | return -EINVAL; | 107 | return -EINVAL; |
| 116 | pc = tcf_hash_create(parm->index, est, a, sizeof(*m), bind, | 108 | pc = tcf_hash_create(parm->index, est, a, sizeof(*m), bind); |
| 117 | &mirred_idx_gen, &mirred_hash_info); | ||
| 118 | if (IS_ERR(pc)) | 109 | if (IS_ERR(pc)) |
| 119 | return PTR_ERR(pc); | 110 | return PTR_ERR(pc); |
| 120 | ret = ACT_P_CREATED; | 111 | ret = ACT_P_CREATED; |
| @@ -140,7 +131,7 @@ static int tcf_mirred_init(struct net *net, struct nlattr *nla, | |||
| 140 | spin_unlock_bh(&m->tcf_lock); | 131 | spin_unlock_bh(&m->tcf_lock); |
| 141 | if (ret == ACT_P_CREATED) { | 132 | if (ret == ACT_P_CREATED) { |
| 142 | list_add(&m->tcfm_list, &mirred_list); | 133 | list_add(&m->tcfm_list, &mirred_list); |
| 143 | tcf_hash_insert(pc, &mirred_hash_info); | 134 | tcf_hash_insert(pc, a->ops->hinfo); |
| 144 | } | 135 | } |
| 145 | 136 | ||
| 146 | return ret; | 137 | return ret; |
| @@ -261,12 +252,10 @@ static struct notifier_block mirred_device_notifier = { | |||
| 261 | .notifier_call = mirred_device_event, | 252 | .notifier_call = mirred_device_event, |
| 262 | }; | 253 | }; |
| 263 | 254 | ||
| 264 | |||
| 265 | static struct tc_action_ops act_mirred_ops = { | 255 | static struct tc_action_ops act_mirred_ops = { |
| 266 | .kind = "mirred", | 256 | .kind = "mirred", |
| 267 | .hinfo = &mirred_hash_info, | 257 | .hinfo = &mirred_hash_info, |
| 268 | .type = TCA_ACT_MIRRED, | 258 | .type = TCA_ACT_MIRRED, |
| 269 | .capab = TCA_CAP_NONE, | ||
| 270 | .owner = THIS_MODULE, | 259 | .owner = THIS_MODULE, |
| 271 | .act = tcf_mirred, | 260 | .act = tcf_mirred, |
| 272 | .dump = tcf_mirred_dump, | 261 | .dump = tcf_mirred_dump, |
| @@ -284,14 +273,20 @@ static int __init mirred_init_module(void) | |||
| 284 | if (err) | 273 | if (err) |
| 285 | return err; | 274 | return err; |
| 286 | 275 | ||
| 276 | err = tcf_hashinfo_init(&mirred_hash_info, MIRRED_TAB_MASK); | ||
| 277 | if (err) { | ||
| 278 | unregister_netdevice_notifier(&mirred_device_notifier); | ||
| 279 | return err; | ||
| 280 | } | ||
| 287 | pr_info("Mirror/redirect action on\n"); | 281 | pr_info("Mirror/redirect action on\n"); |
| 288 | return tcf_register_action(&act_mirred_ops); | 282 | return tcf_register_action(&act_mirred_ops); |
| 289 | } | 283 | } |
| 290 | 284 | ||
| 291 | static void __exit mirred_cleanup_module(void) | 285 | static void __exit mirred_cleanup_module(void) |
| 292 | { | 286 | { |
| 293 | unregister_netdevice_notifier(&mirred_device_notifier); | ||
| 294 | tcf_unregister_action(&act_mirred_ops); | 287 | tcf_unregister_action(&act_mirred_ops); |
| 288 | tcf_hashinfo_destroy(&mirred_hash_info); | ||
| 289 | unregister_netdevice_notifier(&mirred_device_notifier); | ||
| 295 | } | 290 | } |
| 296 | 291 | ||
| 297 | module_init(mirred_init_module); | 292 | module_init(mirred_init_module); |
diff --git a/net/sched/act_nat.c b/net/sched/act_nat.c index 76869538d028..81f0404bb335 100644 --- a/net/sched/act_nat.c +++ b/net/sched/act_nat.c | |||
| @@ -30,15 +30,8 @@ | |||
| 30 | 30 | ||
| 31 | 31 | ||
| 32 | #define NAT_TAB_MASK 15 | 32 | #define NAT_TAB_MASK 15 |
| 33 | static struct tcf_common *tcf_nat_ht[NAT_TAB_MASK + 1]; | 33 | |
| 34 | static u32 nat_idx_gen; | 34 | static struct tcf_hashinfo nat_hash_info; |
| 35 | static DEFINE_RWLOCK(nat_lock); | ||
| 36 | |||
| 37 | static struct tcf_hashinfo nat_hash_info = { | ||
| 38 | .htab = tcf_nat_ht, | ||
| 39 | .hmask = NAT_TAB_MASK, | ||
| 40 | .lock = &nat_lock, | ||
| 41 | }; | ||
| 42 | 35 | ||
| 43 | static const struct nla_policy nat_policy[TCA_NAT_MAX + 1] = { | 36 | static const struct nla_policy nat_policy[TCA_NAT_MAX + 1] = { |
| 44 | [TCA_NAT_PARMS] = { .len = sizeof(struct tc_nat) }, | 37 | [TCA_NAT_PARMS] = { .len = sizeof(struct tc_nat) }, |
| @@ -64,17 +57,16 @@ static int tcf_nat_init(struct net *net, struct nlattr *nla, struct nlattr *est, | |||
| 64 | return -EINVAL; | 57 | return -EINVAL; |
| 65 | parm = nla_data(tb[TCA_NAT_PARMS]); | 58 | parm = nla_data(tb[TCA_NAT_PARMS]); |
| 66 | 59 | ||
| 67 | pc = tcf_hash_check(parm->index, a, bind, &nat_hash_info); | 60 | pc = tcf_hash_check(parm->index, a, bind); |
| 68 | if (!pc) { | 61 | if (!pc) { |
| 69 | pc = tcf_hash_create(parm->index, est, a, sizeof(*p), bind, | 62 | pc = tcf_hash_create(parm->index, est, a, sizeof(*p), bind); |
| 70 | &nat_idx_gen, &nat_hash_info); | ||
| 71 | if (IS_ERR(pc)) | 63 | if (IS_ERR(pc)) |
| 72 | return PTR_ERR(pc); | 64 | return PTR_ERR(pc); |
| 73 | ret = ACT_P_CREATED; | 65 | ret = ACT_P_CREATED; |
| 74 | } else { | 66 | } else { |
| 75 | if (bind) | 67 | if (bind) |
| 76 | return 0; | 68 | return 0; |
| 77 | tcf_hash_release(pc, bind, &nat_hash_info); | 69 | tcf_hash_release(pc, bind, a->ops->hinfo); |
| 78 | if (!ovr) | 70 | if (!ovr) |
| 79 | return -EEXIST; | 71 | return -EEXIST; |
| 80 | } | 72 | } |
| @@ -90,7 +82,7 @@ static int tcf_nat_init(struct net *net, struct nlattr *nla, struct nlattr *est, | |||
| 90 | spin_unlock_bh(&p->tcf_lock); | 82 | spin_unlock_bh(&p->tcf_lock); |
| 91 | 83 | ||
| 92 | if (ret == ACT_P_CREATED) | 84 | if (ret == ACT_P_CREATED) |
| 93 | tcf_hash_insert(pc, &nat_hash_info); | 85 | tcf_hash_insert(pc, a->ops->hinfo); |
| 94 | 86 | ||
| 95 | return ret; | 87 | return ret; |
| 96 | } | 88 | } |
| @@ -303,7 +295,6 @@ static struct tc_action_ops act_nat_ops = { | |||
| 303 | .kind = "nat", | 295 | .kind = "nat", |
| 304 | .hinfo = &nat_hash_info, | 296 | .hinfo = &nat_hash_info, |
| 305 | .type = TCA_ACT_NAT, | 297 | .type = TCA_ACT_NAT, |
| 306 | .capab = TCA_CAP_NONE, | ||
| 307 | .owner = THIS_MODULE, | 298 | .owner = THIS_MODULE, |
| 308 | .act = tcf_nat, | 299 | .act = tcf_nat, |
| 309 | .dump = tcf_nat_dump, | 300 | .dump = tcf_nat_dump, |
| @@ -316,12 +307,16 @@ MODULE_LICENSE("GPL"); | |||
| 316 | 307 | ||
| 317 | static int __init nat_init_module(void) | 308 | static int __init nat_init_module(void) |
| 318 | { | 309 | { |
| 310 | int err = tcf_hashinfo_init(&nat_hash_info, NAT_TAB_MASK); | ||
| 311 | if (err) | ||
| 312 | return err; | ||
| 319 | return tcf_register_action(&act_nat_ops); | 313 | return tcf_register_action(&act_nat_ops); |
| 320 | } | 314 | } |
| 321 | 315 | ||
| 322 | static void __exit nat_cleanup_module(void) | 316 | static void __exit nat_cleanup_module(void) |
| 323 | { | 317 | { |
| 324 | tcf_unregister_action(&act_nat_ops); | 318 | tcf_unregister_action(&act_nat_ops); |
| 319 | tcf_hashinfo_destroy(&nat_hash_info); | ||
| 325 | } | 320 | } |
| 326 | 321 | ||
| 327 | module_init(nat_init_module); | 322 | module_init(nat_init_module); |
diff --git a/net/sched/act_pedit.c b/net/sched/act_pedit.c index 7aa2dcd989f8..be3f0f6875bb 100644 --- a/net/sched/act_pedit.c +++ b/net/sched/act_pedit.c | |||
| @@ -24,15 +24,8 @@ | |||
| 24 | #include <net/tc_act/tc_pedit.h> | 24 | #include <net/tc_act/tc_pedit.h> |
| 25 | 25 | ||
| 26 | #define PEDIT_TAB_MASK 15 | 26 | #define PEDIT_TAB_MASK 15 |
| 27 | static struct tcf_common *tcf_pedit_ht[PEDIT_TAB_MASK + 1]; | 27 | |
| 28 | static u32 pedit_idx_gen; | 28 | static struct tcf_hashinfo pedit_hash_info; |
| 29 | static DEFINE_RWLOCK(pedit_lock); | ||
| 30 | |||
| 31 | static struct tcf_hashinfo pedit_hash_info = { | ||
| 32 | .htab = tcf_pedit_ht, | ||
| 33 | .hmask = PEDIT_TAB_MASK, | ||
| 34 | .lock = &pedit_lock, | ||
| 35 | }; | ||
| 36 | 29 | ||
| 37 | static const struct nla_policy pedit_policy[TCA_PEDIT_MAX + 1] = { | 30 | static const struct nla_policy pedit_policy[TCA_PEDIT_MAX + 1] = { |
| 38 | [TCA_PEDIT_PARMS] = { .len = sizeof(struct tc_pedit) }, | 31 | [TCA_PEDIT_PARMS] = { .len = sizeof(struct tc_pedit) }, |
| @@ -64,12 +57,11 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla, | |||
| 64 | if (nla_len(tb[TCA_PEDIT_PARMS]) < sizeof(*parm) + ksize) | 57 | if (nla_len(tb[TCA_PEDIT_PARMS]) < sizeof(*parm) + ksize) |
| 65 | return -EINVAL; | 58 | return -EINVAL; |
| 66 | 59 | ||
| 67 | pc = tcf_hash_check(parm->index, a, bind, &pedit_hash_info); | 60 | pc = tcf_hash_check(parm->index, a, bind); |
| 68 | if (!pc) { | 61 | if (!pc) { |
| 69 | if (!parm->nkeys) | 62 | if (!parm->nkeys) |
| 70 | return -EINVAL; | 63 | return -EINVAL; |
| 71 | pc = tcf_hash_create(parm->index, est, a, sizeof(*p), bind, | 64 | pc = tcf_hash_create(parm->index, est, a, sizeof(*p), bind); |
| 72 | &pedit_idx_gen, &pedit_hash_info); | ||
| 73 | if (IS_ERR(pc)) | 65 | if (IS_ERR(pc)) |
| 74 | return PTR_ERR(pc); | 66 | return PTR_ERR(pc); |
| 75 | p = to_pedit(pc); | 67 | p = to_pedit(pc); |
| @@ -84,7 +76,7 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla, | |||
| 84 | ret = ACT_P_CREATED; | 76 | ret = ACT_P_CREATED; |
| 85 | } else { | 77 | } else { |
| 86 | p = to_pedit(pc); | 78 | p = to_pedit(pc); |
| 87 | tcf_hash_release(pc, bind, &pedit_hash_info); | 79 | tcf_hash_release(pc, bind, a->ops->hinfo); |
| 88 | if (bind) | 80 | if (bind) |
| 89 | return 0; | 81 | return 0; |
| 90 | if (!ovr) | 82 | if (!ovr) |
| @@ -108,7 +100,7 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla, | |||
| 108 | memcpy(p->tcfp_keys, parm->keys, ksize); | 100 | memcpy(p->tcfp_keys, parm->keys, ksize); |
| 109 | spin_unlock_bh(&p->tcf_lock); | 101 | spin_unlock_bh(&p->tcf_lock); |
| 110 | if (ret == ACT_P_CREATED) | 102 | if (ret == ACT_P_CREATED) |
| 111 | tcf_hash_insert(pc, &pedit_hash_info); | 103 | tcf_hash_insert(pc, a->ops->hinfo); |
| 112 | return ret; | 104 | return ret; |
| 113 | } | 105 | } |
| 114 | 106 | ||
| @@ -240,7 +232,6 @@ static struct tc_action_ops act_pedit_ops = { | |||
| 240 | .kind = "pedit", | 232 | .kind = "pedit", |
| 241 | .hinfo = &pedit_hash_info, | 233 | .hinfo = &pedit_hash_info, |
| 242 | .type = TCA_ACT_PEDIT, | 234 | .type = TCA_ACT_PEDIT, |
| 243 | .capab = TCA_CAP_NONE, | ||
| 244 | .owner = THIS_MODULE, | 235 | .owner = THIS_MODULE, |
| 245 | .act = tcf_pedit, | 236 | .act = tcf_pedit, |
| 246 | .dump = tcf_pedit_dump, | 237 | .dump = tcf_pedit_dump, |
| @@ -254,11 +245,15 @@ MODULE_LICENSE("GPL"); | |||
| 254 | 245 | ||
| 255 | static int __init pedit_init_module(void) | 246 | static int __init pedit_init_module(void) |
| 256 | { | 247 | { |
| 248 | int err = tcf_hashinfo_init(&pedit_hash_info, PEDIT_TAB_MASK); | ||
| 249 | if (err) | ||
| 250 | return err; | ||
| 257 | return tcf_register_action(&act_pedit_ops); | 251 | return tcf_register_action(&act_pedit_ops); |
| 258 | } | 252 | } |
| 259 | 253 | ||
| 260 | static void __exit pedit_cleanup_module(void) | 254 | static void __exit pedit_cleanup_module(void) |
| 261 | { | 255 | { |
| 256 | tcf_hashinfo_destroy(&pedit_hash_info); | ||
| 262 | tcf_unregister_action(&act_pedit_ops); | 257 | tcf_unregister_action(&act_pedit_ops); |
| 263 | } | 258 | } |
| 264 | 259 | ||
diff --git a/net/sched/act_police.c b/net/sched/act_police.c index ef246d87e68b..1778209a332f 100644 --- a/net/sched/act_police.c +++ b/net/sched/act_police.c | |||
| @@ -41,15 +41,7 @@ struct tcf_police { | |||
| 41 | container_of(pc, struct tcf_police, common) | 41 | container_of(pc, struct tcf_police, common) |
| 42 | 42 | ||
| 43 | #define POL_TAB_MASK 15 | 43 | #define POL_TAB_MASK 15 |
| 44 | static struct tcf_common *tcf_police_ht[POL_TAB_MASK + 1]; | 44 | static struct tcf_hashinfo police_hash_info; |
| 45 | static u32 police_idx_gen; | ||
| 46 | static DEFINE_RWLOCK(police_lock); | ||
| 47 | |||
| 48 | static struct tcf_hashinfo police_hash_info = { | ||
| 49 | .htab = tcf_police_ht, | ||
| 50 | .hmask = POL_TAB_MASK, | ||
| 51 | .lock = &police_lock, | ||
| 52 | }; | ||
| 53 | 45 | ||
| 54 | /* old policer structure from before tc actions */ | 46 | /* old policer structure from before tc actions */ |
| 55 | struct tc_police_compat { | 47 | struct tc_police_compat { |
| @@ -67,18 +59,20 @@ struct tc_police_compat { | |||
| 67 | static int tcf_act_police_walker(struct sk_buff *skb, struct netlink_callback *cb, | 59 | static int tcf_act_police_walker(struct sk_buff *skb, struct netlink_callback *cb, |
| 68 | int type, struct tc_action *a) | 60 | int type, struct tc_action *a) |
| 69 | { | 61 | { |
| 62 | struct tcf_hashinfo *hinfo = a->ops->hinfo; | ||
| 63 | struct hlist_head *head; | ||
| 70 | struct tcf_common *p; | 64 | struct tcf_common *p; |
| 71 | int err = 0, index = -1, i = 0, s_i = 0, n_i = 0; | 65 | int err = 0, index = -1, i = 0, s_i = 0, n_i = 0; |
| 72 | struct nlattr *nest; | 66 | struct nlattr *nest; |
| 73 | 67 | ||
| 74 | read_lock_bh(&police_lock); | 68 | spin_lock_bh(&hinfo->lock); |
| 75 | 69 | ||
| 76 | s_i = cb->args[0]; | 70 | s_i = cb->args[0]; |
| 77 | 71 | ||
| 78 | for (i = 0; i < (POL_TAB_MASK + 1); i++) { | 72 | for (i = 0; i < (POL_TAB_MASK + 1); i++) { |
| 79 | p = tcf_police_ht[tcf_hash(i, POL_TAB_MASK)]; | 73 | head = &hinfo->htab[tcf_hash(i, POL_TAB_MASK)]; |
| 80 | 74 | ||
| 81 | for (; p; p = p->tcfc_next) { | 75 | hlist_for_each_entry_rcu(p, head, tcfc_head) { |
| 82 | index++; | 76 | index++; |
| 83 | if (index < s_i) | 77 | if (index < s_i) |
| 84 | continue; | 78 | continue; |
| @@ -101,7 +95,7 @@ static int tcf_act_police_walker(struct sk_buff *skb, struct netlink_callback *c | |||
| 101 | } | 95 | } |
| 102 | } | 96 | } |
| 103 | done: | 97 | done: |
| 104 | read_unlock_bh(&police_lock); | 98 | spin_unlock_bh(&hinfo->lock); |
| 105 | if (n_i) | 99 | if (n_i) |
| 106 | cb->args[0] += n_i; | 100 | cb->args[0] += n_i; |
| 107 | return n_i; | 101 | return n_i; |
| @@ -111,29 +105,6 @@ nla_put_failure: | |||
| 111 | goto done; | 105 | goto done; |
| 112 | } | 106 | } |
| 113 | 107 | ||
| 114 | static void tcf_police_destroy(struct tcf_police *p) | ||
| 115 | { | ||
| 116 | unsigned int h = tcf_hash(p->tcf_index, POL_TAB_MASK); | ||
| 117 | struct tcf_common **p1p; | ||
| 118 | |||
| 119 | for (p1p = &tcf_police_ht[h]; *p1p; p1p = &(*p1p)->tcfc_next) { | ||
| 120 | if (*p1p == &p->common) { | ||
| 121 | write_lock_bh(&police_lock); | ||
| 122 | *p1p = p->tcf_next; | ||
| 123 | write_unlock_bh(&police_lock); | ||
| 124 | gen_kill_estimator(&p->tcf_bstats, | ||
| 125 | &p->tcf_rate_est); | ||
| 126 | /* | ||
| 127 | * gen_estimator est_timer() might access p->tcf_lock | ||
| 128 | * or bstats, wait a RCU grace period before freeing p | ||
| 129 | */ | ||
| 130 | kfree_rcu(p, tcf_rcu); | ||
| 131 | return; | ||
| 132 | } | ||
| 133 | } | ||
| 134 | WARN_ON(1); | ||
| 135 | } | ||
| 136 | |||
| 137 | static const struct nla_policy police_policy[TCA_POLICE_MAX + 1] = { | 108 | static const struct nla_policy police_policy[TCA_POLICE_MAX + 1] = { |
| 138 | [TCA_POLICE_RATE] = { .len = TC_RTAB_SIZE }, | 109 | [TCA_POLICE_RATE] = { .len = TC_RTAB_SIZE }, |
| 139 | [TCA_POLICE_PEAKRATE] = { .len = TC_RTAB_SIZE }, | 110 | [TCA_POLICE_PEAKRATE] = { .len = TC_RTAB_SIZE }, |
| @@ -151,6 +122,7 @@ static int tcf_act_police_locate(struct net *net, struct nlattr *nla, | |||
| 151 | struct tc_police *parm; | 122 | struct tc_police *parm; |
| 152 | struct tcf_police *police; | 123 | struct tcf_police *police; |
| 153 | struct qdisc_rate_table *R_tab = NULL, *P_tab = NULL; | 124 | struct qdisc_rate_table *R_tab = NULL, *P_tab = NULL; |
| 125 | struct tcf_hashinfo *hinfo = a->ops->hinfo; | ||
| 154 | int size; | 126 | int size; |
| 155 | 127 | ||
| 156 | if (nla == NULL) | 128 | if (nla == NULL) |
| @@ -168,12 +140,8 @@ static int tcf_act_police_locate(struct net *net, struct nlattr *nla, | |||
| 168 | parm = nla_data(tb[TCA_POLICE_TBF]); | 140 | parm = nla_data(tb[TCA_POLICE_TBF]); |
| 169 | 141 | ||
| 170 | if (parm->index) { | 142 | if (parm->index) { |
| 171 | struct tcf_common *pc; | 143 | if (tcf_hash_search(a, parm->index)) { |
| 172 | 144 | police = to_police(a->priv); | |
| 173 | pc = tcf_hash_lookup(parm->index, &police_hash_info); | ||
| 174 | if (pc != NULL) { | ||
| 175 | a->priv = pc; | ||
| 176 | police = to_police(pc); | ||
| 177 | if (bind) { | 145 | if (bind) { |
| 178 | police->tcf_bindcnt += 1; | 146 | police->tcf_bindcnt += 1; |
| 179 | police->tcf_refcnt += 1; | 147 | police->tcf_refcnt += 1; |
| @@ -266,12 +234,11 @@ override: | |||
| 266 | 234 | ||
| 267 | police->tcfp_t_c = ktime_to_ns(ktime_get()); | 235 | police->tcfp_t_c = ktime_to_ns(ktime_get()); |
| 268 | police->tcf_index = parm->index ? parm->index : | 236 | police->tcf_index = parm->index ? parm->index : |
| 269 | tcf_hash_new_index(&police_idx_gen, &police_hash_info); | 237 | tcf_hash_new_index(a->ops->hinfo); |
| 270 | h = tcf_hash(police->tcf_index, POL_TAB_MASK); | 238 | h = tcf_hash(police->tcf_index, POL_TAB_MASK); |
| 271 | write_lock_bh(&police_lock); | 239 | spin_lock_bh(&hinfo->lock); |
| 272 | police->tcf_next = tcf_police_ht[h]; | 240 | hlist_add_head(&police->tcf_head, &hinfo->htab[h]); |
| 273 | tcf_police_ht[h] = &police->common; | 241 | spin_unlock_bh(&hinfo->lock); |
| 274 | write_unlock_bh(&police_lock); | ||
| 275 | 242 | ||
| 276 | a->priv = police; | 243 | a->priv = police; |
| 277 | return ret; | 244 | return ret; |
| @@ -279,10 +246,8 @@ override: | |||
| 279 | failure_unlock: | 246 | failure_unlock: |
| 280 | spin_unlock_bh(&police->tcf_lock); | 247 | spin_unlock_bh(&police->tcf_lock); |
| 281 | failure: | 248 | failure: |
| 282 | if (P_tab) | 249 | qdisc_put_rtab(P_tab); |
| 283 | qdisc_put_rtab(P_tab); | 250 | qdisc_put_rtab(R_tab); |
| 284 | if (R_tab) | ||
| 285 | qdisc_put_rtab(R_tab); | ||
| 286 | if (ret == ACT_P_CREATED) | 251 | if (ret == ACT_P_CREATED) |
| 287 | kfree(police); | 252 | kfree(police); |
| 288 | return err; | 253 | return err; |
| @@ -291,19 +256,9 @@ failure: | |||
| 291 | static int tcf_act_police_cleanup(struct tc_action *a, int bind) | 256 | static int tcf_act_police_cleanup(struct tc_action *a, int bind) |
| 292 | { | 257 | { |
| 293 | struct tcf_police *p = a->priv; | 258 | struct tcf_police *p = a->priv; |
| 294 | int ret = 0; | 259 | if (p) |
| 295 | 260 | return tcf_hash_release(&p->common, bind, &police_hash_info); | |
| 296 | if (p != NULL) { | 261 | return 0; |
| 297 | if (bind) | ||
| 298 | p->tcf_bindcnt--; | ||
| 299 | |||
| 300 | p->tcf_refcnt--; | ||
| 301 | if (p->tcf_refcnt <= 0 && !p->tcf_bindcnt) { | ||
| 302 | tcf_police_destroy(p); | ||
| 303 | ret = 1; | ||
| 304 | } | ||
| 305 | } | ||
| 306 | return ret; | ||
| 307 | } | 262 | } |
| 308 | 263 | ||
| 309 | static int tcf_act_police(struct sk_buff *skb, const struct tc_action *a, | 264 | static int tcf_act_police(struct sk_buff *skb, const struct tc_action *a, |
| @@ -404,7 +359,6 @@ static struct tc_action_ops act_police_ops = { | |||
| 404 | .kind = "police", | 359 | .kind = "police", |
| 405 | .hinfo = &police_hash_info, | 360 | .hinfo = &police_hash_info, |
| 406 | .type = TCA_ID_POLICE, | 361 | .type = TCA_ID_POLICE, |
| 407 | .capab = TCA_CAP_NONE, | ||
| 408 | .owner = THIS_MODULE, | 362 | .owner = THIS_MODULE, |
| 409 | .act = tcf_act_police, | 363 | .act = tcf_act_police, |
| 410 | .dump = tcf_act_police_dump, | 364 | .dump = tcf_act_police_dump, |
| @@ -416,12 +370,19 @@ static struct tc_action_ops act_police_ops = { | |||
| 416 | static int __init | 370 | static int __init |
| 417 | police_init_module(void) | 371 | police_init_module(void) |
| 418 | { | 372 | { |
| 419 | return tcf_register_action(&act_police_ops); | 373 | int err = tcf_hashinfo_init(&police_hash_info, POL_TAB_MASK); |
| 374 | if (err) | ||
| 375 | return err; | ||
| 376 | err = tcf_register_action(&act_police_ops); | ||
| 377 | if (err) | ||
| 378 | tcf_hashinfo_destroy(&police_hash_info); | ||
| 379 | return err; | ||
| 420 | } | 380 | } |
| 421 | 381 | ||
| 422 | static void __exit | 382 | static void __exit |
| 423 | police_cleanup_module(void) | 383 | police_cleanup_module(void) |
| 424 | { | 384 | { |
| 385 | tcf_hashinfo_destroy(&police_hash_info); | ||
| 425 | tcf_unregister_action(&act_police_ops); | 386 | tcf_unregister_action(&act_police_ops); |
| 426 | } | 387 | } |
| 427 | 388 | ||
diff --git a/net/sched/act_simple.c b/net/sched/act_simple.c index f7b45ab85388..8ef2f1fcbfba 100644 --- a/net/sched/act_simple.c +++ b/net/sched/act_simple.c | |||
| @@ -25,15 +25,7 @@ | |||
| 25 | #include <net/tc_act/tc_defact.h> | 25 | #include <net/tc_act/tc_defact.h> |
| 26 | 26 | ||
| 27 | #define SIMP_TAB_MASK 7 | 27 | #define SIMP_TAB_MASK 7 |
| 28 | static struct tcf_common *tcf_simp_ht[SIMP_TAB_MASK + 1]; | 28 | static struct tcf_hashinfo simp_hash_info; |
| 29 | static u32 simp_idx_gen; | ||
| 30 | static DEFINE_RWLOCK(simp_lock); | ||
| 31 | |||
| 32 | static struct tcf_hashinfo simp_hash_info = { | ||
| 33 | .htab = tcf_simp_ht, | ||
| 34 | .hmask = SIMP_TAB_MASK, | ||
| 35 | .lock = &simp_lock, | ||
| 36 | }; | ||
| 37 | 29 | ||
| 38 | #define SIMP_MAX_DATA 32 | 30 | #define SIMP_MAX_DATA 32 |
| 39 | static int tcf_simp(struct sk_buff *skb, const struct tc_action *a, | 31 | static int tcf_simp(struct sk_buff *skb, const struct tc_action *a, |
| @@ -122,10 +114,9 @@ static int tcf_simp_init(struct net *net, struct nlattr *nla, | |||
| 122 | parm = nla_data(tb[TCA_DEF_PARMS]); | 114 | parm = nla_data(tb[TCA_DEF_PARMS]); |
| 123 | defdata = nla_data(tb[TCA_DEF_DATA]); | 115 | defdata = nla_data(tb[TCA_DEF_DATA]); |
| 124 | 116 | ||
| 125 | pc = tcf_hash_check(parm->index, a, bind, &simp_hash_info); | 117 | pc = tcf_hash_check(parm->index, a, bind); |
| 126 | if (!pc) { | 118 | if (!pc) { |
| 127 | pc = tcf_hash_create(parm->index, est, a, sizeof(*d), bind, | 119 | pc = tcf_hash_create(parm->index, est, a, sizeof(*d), bind); |
| 128 | &simp_idx_gen, &simp_hash_info); | ||
| 129 | if (IS_ERR(pc)) | 120 | if (IS_ERR(pc)) |
| 130 | return PTR_ERR(pc); | 121 | return PTR_ERR(pc); |
| 131 | 122 | ||
| @@ -153,7 +144,7 @@ static int tcf_simp_init(struct net *net, struct nlattr *nla, | |||
| 153 | } | 144 | } |
| 154 | 145 | ||
| 155 | if (ret == ACT_P_CREATED) | 146 | if (ret == ACT_P_CREATED) |
| 156 | tcf_hash_insert(pc, &simp_hash_info); | 147 | tcf_hash_insert(pc, a->ops->hinfo); |
| 157 | return ret; | 148 | return ret; |
| 158 | } | 149 | } |
| 159 | 150 | ||
| @@ -198,7 +189,6 @@ static struct tc_action_ops act_simp_ops = { | |||
| 198 | .kind = "simple", | 189 | .kind = "simple", |
| 199 | .hinfo = &simp_hash_info, | 190 | .hinfo = &simp_hash_info, |
| 200 | .type = TCA_ACT_SIMP, | 191 | .type = TCA_ACT_SIMP, |
| 201 | .capab = TCA_CAP_NONE, | ||
| 202 | .owner = THIS_MODULE, | 192 | .owner = THIS_MODULE, |
| 203 | .act = tcf_simp, | 193 | .act = tcf_simp, |
| 204 | .dump = tcf_simp_dump, | 194 | .dump = tcf_simp_dump, |
| @@ -212,14 +202,23 @@ MODULE_LICENSE("GPL"); | |||
| 212 | 202 | ||
| 213 | static int __init simp_init_module(void) | 203 | static int __init simp_init_module(void) |
| 214 | { | 204 | { |
| 215 | int ret = tcf_register_action(&act_simp_ops); | 205 | int err, ret; |
| 206 | err = tcf_hashinfo_init(&simp_hash_info, SIMP_TAB_MASK); | ||
| 207 | if (err) | ||
| 208 | return err; | ||
| 209 | |||
| 210 | ret = tcf_register_action(&act_simp_ops); | ||
| 216 | if (!ret) | 211 | if (!ret) |
| 217 | pr_info("Simple TC action Loaded\n"); | 212 | pr_info("Simple TC action Loaded\n"); |
| 213 | else | ||
| 214 | tcf_hashinfo_destroy(&simp_hash_info); | ||
| 215 | |||
| 218 | return ret; | 216 | return ret; |
| 219 | } | 217 | } |
| 220 | 218 | ||
| 221 | static void __exit simp_cleanup_module(void) | 219 | static void __exit simp_cleanup_module(void) |
| 222 | { | 220 | { |
| 221 | tcf_hashinfo_destroy(&simp_hash_info); | ||
| 223 | tcf_unregister_action(&act_simp_ops); | 222 | tcf_unregister_action(&act_simp_ops); |
| 224 | } | 223 | } |
| 225 | 224 | ||
diff --git a/net/sched/act_skbedit.c b/net/sched/act_skbedit.c index 8fe9d25c3008..98725080b5aa 100644 --- a/net/sched/act_skbedit.c +++ b/net/sched/act_skbedit.c | |||
| @@ -11,8 +11,7 @@ | |||
| 11 | * more details. | 11 | * more details. |
| 12 | * | 12 | * |
| 13 | * You should have received a copy of the GNU General Public License along with | 13 | * You should have received a copy of the GNU General Public License along with |
| 14 | * this program; if not, write to the Free Software Foundation, Inc., 59 Temple | 14 | * this program; if not, see <http://www.gnu.org/licenses/>. |
| 15 | * Place - Suite 330, Boston, MA 02111-1307 USA. | ||
| 16 | * | 15 | * |
| 17 | * Author: Alexander Duyck <alexander.h.duyck@intel.com> | 16 | * Author: Alexander Duyck <alexander.h.duyck@intel.com> |
| 18 | */ | 17 | */ |
| @@ -29,15 +28,7 @@ | |||
| 29 | #include <net/tc_act/tc_skbedit.h> | 28 | #include <net/tc_act/tc_skbedit.h> |
| 30 | 29 | ||
| 31 | #define SKBEDIT_TAB_MASK 15 | 30 | #define SKBEDIT_TAB_MASK 15 |
| 32 | static struct tcf_common *tcf_skbedit_ht[SKBEDIT_TAB_MASK + 1]; | 31 | static struct tcf_hashinfo skbedit_hash_info; |
| 33 | static u32 skbedit_idx_gen; | ||
| 34 | static DEFINE_RWLOCK(skbedit_lock); | ||
| 35 | |||
| 36 | static struct tcf_hashinfo skbedit_hash_info = { | ||
| 37 | .htab = tcf_skbedit_ht, | ||
| 38 | .hmask = SKBEDIT_TAB_MASK, | ||
| 39 | .lock = &skbedit_lock, | ||
| 40 | }; | ||
| 41 | 32 | ||
| 42 | static int tcf_skbedit(struct sk_buff *skb, const struct tc_action *a, | 33 | static int tcf_skbedit(struct sk_buff *skb, const struct tc_action *a, |
| 43 | struct tcf_result *res) | 34 | struct tcf_result *res) |
| @@ -109,10 +100,9 @@ static int tcf_skbedit_init(struct net *net, struct nlattr *nla, | |||
| 109 | 100 | ||
| 110 | parm = nla_data(tb[TCA_SKBEDIT_PARMS]); | 101 | parm = nla_data(tb[TCA_SKBEDIT_PARMS]); |
| 111 | 102 | ||
| 112 | pc = tcf_hash_check(parm->index, a, bind, &skbedit_hash_info); | 103 | pc = tcf_hash_check(parm->index, a, bind); |
| 113 | if (!pc) { | 104 | if (!pc) { |
| 114 | pc = tcf_hash_create(parm->index, est, a, sizeof(*d), bind, | 105 | pc = tcf_hash_create(parm->index, est, a, sizeof(*d), bind); |
| 115 | &skbedit_idx_gen, &skbedit_hash_info); | ||
| 116 | if (IS_ERR(pc)) | 106 | if (IS_ERR(pc)) |
| 117 | return PTR_ERR(pc); | 107 | return PTR_ERR(pc); |
| 118 | 108 | ||
| @@ -122,7 +112,7 @@ static int tcf_skbedit_init(struct net *net, struct nlattr *nla, | |||
| 122 | d = to_skbedit(pc); | 112 | d = to_skbedit(pc); |
| 123 | if (bind) | 113 | if (bind) |
| 124 | return 0; | 114 | return 0; |
| 125 | tcf_hash_release(pc, bind, &skbedit_hash_info); | 115 | tcf_hash_release(pc, bind, a->ops->hinfo); |
| 126 | if (!ovr) | 116 | if (!ovr) |
| 127 | return -EEXIST; | 117 | return -EEXIST; |
| 128 | } | 118 | } |
| @@ -142,7 +132,7 @@ static int tcf_skbedit_init(struct net *net, struct nlattr *nla, | |||
| 142 | spin_unlock_bh(&d->tcf_lock); | 132 | spin_unlock_bh(&d->tcf_lock); |
| 143 | 133 | ||
| 144 | if (ret == ACT_P_CREATED) | 134 | if (ret == ACT_P_CREATED) |
| 145 | tcf_hash_insert(pc, &skbedit_hash_info); | 135 | tcf_hash_insert(pc, a->ops->hinfo); |
| 146 | return ret; | 136 | return ret; |
| 147 | } | 137 | } |
| 148 | 138 | ||
| @@ -198,7 +188,6 @@ static struct tc_action_ops act_skbedit_ops = { | |||
| 198 | .kind = "skbedit", | 188 | .kind = "skbedit", |
| 199 | .hinfo = &skbedit_hash_info, | 189 | .hinfo = &skbedit_hash_info, |
| 200 | .type = TCA_ACT_SKBEDIT, | 190 | .type = TCA_ACT_SKBEDIT, |
| 201 | .capab = TCA_CAP_NONE, | ||
| 202 | .owner = THIS_MODULE, | 191 | .owner = THIS_MODULE, |
| 203 | .act = tcf_skbedit, | 192 | .act = tcf_skbedit, |
| 204 | .dump = tcf_skbedit_dump, | 193 | .dump = tcf_skbedit_dump, |
| @@ -212,11 +201,15 @@ MODULE_LICENSE("GPL"); | |||
| 212 | 201 | ||
| 213 | static int __init skbedit_init_module(void) | 202 | static int __init skbedit_init_module(void) |
| 214 | { | 203 | { |
| 204 | int err = tcf_hashinfo_init(&skbedit_hash_info, SKBEDIT_TAB_MASK); | ||
| 205 | if (err) | ||
| 206 | return err; | ||
| 215 | return tcf_register_action(&act_skbedit_ops); | 207 | return tcf_register_action(&act_skbedit_ops); |
| 216 | } | 208 | } |
| 217 | 209 | ||
| 218 | static void __exit skbedit_cleanup_module(void) | 210 | static void __exit skbedit_cleanup_module(void) |
| 219 | { | 211 | { |
| 212 | tcf_hashinfo_destroy(&skbedit_hash_info); | ||
| 220 | tcf_unregister_action(&act_skbedit_ops); | 213 | tcf_unregister_action(&act_skbedit_ops); |
| 221 | } | 214 | } |
| 222 | 215 | ||
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c index 8e118af90973..29a30a14c315 100644 --- a/net/sched/cls_api.c +++ b/net/sched/cls_api.c | |||
| @@ -31,8 +31,7 @@ | |||
| 31 | #include <net/pkt_cls.h> | 31 | #include <net/pkt_cls.h> |
| 32 | 32 | ||
| 33 | /* The list of all installed classifier types */ | 33 | /* The list of all installed classifier types */ |
| 34 | 34 | static LIST_HEAD(tcf_proto_base); | |
| 35 | static struct tcf_proto_ops *tcf_proto_base __read_mostly; | ||
| 36 | 35 | ||
| 37 | /* Protects list of registered TC modules. It is pure SMP lock. */ | 36 | /* Protects list of registered TC modules. It is pure SMP lock. */ |
| 38 | static DEFINE_RWLOCK(cls_mod_lock); | 37 | static DEFINE_RWLOCK(cls_mod_lock); |
| @@ -41,36 +40,35 @@ static DEFINE_RWLOCK(cls_mod_lock); | |||
| 41 | 40 | ||
| 42 | static const struct tcf_proto_ops *tcf_proto_lookup_ops(struct nlattr *kind) | 41 | static const struct tcf_proto_ops *tcf_proto_lookup_ops(struct nlattr *kind) |
| 43 | { | 42 | { |
| 44 | const struct tcf_proto_ops *t = NULL; | 43 | const struct tcf_proto_ops *t, *res = NULL; |
| 45 | 44 | ||
| 46 | if (kind) { | 45 | if (kind) { |
| 47 | read_lock(&cls_mod_lock); | 46 | read_lock(&cls_mod_lock); |
| 48 | for (t = tcf_proto_base; t; t = t->next) { | 47 | list_for_each_entry(t, &tcf_proto_base, head) { |
| 49 | if (nla_strcmp(kind, t->kind) == 0) { | 48 | if (nla_strcmp(kind, t->kind) == 0) { |
| 50 | if (!try_module_get(t->owner)) | 49 | if (try_module_get(t->owner)) |
| 51 | t = NULL; | 50 | res = t; |
| 52 | break; | 51 | break; |
| 53 | } | 52 | } |
| 54 | } | 53 | } |
| 55 | read_unlock(&cls_mod_lock); | 54 | read_unlock(&cls_mod_lock); |
| 56 | } | 55 | } |
| 57 | return t; | 56 | return res; |
| 58 | } | 57 | } |
| 59 | 58 | ||
| 60 | /* Register(unregister) new classifier type */ | 59 | /* Register(unregister) new classifier type */ |
| 61 | 60 | ||
| 62 | int register_tcf_proto_ops(struct tcf_proto_ops *ops) | 61 | int register_tcf_proto_ops(struct tcf_proto_ops *ops) |
| 63 | { | 62 | { |
| 64 | struct tcf_proto_ops *t, **tp; | 63 | struct tcf_proto_ops *t; |
| 65 | int rc = -EEXIST; | 64 | int rc = -EEXIST; |
| 66 | 65 | ||
| 67 | write_lock(&cls_mod_lock); | 66 | write_lock(&cls_mod_lock); |
| 68 | for (tp = &tcf_proto_base; (t = *tp) != NULL; tp = &t->next) | 67 | list_for_each_entry(t, &tcf_proto_base, head) |
| 69 | if (!strcmp(ops->kind, t->kind)) | 68 | if (!strcmp(ops->kind, t->kind)) |
| 70 | goto out; | 69 | goto out; |
| 71 | 70 | ||
| 72 | ops->next = NULL; | 71 | list_add_tail(&ops->head, &tcf_proto_base); |
| 73 | *tp = ops; | ||
| 74 | rc = 0; | 72 | rc = 0; |
| 75 | out: | 73 | out: |
| 76 | write_unlock(&cls_mod_lock); | 74 | write_unlock(&cls_mod_lock); |
| @@ -80,19 +78,17 @@ EXPORT_SYMBOL(register_tcf_proto_ops); | |||
| 80 | 78 | ||
| 81 | int unregister_tcf_proto_ops(struct tcf_proto_ops *ops) | 79 | int unregister_tcf_proto_ops(struct tcf_proto_ops *ops) |
| 82 | { | 80 | { |
| 83 | struct tcf_proto_ops *t, **tp; | 81 | struct tcf_proto_ops *t; |
| 84 | int rc = -ENOENT; | 82 | int rc = -ENOENT; |
| 85 | 83 | ||
| 86 | write_lock(&cls_mod_lock); | 84 | write_lock(&cls_mod_lock); |
| 87 | for (tp = &tcf_proto_base; (t = *tp) != NULL; tp = &t->next) | 85 | list_for_each_entry(t, &tcf_proto_base, head) { |
| 88 | if (t == ops) | 86 | if (t == ops) { |
| 87 | list_del(&t->head); | ||
| 88 | rc = 0; | ||
| 89 | break; | 89 | break; |
| 90 | 90 | } | |
| 91 | if (!t) | 91 | } |
| 92 | goto out; | ||
| 93 | *tp = t->next; | ||
| 94 | rc = 0; | ||
| 95 | out: | ||
| 96 | write_unlock(&cls_mod_lock); | 92 | write_unlock(&cls_mod_lock); |
| 97 | return rc; | 93 | return rc; |
| 98 | } | 94 | } |
| @@ -344,7 +340,7 @@ errout: | |||
| 344 | return err; | 340 | return err; |
| 345 | } | 341 | } |
| 346 | 342 | ||
| 347 | static int tcf_fill_node(struct sk_buff *skb, struct tcf_proto *tp, | 343 | static int tcf_fill_node(struct net *net, struct sk_buff *skb, struct tcf_proto *tp, |
| 348 | unsigned long fh, u32 portid, u32 seq, u16 flags, int event) | 344 | unsigned long fh, u32 portid, u32 seq, u16 flags, int event) |
| 349 | { | 345 | { |
| 350 | struct tcmsg *tcm; | 346 | struct tcmsg *tcm; |
| @@ -366,7 +362,7 @@ static int tcf_fill_node(struct sk_buff *skb, struct tcf_proto *tp, | |||
| 366 | tcm->tcm_handle = fh; | 362 | tcm->tcm_handle = fh; |
| 367 | if (RTM_DELTFILTER != event) { | 363 | if (RTM_DELTFILTER != event) { |
| 368 | tcm->tcm_handle = 0; | 364 | tcm->tcm_handle = 0; |
| 369 | if (tp->ops->dump && tp->ops->dump(tp, fh, skb, tcm) < 0) | 365 | if (tp->ops->dump && tp->ops->dump(net, tp, fh, skb, tcm) < 0) |
| 370 | goto nla_put_failure; | 366 | goto nla_put_failure; |
| 371 | } | 367 | } |
| 372 | nlh->nlmsg_len = skb_tail_pointer(skb) - b; | 368 | nlh->nlmsg_len = skb_tail_pointer(skb) - b; |
| @@ -389,7 +385,7 @@ static int tfilter_notify(struct net *net, struct sk_buff *oskb, | |||
| 389 | if (!skb) | 385 | if (!skb) |
| 390 | return -ENOBUFS; | 386 | return -ENOBUFS; |
| 391 | 387 | ||
| 392 | if (tcf_fill_node(skb, tp, fh, portid, n->nlmsg_seq, 0, event) <= 0) { | 388 | if (tcf_fill_node(net, skb, tp, fh, portid, n->nlmsg_seq, 0, event) <= 0) { |
| 393 | kfree_skb(skb); | 389 | kfree_skb(skb); |
| 394 | return -EINVAL; | 390 | return -EINVAL; |
| 395 | } | 391 | } |
| @@ -408,8 +404,9 @@ static int tcf_node_dump(struct tcf_proto *tp, unsigned long n, | |||
| 408 | struct tcf_walker *arg) | 404 | struct tcf_walker *arg) |
| 409 | { | 405 | { |
| 410 | struct tcf_dump_args *a = (void *)arg; | 406 | struct tcf_dump_args *a = (void *)arg; |
| 407 | struct net *net = sock_net(a->skb->sk); | ||
| 411 | 408 | ||
| 412 | return tcf_fill_node(a->skb, tp, n, NETLINK_CB(a->cb->skb).portid, | 409 | return tcf_fill_node(net, a->skb, tp, n, NETLINK_CB(a->cb->skb).portid, |
| 413 | a->cb->nlh->nlmsg_seq, NLM_F_MULTI, RTM_NEWTFILTER); | 410 | a->cb->nlh->nlmsg_seq, NLM_F_MULTI, RTM_NEWTFILTER); |
| 414 | } | 411 | } |
| 415 | 412 | ||
| @@ -467,7 +464,7 @@ static int tc_dump_tfilter(struct sk_buff *skb, struct netlink_callback *cb) | |||
| 467 | if (t > s_t) | 464 | if (t > s_t) |
| 468 | memset(&cb->args[1], 0, sizeof(cb->args)-sizeof(cb->args[0])); | 465 | memset(&cb->args[1], 0, sizeof(cb->args)-sizeof(cb->args[0])); |
| 469 | if (cb->args[1] == 0) { | 466 | if (cb->args[1] == 0) { |
| 470 | if (tcf_fill_node(skb, tp, 0, NETLINK_CB(cb->skb).portid, | 467 | if (tcf_fill_node(net, skb, tp, 0, NETLINK_CB(cb->skb).portid, |
| 471 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | 468 | cb->nlh->nlmsg_seq, NLM_F_MULTI, |
| 472 | RTM_NEWTFILTER) <= 0) | 469 | RTM_NEWTFILTER) <= 0) |
| 473 | break; | 470 | break; |
| @@ -500,46 +497,41 @@ out: | |||
| 500 | void tcf_exts_destroy(struct tcf_proto *tp, struct tcf_exts *exts) | 497 | void tcf_exts_destroy(struct tcf_proto *tp, struct tcf_exts *exts) |
| 501 | { | 498 | { |
| 502 | #ifdef CONFIG_NET_CLS_ACT | 499 | #ifdef CONFIG_NET_CLS_ACT |
| 503 | if (exts->action) { | 500 | tcf_action_destroy(&exts->actions, TCA_ACT_UNBIND); |
| 504 | tcf_action_destroy(exts->action, TCA_ACT_UNBIND); | 501 | INIT_LIST_HEAD(&exts->actions); |
| 505 | exts->action = NULL; | ||
| 506 | } | ||
| 507 | #endif | 502 | #endif |
| 508 | } | 503 | } |
| 509 | EXPORT_SYMBOL(tcf_exts_destroy); | 504 | EXPORT_SYMBOL(tcf_exts_destroy); |
| 510 | 505 | ||
| 511 | int tcf_exts_validate(struct net *net, struct tcf_proto *tp, struct nlattr **tb, | 506 | int tcf_exts_validate(struct net *net, struct tcf_proto *tp, struct nlattr **tb, |
| 512 | struct nlattr *rate_tlv, struct tcf_exts *exts, | 507 | struct nlattr *rate_tlv, struct tcf_exts *exts) |
| 513 | const struct tcf_ext_map *map) | ||
| 514 | { | 508 | { |
| 515 | memset(exts, 0, sizeof(*exts)); | ||
| 516 | |||
| 517 | #ifdef CONFIG_NET_CLS_ACT | 509 | #ifdef CONFIG_NET_CLS_ACT |
| 518 | { | 510 | { |
| 519 | struct tc_action *act; | 511 | struct tc_action *act; |
| 520 | 512 | ||
| 521 | if (map->police && tb[map->police]) { | 513 | INIT_LIST_HEAD(&exts->actions); |
| 522 | act = tcf_action_init_1(net, tb[map->police], rate_tlv, | 514 | if (exts->police && tb[exts->police]) { |
| 515 | act = tcf_action_init_1(net, tb[exts->police], rate_tlv, | ||
| 523 | "police", TCA_ACT_NOREPLACE, | 516 | "police", TCA_ACT_NOREPLACE, |
| 524 | TCA_ACT_BIND); | 517 | TCA_ACT_BIND); |
| 525 | if (IS_ERR(act)) | 518 | if (IS_ERR(act)) |
| 526 | return PTR_ERR(act); | 519 | return PTR_ERR(act); |
| 527 | 520 | ||
| 528 | act->type = TCA_OLD_COMPAT; | 521 | act->type = exts->type = TCA_OLD_COMPAT; |
| 529 | exts->action = act; | 522 | list_add(&act->list, &exts->actions); |
| 530 | } else if (map->action && tb[map->action]) { | 523 | } else if (exts->action && tb[exts->action]) { |
| 531 | act = tcf_action_init(net, tb[map->action], rate_tlv, | 524 | int err; |
| 525 | err = tcf_action_init(net, tb[exts->action], rate_tlv, | ||
| 532 | NULL, TCA_ACT_NOREPLACE, | 526 | NULL, TCA_ACT_NOREPLACE, |
| 533 | TCA_ACT_BIND); | 527 | TCA_ACT_BIND, &exts->actions); |
| 534 | if (IS_ERR(act)) | 528 | if (err) |
| 535 | return PTR_ERR(act); | 529 | return err; |
| 536 | |||
| 537 | exts->action = act; | ||
| 538 | } | 530 | } |
| 539 | } | 531 | } |
| 540 | #else | 532 | #else |
| 541 | if ((map->action && tb[map->action]) || | 533 | if ((exts->action && tb[exts->action]) || |
| 542 | (map->police && tb[map->police])) | 534 | (exts->police && tb[exts->police])) |
| 543 | return -EOPNOTSUPP; | 535 | return -EOPNOTSUPP; |
| 544 | #endif | 536 | #endif |
| 545 | 537 | ||
| @@ -551,43 +543,44 @@ void tcf_exts_change(struct tcf_proto *tp, struct tcf_exts *dst, | |||
| 551 | struct tcf_exts *src) | 543 | struct tcf_exts *src) |
| 552 | { | 544 | { |
| 553 | #ifdef CONFIG_NET_CLS_ACT | 545 | #ifdef CONFIG_NET_CLS_ACT |
| 554 | if (src->action) { | 546 | if (!list_empty(&src->actions)) { |
| 555 | struct tc_action *act; | 547 | LIST_HEAD(tmp); |
| 556 | tcf_tree_lock(tp); | 548 | tcf_tree_lock(tp); |
| 557 | act = dst->action; | 549 | list_splice_init(&dst->actions, &tmp); |
| 558 | dst->action = src->action; | 550 | list_splice(&src->actions, &dst->actions); |
| 559 | tcf_tree_unlock(tp); | 551 | tcf_tree_unlock(tp); |
| 560 | if (act) | 552 | tcf_action_destroy(&tmp, TCA_ACT_UNBIND); |
| 561 | tcf_action_destroy(act, TCA_ACT_UNBIND); | ||
| 562 | } | 553 | } |
| 563 | #endif | 554 | #endif |
| 564 | } | 555 | } |
| 565 | EXPORT_SYMBOL(tcf_exts_change); | 556 | EXPORT_SYMBOL(tcf_exts_change); |
| 566 | 557 | ||
| 567 | int tcf_exts_dump(struct sk_buff *skb, struct tcf_exts *exts, | 558 | #define tcf_exts_first_act(ext) \ |
| 568 | const struct tcf_ext_map *map) | 559 | list_first_entry(&(exts)->actions, struct tc_action, list) |
| 560 | |||
| 561 | int tcf_exts_dump(struct sk_buff *skb, struct tcf_exts *exts) | ||
| 569 | { | 562 | { |
| 570 | #ifdef CONFIG_NET_CLS_ACT | 563 | #ifdef CONFIG_NET_CLS_ACT |
| 571 | if (map->action && exts->action) { | 564 | if (exts->action && !list_empty(&exts->actions)) { |
| 572 | /* | 565 | /* |
| 573 | * again for backward compatible mode - we want | 566 | * again for backward compatible mode - we want |
| 574 | * to work with both old and new modes of entering | 567 | * to work with both old and new modes of entering |
| 575 | * tc data even if iproute2 was newer - jhs | 568 | * tc data even if iproute2 was newer - jhs |
| 576 | */ | 569 | */ |
| 577 | struct nlattr *nest; | 570 | struct nlattr *nest; |
| 578 | 571 | if (exts->type != TCA_OLD_COMPAT) { | |
| 579 | if (exts->action->type != TCA_OLD_COMPAT) { | 572 | nest = nla_nest_start(skb, exts->action); |
| 580 | nest = nla_nest_start(skb, map->action); | ||
| 581 | if (nest == NULL) | 573 | if (nest == NULL) |
| 582 | goto nla_put_failure; | 574 | goto nla_put_failure; |
| 583 | if (tcf_action_dump(skb, exts->action, 0, 0) < 0) | 575 | if (tcf_action_dump(skb, &exts->actions, 0, 0) < 0) |
| 584 | goto nla_put_failure; | 576 | goto nla_put_failure; |
| 585 | nla_nest_end(skb, nest); | 577 | nla_nest_end(skb, nest); |
| 586 | } else if (map->police) { | 578 | } else if (exts->police) { |
| 587 | nest = nla_nest_start(skb, map->police); | 579 | struct tc_action *act = tcf_exts_first_act(exts); |
| 588 | if (nest == NULL) | 580 | nest = nla_nest_start(skb, exts->police); |
| 581 | if (nest == NULL || !act) | ||
| 589 | goto nla_put_failure; | 582 | goto nla_put_failure; |
| 590 | if (tcf_action_dump_old(skb, exts->action, 0, 0) < 0) | 583 | if (tcf_action_dump_old(skb, act, 0, 0) < 0) |
| 591 | goto nla_put_failure; | 584 | goto nla_put_failure; |
| 592 | nla_nest_end(skb, nest); | 585 | nla_nest_end(skb, nest); |
| 593 | } | 586 | } |
| @@ -600,17 +593,14 @@ nla_put_failure: __attribute__ ((unused)) | |||
| 600 | EXPORT_SYMBOL(tcf_exts_dump); | 593 | EXPORT_SYMBOL(tcf_exts_dump); |
| 601 | 594 | ||
| 602 | 595 | ||
| 603 | int tcf_exts_dump_stats(struct sk_buff *skb, struct tcf_exts *exts, | 596 | int tcf_exts_dump_stats(struct sk_buff *skb, struct tcf_exts *exts) |
| 604 | const struct tcf_ext_map *map) | ||
| 605 | { | 597 | { |
| 606 | #ifdef CONFIG_NET_CLS_ACT | 598 | #ifdef CONFIG_NET_CLS_ACT |
| 607 | if (exts->action) | 599 | struct tc_action *a = tcf_exts_first_act(exts); |
| 608 | if (tcf_action_copy_stats(skb, exts->action, 1) < 0) | 600 | if (tcf_action_copy_stats(skb, a, 1) < 0) |
| 609 | goto nla_put_failure; | 601 | return -1; |
| 610 | #endif | 602 | #endif |
| 611 | return 0; | 603 | return 0; |
| 612 | nla_put_failure: __attribute__ ((unused)) | ||
| 613 | return -1; | ||
| 614 | } | 604 | } |
| 615 | EXPORT_SYMBOL(tcf_exts_dump_stats); | 605 | EXPORT_SYMBOL(tcf_exts_dump_stats); |
| 616 | 606 | ||
diff --git a/net/sched/cls_basic.c b/net/sched/cls_basic.c index 636d9131d870..e98ca99c202b 100644 --- a/net/sched/cls_basic.c +++ b/net/sched/cls_basic.c | |||
| @@ -34,16 +34,11 @@ struct basic_filter { | |||
| 34 | struct list_head link; | 34 | struct list_head link; |
| 35 | }; | 35 | }; |
| 36 | 36 | ||
| 37 | static const struct tcf_ext_map basic_ext_map = { | ||
| 38 | .action = TCA_BASIC_ACT, | ||
| 39 | .police = TCA_BASIC_POLICE | ||
| 40 | }; | ||
| 41 | |||
| 42 | static int basic_classify(struct sk_buff *skb, const struct tcf_proto *tp, | 37 | static int basic_classify(struct sk_buff *skb, const struct tcf_proto *tp, |
| 43 | struct tcf_result *res) | 38 | struct tcf_result *res) |
| 44 | { | 39 | { |
| 45 | int r; | 40 | int r; |
| 46 | struct basic_head *head = (struct basic_head *) tp->root; | 41 | struct basic_head *head = tp->root; |
| 47 | struct basic_filter *f; | 42 | struct basic_filter *f; |
| 48 | 43 | ||
| 49 | list_for_each_entry(f, &head->flist, link) { | 44 | list_for_each_entry(f, &head->flist, link) { |
| @@ -61,7 +56,7 @@ static int basic_classify(struct sk_buff *skb, const struct tcf_proto *tp, | |||
| 61 | static unsigned long basic_get(struct tcf_proto *tp, u32 handle) | 56 | static unsigned long basic_get(struct tcf_proto *tp, u32 handle) |
| 62 | { | 57 | { |
| 63 | unsigned long l = 0UL; | 58 | unsigned long l = 0UL; |
| 64 | struct basic_head *head = (struct basic_head *) tp->root; | 59 | struct basic_head *head = tp->root; |
| 65 | struct basic_filter *f; | 60 | struct basic_filter *f; |
| 66 | 61 | ||
| 67 | if (head == NULL) | 62 | if (head == NULL) |
| @@ -112,7 +107,7 @@ static void basic_destroy(struct tcf_proto *tp) | |||
| 112 | 107 | ||
| 113 | static int basic_delete(struct tcf_proto *tp, unsigned long arg) | 108 | static int basic_delete(struct tcf_proto *tp, unsigned long arg) |
| 114 | { | 109 | { |
| 115 | struct basic_head *head = (struct basic_head *) tp->root; | 110 | struct basic_head *head = tp->root; |
| 116 | struct basic_filter *t, *f = (struct basic_filter *) arg; | 111 | struct basic_filter *t, *f = (struct basic_filter *) arg; |
| 117 | 112 | ||
| 118 | list_for_each_entry(t, &head->flist, link) | 113 | list_for_each_entry(t, &head->flist, link) |
| @@ -141,7 +136,8 @@ static int basic_set_parms(struct net *net, struct tcf_proto *tp, | |||
| 141 | struct tcf_exts e; | 136 | struct tcf_exts e; |
| 142 | struct tcf_ematch_tree t; | 137 | struct tcf_ematch_tree t; |
| 143 | 138 | ||
| 144 | err = tcf_exts_validate(net, tp, tb, est, &e, &basic_ext_map); | 139 | tcf_exts_init(&e, TCA_BASIC_ACT, TCA_BASIC_POLICE); |
| 140 | err = tcf_exts_validate(net, tp, tb, est, &e); | ||
| 145 | if (err < 0) | 141 | if (err < 0) |
| 146 | return err; | 142 | return err; |
| 147 | 143 | ||
| @@ -168,7 +164,7 @@ static int basic_change(struct net *net, struct sk_buff *in_skb, | |||
| 168 | struct nlattr **tca, unsigned long *arg) | 164 | struct nlattr **tca, unsigned long *arg) |
| 169 | { | 165 | { |
| 170 | int err; | 166 | int err; |
| 171 | struct basic_head *head = (struct basic_head *) tp->root; | 167 | struct basic_head *head = tp->root; |
| 172 | struct nlattr *tb[TCA_BASIC_MAX + 1]; | 168 | struct nlattr *tb[TCA_BASIC_MAX + 1]; |
| 173 | struct basic_filter *f = (struct basic_filter *) *arg; | 169 | struct basic_filter *f = (struct basic_filter *) *arg; |
| 174 | 170 | ||
| @@ -191,6 +187,7 @@ static int basic_change(struct net *net, struct sk_buff *in_skb, | |||
| 191 | if (f == NULL) | 187 | if (f == NULL) |
| 192 | goto errout; | 188 | goto errout; |
| 193 | 189 | ||
| 190 | tcf_exts_init(&f->exts, TCA_BASIC_ACT, TCA_BASIC_POLICE); | ||
| 194 | err = -EINVAL; | 191 | err = -EINVAL; |
| 195 | if (handle) | 192 | if (handle) |
| 196 | f->handle = handle; | 193 | f->handle = handle; |
| @@ -228,7 +225,7 @@ errout: | |||
| 228 | 225 | ||
| 229 | static void basic_walk(struct tcf_proto *tp, struct tcf_walker *arg) | 226 | static void basic_walk(struct tcf_proto *tp, struct tcf_walker *arg) |
| 230 | { | 227 | { |
| 231 | struct basic_head *head = (struct basic_head *) tp->root; | 228 | struct basic_head *head = tp->root; |
| 232 | struct basic_filter *f; | 229 | struct basic_filter *f; |
| 233 | 230 | ||
| 234 | list_for_each_entry(f, &head->flist, link) { | 231 | list_for_each_entry(f, &head->flist, link) { |
| @@ -244,7 +241,7 @@ skip: | |||
| 244 | } | 241 | } |
| 245 | } | 242 | } |
| 246 | 243 | ||
| 247 | static int basic_dump(struct tcf_proto *tp, unsigned long fh, | 244 | static int basic_dump(struct net *net, struct tcf_proto *tp, unsigned long fh, |
| 248 | struct sk_buff *skb, struct tcmsg *t) | 245 | struct sk_buff *skb, struct tcmsg *t) |
| 249 | { | 246 | { |
| 250 | struct basic_filter *f = (struct basic_filter *) fh; | 247 | struct basic_filter *f = (struct basic_filter *) fh; |
| @@ -263,13 +260,13 @@ static int basic_dump(struct tcf_proto *tp, unsigned long fh, | |||
| 263 | nla_put_u32(skb, TCA_BASIC_CLASSID, f->res.classid)) | 260 | nla_put_u32(skb, TCA_BASIC_CLASSID, f->res.classid)) |
| 264 | goto nla_put_failure; | 261 | goto nla_put_failure; |
| 265 | 262 | ||
| 266 | if (tcf_exts_dump(skb, &f->exts, &basic_ext_map) < 0 || | 263 | if (tcf_exts_dump(skb, &f->exts) < 0 || |
| 267 | tcf_em_tree_dump(skb, &f->ematches, TCA_BASIC_EMATCHES) < 0) | 264 | tcf_em_tree_dump(skb, &f->ematches, TCA_BASIC_EMATCHES) < 0) |
| 268 | goto nla_put_failure; | 265 | goto nla_put_failure; |
| 269 | 266 | ||
| 270 | nla_nest_end(skb, nest); | 267 | nla_nest_end(skb, nest); |
| 271 | 268 | ||
| 272 | if (tcf_exts_dump_stats(skb, &f->exts, &basic_ext_map) < 0) | 269 | if (tcf_exts_dump_stats(skb, &f->exts) < 0) |
| 273 | goto nla_put_failure; | 270 | goto nla_put_failure; |
| 274 | 271 | ||
| 275 | return skb->len; | 272 | return skb->len; |
diff --git a/net/sched/cls_bpf.c b/net/sched/cls_bpf.c index 1002a8226281..8e3cf49118e3 100644 --- a/net/sched/cls_bpf.c +++ b/net/sched/cls_bpf.c | |||
| @@ -46,11 +46,6 @@ static const struct nla_policy bpf_policy[TCA_BPF_MAX + 1] = { | |||
| 46 | .len = sizeof(struct sock_filter) * BPF_MAXINSNS }, | 46 | .len = sizeof(struct sock_filter) * BPF_MAXINSNS }, |
| 47 | }; | 47 | }; |
| 48 | 48 | ||
| 49 | static const struct tcf_ext_map bpf_ext_map = { | ||
| 50 | .action = TCA_BPF_ACT, | ||
| 51 | .police = TCA_BPF_POLICE, | ||
| 52 | }; | ||
| 53 | |||
| 54 | static int cls_bpf_classify(struct sk_buff *skb, const struct tcf_proto *tp, | 49 | static int cls_bpf_classify(struct sk_buff *skb, const struct tcf_proto *tp, |
| 55 | struct tcf_result *res) | 50 | struct tcf_result *res) |
| 56 | { | 51 | { |
| @@ -174,7 +169,8 @@ static int cls_bpf_modify_existing(struct net *net, struct tcf_proto *tp, | |||
| 174 | if (!tb[TCA_BPF_OPS_LEN] || !tb[TCA_BPF_OPS] || !tb[TCA_BPF_CLASSID]) | 169 | if (!tb[TCA_BPF_OPS_LEN] || !tb[TCA_BPF_OPS] || !tb[TCA_BPF_CLASSID]) |
| 175 | return -EINVAL; | 170 | return -EINVAL; |
| 176 | 171 | ||
| 177 | ret = tcf_exts_validate(net, tp, tb, est, &exts, &bpf_ext_map); | 172 | tcf_exts_init(&exts, TCA_BPF_ACT, TCA_BPF_POLICE); |
| 173 | ret = tcf_exts_validate(net, tp, tb, est, &exts); | ||
| 178 | if (ret < 0) | 174 | if (ret < 0) |
| 179 | return ret; | 175 | return ret; |
| 180 | 176 | ||
| @@ -271,6 +267,7 @@ static int cls_bpf_change(struct net *net, struct sk_buff *in_skb, | |||
| 271 | if (prog == NULL) | 267 | if (prog == NULL) |
| 272 | return -ENOBUFS; | 268 | return -ENOBUFS; |
| 273 | 269 | ||
| 270 | tcf_exts_init(&prog->exts, TCA_BPF_ACT, TCA_BPF_POLICE); | ||
| 274 | if (handle == 0) | 271 | if (handle == 0) |
| 275 | prog->handle = cls_bpf_grab_new_handle(tp, head); | 272 | prog->handle = cls_bpf_grab_new_handle(tp, head); |
| 276 | else | 273 | else |
| @@ -298,7 +295,7 @@ errout: | |||
| 298 | return ret; | 295 | return ret; |
| 299 | } | 296 | } |
| 300 | 297 | ||
| 301 | static int cls_bpf_dump(struct tcf_proto *tp, unsigned long fh, | 298 | static int cls_bpf_dump(struct net *net, struct tcf_proto *tp, unsigned long fh, |
| 302 | struct sk_buff *skb, struct tcmsg *tm) | 299 | struct sk_buff *skb, struct tcmsg *tm) |
| 303 | { | 300 | { |
| 304 | struct cls_bpf_prog *prog = (struct cls_bpf_prog *) fh; | 301 | struct cls_bpf_prog *prog = (struct cls_bpf_prog *) fh; |
| @@ -323,14 +320,14 @@ static int cls_bpf_dump(struct tcf_proto *tp, unsigned long fh, | |||
| 323 | if (nla == NULL) | 320 | if (nla == NULL) |
| 324 | goto nla_put_failure; | 321 | goto nla_put_failure; |
| 325 | 322 | ||
| 326 | memcpy(nla_data(nla), prog->bpf_ops, nla_len(nla)); | 323 | memcpy(nla_data(nla), prog->bpf_ops, nla_len(nla)); |
| 327 | 324 | ||
| 328 | if (tcf_exts_dump(skb, &prog->exts, &bpf_ext_map) < 0) | 325 | if (tcf_exts_dump(skb, &prog->exts) < 0) |
| 329 | goto nla_put_failure; | 326 | goto nla_put_failure; |
| 330 | 327 | ||
| 331 | nla_nest_end(skb, nest); | 328 | nla_nest_end(skb, nest); |
| 332 | 329 | ||
| 333 | if (tcf_exts_dump_stats(skb, &prog->exts, &bpf_ext_map) < 0) | 330 | if (tcf_exts_dump_stats(skb, &prog->exts) < 0) |
| 334 | goto nla_put_failure; | 331 | goto nla_put_failure; |
| 335 | 332 | ||
| 336 | return skb->len; | 333 | return skb->len; |
diff --git a/net/sched/cls_cgroup.c b/net/sched/cls_cgroup.c index 16006c92c3fd..8e2158ab551c 100644 --- a/net/sched/cls_cgroup.c +++ b/net/sched/cls_cgroup.c | |||
| @@ -11,109 +11,13 @@ | |||
| 11 | 11 | ||
| 12 | #include <linux/module.h> | 12 | #include <linux/module.h> |
| 13 | #include <linux/slab.h> | 13 | #include <linux/slab.h> |
| 14 | #include <linux/types.h> | ||
| 15 | #include <linux/string.h> | ||
| 16 | #include <linux/errno.h> | ||
| 17 | #include <linux/skbuff.h> | 14 | #include <linux/skbuff.h> |
| 18 | #include <linux/cgroup.h> | ||
| 19 | #include <linux/rcupdate.h> | 15 | #include <linux/rcupdate.h> |
| 20 | #include <linux/fdtable.h> | ||
| 21 | #include <net/rtnetlink.h> | 16 | #include <net/rtnetlink.h> |
| 22 | #include <net/pkt_cls.h> | 17 | #include <net/pkt_cls.h> |
| 23 | #include <net/sock.h> | 18 | #include <net/sock.h> |
| 24 | #include <net/cls_cgroup.h> | 19 | #include <net/cls_cgroup.h> |
| 25 | 20 | ||
| 26 | static inline struct cgroup_cls_state *css_cls_state(struct cgroup_subsys_state *css) | ||
| 27 | { | ||
| 28 | return css ? container_of(css, struct cgroup_cls_state, css) : NULL; | ||
| 29 | } | ||
| 30 | |||
| 31 | static inline struct cgroup_cls_state *task_cls_state(struct task_struct *p) | ||
| 32 | { | ||
| 33 | return css_cls_state(task_css(p, net_cls_subsys_id)); | ||
| 34 | } | ||
| 35 | |||
| 36 | static struct cgroup_subsys_state * | ||
| 37 | cgrp_css_alloc(struct cgroup_subsys_state *parent_css) | ||
| 38 | { | ||
| 39 | struct cgroup_cls_state *cs; | ||
| 40 | |||
| 41 | cs = kzalloc(sizeof(*cs), GFP_KERNEL); | ||
| 42 | if (!cs) | ||
| 43 | return ERR_PTR(-ENOMEM); | ||
| 44 | return &cs->css; | ||
| 45 | } | ||
| 46 | |||
| 47 | static int cgrp_css_online(struct cgroup_subsys_state *css) | ||
| 48 | { | ||
| 49 | struct cgroup_cls_state *cs = css_cls_state(css); | ||
| 50 | struct cgroup_cls_state *parent = css_cls_state(css_parent(css)); | ||
| 51 | |||
| 52 | if (parent) | ||
| 53 | cs->classid = parent->classid; | ||
| 54 | return 0; | ||
| 55 | } | ||
| 56 | |||
| 57 | static void cgrp_css_free(struct cgroup_subsys_state *css) | ||
| 58 | { | ||
| 59 | kfree(css_cls_state(css)); | ||
| 60 | } | ||
| 61 | |||
| 62 | static int update_classid(const void *v, struct file *file, unsigned n) | ||
| 63 | { | ||
| 64 | int err; | ||
| 65 | struct socket *sock = sock_from_file(file, &err); | ||
| 66 | if (sock) | ||
| 67 | sock->sk->sk_classid = (u32)(unsigned long)v; | ||
| 68 | return 0; | ||
| 69 | } | ||
| 70 | |||
| 71 | static void cgrp_attach(struct cgroup_subsys_state *css, | ||
| 72 | struct cgroup_taskset *tset) | ||
| 73 | { | ||
| 74 | struct task_struct *p; | ||
| 75 | struct cgroup_cls_state *cs = css_cls_state(css); | ||
| 76 | void *v = (void *)(unsigned long)cs->classid; | ||
| 77 | |||
| 78 | cgroup_taskset_for_each(p, css, tset) { | ||
| 79 | task_lock(p); | ||
| 80 | iterate_fd(p->files, 0, update_classid, v); | ||
| 81 | task_unlock(p); | ||
| 82 | } | ||
| 83 | } | ||
| 84 | |||
| 85 | static u64 read_classid(struct cgroup_subsys_state *css, struct cftype *cft) | ||
| 86 | { | ||
| 87 | return css_cls_state(css)->classid; | ||
| 88 | } | ||
| 89 | |||
| 90 | static int write_classid(struct cgroup_subsys_state *css, struct cftype *cft, | ||
| 91 | u64 value) | ||
| 92 | { | ||
| 93 | css_cls_state(css)->classid = (u32) value; | ||
| 94 | return 0; | ||
| 95 | } | ||
| 96 | |||
| 97 | static struct cftype ss_files[] = { | ||
| 98 | { | ||
| 99 | .name = "classid", | ||
| 100 | .read_u64 = read_classid, | ||
| 101 | .write_u64 = write_classid, | ||
| 102 | }, | ||
| 103 | { } /* terminate */ | ||
| 104 | }; | ||
| 105 | |||
| 106 | struct cgroup_subsys net_cls_subsys = { | ||
| 107 | .name = "net_cls", | ||
| 108 | .css_alloc = cgrp_css_alloc, | ||
| 109 | .css_online = cgrp_css_online, | ||
| 110 | .css_free = cgrp_css_free, | ||
| 111 | .attach = cgrp_attach, | ||
| 112 | .subsys_id = net_cls_subsys_id, | ||
| 113 | .base_cftypes = ss_files, | ||
| 114 | .module = THIS_MODULE, | ||
| 115 | }; | ||
| 116 | |||
| 117 | struct cls_cgroup_head { | 21 | struct cls_cgroup_head { |
| 118 | u32 handle; | 22 | u32 handle; |
| 119 | struct tcf_exts exts; | 23 | struct tcf_exts exts; |
| @@ -172,11 +76,6 @@ static int cls_cgroup_init(struct tcf_proto *tp) | |||
| 172 | return 0; | 76 | return 0; |
| 173 | } | 77 | } |
| 174 | 78 | ||
| 175 | static const struct tcf_ext_map cgroup_ext_map = { | ||
| 176 | .action = TCA_CGROUP_ACT, | ||
| 177 | .police = TCA_CGROUP_POLICE, | ||
| 178 | }; | ||
| 179 | |||
| 180 | static const struct nla_policy cgroup_policy[TCA_CGROUP_MAX + 1] = { | 79 | static const struct nla_policy cgroup_policy[TCA_CGROUP_MAX + 1] = { |
| 181 | [TCA_CGROUP_EMATCHES] = { .type = NLA_NESTED }, | 80 | [TCA_CGROUP_EMATCHES] = { .type = NLA_NESTED }, |
| 182 | }; | 81 | }; |
| @@ -203,6 +102,7 @@ static int cls_cgroup_change(struct net *net, struct sk_buff *in_skb, | |||
| 203 | if (head == NULL) | 102 | if (head == NULL) |
| 204 | return -ENOBUFS; | 103 | return -ENOBUFS; |
| 205 | 104 | ||
| 105 | tcf_exts_init(&head->exts, TCA_CGROUP_ACT, TCA_CGROUP_POLICE); | ||
| 206 | head->handle = handle; | 106 | head->handle = handle; |
| 207 | 107 | ||
| 208 | tcf_tree_lock(tp); | 108 | tcf_tree_lock(tp); |
| @@ -218,8 +118,8 @@ static int cls_cgroup_change(struct net *net, struct sk_buff *in_skb, | |||
| 218 | if (err < 0) | 118 | if (err < 0) |
| 219 | return err; | 119 | return err; |
| 220 | 120 | ||
| 221 | err = tcf_exts_validate(net, tp, tb, tca[TCA_RATE], &e, | 121 | tcf_exts_init(&e, TCA_CGROUP_ACT, TCA_CGROUP_POLICE); |
| 222 | &cgroup_ext_map); | 122 | err = tcf_exts_validate(net, tp, tb, tca[TCA_RATE], &e); |
| 223 | if (err < 0) | 123 | if (err < 0) |
| 224 | return err; | 124 | return err; |
| 225 | 125 | ||
| @@ -264,7 +164,7 @@ skip: | |||
| 264 | arg->count++; | 164 | arg->count++; |
| 265 | } | 165 | } |
| 266 | 166 | ||
| 267 | static int cls_cgroup_dump(struct tcf_proto *tp, unsigned long fh, | 167 | static int cls_cgroup_dump(struct net *net, struct tcf_proto *tp, unsigned long fh, |
| 268 | struct sk_buff *skb, struct tcmsg *t) | 168 | struct sk_buff *skb, struct tcmsg *t) |
| 269 | { | 169 | { |
| 270 | struct cls_cgroup_head *head = tp->root; | 170 | struct cls_cgroup_head *head = tp->root; |
| @@ -277,13 +177,13 @@ static int cls_cgroup_dump(struct tcf_proto *tp, unsigned long fh, | |||
| 277 | if (nest == NULL) | 177 | if (nest == NULL) |
| 278 | goto nla_put_failure; | 178 | goto nla_put_failure; |
| 279 | 179 | ||
| 280 | if (tcf_exts_dump(skb, &head->exts, &cgroup_ext_map) < 0 || | 180 | if (tcf_exts_dump(skb, &head->exts) < 0 || |
| 281 | tcf_em_tree_dump(skb, &head->ematches, TCA_CGROUP_EMATCHES) < 0) | 181 | tcf_em_tree_dump(skb, &head->ematches, TCA_CGROUP_EMATCHES) < 0) |
| 282 | goto nla_put_failure; | 182 | goto nla_put_failure; |
| 283 | 183 | ||
| 284 | nla_nest_end(skb, nest); | 184 | nla_nest_end(skb, nest); |
| 285 | 185 | ||
| 286 | if (tcf_exts_dump_stats(skb, &head->exts, &cgroup_ext_map) < 0) | 186 | if (tcf_exts_dump_stats(skb, &head->exts) < 0) |
| 287 | goto nla_put_failure; | 187 | goto nla_put_failure; |
| 288 | 188 | ||
| 289 | return skb->len; | 189 | return skb->len; |
| @@ -309,25 +209,12 @@ static struct tcf_proto_ops cls_cgroup_ops __read_mostly = { | |||
| 309 | 209 | ||
| 310 | static int __init init_cgroup_cls(void) | 210 | static int __init init_cgroup_cls(void) |
| 311 | { | 211 | { |
| 312 | int ret; | 212 | return register_tcf_proto_ops(&cls_cgroup_ops); |
| 313 | |||
| 314 | ret = cgroup_load_subsys(&net_cls_subsys); | ||
| 315 | if (ret) | ||
| 316 | goto out; | ||
| 317 | |||
| 318 | ret = register_tcf_proto_ops(&cls_cgroup_ops); | ||
| 319 | if (ret) | ||
| 320 | cgroup_unload_subsys(&net_cls_subsys); | ||
| 321 | |||
| 322 | out: | ||
| 323 | return ret; | ||
| 324 | } | 213 | } |
| 325 | 214 | ||
| 326 | static void __exit exit_cgroup_cls(void) | 215 | static void __exit exit_cgroup_cls(void) |
| 327 | { | 216 | { |
| 328 | unregister_tcf_proto_ops(&cls_cgroup_ops); | 217 | unregister_tcf_proto_ops(&cls_cgroup_ops); |
| 329 | |||
| 330 | cgroup_unload_subsys(&net_cls_subsys); | ||
| 331 | } | 218 | } |
| 332 | 219 | ||
| 333 | module_init(init_cgroup_cls); | 220 | module_init(init_cgroup_cls); |
diff --git a/net/sched/cls_flow.c b/net/sched/cls_flow.c index 7881e2fccbc2..257029c54332 100644 --- a/net/sched/cls_flow.c +++ b/net/sched/cls_flow.c | |||
| @@ -56,11 +56,6 @@ struct flow_filter { | |||
| 56 | u32 hashrnd; | 56 | u32 hashrnd; |
| 57 | }; | 57 | }; |
| 58 | 58 | ||
| 59 | static const struct tcf_ext_map flow_ext_map = { | ||
| 60 | .action = TCA_FLOW_ACT, | ||
| 61 | .police = TCA_FLOW_POLICE, | ||
| 62 | }; | ||
| 63 | |||
| 64 | static inline u32 addr_fold(void *addr) | 59 | static inline u32 addr_fold(void *addr) |
| 65 | { | 60 | { |
| 66 | unsigned long a = (unsigned long)addr; | 61 | unsigned long a = (unsigned long)addr; |
| @@ -220,7 +215,7 @@ static u32 flow_get_vlan_tag(const struct sk_buff *skb) | |||
| 220 | 215 | ||
| 221 | static u32 flow_get_rxhash(struct sk_buff *skb) | 216 | static u32 flow_get_rxhash(struct sk_buff *skb) |
| 222 | { | 217 | { |
| 223 | return skb_get_rxhash(skb); | 218 | return skb_get_hash(skb); |
| 224 | } | 219 | } |
| 225 | 220 | ||
| 226 | static u32 flow_key_get(struct sk_buff *skb, int key, struct flow_keys *flow) | 221 | static u32 flow_key_get(struct sk_buff *skb, int key, struct flow_keys *flow) |
| @@ -397,7 +392,8 @@ static int flow_change(struct net *net, struct sk_buff *in_skb, | |||
| 397 | return -EOPNOTSUPP; | 392 | return -EOPNOTSUPP; |
| 398 | } | 393 | } |
| 399 | 394 | ||
| 400 | err = tcf_exts_validate(net, tp, tb, tca[TCA_RATE], &e, &flow_ext_map); | 395 | tcf_exts_init(&e, TCA_FLOW_ACT, TCA_FLOW_POLICE); |
| 396 | err = tcf_exts_validate(net, tp, tb, tca[TCA_RATE], &e); | ||
| 401 | if (err < 0) | 397 | if (err < 0) |
| 402 | return err; | 398 | return err; |
| 403 | 399 | ||
| @@ -455,6 +451,7 @@ static int flow_change(struct net *net, struct sk_buff *in_skb, | |||
| 455 | 451 | ||
| 456 | f->handle = handle; | 452 | f->handle = handle; |
| 457 | f->mask = ~0U; | 453 | f->mask = ~0U; |
| 454 | tcf_exts_init(&f->exts, TCA_FLOW_ACT, TCA_FLOW_POLICE); | ||
| 458 | 455 | ||
| 459 | get_random_bytes(&f->hashrnd, 4); | 456 | get_random_bytes(&f->hashrnd, 4); |
| 460 | f->perturb_timer.function = flow_perturbation; | 457 | f->perturb_timer.function = flow_perturbation; |
| @@ -566,7 +563,7 @@ static void flow_put(struct tcf_proto *tp, unsigned long f) | |||
| 566 | { | 563 | { |
| 567 | } | 564 | } |
| 568 | 565 | ||
| 569 | static int flow_dump(struct tcf_proto *tp, unsigned long fh, | 566 | static int flow_dump(struct net *net, struct tcf_proto *tp, unsigned long fh, |
| 570 | struct sk_buff *skb, struct tcmsg *t) | 567 | struct sk_buff *skb, struct tcmsg *t) |
| 571 | { | 568 | { |
| 572 | struct flow_filter *f = (struct flow_filter *)fh; | 569 | struct flow_filter *f = (struct flow_filter *)fh; |
| @@ -608,7 +605,7 @@ static int flow_dump(struct tcf_proto *tp, unsigned long fh, | |||
| 608 | nla_put_u32(skb, TCA_FLOW_PERTURB, f->perturb_period / HZ)) | 605 | nla_put_u32(skb, TCA_FLOW_PERTURB, f->perturb_period / HZ)) |
| 609 | goto nla_put_failure; | 606 | goto nla_put_failure; |
| 610 | 607 | ||
| 611 | if (tcf_exts_dump(skb, &f->exts, &flow_ext_map) < 0) | 608 | if (tcf_exts_dump(skb, &f->exts) < 0) |
| 612 | goto nla_put_failure; | 609 | goto nla_put_failure; |
| 613 | #ifdef CONFIG_NET_EMATCH | 610 | #ifdef CONFIG_NET_EMATCH |
| 614 | if (f->ematches.hdr.nmatches && | 611 | if (f->ematches.hdr.nmatches && |
| @@ -617,7 +614,7 @@ static int flow_dump(struct tcf_proto *tp, unsigned long fh, | |||
| 617 | #endif | 614 | #endif |
| 618 | nla_nest_end(skb, nest); | 615 | nla_nest_end(skb, nest); |
| 619 | 616 | ||
| 620 | if (tcf_exts_dump_stats(skb, &f->exts, &flow_ext_map) < 0) | 617 | if (tcf_exts_dump_stats(skb, &f->exts) < 0) |
| 621 | goto nla_put_failure; | 618 | goto nla_put_failure; |
| 622 | 619 | ||
| 623 | return skb->len; | 620 | return skb->len; |
diff --git a/net/sched/cls_fw.c b/net/sched/cls_fw.c index 9b97172db84a..a366537f82c6 100644 --- a/net/sched/cls_fw.c +++ b/net/sched/cls_fw.c | |||
| @@ -41,16 +41,11 @@ struct fw_filter { | |||
| 41 | u32 id; | 41 | u32 id; |
| 42 | struct tcf_result res; | 42 | struct tcf_result res; |
| 43 | #ifdef CONFIG_NET_CLS_IND | 43 | #ifdef CONFIG_NET_CLS_IND |
| 44 | char indev[IFNAMSIZ]; | 44 | int ifindex; |
| 45 | #endif /* CONFIG_NET_CLS_IND */ | 45 | #endif /* CONFIG_NET_CLS_IND */ |
| 46 | struct tcf_exts exts; | 46 | struct tcf_exts exts; |
| 47 | }; | 47 | }; |
| 48 | 48 | ||
| 49 | static const struct tcf_ext_map fw_ext_map = { | ||
| 50 | .action = TCA_FW_ACT, | ||
| 51 | .police = TCA_FW_POLICE | ||
| 52 | }; | ||
| 53 | |||
| 54 | static inline int fw_hash(u32 handle) | 49 | static inline int fw_hash(u32 handle) |
| 55 | { | 50 | { |
| 56 | if (HTSIZE == 4096) | 51 | if (HTSIZE == 4096) |
| @@ -80,7 +75,7 @@ static inline int fw_hash(u32 handle) | |||
| 80 | static int fw_classify(struct sk_buff *skb, const struct tcf_proto *tp, | 75 | static int fw_classify(struct sk_buff *skb, const struct tcf_proto *tp, |
| 81 | struct tcf_result *res) | 76 | struct tcf_result *res) |
| 82 | { | 77 | { |
| 83 | struct fw_head *head = (struct fw_head *)tp->root; | 78 | struct fw_head *head = tp->root; |
| 84 | struct fw_filter *f; | 79 | struct fw_filter *f; |
| 85 | int r; | 80 | int r; |
| 86 | u32 id = skb->mark; | 81 | u32 id = skb->mark; |
| @@ -91,7 +86,7 @@ static int fw_classify(struct sk_buff *skb, const struct tcf_proto *tp, | |||
| 91 | if (f->id == id) { | 86 | if (f->id == id) { |
| 92 | *res = f->res; | 87 | *res = f->res; |
| 93 | #ifdef CONFIG_NET_CLS_IND | 88 | #ifdef CONFIG_NET_CLS_IND |
| 94 | if (!tcf_match_indev(skb, f->indev)) | 89 | if (!tcf_match_indev(skb, f->ifindex)) |
| 95 | continue; | 90 | continue; |
| 96 | #endif /* CONFIG_NET_CLS_IND */ | 91 | #endif /* CONFIG_NET_CLS_IND */ |
| 97 | r = tcf_exts_exec(skb, &f->exts, res); | 92 | r = tcf_exts_exec(skb, &f->exts, res); |
| @@ -116,7 +111,7 @@ static int fw_classify(struct sk_buff *skb, const struct tcf_proto *tp, | |||
| 116 | 111 | ||
| 117 | static unsigned long fw_get(struct tcf_proto *tp, u32 handle) | 112 | static unsigned long fw_get(struct tcf_proto *tp, u32 handle) |
| 118 | { | 113 | { |
| 119 | struct fw_head *head = (struct fw_head *)tp->root; | 114 | struct fw_head *head = tp->root; |
| 120 | struct fw_filter *f; | 115 | struct fw_filter *f; |
| 121 | 116 | ||
| 122 | if (head == NULL) | 117 | if (head == NULL) |
| @@ -165,7 +160,7 @@ static void fw_destroy(struct tcf_proto *tp) | |||
| 165 | 160 | ||
| 166 | static int fw_delete(struct tcf_proto *tp, unsigned long arg) | 161 | static int fw_delete(struct tcf_proto *tp, unsigned long arg) |
| 167 | { | 162 | { |
| 168 | struct fw_head *head = (struct fw_head *)tp->root; | 163 | struct fw_head *head = tp->root; |
| 169 | struct fw_filter *f = (struct fw_filter *)arg; | 164 | struct fw_filter *f = (struct fw_filter *)arg; |
| 170 | struct fw_filter **fp; | 165 | struct fw_filter **fp; |
| 171 | 166 | ||
| @@ -195,12 +190,13 @@ static int | |||
| 195 | fw_change_attrs(struct net *net, struct tcf_proto *tp, struct fw_filter *f, | 190 | fw_change_attrs(struct net *net, struct tcf_proto *tp, struct fw_filter *f, |
| 196 | struct nlattr **tb, struct nlattr **tca, unsigned long base) | 191 | struct nlattr **tb, struct nlattr **tca, unsigned long base) |
| 197 | { | 192 | { |
| 198 | struct fw_head *head = (struct fw_head *)tp->root; | 193 | struct fw_head *head = tp->root; |
| 199 | struct tcf_exts e; | 194 | struct tcf_exts e; |
| 200 | u32 mask; | 195 | u32 mask; |
| 201 | int err; | 196 | int err; |
| 202 | 197 | ||
| 203 | err = tcf_exts_validate(net, tp, tb, tca[TCA_RATE], &e, &fw_ext_map); | 198 | tcf_exts_init(&e, TCA_FW_ACT, TCA_FW_POLICE); |
| 199 | err = tcf_exts_validate(net, tp, tb, tca[TCA_RATE], &e); | ||
| 204 | if (err < 0) | 200 | if (err < 0) |
| 205 | return err; | 201 | return err; |
| 206 | 202 | ||
| @@ -211,9 +207,13 @@ fw_change_attrs(struct net *net, struct tcf_proto *tp, struct fw_filter *f, | |||
| 211 | 207 | ||
| 212 | #ifdef CONFIG_NET_CLS_IND | 208 | #ifdef CONFIG_NET_CLS_IND |
| 213 | if (tb[TCA_FW_INDEV]) { | 209 | if (tb[TCA_FW_INDEV]) { |
| 214 | err = tcf_change_indev(tp, f->indev, tb[TCA_FW_INDEV]); | 210 | int ret; |
| 215 | if (err < 0) | 211 | ret = tcf_change_indev(net, tb[TCA_FW_INDEV]); |
| 212 | if (ret < 0) { | ||
| 213 | err = ret; | ||
| 216 | goto errout; | 214 | goto errout; |
| 215 | } | ||
| 216 | f->ifindex = ret; | ||
| 217 | } | 217 | } |
| 218 | #endif /* CONFIG_NET_CLS_IND */ | 218 | #endif /* CONFIG_NET_CLS_IND */ |
| 219 | 219 | ||
| @@ -239,7 +239,7 @@ static int fw_change(struct net *net, struct sk_buff *in_skb, | |||
| 239 | struct nlattr **tca, | 239 | struct nlattr **tca, |
| 240 | unsigned long *arg) | 240 | unsigned long *arg) |
| 241 | { | 241 | { |
| 242 | struct fw_head *head = (struct fw_head *)tp->root; | 242 | struct fw_head *head = tp->root; |
| 243 | struct fw_filter *f = (struct fw_filter *) *arg; | 243 | struct fw_filter *f = (struct fw_filter *) *arg; |
| 244 | struct nlattr *opt = tca[TCA_OPTIONS]; | 244 | struct nlattr *opt = tca[TCA_OPTIONS]; |
| 245 | struct nlattr *tb[TCA_FW_MAX + 1]; | 245 | struct nlattr *tb[TCA_FW_MAX + 1]; |
| @@ -280,6 +280,7 @@ static int fw_change(struct net *net, struct sk_buff *in_skb, | |||
| 280 | if (f == NULL) | 280 | if (f == NULL) |
| 281 | return -ENOBUFS; | 281 | return -ENOBUFS; |
| 282 | 282 | ||
| 283 | tcf_exts_init(&f->exts, TCA_FW_ACT, TCA_FW_POLICE); | ||
| 283 | f->id = handle; | 284 | f->id = handle; |
| 284 | 285 | ||
| 285 | err = fw_change_attrs(net, tp, f, tb, tca, base); | 286 | err = fw_change_attrs(net, tp, f, tb, tca, base); |
| @@ -301,7 +302,7 @@ errout: | |||
| 301 | 302 | ||
| 302 | static void fw_walk(struct tcf_proto *tp, struct tcf_walker *arg) | 303 | static void fw_walk(struct tcf_proto *tp, struct tcf_walker *arg) |
| 303 | { | 304 | { |
| 304 | struct fw_head *head = (struct fw_head *)tp->root; | 305 | struct fw_head *head = tp->root; |
| 305 | int h; | 306 | int h; |
| 306 | 307 | ||
| 307 | if (head == NULL) | 308 | if (head == NULL) |
| @@ -327,10 +328,10 @@ static void fw_walk(struct tcf_proto *tp, struct tcf_walker *arg) | |||
| 327 | } | 328 | } |
| 328 | } | 329 | } |
| 329 | 330 | ||
| 330 | static int fw_dump(struct tcf_proto *tp, unsigned long fh, | 331 | static int fw_dump(struct net *net, struct tcf_proto *tp, unsigned long fh, |
| 331 | struct sk_buff *skb, struct tcmsg *t) | 332 | struct sk_buff *skb, struct tcmsg *t) |
| 332 | { | 333 | { |
| 333 | struct fw_head *head = (struct fw_head *)tp->root; | 334 | struct fw_head *head = tp->root; |
| 334 | struct fw_filter *f = (struct fw_filter *)fh; | 335 | struct fw_filter *f = (struct fw_filter *)fh; |
| 335 | unsigned char *b = skb_tail_pointer(skb); | 336 | unsigned char *b = skb_tail_pointer(skb); |
| 336 | struct nlattr *nest; | 337 | struct nlattr *nest; |
| @@ -351,20 +352,23 @@ static int fw_dump(struct tcf_proto *tp, unsigned long fh, | |||
| 351 | nla_put_u32(skb, TCA_FW_CLASSID, f->res.classid)) | 352 | nla_put_u32(skb, TCA_FW_CLASSID, f->res.classid)) |
| 352 | goto nla_put_failure; | 353 | goto nla_put_failure; |
| 353 | #ifdef CONFIG_NET_CLS_IND | 354 | #ifdef CONFIG_NET_CLS_IND |
| 354 | if (strlen(f->indev) && | 355 | if (f->ifindex) { |
| 355 | nla_put_string(skb, TCA_FW_INDEV, f->indev)) | 356 | struct net_device *dev; |
| 356 | goto nla_put_failure; | 357 | dev = __dev_get_by_index(net, f->ifindex); |
| 358 | if (dev && nla_put_string(skb, TCA_FW_INDEV, dev->name)) | ||
| 359 | goto nla_put_failure; | ||
| 360 | } | ||
| 357 | #endif /* CONFIG_NET_CLS_IND */ | 361 | #endif /* CONFIG_NET_CLS_IND */ |
| 358 | if (head->mask != 0xFFFFFFFF && | 362 | if (head->mask != 0xFFFFFFFF && |
| 359 | nla_put_u32(skb, TCA_FW_MASK, head->mask)) | 363 | nla_put_u32(skb, TCA_FW_MASK, head->mask)) |
| 360 | goto nla_put_failure; | 364 | goto nla_put_failure; |
| 361 | 365 | ||
| 362 | if (tcf_exts_dump(skb, &f->exts, &fw_ext_map) < 0) | 366 | if (tcf_exts_dump(skb, &f->exts) < 0) |
| 363 | goto nla_put_failure; | 367 | goto nla_put_failure; |
| 364 | 368 | ||
| 365 | nla_nest_end(skb, nest); | 369 | nla_nest_end(skb, nest); |
| 366 | 370 | ||
| 367 | if (tcf_exts_dump_stats(skb, &f->exts, &fw_ext_map) < 0) | 371 | if (tcf_exts_dump_stats(skb, &f->exts) < 0) |
| 368 | goto nla_put_failure; | 372 | goto nla_put_failure; |
| 369 | 373 | ||
| 370 | return skb->len; | 374 | return skb->len; |
diff --git a/net/sched/cls_route.c b/net/sched/cls_route.c index 37da567d833e..1ad3068f2ce1 100644 --- a/net/sched/cls_route.c +++ b/net/sched/cls_route.c | |||
| @@ -59,11 +59,6 @@ struct route4_filter { | |||
| 59 | 59 | ||
| 60 | #define ROUTE4_FAILURE ((struct route4_filter *)(-1L)) | 60 | #define ROUTE4_FAILURE ((struct route4_filter *)(-1L)) |
| 61 | 61 | ||
| 62 | static const struct tcf_ext_map route_ext_map = { | ||
| 63 | .police = TCA_ROUTE4_POLICE, | ||
| 64 | .action = TCA_ROUTE4_ACT | ||
| 65 | }; | ||
| 66 | |||
| 67 | static inline int route4_fastmap_hash(u32 id, int iif) | 62 | static inline int route4_fastmap_hash(u32 id, int iif) |
| 68 | { | 63 | { |
| 69 | return id & 0xF; | 64 | return id & 0xF; |
| @@ -128,7 +123,7 @@ static inline int route4_hash_wild(void) | |||
| 128 | static int route4_classify(struct sk_buff *skb, const struct tcf_proto *tp, | 123 | static int route4_classify(struct sk_buff *skb, const struct tcf_proto *tp, |
| 129 | struct tcf_result *res) | 124 | struct tcf_result *res) |
| 130 | { | 125 | { |
| 131 | struct route4_head *head = (struct route4_head *)tp->root; | 126 | struct route4_head *head = tp->root; |
| 132 | struct dst_entry *dst; | 127 | struct dst_entry *dst; |
| 133 | struct route4_bucket *b; | 128 | struct route4_bucket *b; |
| 134 | struct route4_filter *f; | 129 | struct route4_filter *f; |
| @@ -218,7 +213,7 @@ static inline u32 from_hash(u32 id) | |||
| 218 | 213 | ||
| 219 | static unsigned long route4_get(struct tcf_proto *tp, u32 handle) | 214 | static unsigned long route4_get(struct tcf_proto *tp, u32 handle) |
| 220 | { | 215 | { |
| 221 | struct route4_head *head = (struct route4_head *)tp->root; | 216 | struct route4_head *head = tp->root; |
| 222 | struct route4_bucket *b; | 217 | struct route4_bucket *b; |
| 223 | struct route4_filter *f; | 218 | struct route4_filter *f; |
| 224 | unsigned int h1, h2; | 219 | unsigned int h1, h2; |
| @@ -289,7 +284,7 @@ static void route4_destroy(struct tcf_proto *tp) | |||
| 289 | 284 | ||
| 290 | static int route4_delete(struct tcf_proto *tp, unsigned long arg) | 285 | static int route4_delete(struct tcf_proto *tp, unsigned long arg) |
| 291 | { | 286 | { |
| 292 | struct route4_head *head = (struct route4_head *)tp->root; | 287 | struct route4_head *head = tp->root; |
| 293 | struct route4_filter **fp, *f = (struct route4_filter *)arg; | 288 | struct route4_filter **fp, *f = (struct route4_filter *)arg; |
| 294 | unsigned int h = 0; | 289 | unsigned int h = 0; |
| 295 | struct route4_bucket *b; | 290 | struct route4_bucket *b; |
| @@ -347,7 +342,8 @@ static int route4_set_parms(struct net *net, struct tcf_proto *tp, | |||
| 347 | struct route4_bucket *b; | 342 | struct route4_bucket *b; |
| 348 | struct tcf_exts e; | 343 | struct tcf_exts e; |
| 349 | 344 | ||
| 350 | err = tcf_exts_validate(net, tp, tb, est, &e, &route_ext_map); | 345 | tcf_exts_init(&e, TCA_ROUTE4_ACT, TCA_ROUTE4_POLICE); |
| 346 | err = tcf_exts_validate(net, tp, tb, est, &e); | ||
| 351 | if (err < 0) | 347 | if (err < 0) |
| 352 | return err; | 348 | return err; |
| 353 | 349 | ||
| @@ -481,6 +477,7 @@ static int route4_change(struct net *net, struct sk_buff *in_skb, | |||
| 481 | if (f == NULL) | 477 | if (f == NULL) |
| 482 | goto errout; | 478 | goto errout; |
| 483 | 479 | ||
| 480 | tcf_exts_init(&f->exts, TCA_ROUTE4_ACT, TCA_ROUTE4_POLICE); | ||
| 484 | err = route4_set_parms(net, tp, base, f, handle, head, tb, | 481 | err = route4_set_parms(net, tp, base, f, handle, head, tb, |
| 485 | tca[TCA_RATE], 1); | 482 | tca[TCA_RATE], 1); |
| 486 | if (err < 0) | 483 | if (err < 0) |
| @@ -554,7 +551,7 @@ static void route4_walk(struct tcf_proto *tp, struct tcf_walker *arg) | |||
| 554 | } | 551 | } |
| 555 | } | 552 | } |
| 556 | 553 | ||
| 557 | static int route4_dump(struct tcf_proto *tp, unsigned long fh, | 554 | static int route4_dump(struct net *net, struct tcf_proto *tp, unsigned long fh, |
| 558 | struct sk_buff *skb, struct tcmsg *t) | 555 | struct sk_buff *skb, struct tcmsg *t) |
| 559 | { | 556 | { |
| 560 | struct route4_filter *f = (struct route4_filter *)fh; | 557 | struct route4_filter *f = (struct route4_filter *)fh; |
| @@ -589,12 +586,12 @@ static int route4_dump(struct tcf_proto *tp, unsigned long fh, | |||
| 589 | nla_put_u32(skb, TCA_ROUTE4_CLASSID, f->res.classid)) | 586 | nla_put_u32(skb, TCA_ROUTE4_CLASSID, f->res.classid)) |
| 590 | goto nla_put_failure; | 587 | goto nla_put_failure; |
| 591 | 588 | ||
| 592 | if (tcf_exts_dump(skb, &f->exts, &route_ext_map) < 0) | 589 | if (tcf_exts_dump(skb, &f->exts) < 0) |
| 593 | goto nla_put_failure; | 590 | goto nla_put_failure; |
| 594 | 591 | ||
| 595 | nla_nest_end(skb, nest); | 592 | nla_nest_end(skb, nest); |
| 596 | 593 | ||
| 597 | if (tcf_exts_dump_stats(skb, &f->exts, &route_ext_map) < 0) | 594 | if (tcf_exts_dump_stats(skb, &f->exts) < 0) |
| 598 | goto nla_put_failure; | 595 | goto nla_put_failure; |
| 599 | 596 | ||
| 600 | return skb->len; | 597 | return skb->len; |
diff --git a/net/sched/cls_rsvp.h b/net/sched/cls_rsvp.h index 252d8b05872e..19f8e5dfa8bd 100644 --- a/net/sched/cls_rsvp.h +++ b/net/sched/cls_rsvp.h | |||
| @@ -116,11 +116,6 @@ static inline unsigned int hash_src(__be32 *src) | |||
| 116 | return h & 0xF; | 116 | return h & 0xF; |
| 117 | } | 117 | } |
| 118 | 118 | ||
| 119 | static struct tcf_ext_map rsvp_ext_map = { | ||
| 120 | .police = TCA_RSVP_POLICE, | ||
| 121 | .action = TCA_RSVP_ACT | ||
| 122 | }; | ||
| 123 | |||
| 124 | #define RSVP_APPLY_RESULT() \ | 119 | #define RSVP_APPLY_RESULT() \ |
| 125 | { \ | 120 | { \ |
| 126 | int r = tcf_exts_exec(skb, &f->exts, res); \ | 121 | int r = tcf_exts_exec(skb, &f->exts, res); \ |
| @@ -440,7 +435,8 @@ static int rsvp_change(struct net *net, struct sk_buff *in_skb, | |||
| 440 | if (err < 0) | 435 | if (err < 0) |
| 441 | return err; | 436 | return err; |
| 442 | 437 | ||
| 443 | err = tcf_exts_validate(net, tp, tb, tca[TCA_RATE], &e, &rsvp_ext_map); | 438 | tcf_exts_init(&e, TCA_RSVP_ACT, TCA_RSVP_POLICE); |
| 439 | err = tcf_exts_validate(net, tp, tb, tca[TCA_RATE], &e); | ||
| 444 | if (err < 0) | 440 | if (err < 0) |
| 445 | return err; | 441 | return err; |
| 446 | 442 | ||
| @@ -471,6 +467,7 @@ static int rsvp_change(struct net *net, struct sk_buff *in_skb, | |||
| 471 | if (f == NULL) | 467 | if (f == NULL) |
| 472 | goto errout2; | 468 | goto errout2; |
| 473 | 469 | ||
| 470 | tcf_exts_init(&f->exts, TCA_RSVP_ACT, TCA_RSVP_POLICE); | ||
| 474 | h2 = 16; | 471 | h2 = 16; |
| 475 | if (tb[TCA_RSVP_SRC]) { | 472 | if (tb[TCA_RSVP_SRC]) { |
| 476 | memcpy(f->src, nla_data(tb[TCA_RSVP_SRC]), sizeof(f->src)); | 473 | memcpy(f->src, nla_data(tb[TCA_RSVP_SRC]), sizeof(f->src)); |
| @@ -597,7 +594,7 @@ static void rsvp_walk(struct tcf_proto *tp, struct tcf_walker *arg) | |||
| 597 | } | 594 | } |
| 598 | } | 595 | } |
| 599 | 596 | ||
| 600 | static int rsvp_dump(struct tcf_proto *tp, unsigned long fh, | 597 | static int rsvp_dump(struct net *net, struct tcf_proto *tp, unsigned long fh, |
| 601 | struct sk_buff *skb, struct tcmsg *t) | 598 | struct sk_buff *skb, struct tcmsg *t) |
| 602 | { | 599 | { |
| 603 | struct rsvp_filter *f = (struct rsvp_filter *)fh; | 600 | struct rsvp_filter *f = (struct rsvp_filter *)fh; |
| @@ -633,12 +630,12 @@ static int rsvp_dump(struct tcf_proto *tp, unsigned long fh, | |||
| 633 | nla_put(skb, TCA_RSVP_SRC, sizeof(f->src), f->src)) | 630 | nla_put(skb, TCA_RSVP_SRC, sizeof(f->src), f->src)) |
| 634 | goto nla_put_failure; | 631 | goto nla_put_failure; |
| 635 | 632 | ||
| 636 | if (tcf_exts_dump(skb, &f->exts, &rsvp_ext_map) < 0) | 633 | if (tcf_exts_dump(skb, &f->exts) < 0) |
| 637 | goto nla_put_failure; | 634 | goto nla_put_failure; |
| 638 | 635 | ||
| 639 | nla_nest_end(skb, nest); | 636 | nla_nest_end(skb, nest); |
| 640 | 637 | ||
| 641 | if (tcf_exts_dump_stats(skb, &f->exts, &rsvp_ext_map) < 0) | 638 | if (tcf_exts_dump_stats(skb, &f->exts) < 0) |
| 642 | goto nla_put_failure; | 639 | goto nla_put_failure; |
| 643 | return skb->len; | 640 | return skb->len; |
| 644 | 641 | ||
diff --git a/net/sched/cls_tcindex.c b/net/sched/cls_tcindex.c index b86535a40169..eed8404443d8 100644 --- a/net/sched/cls_tcindex.c +++ b/net/sched/cls_tcindex.c | |||
| @@ -24,9 +24,6 @@ | |||
| 24 | #define DEFAULT_HASH_SIZE 64 /* optimized for diffserv */ | 24 | #define DEFAULT_HASH_SIZE 64 /* optimized for diffserv */ |
| 25 | 25 | ||
| 26 | 26 | ||
| 27 | #define PRIV(tp) ((struct tcindex_data *) (tp)->root) | ||
| 28 | |||
| 29 | |||
| 30 | struct tcindex_filter_result { | 27 | struct tcindex_filter_result { |
| 31 | struct tcf_exts exts; | 28 | struct tcf_exts exts; |
| 32 | struct tcf_result res; | 29 | struct tcf_result res; |
| @@ -50,11 +47,6 @@ struct tcindex_data { | |||
| 50 | int fall_through; /* 0: only classify if explicit match */ | 47 | int fall_through; /* 0: only classify if explicit match */ |
| 51 | }; | 48 | }; |
| 52 | 49 | ||
| 53 | static const struct tcf_ext_map tcindex_ext_map = { | ||
| 54 | .police = TCA_TCINDEX_POLICE, | ||
| 55 | .action = TCA_TCINDEX_ACT | ||
| 56 | }; | ||
| 57 | |||
| 58 | static inline int | 50 | static inline int |
| 59 | tcindex_filter_is_set(struct tcindex_filter_result *r) | 51 | tcindex_filter_is_set(struct tcindex_filter_result *r) |
| 60 | { | 52 | { |
| @@ -82,7 +74,7 @@ tcindex_lookup(struct tcindex_data *p, u16 key) | |||
| 82 | static int tcindex_classify(struct sk_buff *skb, const struct tcf_proto *tp, | 74 | static int tcindex_classify(struct sk_buff *skb, const struct tcf_proto *tp, |
| 83 | struct tcf_result *res) | 75 | struct tcf_result *res) |
| 84 | { | 76 | { |
| 85 | struct tcindex_data *p = PRIV(tp); | 77 | struct tcindex_data *p = tp->root; |
| 86 | struct tcindex_filter_result *f; | 78 | struct tcindex_filter_result *f; |
| 87 | int key = (skb->tc_index & p->mask) >> p->shift; | 79 | int key = (skb->tc_index & p->mask) >> p->shift; |
| 88 | 80 | ||
| @@ -107,7 +99,7 @@ static int tcindex_classify(struct sk_buff *skb, const struct tcf_proto *tp, | |||
| 107 | 99 | ||
| 108 | static unsigned long tcindex_get(struct tcf_proto *tp, u32 handle) | 100 | static unsigned long tcindex_get(struct tcf_proto *tp, u32 handle) |
| 109 | { | 101 | { |
| 110 | struct tcindex_data *p = PRIV(tp); | 102 | struct tcindex_data *p = tp->root; |
| 111 | struct tcindex_filter_result *r; | 103 | struct tcindex_filter_result *r; |
| 112 | 104 | ||
| 113 | pr_debug("tcindex_get(tp %p,handle 0x%08x)\n", tp, handle); | 105 | pr_debug("tcindex_get(tp %p,handle 0x%08x)\n", tp, handle); |
| @@ -145,7 +137,7 @@ static int tcindex_init(struct tcf_proto *tp) | |||
| 145 | static int | 137 | static int |
| 146 | __tcindex_delete(struct tcf_proto *tp, unsigned long arg, int lock) | 138 | __tcindex_delete(struct tcf_proto *tp, unsigned long arg, int lock) |
| 147 | { | 139 | { |
| 148 | struct tcindex_data *p = PRIV(tp); | 140 | struct tcindex_data *p = tp->root; |
| 149 | struct tcindex_filter_result *r = (struct tcindex_filter_result *) arg; | 141 | struct tcindex_filter_result *r = (struct tcindex_filter_result *) arg; |
| 150 | struct tcindex_filter *f = NULL; | 142 | struct tcindex_filter *f = NULL; |
| 151 | 143 | ||
| @@ -209,17 +201,21 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base, | |||
| 209 | struct tcindex_filter *f = NULL; /* make gcc behave */ | 201 | struct tcindex_filter *f = NULL; /* make gcc behave */ |
| 210 | struct tcf_exts e; | 202 | struct tcf_exts e; |
| 211 | 203 | ||
| 212 | err = tcf_exts_validate(net, tp, tb, est, &e, &tcindex_ext_map); | 204 | tcf_exts_init(&e, TCA_TCINDEX_ACT, TCA_TCINDEX_POLICE); |
| 205 | err = tcf_exts_validate(net, tp, tb, est, &e); | ||
| 213 | if (err < 0) | 206 | if (err < 0) |
| 214 | return err; | 207 | return err; |
| 215 | 208 | ||
| 216 | memcpy(&cp, p, sizeof(cp)); | 209 | memcpy(&cp, p, sizeof(cp)); |
| 217 | memset(&new_filter_result, 0, sizeof(new_filter_result)); | 210 | memset(&new_filter_result, 0, sizeof(new_filter_result)); |
| 211 | tcf_exts_init(&new_filter_result.exts, TCA_TCINDEX_ACT, TCA_TCINDEX_POLICE); | ||
| 218 | 212 | ||
| 219 | if (old_r) | 213 | if (old_r) |
| 220 | memcpy(&cr, r, sizeof(cr)); | 214 | memcpy(&cr, r, sizeof(cr)); |
| 221 | else | 215 | else { |
| 222 | memset(&cr, 0, sizeof(cr)); | 216 | memset(&cr, 0, sizeof(cr)); |
| 217 | tcf_exts_init(&cr.exts, TCA_TCINDEX_ACT, TCA_TCINDEX_POLICE); | ||
| 218 | } | ||
| 223 | 219 | ||
| 224 | if (tb[TCA_TCINDEX_HASH]) | 220 | if (tb[TCA_TCINDEX_HASH]) |
| 225 | cp.hash = nla_get_u32(tb[TCA_TCINDEX_HASH]); | 221 | cp.hash = nla_get_u32(tb[TCA_TCINDEX_HASH]); |
| @@ -339,7 +335,7 @@ tcindex_change(struct net *net, struct sk_buff *in_skb, | |||
| 339 | { | 335 | { |
| 340 | struct nlattr *opt = tca[TCA_OPTIONS]; | 336 | struct nlattr *opt = tca[TCA_OPTIONS]; |
| 341 | struct nlattr *tb[TCA_TCINDEX_MAX + 1]; | 337 | struct nlattr *tb[TCA_TCINDEX_MAX + 1]; |
| 342 | struct tcindex_data *p = PRIV(tp); | 338 | struct tcindex_data *p = tp->root; |
| 343 | struct tcindex_filter_result *r = (struct tcindex_filter_result *) *arg; | 339 | struct tcindex_filter_result *r = (struct tcindex_filter_result *) *arg; |
| 344 | int err; | 340 | int err; |
| 345 | 341 | ||
| @@ -361,7 +357,7 @@ tcindex_change(struct net *net, struct sk_buff *in_skb, | |||
| 361 | 357 | ||
| 362 | static void tcindex_walk(struct tcf_proto *tp, struct tcf_walker *walker) | 358 | static void tcindex_walk(struct tcf_proto *tp, struct tcf_walker *walker) |
| 363 | { | 359 | { |
| 364 | struct tcindex_data *p = PRIV(tp); | 360 | struct tcindex_data *p = tp->root; |
| 365 | struct tcindex_filter *f, *next; | 361 | struct tcindex_filter *f, *next; |
| 366 | int i; | 362 | int i; |
| 367 | 363 | ||
| @@ -408,7 +404,7 @@ static int tcindex_destroy_element(struct tcf_proto *tp, | |||
| 408 | 404 | ||
| 409 | static void tcindex_destroy(struct tcf_proto *tp) | 405 | static void tcindex_destroy(struct tcf_proto *tp) |
| 410 | { | 406 | { |
| 411 | struct tcindex_data *p = PRIV(tp); | 407 | struct tcindex_data *p = tp->root; |
| 412 | struct tcf_walker walker; | 408 | struct tcf_walker walker; |
| 413 | 409 | ||
| 414 | pr_debug("tcindex_destroy(tp %p),p %p\n", tp, p); | 410 | pr_debug("tcindex_destroy(tp %p),p %p\n", tp, p); |
| @@ -423,10 +419,10 @@ static void tcindex_destroy(struct tcf_proto *tp) | |||
| 423 | } | 419 | } |
| 424 | 420 | ||
| 425 | 421 | ||
| 426 | static int tcindex_dump(struct tcf_proto *tp, unsigned long fh, | 422 | static int tcindex_dump(struct net *net, struct tcf_proto *tp, unsigned long fh, |
| 427 | struct sk_buff *skb, struct tcmsg *t) | 423 | struct sk_buff *skb, struct tcmsg *t) |
| 428 | { | 424 | { |
| 429 | struct tcindex_data *p = PRIV(tp); | 425 | struct tcindex_data *p = tp->root; |
| 430 | struct tcindex_filter_result *r = (struct tcindex_filter_result *) fh; | 426 | struct tcindex_filter_result *r = (struct tcindex_filter_result *) fh; |
| 431 | unsigned char *b = skb_tail_pointer(skb); | 427 | unsigned char *b = skb_tail_pointer(skb); |
| 432 | struct nlattr *nest; | 428 | struct nlattr *nest; |
| @@ -468,11 +464,11 @@ static int tcindex_dump(struct tcf_proto *tp, unsigned long fh, | |||
| 468 | nla_put_u32(skb, TCA_TCINDEX_CLASSID, r->res.classid)) | 464 | nla_put_u32(skb, TCA_TCINDEX_CLASSID, r->res.classid)) |
| 469 | goto nla_put_failure; | 465 | goto nla_put_failure; |
| 470 | 466 | ||
| 471 | if (tcf_exts_dump(skb, &r->exts, &tcindex_ext_map) < 0) | 467 | if (tcf_exts_dump(skb, &r->exts) < 0) |
| 472 | goto nla_put_failure; | 468 | goto nla_put_failure; |
| 473 | nla_nest_end(skb, nest); | 469 | nla_nest_end(skb, nest); |
| 474 | 470 | ||
| 475 | if (tcf_exts_dump_stats(skb, &r->exts, &tcindex_ext_map) < 0) | 471 | if (tcf_exts_dump_stats(skb, &r->exts) < 0) |
| 476 | goto nla_put_failure; | 472 | goto nla_put_failure; |
| 477 | } | 473 | } |
| 478 | 474 | ||
diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c index eb07a1e536e6..84c28daff848 100644 --- a/net/sched/cls_u32.c +++ b/net/sched/cls_u32.c | |||
| @@ -48,7 +48,7 @@ struct tc_u_knode { | |||
| 48 | struct tc_u_hnode *ht_up; | 48 | struct tc_u_hnode *ht_up; |
| 49 | struct tcf_exts exts; | 49 | struct tcf_exts exts; |
| 50 | #ifdef CONFIG_NET_CLS_IND | 50 | #ifdef CONFIG_NET_CLS_IND |
| 51 | char indev[IFNAMSIZ]; | 51 | int ifindex; |
| 52 | #endif | 52 | #endif |
| 53 | u8 fshift; | 53 | u8 fshift; |
| 54 | struct tcf_result res; | 54 | struct tcf_result res; |
| @@ -79,11 +79,6 @@ struct tc_u_common { | |||
| 79 | u32 hgenerator; | 79 | u32 hgenerator; |
| 80 | }; | 80 | }; |
| 81 | 81 | ||
| 82 | static const struct tcf_ext_map u32_ext_map = { | ||
| 83 | .action = TCA_U32_ACT, | ||
| 84 | .police = TCA_U32_POLICE | ||
| 85 | }; | ||
| 86 | |||
| 87 | static inline unsigned int u32_hash_fold(__be32 key, | 82 | static inline unsigned int u32_hash_fold(__be32 key, |
| 88 | const struct tc_u32_sel *sel, | 83 | const struct tc_u32_sel *sel, |
| 89 | u8 fshift) | 84 | u8 fshift) |
| @@ -100,7 +95,7 @@ static int u32_classify(struct sk_buff *skb, const struct tcf_proto *tp, struct | |||
| 100 | unsigned int off; | 95 | unsigned int off; |
| 101 | } stack[TC_U32_MAXDEPTH]; | 96 | } stack[TC_U32_MAXDEPTH]; |
| 102 | 97 | ||
| 103 | struct tc_u_hnode *ht = (struct tc_u_hnode *)tp->root; | 98 | struct tc_u_hnode *ht = tp->root; |
| 104 | unsigned int off = skb_network_offset(skb); | 99 | unsigned int off = skb_network_offset(skb); |
| 105 | struct tc_u_knode *n; | 100 | struct tc_u_knode *n; |
| 106 | int sdepth = 0; | 101 | int sdepth = 0; |
| @@ -157,7 +152,7 @@ check_terminal: | |||
| 157 | 152 | ||
| 158 | *res = n->res; | 153 | *res = n->res; |
| 159 | #ifdef CONFIG_NET_CLS_IND | 154 | #ifdef CONFIG_NET_CLS_IND |
| 160 | if (!tcf_match_indev(skb, n->indev)) { | 155 | if (!tcf_match_indev(skb, n->ifindex)) { |
| 161 | n = n->next; | 156 | n = n->next; |
| 162 | goto next_knode; | 157 | goto next_knode; |
| 163 | } | 158 | } |
| @@ -352,7 +347,7 @@ static int u32_destroy_key(struct tcf_proto *tp, struct tc_u_knode *n) | |||
| 352 | return 0; | 347 | return 0; |
| 353 | } | 348 | } |
| 354 | 349 | ||
| 355 | static int u32_delete_key(struct tcf_proto *tp, struct tc_u_knode* key) | 350 | static int u32_delete_key(struct tcf_proto *tp, struct tc_u_knode *key) |
| 356 | { | 351 | { |
| 357 | struct tc_u_knode **kp; | 352 | struct tc_u_knode **kp; |
| 358 | struct tc_u_hnode *ht = key->ht_up; | 353 | struct tc_u_hnode *ht = key->ht_up; |
| @@ -496,7 +491,8 @@ static int u32_set_parms(struct net *net, struct tcf_proto *tp, | |||
| 496 | int err; | 491 | int err; |
| 497 | struct tcf_exts e; | 492 | struct tcf_exts e; |
| 498 | 493 | ||
| 499 | err = tcf_exts_validate(net, tp, tb, est, &e, &u32_ext_map); | 494 | tcf_exts_init(&e, TCA_U32_ACT, TCA_U32_POLICE); |
| 495 | err = tcf_exts_validate(net, tp, tb, est, &e); | ||
| 500 | if (err < 0) | 496 | if (err < 0) |
| 501 | return err; | 497 | return err; |
| 502 | 498 | ||
| @@ -531,9 +527,11 @@ static int u32_set_parms(struct net *net, struct tcf_proto *tp, | |||
| 531 | 527 | ||
| 532 | #ifdef CONFIG_NET_CLS_IND | 528 | #ifdef CONFIG_NET_CLS_IND |
| 533 | if (tb[TCA_U32_INDEV]) { | 529 | if (tb[TCA_U32_INDEV]) { |
| 534 | err = tcf_change_indev(tp, n->indev, tb[TCA_U32_INDEV]); | 530 | int ret; |
| 535 | if (err < 0) | 531 | ret = tcf_change_indev(net, tb[TCA_U32_INDEV]); |
| 532 | if (ret < 0) | ||
| 536 | goto errout; | 533 | goto errout; |
| 534 | n->ifindex = ret; | ||
| 537 | } | 535 | } |
| 538 | #endif | 536 | #endif |
| 539 | tcf_exts_change(tp, &n->exts, &e); | 537 | tcf_exts_change(tp, &n->exts, &e); |
| @@ -646,6 +644,7 @@ static int u32_change(struct net *net, struct sk_buff *in_skb, | |||
| 646 | n->ht_up = ht; | 644 | n->ht_up = ht; |
| 647 | n->handle = handle; | 645 | n->handle = handle; |
| 648 | n->fshift = s->hmask ? ffs(ntohl(s->hmask)) - 1 : 0; | 646 | n->fshift = s->hmask ? ffs(ntohl(s->hmask)) - 1 : 0; |
| 647 | tcf_exts_init(&n->exts, TCA_U32_ACT, TCA_U32_POLICE); | ||
| 649 | 648 | ||
| 650 | #ifdef CONFIG_CLS_U32_MARK | 649 | #ifdef CONFIG_CLS_U32_MARK |
| 651 | if (tb[TCA_U32_MARK]) { | 650 | if (tb[TCA_U32_MARK]) { |
| @@ -715,7 +714,7 @@ static void u32_walk(struct tcf_proto *tp, struct tcf_walker *arg) | |||
| 715 | } | 714 | } |
| 716 | } | 715 | } |
| 717 | 716 | ||
| 718 | static int u32_dump(struct tcf_proto *tp, unsigned long fh, | 717 | static int u32_dump(struct net *net, struct tcf_proto *tp, unsigned long fh, |
| 719 | struct sk_buff *skb, struct tcmsg *t) | 718 | struct sk_buff *skb, struct tcmsg *t) |
| 720 | { | 719 | { |
| 721 | struct tc_u_knode *n = (struct tc_u_knode *)fh; | 720 | struct tc_u_knode *n = (struct tc_u_knode *)fh; |
| @@ -759,13 +758,16 @@ static int u32_dump(struct tcf_proto *tp, unsigned long fh, | |||
| 759 | goto nla_put_failure; | 758 | goto nla_put_failure; |
| 760 | #endif | 759 | #endif |
| 761 | 760 | ||
| 762 | if (tcf_exts_dump(skb, &n->exts, &u32_ext_map) < 0) | 761 | if (tcf_exts_dump(skb, &n->exts) < 0) |
| 763 | goto nla_put_failure; | 762 | goto nla_put_failure; |
| 764 | 763 | ||
| 765 | #ifdef CONFIG_NET_CLS_IND | 764 | #ifdef CONFIG_NET_CLS_IND |
| 766 | if (strlen(n->indev) && | 765 | if (n->ifindex) { |
| 767 | nla_put_string(skb, TCA_U32_INDEV, n->indev)) | 766 | struct net_device *dev; |
| 768 | goto nla_put_failure; | 767 | dev = __dev_get_by_index(net, n->ifindex); |
| 768 | if (dev && nla_put_string(skb, TCA_U32_INDEV, dev->name)) | ||
| 769 | goto nla_put_failure; | ||
| 770 | } | ||
| 769 | #endif | 771 | #endif |
| 770 | #ifdef CONFIG_CLS_U32_PERF | 772 | #ifdef CONFIG_CLS_U32_PERF |
| 771 | if (nla_put(skb, TCA_U32_PCNT, | 773 | if (nla_put(skb, TCA_U32_PCNT, |
| @@ -778,7 +780,7 @@ static int u32_dump(struct tcf_proto *tp, unsigned long fh, | |||
| 778 | nla_nest_end(skb, nest); | 780 | nla_nest_end(skb, nest); |
| 779 | 781 | ||
| 780 | if (TC_U32_KEY(n->handle)) | 782 | if (TC_U32_KEY(n->handle)) |
| 781 | if (tcf_exts_dump_stats(skb, &n->exts, &u32_ext_map) < 0) | 783 | if (tcf_exts_dump_stats(skb, &n->exts) < 0) |
| 782 | goto nla_put_failure; | 784 | goto nla_put_failure; |
| 783 | return skb->len; | 785 | return skb->len; |
| 784 | 786 | ||
diff --git a/net/sched/em_meta.c b/net/sched/em_meta.c index e5cef9567225..9b8c0b0e60d7 100644 --- a/net/sched/em_meta.c +++ b/net/sched/em_meta.c | |||
| @@ -222,7 +222,7 @@ META_COLLECTOR(int_maclen) | |||
| 222 | 222 | ||
| 223 | META_COLLECTOR(int_rxhash) | 223 | META_COLLECTOR(int_rxhash) |
| 224 | { | 224 | { |
| 225 | dst->value = skb_get_rxhash(skb); | 225 | dst->value = skb_get_hash(skb); |
| 226 | } | 226 | } |
| 227 | 227 | ||
| 228 | /************************************************************************** | 228 | /************************************************************************** |
| @@ -271,40 +271,52 @@ META_COLLECTOR(int_rtiif) | |||
| 271 | * Socket Attributes | 271 | * Socket Attributes |
| 272 | **************************************************************************/ | 272 | **************************************************************************/ |
| 273 | 273 | ||
| 274 | #define SKIP_NONLOCAL(skb) \ | 274 | #define skip_nonlocal(skb) \ |
| 275 | if (unlikely(skb->sk == NULL)) { \ | 275 | (unlikely(skb->sk == NULL)) |
| 276 | *err = -1; \ | ||
| 277 | return; \ | ||
| 278 | } | ||
| 279 | 276 | ||
| 280 | META_COLLECTOR(int_sk_family) | 277 | META_COLLECTOR(int_sk_family) |
| 281 | { | 278 | { |
| 282 | SKIP_NONLOCAL(skb); | 279 | if (skip_nonlocal(skb)) { |
| 280 | *err = -1; | ||
| 281 | return; | ||
| 282 | } | ||
| 283 | dst->value = skb->sk->sk_family; | 283 | dst->value = skb->sk->sk_family; |
| 284 | } | 284 | } |
| 285 | 285 | ||
| 286 | META_COLLECTOR(int_sk_state) | 286 | META_COLLECTOR(int_sk_state) |
| 287 | { | 287 | { |
| 288 | SKIP_NONLOCAL(skb); | 288 | if (skip_nonlocal(skb)) { |
| 289 | *err = -1; | ||
| 290 | return; | ||
| 291 | } | ||
| 289 | dst->value = skb->sk->sk_state; | 292 | dst->value = skb->sk->sk_state; |
| 290 | } | 293 | } |
| 291 | 294 | ||
| 292 | META_COLLECTOR(int_sk_reuse) | 295 | META_COLLECTOR(int_sk_reuse) |
| 293 | { | 296 | { |
| 294 | SKIP_NONLOCAL(skb); | 297 | if (skip_nonlocal(skb)) { |
| 298 | *err = -1; | ||
| 299 | return; | ||
| 300 | } | ||
| 295 | dst->value = skb->sk->sk_reuse; | 301 | dst->value = skb->sk->sk_reuse; |
| 296 | } | 302 | } |
| 297 | 303 | ||
| 298 | META_COLLECTOR(int_sk_bound_if) | 304 | META_COLLECTOR(int_sk_bound_if) |
| 299 | { | 305 | { |
| 300 | SKIP_NONLOCAL(skb); | 306 | if (skip_nonlocal(skb)) { |
| 307 | *err = -1; | ||
| 308 | return; | ||
| 309 | } | ||
| 301 | /* No error if bound_dev_if is 0, legal userspace check */ | 310 | /* No error if bound_dev_if is 0, legal userspace check */ |
| 302 | dst->value = skb->sk->sk_bound_dev_if; | 311 | dst->value = skb->sk->sk_bound_dev_if; |
| 303 | } | 312 | } |
| 304 | 313 | ||
| 305 | META_COLLECTOR(var_sk_bound_if) | 314 | META_COLLECTOR(var_sk_bound_if) |
| 306 | { | 315 | { |
| 307 | SKIP_NONLOCAL(skb); | 316 | if (skip_nonlocal(skb)) { |
| 317 | *err = -1; | ||
| 318 | return; | ||
| 319 | } | ||
| 308 | 320 | ||
| 309 | if (skb->sk->sk_bound_dev_if == 0) { | 321 | if (skb->sk->sk_bound_dev_if == 0) { |
| 310 | dst->value = (unsigned long) "any"; | 322 | dst->value = (unsigned long) "any"; |
| @@ -322,151 +334,226 @@ META_COLLECTOR(var_sk_bound_if) | |||
| 322 | 334 | ||
| 323 | META_COLLECTOR(int_sk_refcnt) | 335 | META_COLLECTOR(int_sk_refcnt) |
| 324 | { | 336 | { |
| 325 | SKIP_NONLOCAL(skb); | 337 | if (skip_nonlocal(skb)) { |
| 338 | *err = -1; | ||
| 339 | return; | ||
| 340 | } | ||
| 326 | dst->value = atomic_read(&skb->sk->sk_refcnt); | 341 | dst->value = atomic_read(&skb->sk->sk_refcnt); |
| 327 | } | 342 | } |
| 328 | 343 | ||
| 329 | META_COLLECTOR(int_sk_rcvbuf) | 344 | META_COLLECTOR(int_sk_rcvbuf) |
| 330 | { | 345 | { |
| 331 | SKIP_NONLOCAL(skb); | 346 | if (skip_nonlocal(skb)) { |
| 347 | *err = -1; | ||
| 348 | return; | ||
| 349 | } | ||
| 332 | dst->value = skb->sk->sk_rcvbuf; | 350 | dst->value = skb->sk->sk_rcvbuf; |
| 333 | } | 351 | } |
| 334 | 352 | ||
| 335 | META_COLLECTOR(int_sk_shutdown) | 353 | META_COLLECTOR(int_sk_shutdown) |
| 336 | { | 354 | { |
| 337 | SKIP_NONLOCAL(skb); | 355 | if (skip_nonlocal(skb)) { |
| 356 | *err = -1; | ||
| 357 | return; | ||
| 358 | } | ||
| 338 | dst->value = skb->sk->sk_shutdown; | 359 | dst->value = skb->sk->sk_shutdown; |
| 339 | } | 360 | } |
| 340 | 361 | ||
| 341 | META_COLLECTOR(int_sk_proto) | 362 | META_COLLECTOR(int_sk_proto) |
| 342 | { | 363 | { |
| 343 | SKIP_NONLOCAL(skb); | 364 | if (skip_nonlocal(skb)) { |
| 365 | *err = -1; | ||
| 366 | return; | ||
| 367 | } | ||
| 344 | dst->value = skb->sk->sk_protocol; | 368 | dst->value = skb->sk->sk_protocol; |
| 345 | } | 369 | } |
| 346 | 370 | ||
| 347 | META_COLLECTOR(int_sk_type) | 371 | META_COLLECTOR(int_sk_type) |
| 348 | { | 372 | { |
| 349 | SKIP_NONLOCAL(skb); | 373 | if (skip_nonlocal(skb)) { |
| 374 | *err = -1; | ||
| 375 | return; | ||
| 376 | } | ||
| 350 | dst->value = skb->sk->sk_type; | 377 | dst->value = skb->sk->sk_type; |
| 351 | } | 378 | } |
| 352 | 379 | ||
| 353 | META_COLLECTOR(int_sk_rmem_alloc) | 380 | META_COLLECTOR(int_sk_rmem_alloc) |
| 354 | { | 381 | { |
| 355 | SKIP_NONLOCAL(skb); | 382 | if (skip_nonlocal(skb)) { |
| 383 | *err = -1; | ||
| 384 | return; | ||
| 385 | } | ||
| 356 | dst->value = sk_rmem_alloc_get(skb->sk); | 386 | dst->value = sk_rmem_alloc_get(skb->sk); |
| 357 | } | 387 | } |
| 358 | 388 | ||
| 359 | META_COLLECTOR(int_sk_wmem_alloc) | 389 | META_COLLECTOR(int_sk_wmem_alloc) |
| 360 | { | 390 | { |
| 361 | SKIP_NONLOCAL(skb); | 391 | if (skip_nonlocal(skb)) { |
| 392 | *err = -1; | ||
| 393 | return; | ||
| 394 | } | ||
| 362 | dst->value = sk_wmem_alloc_get(skb->sk); | 395 | dst->value = sk_wmem_alloc_get(skb->sk); |
| 363 | } | 396 | } |
| 364 | 397 | ||
| 365 | META_COLLECTOR(int_sk_omem_alloc) | 398 | META_COLLECTOR(int_sk_omem_alloc) |
| 366 | { | 399 | { |
| 367 | SKIP_NONLOCAL(skb); | 400 | if (skip_nonlocal(skb)) { |
| 401 | *err = -1; | ||
| 402 | return; | ||
| 403 | } | ||
| 368 | dst->value = atomic_read(&skb->sk->sk_omem_alloc); | 404 | dst->value = atomic_read(&skb->sk->sk_omem_alloc); |
| 369 | } | 405 | } |
| 370 | 406 | ||
| 371 | META_COLLECTOR(int_sk_rcv_qlen) | 407 | META_COLLECTOR(int_sk_rcv_qlen) |
| 372 | { | 408 | { |
| 373 | SKIP_NONLOCAL(skb); | 409 | if (skip_nonlocal(skb)) { |
| 410 | *err = -1; | ||
| 411 | return; | ||
| 412 | } | ||
| 374 | dst->value = skb->sk->sk_receive_queue.qlen; | 413 | dst->value = skb->sk->sk_receive_queue.qlen; |
| 375 | } | 414 | } |
| 376 | 415 | ||
| 377 | META_COLLECTOR(int_sk_snd_qlen) | 416 | META_COLLECTOR(int_sk_snd_qlen) |
| 378 | { | 417 | { |
| 379 | SKIP_NONLOCAL(skb); | 418 | if (skip_nonlocal(skb)) { |
| 419 | *err = -1; | ||
| 420 | return; | ||
| 421 | } | ||
| 380 | dst->value = skb->sk->sk_write_queue.qlen; | 422 | dst->value = skb->sk->sk_write_queue.qlen; |
| 381 | } | 423 | } |
| 382 | 424 | ||
| 383 | META_COLLECTOR(int_sk_wmem_queued) | 425 | META_COLLECTOR(int_sk_wmem_queued) |
| 384 | { | 426 | { |
| 385 | SKIP_NONLOCAL(skb); | 427 | if (skip_nonlocal(skb)) { |
| 428 | *err = -1; | ||
| 429 | return; | ||
| 430 | } | ||
| 386 | dst->value = skb->sk->sk_wmem_queued; | 431 | dst->value = skb->sk->sk_wmem_queued; |
| 387 | } | 432 | } |
| 388 | 433 | ||
| 389 | META_COLLECTOR(int_sk_fwd_alloc) | 434 | META_COLLECTOR(int_sk_fwd_alloc) |
| 390 | { | 435 | { |
| 391 | SKIP_NONLOCAL(skb); | 436 | if (skip_nonlocal(skb)) { |
| 437 | *err = -1; | ||
| 438 | return; | ||
| 439 | } | ||
| 392 | dst->value = skb->sk->sk_forward_alloc; | 440 | dst->value = skb->sk->sk_forward_alloc; |
| 393 | } | 441 | } |
| 394 | 442 | ||
| 395 | META_COLLECTOR(int_sk_sndbuf) | 443 | META_COLLECTOR(int_sk_sndbuf) |
| 396 | { | 444 | { |
| 397 | SKIP_NONLOCAL(skb); | 445 | if (skip_nonlocal(skb)) { |
| 446 | *err = -1; | ||
| 447 | return; | ||
| 448 | } | ||
| 398 | dst->value = skb->sk->sk_sndbuf; | 449 | dst->value = skb->sk->sk_sndbuf; |
| 399 | } | 450 | } |
| 400 | 451 | ||
| 401 | META_COLLECTOR(int_sk_alloc) | 452 | META_COLLECTOR(int_sk_alloc) |
| 402 | { | 453 | { |
| 403 | SKIP_NONLOCAL(skb); | 454 | if (skip_nonlocal(skb)) { |
| 455 | *err = -1; | ||
| 456 | return; | ||
| 457 | } | ||
| 404 | dst->value = (__force int) skb->sk->sk_allocation; | 458 | dst->value = (__force int) skb->sk->sk_allocation; |
| 405 | } | 459 | } |
| 406 | 460 | ||
| 407 | META_COLLECTOR(int_sk_hash) | 461 | META_COLLECTOR(int_sk_hash) |
| 408 | { | 462 | { |
| 409 | SKIP_NONLOCAL(skb); | 463 | if (skip_nonlocal(skb)) { |
| 464 | *err = -1; | ||
| 465 | return; | ||
| 466 | } | ||
| 410 | dst->value = skb->sk->sk_hash; | 467 | dst->value = skb->sk->sk_hash; |
| 411 | } | 468 | } |
| 412 | 469 | ||
| 413 | META_COLLECTOR(int_sk_lingertime) | 470 | META_COLLECTOR(int_sk_lingertime) |
| 414 | { | 471 | { |
| 415 | SKIP_NONLOCAL(skb); | 472 | if (skip_nonlocal(skb)) { |
| 473 | *err = -1; | ||
| 474 | return; | ||
| 475 | } | ||
| 416 | dst->value = skb->sk->sk_lingertime / HZ; | 476 | dst->value = skb->sk->sk_lingertime / HZ; |
| 417 | } | 477 | } |
| 418 | 478 | ||
| 419 | META_COLLECTOR(int_sk_err_qlen) | 479 | META_COLLECTOR(int_sk_err_qlen) |
| 420 | { | 480 | { |
| 421 | SKIP_NONLOCAL(skb); | 481 | if (skip_nonlocal(skb)) { |
| 482 | *err = -1; | ||
| 483 | return; | ||
| 484 | } | ||
| 422 | dst->value = skb->sk->sk_error_queue.qlen; | 485 | dst->value = skb->sk->sk_error_queue.qlen; |
| 423 | } | 486 | } |
| 424 | 487 | ||
| 425 | META_COLLECTOR(int_sk_ack_bl) | 488 | META_COLLECTOR(int_sk_ack_bl) |
| 426 | { | 489 | { |
| 427 | SKIP_NONLOCAL(skb); | 490 | if (skip_nonlocal(skb)) { |
| 491 | *err = -1; | ||
| 492 | return; | ||
| 493 | } | ||
| 428 | dst->value = skb->sk->sk_ack_backlog; | 494 | dst->value = skb->sk->sk_ack_backlog; |
| 429 | } | 495 | } |
| 430 | 496 | ||
| 431 | META_COLLECTOR(int_sk_max_ack_bl) | 497 | META_COLLECTOR(int_sk_max_ack_bl) |
| 432 | { | 498 | { |
| 433 | SKIP_NONLOCAL(skb); | 499 | if (skip_nonlocal(skb)) { |
| 500 | *err = -1; | ||
| 501 | return; | ||
| 502 | } | ||
| 434 | dst->value = skb->sk->sk_max_ack_backlog; | 503 | dst->value = skb->sk->sk_max_ack_backlog; |
| 435 | } | 504 | } |
| 436 | 505 | ||
| 437 | META_COLLECTOR(int_sk_prio) | 506 | META_COLLECTOR(int_sk_prio) |
| 438 | { | 507 | { |
| 439 | SKIP_NONLOCAL(skb); | 508 | if (skip_nonlocal(skb)) { |
| 509 | *err = -1; | ||
| 510 | return; | ||
| 511 | } | ||
| 440 | dst->value = skb->sk->sk_priority; | 512 | dst->value = skb->sk->sk_priority; |
| 441 | } | 513 | } |
| 442 | 514 | ||
| 443 | META_COLLECTOR(int_sk_rcvlowat) | 515 | META_COLLECTOR(int_sk_rcvlowat) |
| 444 | { | 516 | { |
| 445 | SKIP_NONLOCAL(skb); | 517 | if (skip_nonlocal(skb)) { |
| 518 | *err = -1; | ||
| 519 | return; | ||
| 520 | } | ||
| 446 | dst->value = skb->sk->sk_rcvlowat; | 521 | dst->value = skb->sk->sk_rcvlowat; |
| 447 | } | 522 | } |
| 448 | 523 | ||
| 449 | META_COLLECTOR(int_sk_rcvtimeo) | 524 | META_COLLECTOR(int_sk_rcvtimeo) |
| 450 | { | 525 | { |
| 451 | SKIP_NONLOCAL(skb); | 526 | if (skip_nonlocal(skb)) { |
| 527 | *err = -1; | ||
| 528 | return; | ||
| 529 | } | ||
| 452 | dst->value = skb->sk->sk_rcvtimeo / HZ; | 530 | dst->value = skb->sk->sk_rcvtimeo / HZ; |
| 453 | } | 531 | } |
| 454 | 532 | ||
| 455 | META_COLLECTOR(int_sk_sndtimeo) | 533 | META_COLLECTOR(int_sk_sndtimeo) |
| 456 | { | 534 | { |
| 457 | SKIP_NONLOCAL(skb); | 535 | if (skip_nonlocal(skb)) { |
| 536 | *err = -1; | ||
| 537 | return; | ||
| 538 | } | ||
| 458 | dst->value = skb->sk->sk_sndtimeo / HZ; | 539 | dst->value = skb->sk->sk_sndtimeo / HZ; |
| 459 | } | 540 | } |
| 460 | 541 | ||
| 461 | META_COLLECTOR(int_sk_sendmsg_off) | 542 | META_COLLECTOR(int_sk_sendmsg_off) |
| 462 | { | 543 | { |
| 463 | SKIP_NONLOCAL(skb); | 544 | if (skip_nonlocal(skb)) { |
| 545 | *err = -1; | ||
| 546 | return; | ||
| 547 | } | ||
| 464 | dst->value = skb->sk->sk_frag.offset; | 548 | dst->value = skb->sk->sk_frag.offset; |
| 465 | } | 549 | } |
| 466 | 550 | ||
| 467 | META_COLLECTOR(int_sk_write_pend) | 551 | META_COLLECTOR(int_sk_write_pend) |
| 468 | { | 552 | { |
| 469 | SKIP_NONLOCAL(skb); | 553 | if (skip_nonlocal(skb)) { |
| 554 | *err = -1; | ||
| 555 | return; | ||
| 556 | } | ||
| 470 | dst->value = skb->sk->sk_write_pending; | 557 | dst->value = skb->sk->sk_write_pending; |
| 471 | } | 558 | } |
| 472 | 559 | ||
diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index cd81505662b8..1313145e3b86 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c | |||
| @@ -135,7 +135,7 @@ static DEFINE_RWLOCK(qdisc_mod_lock); | |||
| 135 | 135 | ||
| 136 | static struct Qdisc_ops *qdisc_base; | 136 | static struct Qdisc_ops *qdisc_base; |
| 137 | 137 | ||
| 138 | /* Register/uregister queueing discipline */ | 138 | /* Register/unregister queueing discipline */ |
| 139 | 139 | ||
| 140 | int register_qdisc(struct Qdisc_ops *qops) | 140 | int register_qdisc(struct Qdisc_ops *qops) |
| 141 | { | 141 | { |
| @@ -271,11 +271,15 @@ static struct Qdisc *qdisc_match_from_root(struct Qdisc *root, u32 handle) | |||
| 271 | return NULL; | 271 | return NULL; |
| 272 | } | 272 | } |
| 273 | 273 | ||
| 274 | static void qdisc_list_add(struct Qdisc *q) | 274 | void qdisc_list_add(struct Qdisc *q) |
| 275 | { | 275 | { |
| 276 | struct Qdisc *root = qdisc_dev(q)->qdisc; | ||
| 277 | |||
| 278 | WARN_ON_ONCE(root == &noop_qdisc); | ||
| 276 | if ((q->parent != TC_H_ROOT) && !(q->flags & TCQ_F_INGRESS)) | 279 | if ((q->parent != TC_H_ROOT) && !(q->flags & TCQ_F_INGRESS)) |
| 277 | list_add_tail(&q->list, &qdisc_dev(q)->qdisc->list); | 280 | list_add_tail(&q->list, &root->list); |
| 278 | } | 281 | } |
| 282 | EXPORT_SYMBOL(qdisc_list_add); | ||
| 279 | 283 | ||
| 280 | void qdisc_list_del(struct Qdisc *q) | 284 | void qdisc_list_del(struct Qdisc *q) |
| 281 | { | 285 | { |
diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c index 7a42c81a19eb..2f80d01d42a6 100644 --- a/net/sched/sch_cbq.c +++ b/net/sched/sch_cbq.c | |||
| @@ -1058,9 +1058,10 @@ static void cbq_normalize_quanta(struct cbq_sched_data *q, int prio) | |||
| 1058 | cl->quantum = (cl->weight*cl->allot*q->nclasses[prio])/ | 1058 | cl->quantum = (cl->weight*cl->allot*q->nclasses[prio])/ |
| 1059 | q->quanta[prio]; | 1059 | q->quanta[prio]; |
| 1060 | } | 1060 | } |
| 1061 | if (cl->quantum <= 0 || cl->quantum>32*qdisc_dev(cl->qdisc)->mtu) { | 1061 | if (cl->quantum <= 0 || |
| 1062 | pr_warning("CBQ: class %08x has bad quantum==%ld, repaired.\n", | 1062 | cl->quantum > 32*qdisc_dev(cl->qdisc)->mtu) { |
| 1063 | cl->common.classid, cl->quantum); | 1063 | pr_warn("CBQ: class %08x has bad quantum==%ld, repaired.\n", |
| 1064 | cl->common.classid, cl->quantum); | ||
| 1064 | cl->quantum = qdisc_dev(cl->qdisc)->mtu/2 + 1; | 1065 | cl->quantum = qdisc_dev(cl->qdisc)->mtu/2 + 1; |
| 1065 | } | 1066 | } |
| 1066 | } | 1067 | } |
| @@ -1782,8 +1783,7 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t | |||
| 1782 | qdisc_root_sleeping_lock(sch), | 1783 | qdisc_root_sleeping_lock(sch), |
| 1783 | tca[TCA_RATE]); | 1784 | tca[TCA_RATE]); |
| 1784 | if (err) { | 1785 | if (err) { |
| 1785 | if (rtab) | 1786 | qdisc_put_rtab(rtab); |
| 1786 | qdisc_put_rtab(rtab); | ||
| 1787 | return err; | 1787 | return err; |
| 1788 | } | 1788 | } |
| 1789 | } | 1789 | } |
diff --git a/net/sched/sch_choke.c b/net/sched/sch_choke.c index ddd73cb2d7ba..2aee02802c27 100644 --- a/net/sched/sch_choke.c +++ b/net/sched/sch_choke.c | |||
| @@ -14,7 +14,6 @@ | |||
| 14 | #include <linux/types.h> | 14 | #include <linux/types.h> |
| 15 | #include <linux/kernel.h> | 15 | #include <linux/kernel.h> |
| 16 | #include <linux/skbuff.h> | 16 | #include <linux/skbuff.h> |
| 17 | #include <linux/reciprocal_div.h> | ||
| 18 | #include <linux/vmalloc.h> | 17 | #include <linux/vmalloc.h> |
| 19 | #include <net/pkt_sched.h> | 18 | #include <net/pkt_sched.h> |
| 20 | #include <net/inet_ecn.h> | 19 | #include <net/inet_ecn.h> |
| @@ -77,12 +76,6 @@ struct choke_sched_data { | |||
| 77 | struct sk_buff **tab; | 76 | struct sk_buff **tab; |
| 78 | }; | 77 | }; |
| 79 | 78 | ||
| 80 | /* deliver a random number between 0 and N - 1 */ | ||
| 81 | static u32 random_N(unsigned int N) | ||
| 82 | { | ||
| 83 | return reciprocal_divide(prandom_u32(), N); | ||
| 84 | } | ||
| 85 | |||
| 86 | /* number of elements in queue including holes */ | 79 | /* number of elements in queue including holes */ |
| 87 | static unsigned int choke_len(const struct choke_sched_data *q) | 80 | static unsigned int choke_len(const struct choke_sched_data *q) |
| 88 | { | 81 | { |
| @@ -233,7 +226,7 @@ static struct sk_buff *choke_peek_random(const struct choke_sched_data *q, | |||
| 233 | int retrys = 3; | 226 | int retrys = 3; |
| 234 | 227 | ||
| 235 | do { | 228 | do { |
| 236 | *pidx = (q->head + random_N(choke_len(q))) & q->tab_mask; | 229 | *pidx = (q->head + prandom_u32_max(choke_len(q))) & q->tab_mask; |
| 237 | skb = q->tab[*pidx]; | 230 | skb = q->tab[*pidx]; |
| 238 | if (skb) | 231 | if (skb) |
| 239 | return skb; | 232 | return skb; |
diff --git a/net/sched/sch_dsmark.c b/net/sched/sch_dsmark.c index 3886365cc207..49d6ef338b55 100644 --- a/net/sched/sch_dsmark.c +++ b/net/sched/sch_dsmark.c | |||
| @@ -47,7 +47,7 @@ struct dsmark_qdisc_data { | |||
| 47 | 47 | ||
| 48 | static inline int dsmark_valid_index(struct dsmark_qdisc_data *p, u16 index) | 48 | static inline int dsmark_valid_index(struct dsmark_qdisc_data *p, u16 index) |
| 49 | { | 49 | { |
| 50 | return (index <= p->indices && index > 0); | 50 | return index <= p->indices && index > 0; |
| 51 | } | 51 | } |
| 52 | 52 | ||
| 53 | /* ------------------------- Class/flow operations ------------------------- */ | 53 | /* ------------------------- Class/flow operations ------------------------- */ |
| @@ -57,8 +57,8 @@ static int dsmark_graft(struct Qdisc *sch, unsigned long arg, | |||
| 57 | { | 57 | { |
| 58 | struct dsmark_qdisc_data *p = qdisc_priv(sch); | 58 | struct dsmark_qdisc_data *p = qdisc_priv(sch); |
| 59 | 59 | ||
| 60 | pr_debug("dsmark_graft(sch %p,[qdisc %p],new %p,old %p)\n", | 60 | pr_debug("%s(sch %p,[qdisc %p],new %p,old %p)\n", |
| 61 | sch, p, new, old); | 61 | __func__, sch, p, new, old); |
| 62 | 62 | ||
| 63 | if (new == NULL) { | 63 | if (new == NULL) { |
| 64 | new = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops, | 64 | new = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops, |
| @@ -85,8 +85,8 @@ static struct Qdisc *dsmark_leaf(struct Qdisc *sch, unsigned long arg) | |||
| 85 | 85 | ||
| 86 | static unsigned long dsmark_get(struct Qdisc *sch, u32 classid) | 86 | static unsigned long dsmark_get(struct Qdisc *sch, u32 classid) |
| 87 | { | 87 | { |
| 88 | pr_debug("dsmark_get(sch %p,[qdisc %p],classid %x)\n", | 88 | pr_debug("%s(sch %p,[qdisc %p],classid %x)\n", |
| 89 | sch, qdisc_priv(sch), classid); | 89 | __func__, sch, qdisc_priv(sch), classid); |
| 90 | 90 | ||
| 91 | return TC_H_MIN(classid) + 1; | 91 | return TC_H_MIN(classid) + 1; |
| 92 | } | 92 | } |
| @@ -118,8 +118,8 @@ static int dsmark_change(struct Qdisc *sch, u32 classid, u32 parent, | |||
| 118 | int err = -EINVAL; | 118 | int err = -EINVAL; |
| 119 | u8 mask = 0; | 119 | u8 mask = 0; |
| 120 | 120 | ||
| 121 | pr_debug("dsmark_change(sch %p,[qdisc %p],classid %x,parent %x)," | 121 | pr_debug("%s(sch %p,[qdisc %p],classid %x,parent %x), arg 0x%lx\n", |
| 122 | "arg 0x%lx\n", sch, p, classid, parent, *arg); | 122 | __func__, sch, p, classid, parent, *arg); |
| 123 | 123 | ||
| 124 | if (!dsmark_valid_index(p, *arg)) { | 124 | if (!dsmark_valid_index(p, *arg)) { |
| 125 | err = -ENOENT; | 125 | err = -ENOENT; |
| @@ -166,7 +166,8 @@ static void dsmark_walk(struct Qdisc *sch, struct qdisc_walker *walker) | |||
| 166 | struct dsmark_qdisc_data *p = qdisc_priv(sch); | 166 | struct dsmark_qdisc_data *p = qdisc_priv(sch); |
| 167 | int i; | 167 | int i; |
| 168 | 168 | ||
| 169 | pr_debug("dsmark_walk(sch %p,[qdisc %p],walker %p)\n", sch, p, walker); | 169 | pr_debug("%s(sch %p,[qdisc %p],walker %p)\n", |
| 170 | __func__, sch, p, walker); | ||
| 170 | 171 | ||
| 171 | if (walker->stop) | 172 | if (walker->stop) |
| 172 | return; | 173 | return; |
| @@ -199,7 +200,7 @@ static int dsmark_enqueue(struct sk_buff *skb, struct Qdisc *sch) | |||
| 199 | struct dsmark_qdisc_data *p = qdisc_priv(sch); | 200 | struct dsmark_qdisc_data *p = qdisc_priv(sch); |
| 200 | int err; | 201 | int err; |
| 201 | 202 | ||
| 202 | pr_debug("dsmark_enqueue(skb %p,sch %p,[qdisc %p])\n", skb, sch, p); | 203 | pr_debug("%s(skb %p,sch %p,[qdisc %p])\n", __func__, skb, sch, p); |
| 203 | 204 | ||
| 204 | if (p->set_tc_index) { | 205 | if (p->set_tc_index) { |
| 205 | switch (skb->protocol) { | 206 | switch (skb->protocol) { |
| @@ -275,7 +276,7 @@ static struct sk_buff *dsmark_dequeue(struct Qdisc *sch) | |||
| 275 | struct sk_buff *skb; | 276 | struct sk_buff *skb; |
| 276 | u32 index; | 277 | u32 index; |
| 277 | 278 | ||
| 278 | pr_debug("dsmark_dequeue(sch %p,[qdisc %p])\n", sch, p); | 279 | pr_debug("%s(sch %p,[qdisc %p])\n", __func__, sch, p); |
| 279 | 280 | ||
| 280 | skb = p->q->ops->dequeue(p->q); | 281 | skb = p->q->ops->dequeue(p->q); |
| 281 | if (skb == NULL) | 282 | if (skb == NULL) |
| @@ -303,8 +304,8 @@ static struct sk_buff *dsmark_dequeue(struct Qdisc *sch) | |||
| 303 | * and don't need yet another qdisc as a bypass. | 304 | * and don't need yet another qdisc as a bypass. |
| 304 | */ | 305 | */ |
| 305 | if (p->mask[index] != 0xff || p->value[index]) | 306 | if (p->mask[index] != 0xff || p->value[index]) |
| 306 | pr_warning("dsmark_dequeue: unsupported protocol %d\n", | 307 | pr_warn("%s: unsupported protocol %d\n", |
| 307 | ntohs(skb->protocol)); | 308 | __func__, ntohs(skb->protocol)); |
| 308 | break; | 309 | break; |
| 309 | } | 310 | } |
| 310 | 311 | ||
| @@ -315,7 +316,7 @@ static struct sk_buff *dsmark_peek(struct Qdisc *sch) | |||
| 315 | { | 316 | { |
| 316 | struct dsmark_qdisc_data *p = qdisc_priv(sch); | 317 | struct dsmark_qdisc_data *p = qdisc_priv(sch); |
| 317 | 318 | ||
| 318 | pr_debug("dsmark_peek(sch %p,[qdisc %p])\n", sch, p); | 319 | pr_debug("%s(sch %p,[qdisc %p])\n", __func__, sch, p); |
| 319 | 320 | ||
| 320 | return p->q->ops->peek(p->q); | 321 | return p->q->ops->peek(p->q); |
| 321 | } | 322 | } |
| @@ -325,7 +326,7 @@ static unsigned int dsmark_drop(struct Qdisc *sch) | |||
| 325 | struct dsmark_qdisc_data *p = qdisc_priv(sch); | 326 | struct dsmark_qdisc_data *p = qdisc_priv(sch); |
| 326 | unsigned int len; | 327 | unsigned int len; |
| 327 | 328 | ||
| 328 | pr_debug("dsmark_reset(sch %p,[qdisc %p])\n", sch, p); | 329 | pr_debug("%s(sch %p,[qdisc %p])\n", __func__, sch, p); |
| 329 | 330 | ||
| 330 | if (p->q->ops->drop == NULL) | 331 | if (p->q->ops->drop == NULL) |
| 331 | return 0; | 332 | return 0; |
| @@ -346,7 +347,7 @@ static int dsmark_init(struct Qdisc *sch, struct nlattr *opt) | |||
| 346 | u16 indices; | 347 | u16 indices; |
| 347 | u8 *mask; | 348 | u8 *mask; |
| 348 | 349 | ||
| 349 | pr_debug("dsmark_init(sch %p,[qdisc %p],opt %p)\n", sch, p, opt); | 350 | pr_debug("%s(sch %p,[qdisc %p],opt %p)\n", __func__, sch, p, opt); |
| 350 | 351 | ||
| 351 | if (!opt) | 352 | if (!opt) |
| 352 | goto errout; | 353 | goto errout; |
| @@ -384,7 +385,7 @@ static int dsmark_init(struct Qdisc *sch, struct nlattr *opt) | |||
| 384 | if (p->q == NULL) | 385 | if (p->q == NULL) |
| 385 | p->q = &noop_qdisc; | 386 | p->q = &noop_qdisc; |
| 386 | 387 | ||
| 387 | pr_debug("dsmark_init: qdisc %p\n", p->q); | 388 | pr_debug("%s: qdisc %p\n", __func__, p->q); |
| 388 | 389 | ||
| 389 | err = 0; | 390 | err = 0; |
| 390 | errout: | 391 | errout: |
| @@ -395,7 +396,7 @@ static void dsmark_reset(struct Qdisc *sch) | |||
| 395 | { | 396 | { |
| 396 | struct dsmark_qdisc_data *p = qdisc_priv(sch); | 397 | struct dsmark_qdisc_data *p = qdisc_priv(sch); |
| 397 | 398 | ||
| 398 | pr_debug("dsmark_reset(sch %p,[qdisc %p])\n", sch, p); | 399 | pr_debug("%s(sch %p,[qdisc %p])\n", __func__, sch, p); |
| 399 | qdisc_reset(p->q); | 400 | qdisc_reset(p->q); |
| 400 | sch->q.qlen = 0; | 401 | sch->q.qlen = 0; |
| 401 | } | 402 | } |
| @@ -404,7 +405,7 @@ static void dsmark_destroy(struct Qdisc *sch) | |||
| 404 | { | 405 | { |
| 405 | struct dsmark_qdisc_data *p = qdisc_priv(sch); | 406 | struct dsmark_qdisc_data *p = qdisc_priv(sch); |
| 406 | 407 | ||
| 407 | pr_debug("dsmark_destroy(sch %p,[qdisc %p])\n", sch, p); | 408 | pr_debug("%s(sch %p,[qdisc %p])\n", __func__, sch, p); |
| 408 | 409 | ||
| 409 | tcf_destroy_chain(&p->filter_list); | 410 | tcf_destroy_chain(&p->filter_list); |
| 410 | qdisc_destroy(p->q); | 411 | qdisc_destroy(p->q); |
| @@ -417,7 +418,7 @@ static int dsmark_dump_class(struct Qdisc *sch, unsigned long cl, | |||
| 417 | struct dsmark_qdisc_data *p = qdisc_priv(sch); | 418 | struct dsmark_qdisc_data *p = qdisc_priv(sch); |
| 418 | struct nlattr *opts = NULL; | 419 | struct nlattr *opts = NULL; |
| 419 | 420 | ||
| 420 | pr_debug("dsmark_dump_class(sch %p,[qdisc %p],class %ld\n", sch, p, cl); | 421 | pr_debug("%s(sch %p,[qdisc %p],class %ld\n", __func__, sch, p, cl); |
| 421 | 422 | ||
| 422 | if (!dsmark_valid_index(p, cl)) | 423 | if (!dsmark_valid_index(p, cl)) |
| 423 | return -EINVAL; | 424 | return -EINVAL; |
diff --git a/net/sched/sch_fq.c b/net/sched/sch_fq.c index 95d843961907..08ef7a42c0e4 100644 --- a/net/sched/sch_fq.c +++ b/net/sched/sch_fq.c | |||
| @@ -47,6 +47,7 @@ | |||
| 47 | #include <linux/rbtree.h> | 47 | #include <linux/rbtree.h> |
| 48 | #include <linux/hash.h> | 48 | #include <linux/hash.h> |
| 49 | #include <linux/prefetch.h> | 49 | #include <linux/prefetch.h> |
| 50 | #include <linux/vmalloc.h> | ||
| 50 | #include <net/netlink.h> | 51 | #include <net/netlink.h> |
| 51 | #include <net/pkt_sched.h> | 52 | #include <net/pkt_sched.h> |
| 52 | #include <net/sock.h> | 53 | #include <net/sock.h> |
| @@ -225,7 +226,7 @@ static struct fq_flow *fq_classify(struct sk_buff *skb, struct fq_sched_data *q) | |||
| 225 | /* By forcing low order bit to 1, we make sure to not | 226 | /* By forcing low order bit to 1, we make sure to not |
| 226 | * collide with a local flow (socket pointers are word aligned) | 227 | * collide with a local flow (socket pointers are word aligned) |
| 227 | */ | 228 | */ |
| 228 | sk = (struct sock *)(skb_get_rxhash(skb) | 1L); | 229 | sk = (struct sock *)(skb_get_hash(skb) | 1L); |
| 229 | } | 230 | } |
| 230 | 231 | ||
| 231 | root = &q->fq_root[hash_32((u32)(long)sk, q->fq_trees_log)]; | 232 | root = &q->fq_root[hash_32((u32)(long)sk, q->fq_trees_log)]; |
| @@ -578,15 +579,36 @@ static void fq_rehash(struct fq_sched_data *q, | |||
| 578 | q->stat_gc_flows += fcnt; | 579 | q->stat_gc_flows += fcnt; |
| 579 | } | 580 | } |
| 580 | 581 | ||
| 581 | static int fq_resize(struct fq_sched_data *q, u32 log) | 582 | static void *fq_alloc_node(size_t sz, int node) |
| 582 | { | 583 | { |
| 584 | void *ptr; | ||
| 585 | |||
| 586 | ptr = kmalloc_node(sz, GFP_KERNEL | __GFP_REPEAT | __GFP_NOWARN, node); | ||
| 587 | if (!ptr) | ||
| 588 | ptr = vmalloc_node(sz, node); | ||
| 589 | return ptr; | ||
| 590 | } | ||
| 591 | |||
| 592 | static void fq_free(void *addr) | ||
| 593 | { | ||
| 594 | if (addr && is_vmalloc_addr(addr)) | ||
| 595 | vfree(addr); | ||
| 596 | else | ||
| 597 | kfree(addr); | ||
| 598 | } | ||
| 599 | |||
| 600 | static int fq_resize(struct Qdisc *sch, u32 log) | ||
| 601 | { | ||
| 602 | struct fq_sched_data *q = qdisc_priv(sch); | ||
| 583 | struct rb_root *array; | 603 | struct rb_root *array; |
| 584 | u32 idx; | 604 | u32 idx; |
| 585 | 605 | ||
| 586 | if (q->fq_root && log == q->fq_trees_log) | 606 | if (q->fq_root && log == q->fq_trees_log) |
| 587 | return 0; | 607 | return 0; |
| 588 | 608 | ||
| 589 | array = kmalloc(sizeof(struct rb_root) << log, GFP_KERNEL); | 609 | /* If XPS was setup, we can allocate memory on right NUMA node */ |
| 610 | array = fq_alloc_node(sizeof(struct rb_root) << log, | ||
| 611 | netdev_queue_numa_node_read(sch->dev_queue)); | ||
| 590 | if (!array) | 612 | if (!array) |
| 591 | return -ENOMEM; | 613 | return -ENOMEM; |
| 592 | 614 | ||
| @@ -595,7 +617,7 @@ static int fq_resize(struct fq_sched_data *q, u32 log) | |||
| 595 | 617 | ||
| 596 | if (q->fq_root) { | 618 | if (q->fq_root) { |
| 597 | fq_rehash(q, q->fq_root, q->fq_trees_log, array, log); | 619 | fq_rehash(q, q->fq_root, q->fq_trees_log, array, log); |
| 598 | kfree(q->fq_root); | 620 | fq_free(q->fq_root); |
| 599 | } | 621 | } |
| 600 | q->fq_root = array; | 622 | q->fq_root = array; |
| 601 | q->fq_trees_log = log; | 623 | q->fq_trees_log = log; |
| @@ -676,7 +698,7 @@ static int fq_change(struct Qdisc *sch, struct nlattr *opt) | |||
| 676 | } | 698 | } |
| 677 | 699 | ||
| 678 | if (!err) | 700 | if (!err) |
| 679 | err = fq_resize(q, fq_log); | 701 | err = fq_resize(sch, fq_log); |
| 680 | 702 | ||
| 681 | while (sch->q.qlen > sch->limit) { | 703 | while (sch->q.qlen > sch->limit) { |
| 682 | struct sk_buff *skb = fq_dequeue(sch); | 704 | struct sk_buff *skb = fq_dequeue(sch); |
| @@ -697,7 +719,7 @@ static void fq_destroy(struct Qdisc *sch) | |||
| 697 | struct fq_sched_data *q = qdisc_priv(sch); | 719 | struct fq_sched_data *q = qdisc_priv(sch); |
| 698 | 720 | ||
| 699 | fq_reset(sch); | 721 | fq_reset(sch); |
| 700 | kfree(q->fq_root); | 722 | fq_free(q->fq_root); |
| 701 | qdisc_watchdog_cancel(&q->watchdog); | 723 | qdisc_watchdog_cancel(&q->watchdog); |
| 702 | } | 724 | } |
| 703 | 725 | ||
| @@ -723,7 +745,7 @@ static int fq_init(struct Qdisc *sch, struct nlattr *opt) | |||
| 723 | if (opt) | 745 | if (opt) |
| 724 | err = fq_change(sch, opt); | 746 | err = fq_change(sch, opt); |
| 725 | else | 747 | else |
| 726 | err = fq_resize(q, q->fq_trees_log); | 748 | err = fq_resize(sch, q->fq_trees_log); |
| 727 | 749 | ||
| 728 | return err; | 750 | return err; |
| 729 | } | 751 | } |
diff --git a/net/sched/sch_fq_codel.c b/net/sched/sch_fq_codel.c index 55786283a3df..ba5bc929eac7 100644 --- a/net/sched/sch_fq_codel.c +++ b/net/sched/sch_fq_codel.c | |||
| @@ -390,7 +390,7 @@ static int fq_codel_init(struct Qdisc *sch, struct nlattr *opt) | |||
| 390 | sch->limit = 10*1024; | 390 | sch->limit = 10*1024; |
| 391 | q->flows_cnt = 1024; | 391 | q->flows_cnt = 1024; |
| 392 | q->quantum = psched_mtu(qdisc_dev(sch)); | 392 | q->quantum = psched_mtu(qdisc_dev(sch)); |
| 393 | q->perturbation = net_random(); | 393 | q->perturbation = prandom_u32(); |
| 394 | INIT_LIST_HEAD(&q->new_flows); | 394 | INIT_LIST_HEAD(&q->new_flows); |
| 395 | INIT_LIST_HEAD(&q->old_flows); | 395 | INIT_LIST_HEAD(&q->old_flows); |
| 396 | codel_params_init(&q->cparams); | 396 | codel_params_init(&q->cparams); |
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index 7fc899a943a8..e82e43b69c33 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c | |||
| @@ -338,13 +338,13 @@ EXPORT_SYMBOL(netif_carrier_off); | |||
| 338 | cheaper. | 338 | cheaper. |
| 339 | */ | 339 | */ |
| 340 | 340 | ||
| 341 | static int noop_enqueue(struct sk_buff *skb, struct Qdisc * qdisc) | 341 | static int noop_enqueue(struct sk_buff *skb, struct Qdisc *qdisc) |
| 342 | { | 342 | { |
| 343 | kfree_skb(skb); | 343 | kfree_skb(skb); |
| 344 | return NET_XMIT_CN; | 344 | return NET_XMIT_CN; |
| 345 | } | 345 | } |
| 346 | 346 | ||
| 347 | static struct sk_buff *noop_dequeue(struct Qdisc * qdisc) | 347 | static struct sk_buff *noop_dequeue(struct Qdisc *qdisc) |
| 348 | { | 348 | { |
| 349 | return NULL; | 349 | return NULL; |
| 350 | } | 350 | } |
| @@ -718,8 +718,8 @@ static void attach_default_qdiscs(struct net_device *dev) | |||
| 718 | } else { | 718 | } else { |
| 719 | qdisc = qdisc_create_dflt(txq, &mq_qdisc_ops, TC_H_ROOT); | 719 | qdisc = qdisc_create_dflt(txq, &mq_qdisc_ops, TC_H_ROOT); |
| 720 | if (qdisc) { | 720 | if (qdisc) { |
| 721 | qdisc->ops->attach(qdisc); | ||
| 722 | dev->qdisc = qdisc; | 721 | dev->qdisc = qdisc; |
| 722 | qdisc->ops->attach(qdisc); | ||
| 723 | } | 723 | } |
| 724 | } | 724 | } |
| 725 | } | 725 | } |
diff --git a/net/sched/sch_gred.c b/net/sched/sch_gred.c index d42234c0f13b..12cbc09157fc 100644 --- a/net/sched/sch_gred.c +++ b/net/sched/sch_gred.c | |||
| @@ -370,8 +370,8 @@ static inline int gred_change_table_def(struct Qdisc *sch, struct nlattr *dps) | |||
| 370 | 370 | ||
| 371 | for (i = table->DPs; i < MAX_DPs; i++) { | 371 | for (i = table->DPs; i < MAX_DPs; i++) { |
| 372 | if (table->tab[i]) { | 372 | if (table->tab[i]) { |
| 373 | pr_warning("GRED: Warning: Destroying " | 373 | pr_warn("GRED: Warning: Destroying shadowed VQ 0x%x\n", |
| 374 | "shadowed VQ 0x%x\n", i); | 374 | i); |
| 375 | gred_destroy_vq(table->tab[i]); | 375 | gred_destroy_vq(table->tab[i]); |
| 376 | table->tab[i] = NULL; | 376 | table->tab[i] = NULL; |
| 377 | } | 377 | } |
diff --git a/net/sched/sch_hhf.c b/net/sched/sch_hhf.c new file mode 100644 index 000000000000..647680b1c625 --- /dev/null +++ b/net/sched/sch_hhf.c | |||
| @@ -0,0 +1,745 @@ | |||
| 1 | /* net/sched/sch_hhf.c Heavy-Hitter Filter (HHF) | ||
| 2 | * | ||
| 3 | * Copyright (C) 2013 Terry Lam <vtlam@google.com> | ||
| 4 | * Copyright (C) 2013 Nandita Dukkipati <nanditad@google.com> | ||
| 5 | */ | ||
| 6 | |||
| 7 | #include <linux/jhash.h> | ||
| 8 | #include <linux/jiffies.h> | ||
| 9 | #include <linux/module.h> | ||
| 10 | #include <linux/skbuff.h> | ||
| 11 | #include <linux/vmalloc.h> | ||
| 12 | #include <net/flow_keys.h> | ||
| 13 | #include <net/pkt_sched.h> | ||
| 14 | #include <net/sock.h> | ||
| 15 | |||
| 16 | /* Heavy-Hitter Filter (HHF) | ||
| 17 | * | ||
| 18 | * Principles : | ||
| 19 | * Flows are classified into two buckets: non-heavy-hitter and heavy-hitter | ||
| 20 | * buckets. Initially, a new flow starts as non-heavy-hitter. Once classified | ||
| 21 | * as heavy-hitter, it is immediately switched to the heavy-hitter bucket. | ||
| 22 | * The buckets are dequeued by a Weighted Deficit Round Robin (WDRR) scheduler, | ||
| 23 | * in which the heavy-hitter bucket is served with less weight. | ||
| 24 | * In other words, non-heavy-hitters (e.g., short bursts of critical traffic) | ||
| 25 | * are isolated from heavy-hitters (e.g., persistent bulk traffic) and also have | ||
| 26 | * higher share of bandwidth. | ||
| 27 | * | ||
| 28 | * To capture heavy-hitters, we use the "multi-stage filter" algorithm in the | ||
| 29 | * following paper: | ||
| 30 | * [EV02] C. Estan and G. Varghese, "New Directions in Traffic Measurement and | ||
| 31 | * Accounting", in ACM SIGCOMM, 2002. | ||
| 32 | * | ||
| 33 | * Conceptually, a multi-stage filter comprises k independent hash functions | ||
| 34 | * and k counter arrays. Packets are indexed into k counter arrays by k hash | ||
| 35 | * functions, respectively. The counters are then increased by the packet sizes. | ||
| 36 | * Therefore, | ||
| 37 | * - For a heavy-hitter flow: *all* of its k array counters must be large. | ||
| 38 | * - For a non-heavy-hitter flow: some of its k array counters can be large | ||
| 39 | * due to hash collision with other small flows; however, with high | ||
| 40 | * probability, not *all* k counters are large. | ||
| 41 | * | ||
| 42 | * By the design of the multi-stage filter algorithm, the false negative rate | ||
| 43 | * (heavy-hitters getting away uncaptured) is zero. However, the algorithm is | ||
| 44 | * susceptible to false positives (non-heavy-hitters mistakenly classified as | ||
| 45 | * heavy-hitters). | ||
| 46 | * Therefore, we also implement the following optimizations to reduce false | ||
| 47 | * positives by avoiding unnecessary increment of the counter values: | ||
| 48 | * - Optimization O1: once a heavy-hitter is identified, its bytes are not | ||
| 49 | * accounted in the array counters. This technique is called "shielding" | ||
| 50 | * in Section 3.3.1 of [EV02]. | ||
| 51 | * - Optimization O2: conservative update of counters | ||
| 52 | * (Section 3.3.2 of [EV02]), | ||
| 53 | * New counter value = max {old counter value, | ||
| 54 | * smallest counter value + packet bytes} | ||
| 55 | * | ||
| 56 | * Finally, we refresh the counters periodically since otherwise the counter | ||
| 57 | * values will keep accumulating. | ||
| 58 | * | ||
| 59 | * Once a flow is classified as heavy-hitter, we also save its per-flow state | ||
| 60 | * in an exact-matching flow table so that its subsequent packets can be | ||
| 61 | * dispatched to the heavy-hitter bucket accordingly. | ||
| 62 | * | ||
| 63 | * | ||
| 64 | * At a high level, this qdisc works as follows: | ||
| 65 | * Given a packet p: | ||
| 66 | * - If the flow-id of p (e.g., TCP 5-tuple) is already in the exact-matching | ||
| 67 | * heavy-hitter flow table, denoted table T, then send p to the heavy-hitter | ||
| 68 | * bucket. | ||
| 69 | * - Otherwise, forward p to the multi-stage filter, denoted filter F | ||
| 70 | * + If F decides that p belongs to a non-heavy-hitter flow, then send p | ||
| 71 | * to the non-heavy-hitter bucket. | ||
| 72 | * + Otherwise, if F decides that p belongs to a new heavy-hitter flow, | ||
| 73 | * then set up a new flow entry for the flow-id of p in the table T and | ||
| 74 | * send p to the heavy-hitter bucket. | ||
| 75 | * | ||
| 76 | * In this implementation: | ||
| 77 | * - T is a fixed-size hash-table with 1024 entries. Hash collision is | ||
| 78 | * resolved by linked-list chaining. | ||
| 79 | * - F has four counter arrays, each array containing 1024 32-bit counters. | ||
| 80 | * That means 4 * 1024 * 32 bits = 16KB of memory. | ||
| 81 | * - Since each array in F contains 1024 counters, 10 bits are sufficient to | ||
| 82 | * index into each array. | ||
| 83 | * Hence, instead of having four hash functions, we chop the 32-bit | ||
| 84 | * skb-hash into three 10-bit chunks, and the remaining 10-bit chunk is | ||
| 85 | * computed as XOR sum of those three chunks. | ||
| 86 | * - We need to clear the counter arrays periodically; however, directly | ||
| 87 | * memsetting 16KB of memory can lead to cache eviction and unwanted delay. | ||
| 88 | * So by representing each counter by a valid bit, we only need to reset | ||
| 89 | * 4K of 1 bit (i.e. 512 bytes) instead of 16KB of memory. | ||
| 90 | * - The Deficit Round Robin engine is taken from fq_codel implementation | ||
| 91 | * (net/sched/sch_fq_codel.c). Note that wdrr_bucket corresponds to | ||
| 92 | * fq_codel_flow in fq_codel implementation. | ||
| 93 | * | ||
| 94 | */ | ||
| 95 | |||
| 96 | /* Non-configurable parameters */ | ||
| 97 | #define HH_FLOWS_CNT 1024 /* number of entries in exact-matching table T */ | ||
| 98 | #define HHF_ARRAYS_CNT 4 /* number of arrays in multi-stage filter F */ | ||
| 99 | #define HHF_ARRAYS_LEN 1024 /* number of counters in each array of F */ | ||
| 100 | #define HHF_BIT_MASK_LEN 10 /* masking 10 bits */ | ||
| 101 | #define HHF_BIT_MASK 0x3FF /* bitmask of 10 bits */ | ||
| 102 | |||
| 103 | #define WDRR_BUCKET_CNT 2 /* two buckets for Weighted DRR */ | ||
| 104 | enum wdrr_bucket_idx { | ||
| 105 | WDRR_BUCKET_FOR_HH = 0, /* bucket id for heavy-hitters */ | ||
| 106 | WDRR_BUCKET_FOR_NON_HH = 1 /* bucket id for non-heavy-hitters */ | ||
| 107 | }; | ||
| 108 | |||
| 109 | #define hhf_time_before(a, b) \ | ||
| 110 | (typecheck(u32, a) && typecheck(u32, b) && ((s32)((a) - (b)) < 0)) | ||
| 111 | |||
| 112 | /* Heavy-hitter per-flow state */ | ||
| 113 | struct hh_flow_state { | ||
| 114 | u32 hash_id; /* hash of flow-id (e.g. TCP 5-tuple) */ | ||
| 115 | u32 hit_timestamp; /* last time heavy-hitter was seen */ | ||
| 116 | struct list_head flowchain; /* chaining under hash collision */ | ||
| 117 | }; | ||
| 118 | |||
| 119 | /* Weighted Deficit Round Robin (WDRR) scheduler */ | ||
| 120 | struct wdrr_bucket { | ||
| 121 | struct sk_buff *head; | ||
| 122 | struct sk_buff *tail; | ||
| 123 | struct list_head bucketchain; | ||
| 124 | int deficit; | ||
| 125 | }; | ||
| 126 | |||
| 127 | struct hhf_sched_data { | ||
| 128 | struct wdrr_bucket buckets[WDRR_BUCKET_CNT]; | ||
| 129 | u32 perturbation; /* hash perturbation */ | ||
| 130 | u32 quantum; /* psched_mtu(qdisc_dev(sch)); */ | ||
| 131 | u32 drop_overlimit; /* number of times max qdisc packet | ||
| 132 | * limit was hit | ||
| 133 | */ | ||
| 134 | struct list_head *hh_flows; /* table T (currently active HHs) */ | ||
| 135 | u32 hh_flows_limit; /* max active HH allocs */ | ||
| 136 | u32 hh_flows_overlimit; /* num of disallowed HH allocs */ | ||
| 137 | u32 hh_flows_total_cnt; /* total admitted HHs */ | ||
| 138 | u32 hh_flows_current_cnt; /* total current HHs */ | ||
| 139 | u32 *hhf_arrays[HHF_ARRAYS_CNT]; /* HH filter F */ | ||
| 140 | u32 hhf_arrays_reset_timestamp; /* last time hhf_arrays | ||
| 141 | * was reset | ||
| 142 | */ | ||
| 143 | unsigned long *hhf_valid_bits[HHF_ARRAYS_CNT]; /* shadow valid bits | ||
| 144 | * of hhf_arrays | ||
| 145 | */ | ||
| 146 | /* Similar to the "new_flows" vs. "old_flows" concept in fq_codel DRR */ | ||
| 147 | struct list_head new_buckets; /* list of new buckets */ | ||
| 148 | struct list_head old_buckets; /* list of old buckets */ | ||
| 149 | |||
| 150 | /* Configurable HHF parameters */ | ||
| 151 | u32 hhf_reset_timeout; /* interval to reset counter | ||
| 152 | * arrays in filter F | ||
| 153 | * (default 40ms) | ||
| 154 | */ | ||
| 155 | u32 hhf_admit_bytes; /* counter thresh to classify as | ||
| 156 | * HH (default 128KB). | ||
| 157 | * With these default values, | ||
| 158 | * 128KB / 40ms = 25 Mbps | ||
| 159 | * i.e., we expect to capture HHs | ||
| 160 | * sending > 25 Mbps. | ||
| 161 | */ | ||
| 162 | u32 hhf_evict_timeout; /* aging threshold to evict idle | ||
| 163 | * HHs out of table T. This should | ||
| 164 | * be large enough to avoid | ||
| 165 | * reordering during HH eviction. | ||
| 166 | * (default 1s) | ||
| 167 | */ | ||
| 168 | u32 hhf_non_hh_weight; /* WDRR weight for non-HHs | ||
| 169 | * (default 2, | ||
| 170 | * i.e., non-HH : HH = 2 : 1) | ||
| 171 | */ | ||
| 172 | }; | ||
| 173 | |||
| 174 | static u32 hhf_time_stamp(void) | ||
| 175 | { | ||
| 176 | return jiffies; | ||
| 177 | } | ||
| 178 | |||
| 179 | static unsigned int skb_hash(const struct hhf_sched_data *q, | ||
| 180 | const struct sk_buff *skb) | ||
| 181 | { | ||
| 182 | struct flow_keys keys; | ||
| 183 | unsigned int hash; | ||
| 184 | |||
| 185 | if (skb->sk && skb->sk->sk_hash) | ||
| 186 | return skb->sk->sk_hash; | ||
| 187 | |||
| 188 | skb_flow_dissect(skb, &keys); | ||
| 189 | hash = jhash_3words((__force u32)keys.dst, | ||
| 190 | (__force u32)keys.src ^ keys.ip_proto, | ||
| 191 | (__force u32)keys.ports, q->perturbation); | ||
| 192 | return hash; | ||
| 193 | } | ||
| 194 | |||
| 195 | /* Looks up a heavy-hitter flow in a chaining list of table T. */ | ||
| 196 | static struct hh_flow_state *seek_list(const u32 hash, | ||
| 197 | struct list_head *head, | ||
| 198 | struct hhf_sched_data *q) | ||
| 199 | { | ||
| 200 | struct hh_flow_state *flow, *next; | ||
| 201 | u32 now = hhf_time_stamp(); | ||
| 202 | |||
| 203 | if (list_empty(head)) | ||
| 204 | return NULL; | ||
| 205 | |||
| 206 | list_for_each_entry_safe(flow, next, head, flowchain) { | ||
| 207 | u32 prev = flow->hit_timestamp + q->hhf_evict_timeout; | ||
| 208 | |||
| 209 | if (hhf_time_before(prev, now)) { | ||
| 210 | /* Delete expired heavy-hitters, but preserve one entry | ||
| 211 | * to avoid kzalloc() when next time this slot is hit. | ||
| 212 | */ | ||
| 213 | if (list_is_last(&flow->flowchain, head)) | ||
| 214 | return NULL; | ||
| 215 | list_del(&flow->flowchain); | ||
| 216 | kfree(flow); | ||
| 217 | q->hh_flows_current_cnt--; | ||
| 218 | } else if (flow->hash_id == hash) { | ||
| 219 | return flow; | ||
| 220 | } | ||
| 221 | } | ||
| 222 | return NULL; | ||
| 223 | } | ||
| 224 | |||
| 225 | /* Returns a flow state entry for a new heavy-hitter. Either reuses an expired | ||
| 226 | * entry or dynamically alloc a new entry. | ||
| 227 | */ | ||
| 228 | static struct hh_flow_state *alloc_new_hh(struct list_head *head, | ||
| 229 | struct hhf_sched_data *q) | ||
| 230 | { | ||
| 231 | struct hh_flow_state *flow; | ||
| 232 | u32 now = hhf_time_stamp(); | ||
| 233 | |||
| 234 | if (!list_empty(head)) { | ||
| 235 | /* Find an expired heavy-hitter flow entry. */ | ||
| 236 | list_for_each_entry(flow, head, flowchain) { | ||
| 237 | u32 prev = flow->hit_timestamp + q->hhf_evict_timeout; | ||
| 238 | |||
| 239 | if (hhf_time_before(prev, now)) | ||
| 240 | return flow; | ||
| 241 | } | ||
| 242 | } | ||
| 243 | |||
| 244 | if (q->hh_flows_current_cnt >= q->hh_flows_limit) { | ||
| 245 | q->hh_flows_overlimit++; | ||
| 246 | return NULL; | ||
| 247 | } | ||
| 248 | /* Create new entry. */ | ||
| 249 | flow = kzalloc(sizeof(struct hh_flow_state), GFP_ATOMIC); | ||
| 250 | if (!flow) | ||
| 251 | return NULL; | ||
| 252 | |||
| 253 | q->hh_flows_current_cnt++; | ||
| 254 | INIT_LIST_HEAD(&flow->flowchain); | ||
| 255 | list_add_tail(&flow->flowchain, head); | ||
| 256 | |||
| 257 | return flow; | ||
| 258 | } | ||
| 259 | |||
| 260 | /* Assigns packets to WDRR buckets. Implements a multi-stage filter to | ||
| 261 | * classify heavy-hitters. | ||
| 262 | */ | ||
| 263 | static enum wdrr_bucket_idx hhf_classify(struct sk_buff *skb, struct Qdisc *sch) | ||
| 264 | { | ||
| 265 | struct hhf_sched_data *q = qdisc_priv(sch); | ||
| 266 | u32 tmp_hash, hash; | ||
| 267 | u32 xorsum, filter_pos[HHF_ARRAYS_CNT], flow_pos; | ||
| 268 | struct hh_flow_state *flow; | ||
| 269 | u32 pkt_len, min_hhf_val; | ||
| 270 | int i; | ||
| 271 | u32 prev; | ||
| 272 | u32 now = hhf_time_stamp(); | ||
| 273 | |||
| 274 | /* Reset the HHF counter arrays if this is the right time. */ | ||
| 275 | prev = q->hhf_arrays_reset_timestamp + q->hhf_reset_timeout; | ||
| 276 | if (hhf_time_before(prev, now)) { | ||
| 277 | for (i = 0; i < HHF_ARRAYS_CNT; i++) | ||
| 278 | bitmap_zero(q->hhf_valid_bits[i], HHF_ARRAYS_LEN); | ||
| 279 | q->hhf_arrays_reset_timestamp = now; | ||
| 280 | } | ||
| 281 | |||
| 282 | /* Get hashed flow-id of the skb. */ | ||
| 283 | hash = skb_hash(q, skb); | ||
| 284 | |||
| 285 | /* Check if this packet belongs to an already established HH flow. */ | ||
| 286 | flow_pos = hash & HHF_BIT_MASK; | ||
| 287 | flow = seek_list(hash, &q->hh_flows[flow_pos], q); | ||
| 288 | if (flow) { /* found its HH flow */ | ||
| 289 | flow->hit_timestamp = now; | ||
| 290 | return WDRR_BUCKET_FOR_HH; | ||
| 291 | } | ||
| 292 | |||
| 293 | /* Now pass the packet through the multi-stage filter. */ | ||
| 294 | tmp_hash = hash; | ||
| 295 | xorsum = 0; | ||
| 296 | for (i = 0; i < HHF_ARRAYS_CNT - 1; i++) { | ||
| 297 | /* Split the skb_hash into three 10-bit chunks. */ | ||
| 298 | filter_pos[i] = tmp_hash & HHF_BIT_MASK; | ||
| 299 | xorsum ^= filter_pos[i]; | ||
| 300 | tmp_hash >>= HHF_BIT_MASK_LEN; | ||
| 301 | } | ||
| 302 | /* The last chunk is computed as XOR sum of other chunks. */ | ||
| 303 | filter_pos[HHF_ARRAYS_CNT - 1] = xorsum ^ tmp_hash; | ||
| 304 | |||
| 305 | pkt_len = qdisc_pkt_len(skb); | ||
| 306 | min_hhf_val = ~0U; | ||
| 307 | for (i = 0; i < HHF_ARRAYS_CNT; i++) { | ||
| 308 | u32 val; | ||
| 309 | |||
| 310 | if (!test_bit(filter_pos[i], q->hhf_valid_bits[i])) { | ||
| 311 | q->hhf_arrays[i][filter_pos[i]] = 0; | ||
| 312 | __set_bit(filter_pos[i], q->hhf_valid_bits[i]); | ||
| 313 | } | ||
| 314 | |||
| 315 | val = q->hhf_arrays[i][filter_pos[i]] + pkt_len; | ||
| 316 | if (min_hhf_val > val) | ||
| 317 | min_hhf_val = val; | ||
| 318 | } | ||
| 319 | |||
| 320 | /* Found a new HH iff all counter values > HH admit threshold. */ | ||
| 321 | if (min_hhf_val > q->hhf_admit_bytes) { | ||
| 322 | /* Just captured a new heavy-hitter. */ | ||
| 323 | flow = alloc_new_hh(&q->hh_flows[flow_pos], q); | ||
| 324 | if (!flow) /* memory alloc problem */ | ||
| 325 | return WDRR_BUCKET_FOR_NON_HH; | ||
| 326 | flow->hash_id = hash; | ||
| 327 | flow->hit_timestamp = now; | ||
| 328 | q->hh_flows_total_cnt++; | ||
| 329 | |||
| 330 | /* By returning without updating counters in q->hhf_arrays, | ||
| 331 | * we implicitly implement "shielding" (see Optimization O1). | ||
| 332 | */ | ||
| 333 | return WDRR_BUCKET_FOR_HH; | ||
| 334 | } | ||
| 335 | |||
| 336 | /* Conservative update of HHF arrays (see Optimization O2). */ | ||
| 337 | for (i = 0; i < HHF_ARRAYS_CNT; i++) { | ||
| 338 | if (q->hhf_arrays[i][filter_pos[i]] < min_hhf_val) | ||
| 339 | q->hhf_arrays[i][filter_pos[i]] = min_hhf_val; | ||
| 340 | } | ||
| 341 | return WDRR_BUCKET_FOR_NON_HH; | ||
| 342 | } | ||
| 343 | |||
| 344 | /* Removes one skb from head of bucket. */ | ||
| 345 | static struct sk_buff *dequeue_head(struct wdrr_bucket *bucket) | ||
| 346 | { | ||
| 347 | struct sk_buff *skb = bucket->head; | ||
| 348 | |||
| 349 | bucket->head = skb->next; | ||
| 350 | skb->next = NULL; | ||
| 351 | return skb; | ||
| 352 | } | ||
| 353 | |||
| 354 | /* Tail-adds skb to bucket. */ | ||
| 355 | static void bucket_add(struct wdrr_bucket *bucket, struct sk_buff *skb) | ||
| 356 | { | ||
| 357 | if (bucket->head == NULL) | ||
| 358 | bucket->head = skb; | ||
| 359 | else | ||
| 360 | bucket->tail->next = skb; | ||
| 361 | bucket->tail = skb; | ||
| 362 | skb->next = NULL; | ||
| 363 | } | ||
| 364 | |||
| 365 | static unsigned int hhf_drop(struct Qdisc *sch) | ||
| 366 | { | ||
| 367 | struct hhf_sched_data *q = qdisc_priv(sch); | ||
| 368 | struct wdrr_bucket *bucket; | ||
| 369 | |||
| 370 | /* Always try to drop from heavy-hitters first. */ | ||
| 371 | bucket = &q->buckets[WDRR_BUCKET_FOR_HH]; | ||
| 372 | if (!bucket->head) | ||
| 373 | bucket = &q->buckets[WDRR_BUCKET_FOR_NON_HH]; | ||
| 374 | |||
| 375 | if (bucket->head) { | ||
| 376 | struct sk_buff *skb = dequeue_head(bucket); | ||
| 377 | |||
| 378 | sch->q.qlen--; | ||
| 379 | sch->qstats.drops++; | ||
| 380 | sch->qstats.backlog -= qdisc_pkt_len(skb); | ||
| 381 | kfree_skb(skb); | ||
| 382 | } | ||
| 383 | |||
| 384 | /* Return id of the bucket from which the packet was dropped. */ | ||
| 385 | return bucket - q->buckets; | ||
| 386 | } | ||
| 387 | |||
| 388 | static int hhf_enqueue(struct sk_buff *skb, struct Qdisc *sch) | ||
| 389 | { | ||
| 390 | struct hhf_sched_data *q = qdisc_priv(sch); | ||
| 391 | enum wdrr_bucket_idx idx; | ||
| 392 | struct wdrr_bucket *bucket; | ||
| 393 | |||
| 394 | idx = hhf_classify(skb, sch); | ||
| 395 | |||
| 396 | bucket = &q->buckets[idx]; | ||
| 397 | bucket_add(bucket, skb); | ||
| 398 | sch->qstats.backlog += qdisc_pkt_len(skb); | ||
| 399 | |||
| 400 | if (list_empty(&bucket->bucketchain)) { | ||
| 401 | unsigned int weight; | ||
| 402 | |||
| 403 | /* The logic of new_buckets vs. old_buckets is the same as | ||
| 404 | * new_flows vs. old_flows in the implementation of fq_codel, | ||
| 405 | * i.e., short bursts of non-HHs should have strict priority. | ||
| 406 | */ | ||
| 407 | if (idx == WDRR_BUCKET_FOR_HH) { | ||
| 408 | /* Always move heavy-hitters to old bucket. */ | ||
| 409 | weight = 1; | ||
| 410 | list_add_tail(&bucket->bucketchain, &q->old_buckets); | ||
| 411 | } else { | ||
| 412 | weight = q->hhf_non_hh_weight; | ||
| 413 | list_add_tail(&bucket->bucketchain, &q->new_buckets); | ||
| 414 | } | ||
| 415 | bucket->deficit = weight * q->quantum; | ||
| 416 | } | ||
| 417 | if (++sch->q.qlen < sch->limit) | ||
| 418 | return NET_XMIT_SUCCESS; | ||
| 419 | |||
| 420 | q->drop_overlimit++; | ||
| 421 | /* Return Congestion Notification only if we dropped a packet from this | ||
| 422 | * bucket. | ||
| 423 | */ | ||
| 424 | if (hhf_drop(sch) == idx) | ||
| 425 | return NET_XMIT_CN; | ||
| 426 | |||
| 427 | /* As we dropped a packet, better let upper stack know this. */ | ||
| 428 | qdisc_tree_decrease_qlen(sch, 1); | ||
| 429 | return NET_XMIT_SUCCESS; | ||
| 430 | } | ||
| 431 | |||
| 432 | static struct sk_buff *hhf_dequeue(struct Qdisc *sch) | ||
| 433 | { | ||
| 434 | struct hhf_sched_data *q = qdisc_priv(sch); | ||
| 435 | struct sk_buff *skb = NULL; | ||
| 436 | struct wdrr_bucket *bucket; | ||
| 437 | struct list_head *head; | ||
| 438 | |||
| 439 | begin: | ||
| 440 | head = &q->new_buckets; | ||
| 441 | if (list_empty(head)) { | ||
| 442 | head = &q->old_buckets; | ||
| 443 | if (list_empty(head)) | ||
| 444 | return NULL; | ||
| 445 | } | ||
| 446 | bucket = list_first_entry(head, struct wdrr_bucket, bucketchain); | ||
| 447 | |||
| 448 | if (bucket->deficit <= 0) { | ||
| 449 | int weight = (bucket - q->buckets == WDRR_BUCKET_FOR_HH) ? | ||
| 450 | 1 : q->hhf_non_hh_weight; | ||
| 451 | |||
| 452 | bucket->deficit += weight * q->quantum; | ||
| 453 | list_move_tail(&bucket->bucketchain, &q->old_buckets); | ||
| 454 | goto begin; | ||
| 455 | } | ||
| 456 | |||
| 457 | if (bucket->head) { | ||
| 458 | skb = dequeue_head(bucket); | ||
| 459 | sch->q.qlen--; | ||
| 460 | sch->qstats.backlog -= qdisc_pkt_len(skb); | ||
| 461 | } | ||
| 462 | |||
| 463 | if (!skb) { | ||
| 464 | /* Force a pass through old_buckets to prevent starvation. */ | ||
| 465 | if ((head == &q->new_buckets) && !list_empty(&q->old_buckets)) | ||
| 466 | list_move_tail(&bucket->bucketchain, &q->old_buckets); | ||
| 467 | else | ||
| 468 | list_del_init(&bucket->bucketchain); | ||
| 469 | goto begin; | ||
| 470 | } | ||
| 471 | qdisc_bstats_update(sch, skb); | ||
| 472 | bucket->deficit -= qdisc_pkt_len(skb); | ||
| 473 | |||
| 474 | return skb; | ||
| 475 | } | ||
| 476 | |||
| 477 | static void hhf_reset(struct Qdisc *sch) | ||
| 478 | { | ||
| 479 | struct sk_buff *skb; | ||
| 480 | |||
| 481 | while ((skb = hhf_dequeue(sch)) != NULL) | ||
| 482 | kfree_skb(skb); | ||
| 483 | } | ||
| 484 | |||
| 485 | static void *hhf_zalloc(size_t sz) | ||
| 486 | { | ||
| 487 | void *ptr = kzalloc(sz, GFP_KERNEL | __GFP_NOWARN); | ||
| 488 | |||
| 489 | if (!ptr) | ||
| 490 | ptr = vzalloc(sz); | ||
| 491 | |||
| 492 | return ptr; | ||
| 493 | } | ||
| 494 | |||
| 495 | static void hhf_free(void *addr) | ||
| 496 | { | ||
| 497 | if (addr) { | ||
| 498 | if (is_vmalloc_addr(addr)) | ||
| 499 | vfree(addr); | ||
| 500 | else | ||
| 501 | kfree(addr); | ||
| 502 | } | ||
| 503 | } | ||
| 504 | |||
| 505 | static void hhf_destroy(struct Qdisc *sch) | ||
| 506 | { | ||
| 507 | int i; | ||
| 508 | struct hhf_sched_data *q = qdisc_priv(sch); | ||
| 509 | |||
| 510 | for (i = 0; i < HHF_ARRAYS_CNT; i++) { | ||
| 511 | hhf_free(q->hhf_arrays[i]); | ||
| 512 | hhf_free(q->hhf_valid_bits[i]); | ||
| 513 | } | ||
| 514 | |||
| 515 | for (i = 0; i < HH_FLOWS_CNT; i++) { | ||
| 516 | struct hh_flow_state *flow, *next; | ||
| 517 | struct list_head *head = &q->hh_flows[i]; | ||
| 518 | |||
| 519 | if (list_empty(head)) | ||
| 520 | continue; | ||
| 521 | list_for_each_entry_safe(flow, next, head, flowchain) { | ||
| 522 | list_del(&flow->flowchain); | ||
| 523 | kfree(flow); | ||
| 524 | } | ||
| 525 | } | ||
| 526 | hhf_free(q->hh_flows); | ||
| 527 | } | ||
| 528 | |||
| 529 | static const struct nla_policy hhf_policy[TCA_HHF_MAX + 1] = { | ||
| 530 | [TCA_HHF_BACKLOG_LIMIT] = { .type = NLA_U32 }, | ||
| 531 | [TCA_HHF_QUANTUM] = { .type = NLA_U32 }, | ||
| 532 | [TCA_HHF_HH_FLOWS_LIMIT] = { .type = NLA_U32 }, | ||
| 533 | [TCA_HHF_RESET_TIMEOUT] = { .type = NLA_U32 }, | ||
| 534 | [TCA_HHF_ADMIT_BYTES] = { .type = NLA_U32 }, | ||
| 535 | [TCA_HHF_EVICT_TIMEOUT] = { .type = NLA_U32 }, | ||
| 536 | [TCA_HHF_NON_HH_WEIGHT] = { .type = NLA_U32 }, | ||
| 537 | }; | ||
| 538 | |||
| 539 | static int hhf_change(struct Qdisc *sch, struct nlattr *opt) | ||
| 540 | { | ||
| 541 | struct hhf_sched_data *q = qdisc_priv(sch); | ||
| 542 | struct nlattr *tb[TCA_HHF_MAX + 1]; | ||
| 543 | unsigned int qlen; | ||
| 544 | int err; | ||
| 545 | u64 non_hh_quantum; | ||
| 546 | u32 new_quantum = q->quantum; | ||
| 547 | u32 new_hhf_non_hh_weight = q->hhf_non_hh_weight; | ||
| 548 | |||
| 549 | if (!opt) | ||
| 550 | return -EINVAL; | ||
| 551 | |||
| 552 | err = nla_parse_nested(tb, TCA_HHF_MAX, opt, hhf_policy); | ||
| 553 | if (err < 0) | ||
| 554 | return err; | ||
| 555 | |||
| 556 | sch_tree_lock(sch); | ||
| 557 | |||
| 558 | if (tb[TCA_HHF_BACKLOG_LIMIT]) | ||
| 559 | sch->limit = nla_get_u32(tb[TCA_HHF_BACKLOG_LIMIT]); | ||
| 560 | |||
| 561 | if (tb[TCA_HHF_QUANTUM]) | ||
| 562 | new_quantum = nla_get_u32(tb[TCA_HHF_QUANTUM]); | ||
| 563 | |||
| 564 | if (tb[TCA_HHF_NON_HH_WEIGHT]) | ||
| 565 | new_hhf_non_hh_weight = nla_get_u32(tb[TCA_HHF_NON_HH_WEIGHT]); | ||
| 566 | |||
| 567 | non_hh_quantum = (u64)new_quantum * new_hhf_non_hh_weight; | ||
| 568 | if (non_hh_quantum > INT_MAX) | ||
| 569 | return -EINVAL; | ||
| 570 | q->quantum = new_quantum; | ||
| 571 | q->hhf_non_hh_weight = new_hhf_non_hh_weight; | ||
| 572 | |||
| 573 | if (tb[TCA_HHF_HH_FLOWS_LIMIT]) | ||
| 574 | q->hh_flows_limit = nla_get_u32(tb[TCA_HHF_HH_FLOWS_LIMIT]); | ||
| 575 | |||
| 576 | if (tb[TCA_HHF_RESET_TIMEOUT]) { | ||
| 577 | u32 us = nla_get_u32(tb[TCA_HHF_RESET_TIMEOUT]); | ||
| 578 | |||
| 579 | q->hhf_reset_timeout = usecs_to_jiffies(us); | ||
| 580 | } | ||
| 581 | |||
| 582 | if (tb[TCA_HHF_ADMIT_BYTES]) | ||
| 583 | q->hhf_admit_bytes = nla_get_u32(tb[TCA_HHF_ADMIT_BYTES]); | ||
| 584 | |||
| 585 | if (tb[TCA_HHF_EVICT_TIMEOUT]) { | ||
| 586 | u32 us = nla_get_u32(tb[TCA_HHF_EVICT_TIMEOUT]); | ||
| 587 | |||
| 588 | q->hhf_evict_timeout = usecs_to_jiffies(us); | ||
| 589 | } | ||
| 590 | |||
| 591 | qlen = sch->q.qlen; | ||
| 592 | while (sch->q.qlen > sch->limit) { | ||
| 593 | struct sk_buff *skb = hhf_dequeue(sch); | ||
| 594 | |||
| 595 | kfree_skb(skb); | ||
| 596 | } | ||
| 597 | qdisc_tree_decrease_qlen(sch, qlen - sch->q.qlen); | ||
| 598 | |||
| 599 | sch_tree_unlock(sch); | ||
| 600 | return 0; | ||
| 601 | } | ||
| 602 | |||
| 603 | static int hhf_init(struct Qdisc *sch, struct nlattr *opt) | ||
| 604 | { | ||
| 605 | struct hhf_sched_data *q = qdisc_priv(sch); | ||
| 606 | int i; | ||
| 607 | |||
| 608 | sch->limit = 1000; | ||
| 609 | q->quantum = psched_mtu(qdisc_dev(sch)); | ||
| 610 | q->perturbation = prandom_u32(); | ||
| 611 | INIT_LIST_HEAD(&q->new_buckets); | ||
| 612 | INIT_LIST_HEAD(&q->old_buckets); | ||
| 613 | |||
| 614 | /* Configurable HHF parameters */ | ||
| 615 | q->hhf_reset_timeout = HZ / 25; /* 40 ms */ | ||
| 616 | q->hhf_admit_bytes = 131072; /* 128 KB */ | ||
| 617 | q->hhf_evict_timeout = HZ; /* 1 sec */ | ||
| 618 | q->hhf_non_hh_weight = 2; | ||
| 619 | |||
| 620 | if (opt) { | ||
| 621 | int err = hhf_change(sch, opt); | ||
| 622 | |||
| 623 | if (err) | ||
| 624 | return err; | ||
| 625 | } | ||
| 626 | |||
| 627 | if (!q->hh_flows) { | ||
| 628 | /* Initialize heavy-hitter flow table. */ | ||
| 629 | q->hh_flows = hhf_zalloc(HH_FLOWS_CNT * | ||
| 630 | sizeof(struct list_head)); | ||
| 631 | if (!q->hh_flows) | ||
| 632 | return -ENOMEM; | ||
| 633 | for (i = 0; i < HH_FLOWS_CNT; i++) | ||
| 634 | INIT_LIST_HEAD(&q->hh_flows[i]); | ||
| 635 | |||
| 636 | /* Cap max active HHs at twice len of hh_flows table. */ | ||
| 637 | q->hh_flows_limit = 2 * HH_FLOWS_CNT; | ||
| 638 | q->hh_flows_overlimit = 0; | ||
| 639 | q->hh_flows_total_cnt = 0; | ||
| 640 | q->hh_flows_current_cnt = 0; | ||
| 641 | |||
| 642 | /* Initialize heavy-hitter filter arrays. */ | ||
| 643 | for (i = 0; i < HHF_ARRAYS_CNT; i++) { | ||
| 644 | q->hhf_arrays[i] = hhf_zalloc(HHF_ARRAYS_LEN * | ||
| 645 | sizeof(u32)); | ||
| 646 | if (!q->hhf_arrays[i]) { | ||
| 647 | hhf_destroy(sch); | ||
| 648 | return -ENOMEM; | ||
| 649 | } | ||
| 650 | } | ||
| 651 | q->hhf_arrays_reset_timestamp = hhf_time_stamp(); | ||
| 652 | |||
| 653 | /* Initialize valid bits of heavy-hitter filter arrays. */ | ||
| 654 | for (i = 0; i < HHF_ARRAYS_CNT; i++) { | ||
| 655 | q->hhf_valid_bits[i] = hhf_zalloc(HHF_ARRAYS_LEN / | ||
| 656 | BITS_PER_BYTE); | ||
| 657 | if (!q->hhf_valid_bits[i]) { | ||
| 658 | hhf_destroy(sch); | ||
| 659 | return -ENOMEM; | ||
| 660 | } | ||
| 661 | } | ||
| 662 | |||
| 663 | /* Initialize Weighted DRR buckets. */ | ||
| 664 | for (i = 0; i < WDRR_BUCKET_CNT; i++) { | ||
| 665 | struct wdrr_bucket *bucket = q->buckets + i; | ||
| 666 | |||
| 667 | INIT_LIST_HEAD(&bucket->bucketchain); | ||
| 668 | } | ||
| 669 | } | ||
| 670 | |||
| 671 | return 0; | ||
| 672 | } | ||
| 673 | |||
| 674 | static int hhf_dump(struct Qdisc *sch, struct sk_buff *skb) | ||
| 675 | { | ||
| 676 | struct hhf_sched_data *q = qdisc_priv(sch); | ||
| 677 | struct nlattr *opts; | ||
| 678 | |||
| 679 | opts = nla_nest_start(skb, TCA_OPTIONS); | ||
| 680 | if (opts == NULL) | ||
| 681 | goto nla_put_failure; | ||
| 682 | |||
| 683 | if (nla_put_u32(skb, TCA_HHF_BACKLOG_LIMIT, sch->limit) || | ||
| 684 | nla_put_u32(skb, TCA_HHF_QUANTUM, q->quantum) || | ||
| 685 | nla_put_u32(skb, TCA_HHF_HH_FLOWS_LIMIT, q->hh_flows_limit) || | ||
| 686 | nla_put_u32(skb, TCA_HHF_RESET_TIMEOUT, | ||
| 687 | jiffies_to_usecs(q->hhf_reset_timeout)) || | ||
| 688 | nla_put_u32(skb, TCA_HHF_ADMIT_BYTES, q->hhf_admit_bytes) || | ||
| 689 | nla_put_u32(skb, TCA_HHF_EVICT_TIMEOUT, | ||
| 690 | jiffies_to_usecs(q->hhf_evict_timeout)) || | ||
| 691 | nla_put_u32(skb, TCA_HHF_NON_HH_WEIGHT, q->hhf_non_hh_weight)) | ||
| 692 | goto nla_put_failure; | ||
| 693 | |||
| 694 | nla_nest_end(skb, opts); | ||
| 695 | return skb->len; | ||
| 696 | |||
| 697 | nla_put_failure: | ||
| 698 | return -1; | ||
| 699 | } | ||
| 700 | |||
| 701 | static int hhf_dump_stats(struct Qdisc *sch, struct gnet_dump *d) | ||
| 702 | { | ||
| 703 | struct hhf_sched_data *q = qdisc_priv(sch); | ||
| 704 | struct tc_hhf_xstats st = { | ||
| 705 | .drop_overlimit = q->drop_overlimit, | ||
| 706 | .hh_overlimit = q->hh_flows_overlimit, | ||
| 707 | .hh_tot_count = q->hh_flows_total_cnt, | ||
| 708 | .hh_cur_count = q->hh_flows_current_cnt, | ||
| 709 | }; | ||
| 710 | |||
| 711 | return gnet_stats_copy_app(d, &st, sizeof(st)); | ||
| 712 | } | ||
| 713 | |||
| 714 | static struct Qdisc_ops hhf_qdisc_ops __read_mostly = { | ||
| 715 | .id = "hhf", | ||
| 716 | .priv_size = sizeof(struct hhf_sched_data), | ||
| 717 | |||
| 718 | .enqueue = hhf_enqueue, | ||
| 719 | .dequeue = hhf_dequeue, | ||
| 720 | .peek = qdisc_peek_dequeued, | ||
| 721 | .drop = hhf_drop, | ||
| 722 | .init = hhf_init, | ||
| 723 | .reset = hhf_reset, | ||
| 724 | .destroy = hhf_destroy, | ||
| 725 | .change = hhf_change, | ||
| 726 | .dump = hhf_dump, | ||
| 727 | .dump_stats = hhf_dump_stats, | ||
| 728 | .owner = THIS_MODULE, | ||
| 729 | }; | ||
| 730 | |||
| 731 | static int __init hhf_module_init(void) | ||
| 732 | { | ||
| 733 | return register_qdisc(&hhf_qdisc_ops); | ||
| 734 | } | ||
| 735 | |||
| 736 | static void __exit hhf_module_exit(void) | ||
| 737 | { | ||
| 738 | unregister_qdisc(&hhf_qdisc_ops); | ||
| 739 | } | ||
| 740 | |||
| 741 | module_init(hhf_module_init) | ||
| 742 | module_exit(hhf_module_exit) | ||
| 743 | MODULE_AUTHOR("Terry Lam"); | ||
| 744 | MODULE_AUTHOR("Nandita Dukkipati"); | ||
| 745 | MODULE_LICENSE("GPL"); | ||
diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c index 717b2108f852..722e137df244 100644 --- a/net/sched/sch_htb.c +++ b/net/sched/sch_htb.c | |||
| @@ -219,11 +219,16 @@ static struct htb_class *htb_classify(struct sk_buff *skb, struct Qdisc *sch, | |||
| 219 | if (skb->priority == sch->handle) | 219 | if (skb->priority == sch->handle) |
| 220 | return HTB_DIRECT; /* X:0 (direct flow) selected */ | 220 | return HTB_DIRECT; /* X:0 (direct flow) selected */ |
| 221 | cl = htb_find(skb->priority, sch); | 221 | cl = htb_find(skb->priority, sch); |
| 222 | if (cl && cl->level == 0) | 222 | if (cl) { |
| 223 | return cl; | 223 | if (cl->level == 0) |
| 224 | return cl; | ||
| 225 | /* Start with inner filter chain if a non-leaf class is selected */ | ||
| 226 | tcf = cl->filter_list; | ||
| 227 | } else { | ||
| 228 | tcf = q->filter_list; | ||
| 229 | } | ||
| 224 | 230 | ||
| 225 | *qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS; | 231 | *qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS; |
| 226 | tcf = q->filter_list; | ||
| 227 | while (tcf && (result = tc_classify(skb, tcf, &res)) >= 0) { | 232 | while (tcf && (result = tc_classify(skb, tcf, &res)) >= 0) { |
| 228 | #ifdef CONFIG_NET_CLS_ACT | 233 | #ifdef CONFIG_NET_CLS_ACT |
| 229 | switch (result) { | 234 | switch (result) { |
| @@ -712,7 +717,7 @@ static s64 htb_do_events(struct htb_sched *q, const int level, | |||
| 712 | 717 | ||
| 713 | /* too much load - let's continue after a break for scheduling */ | 718 | /* too much load - let's continue after a break for scheduling */ |
| 714 | if (!(q->warned & HTB_WARN_TOOMANYEVENTS)) { | 719 | if (!(q->warned & HTB_WARN_TOOMANYEVENTS)) { |
| 715 | pr_warning("htb: too many events!\n"); | 720 | pr_warn("htb: too many events!\n"); |
| 716 | q->warned |= HTB_WARN_TOOMANYEVENTS; | 721 | q->warned |= HTB_WARN_TOOMANYEVENTS; |
| 717 | } | 722 | } |
| 718 | 723 | ||
| @@ -1276,9 +1281,10 @@ static int htb_delete(struct Qdisc *sch, unsigned long arg) | |||
| 1276 | struct Qdisc *new_q = NULL; | 1281 | struct Qdisc *new_q = NULL; |
| 1277 | int last_child = 0; | 1282 | int last_child = 0; |
| 1278 | 1283 | ||
| 1279 | // TODO: why don't allow to delete subtree ? references ? does | 1284 | /* TODO: why don't allow to delete subtree ? references ? does |
| 1280 | // tc subsys quarantee us that in htb_destroy it holds no class | 1285 | * tc subsys guarantee us that in htb_destroy it holds no class |
| 1281 | // refs so that we can remove children safely there ? | 1286 | * refs so that we can remove children safely there ? |
| 1287 | */ | ||
| 1282 | if (cl->children || cl->filter_cnt) | 1288 | if (cl->children || cl->filter_cnt) |
| 1283 | return -EBUSY; | 1289 | return -EBUSY; |
| 1284 | 1290 | ||
| @@ -1337,7 +1343,6 @@ static int htb_change_class(struct Qdisc *sch, u32 classid, | |||
| 1337 | struct htb_sched *q = qdisc_priv(sch); | 1343 | struct htb_sched *q = qdisc_priv(sch); |
| 1338 | struct htb_class *cl = (struct htb_class *)*arg, *parent; | 1344 | struct htb_class *cl = (struct htb_class *)*arg, *parent; |
| 1339 | struct nlattr *opt = tca[TCA_OPTIONS]; | 1345 | struct nlattr *opt = tca[TCA_OPTIONS]; |
| 1340 | struct qdisc_rate_table *rtab = NULL, *ctab = NULL; | ||
| 1341 | struct nlattr *tb[TCA_HTB_MAX + 1]; | 1346 | struct nlattr *tb[TCA_HTB_MAX + 1]; |
| 1342 | struct tc_htb_opt *hopt; | 1347 | struct tc_htb_opt *hopt; |
| 1343 | u64 rate64, ceil64; | 1348 | u64 rate64, ceil64; |
| @@ -1361,16 +1366,11 @@ static int htb_change_class(struct Qdisc *sch, u32 classid, | |||
| 1361 | goto failure; | 1366 | goto failure; |
| 1362 | 1367 | ||
| 1363 | /* Keeping backward compatible with rate_table based iproute2 tc */ | 1368 | /* Keeping backward compatible with rate_table based iproute2 tc */ |
| 1364 | if (hopt->rate.linklayer == TC_LINKLAYER_UNAWARE) { | 1369 | if (hopt->rate.linklayer == TC_LINKLAYER_UNAWARE) |
| 1365 | rtab = qdisc_get_rtab(&hopt->rate, tb[TCA_HTB_RTAB]); | 1370 | qdisc_put_rtab(qdisc_get_rtab(&hopt->rate, tb[TCA_HTB_RTAB])); |
| 1366 | if (rtab) | 1371 | |
| 1367 | qdisc_put_rtab(rtab); | 1372 | if (hopt->ceil.linklayer == TC_LINKLAYER_UNAWARE) |
| 1368 | } | 1373 | qdisc_put_rtab(qdisc_get_rtab(&hopt->ceil, tb[TCA_HTB_CTAB])); |
| 1369 | if (hopt->ceil.linklayer == TC_LINKLAYER_UNAWARE) { | ||
| 1370 | ctab = qdisc_get_rtab(&hopt->ceil, tb[TCA_HTB_CTAB]); | ||
| 1371 | if (ctab) | ||
| 1372 | qdisc_put_rtab(ctab); | ||
| 1373 | } | ||
| 1374 | 1374 | ||
| 1375 | if (!cl) { /* new class */ | 1375 | if (!cl) { /* new class */ |
| 1376 | struct Qdisc *new_q; | 1376 | struct Qdisc *new_q; |
| @@ -1494,15 +1494,13 @@ static int htb_change_class(struct Qdisc *sch, u32 classid, | |||
| 1494 | cl->quantum = min_t(u64, quantum, INT_MAX); | 1494 | cl->quantum = min_t(u64, quantum, INT_MAX); |
| 1495 | 1495 | ||
| 1496 | if (!hopt->quantum && cl->quantum < 1000) { | 1496 | if (!hopt->quantum && cl->quantum < 1000) { |
| 1497 | pr_warning( | 1497 | pr_warn("HTB: quantum of class %X is small. Consider r2q change.\n", |
| 1498 | "HTB: quantum of class %X is small. Consider r2q change.\n", | 1498 | cl->common.classid); |
| 1499 | cl->common.classid); | ||
| 1500 | cl->quantum = 1000; | 1499 | cl->quantum = 1000; |
| 1501 | } | 1500 | } |
| 1502 | if (!hopt->quantum && cl->quantum > 200000) { | 1501 | if (!hopt->quantum && cl->quantum > 200000) { |
| 1503 | pr_warning( | 1502 | pr_warn("HTB: quantum of class %X is big. Consider r2q change.\n", |
| 1504 | "HTB: quantum of class %X is big. Consider r2q change.\n", | 1503 | cl->common.classid); |
| 1505 | cl->common.classid); | ||
| 1506 | cl->quantum = 200000; | 1504 | cl->quantum = 200000; |
| 1507 | } | 1505 | } |
| 1508 | if (hopt->quantum) | 1506 | if (hopt->quantum) |
diff --git a/net/sched/sch_mq.c b/net/sched/sch_mq.c index 2e56185736d6..a8b2864a696b 100644 --- a/net/sched/sch_mq.c +++ b/net/sched/sch_mq.c | |||
| @@ -78,14 +78,19 @@ static void mq_attach(struct Qdisc *sch) | |||
| 78 | { | 78 | { |
| 79 | struct net_device *dev = qdisc_dev(sch); | 79 | struct net_device *dev = qdisc_dev(sch); |
| 80 | struct mq_sched *priv = qdisc_priv(sch); | 80 | struct mq_sched *priv = qdisc_priv(sch); |
| 81 | struct Qdisc *qdisc; | 81 | struct Qdisc *qdisc, *old; |
| 82 | unsigned int ntx; | 82 | unsigned int ntx; |
| 83 | 83 | ||
| 84 | for (ntx = 0; ntx < dev->num_tx_queues; ntx++) { | 84 | for (ntx = 0; ntx < dev->num_tx_queues; ntx++) { |
| 85 | qdisc = priv->qdiscs[ntx]; | 85 | qdisc = priv->qdiscs[ntx]; |
| 86 | qdisc = dev_graft_qdisc(qdisc->dev_queue, qdisc); | 86 | old = dev_graft_qdisc(qdisc->dev_queue, qdisc); |
| 87 | if (qdisc) | 87 | if (old) |
| 88 | qdisc_destroy(qdisc); | 88 | qdisc_destroy(old); |
| 89 | #ifdef CONFIG_NET_SCHED | ||
| 90 | if (ntx < dev->real_num_tx_queues) | ||
| 91 | qdisc_list_add(qdisc); | ||
| 92 | #endif | ||
| 93 | |||
| 89 | } | 94 | } |
| 90 | kfree(priv->qdiscs); | 95 | kfree(priv->qdiscs); |
| 91 | priv->qdiscs = NULL; | 96 | priv->qdiscs = NULL; |
diff --git a/net/sched/sch_mqprio.c b/net/sched/sch_mqprio.c index d44c868cb537..6749e2f540d0 100644 --- a/net/sched/sch_mqprio.c +++ b/net/sched/sch_mqprio.c | |||
| @@ -167,15 +167,17 @@ static void mqprio_attach(struct Qdisc *sch) | |||
| 167 | { | 167 | { |
| 168 | struct net_device *dev = qdisc_dev(sch); | 168 | struct net_device *dev = qdisc_dev(sch); |
| 169 | struct mqprio_sched *priv = qdisc_priv(sch); | 169 | struct mqprio_sched *priv = qdisc_priv(sch); |
| 170 | struct Qdisc *qdisc; | 170 | struct Qdisc *qdisc, *old; |
| 171 | unsigned int ntx; | 171 | unsigned int ntx; |
| 172 | 172 | ||
| 173 | /* Attach underlying qdisc */ | 173 | /* Attach underlying qdisc */ |
| 174 | for (ntx = 0; ntx < dev->num_tx_queues; ntx++) { | 174 | for (ntx = 0; ntx < dev->num_tx_queues; ntx++) { |
| 175 | qdisc = priv->qdiscs[ntx]; | 175 | qdisc = priv->qdiscs[ntx]; |
| 176 | qdisc = dev_graft_qdisc(qdisc->dev_queue, qdisc); | 176 | old = dev_graft_qdisc(qdisc->dev_queue, qdisc); |
| 177 | if (qdisc) | 177 | if (old) |
| 178 | qdisc_destroy(qdisc); | 178 | qdisc_destroy(old); |
| 179 | if (ntx < dev->real_num_tx_queues) | ||
| 180 | qdisc_list_add(qdisc); | ||
| 179 | } | 181 | } |
| 180 | kfree(priv->qdiscs); | 182 | kfree(priv->qdiscs); |
| 181 | priv->qdiscs = NULL; | 183 | priv->qdiscs = NULL; |
diff --git a/net/sched/sch_multiq.c b/net/sched/sch_multiq.c index 2a2b096d9a66..afb050a735fa 100644 --- a/net/sched/sch_multiq.c +++ b/net/sched/sch_multiq.c | |||
| @@ -11,8 +11,7 @@ | |||
| 11 | * more details. | 11 | * more details. |
| 12 | * | 12 | * |
| 13 | * You should have received a copy of the GNU General Public License along with | 13 | * You should have received a copy of the GNU General Public License along with |
| 14 | * this program; if not, write to the Free Software Foundation, Inc., 59 Temple | 14 | * this program; if not, see <http://www.gnu.org/licenses/>. |
| 15 | * Place - Suite 330, Boston, MA 02111-1307 USA. | ||
| 16 | * | 15 | * |
| 17 | * Author: Alexander Duyck <alexander.h.duyck@intel.com> | 16 | * Author: Alexander Duyck <alexander.h.duyck@intel.com> |
| 18 | */ | 17 | */ |
diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c index bccd52b36e97..de1059af6da1 100644 --- a/net/sched/sch_netem.c +++ b/net/sched/sch_netem.c | |||
| @@ -88,10 +88,10 @@ struct netem_sched_data { | |||
| 88 | u32 duplicate; | 88 | u32 duplicate; |
| 89 | u32 reorder; | 89 | u32 reorder; |
| 90 | u32 corrupt; | 90 | u32 corrupt; |
| 91 | u32 rate; | 91 | u64 rate; |
| 92 | s32 packet_overhead; | 92 | s32 packet_overhead; |
| 93 | u32 cell_size; | 93 | u32 cell_size; |
| 94 | u32 cell_size_reciprocal; | 94 | struct reciprocal_value cell_size_reciprocal; |
| 95 | s32 cell_overhead; | 95 | s32 cell_overhead; |
| 96 | 96 | ||
| 97 | struct crndstate { | 97 | struct crndstate { |
| @@ -110,6 +110,13 @@ struct netem_sched_data { | |||
| 110 | CLG_GILB_ELL, | 110 | CLG_GILB_ELL, |
| 111 | } loss_model; | 111 | } loss_model; |
| 112 | 112 | ||
| 113 | enum { | ||
| 114 | TX_IN_GAP_PERIOD = 1, | ||
| 115 | TX_IN_BURST_PERIOD, | ||
| 116 | LOST_IN_GAP_PERIOD, | ||
| 117 | LOST_IN_BURST_PERIOD, | ||
| 118 | } _4_state_model; | ||
| 119 | |||
| 113 | /* Correlated Loss Generation models */ | 120 | /* Correlated Loss Generation models */ |
| 114 | struct clgstate { | 121 | struct clgstate { |
| 115 | /* state of the Markov chain */ | 122 | /* state of the Markov chain */ |
| @@ -169,7 +176,7 @@ static inline struct netem_skb_cb *netem_skb_cb(struct sk_buff *skb) | |||
| 169 | static void init_crandom(struct crndstate *state, unsigned long rho) | 176 | static void init_crandom(struct crndstate *state, unsigned long rho) |
| 170 | { | 177 | { |
| 171 | state->rho = rho; | 178 | state->rho = rho; |
| 172 | state->last = net_random(); | 179 | state->last = prandom_u32(); |
| 173 | } | 180 | } |
| 174 | 181 | ||
| 175 | /* get_crandom - correlated random number generator | 182 | /* get_crandom - correlated random number generator |
| @@ -182,9 +189,9 @@ static u32 get_crandom(struct crndstate *state) | |||
| 182 | unsigned long answer; | 189 | unsigned long answer; |
| 183 | 190 | ||
| 184 | if (state->rho == 0) /* no correlation */ | 191 | if (state->rho == 0) /* no correlation */ |
| 185 | return net_random(); | 192 | return prandom_u32(); |
| 186 | 193 | ||
| 187 | value = net_random(); | 194 | value = prandom_u32(); |
| 188 | rho = (u64)state->rho + 1; | 195 | rho = (u64)state->rho + 1; |
| 189 | answer = (value * ((1ull<<32) - rho) + state->last * rho) >> 32; | 196 | answer = (value * ((1ull<<32) - rho) + state->last * rho) >> 32; |
| 190 | state->last = answer; | 197 | state->last = answer; |
| @@ -198,50 +205,52 @@ static u32 get_crandom(struct crndstate *state) | |||
| 198 | static bool loss_4state(struct netem_sched_data *q) | 205 | static bool loss_4state(struct netem_sched_data *q) |
| 199 | { | 206 | { |
| 200 | struct clgstate *clg = &q->clg; | 207 | struct clgstate *clg = &q->clg; |
| 201 | u32 rnd = net_random(); | 208 | u32 rnd = prandom_u32(); |
| 202 | 209 | ||
| 203 | /* | 210 | /* |
| 204 | * Makes a comparison between rnd and the transition | 211 | * Makes a comparison between rnd and the transition |
| 205 | * probabilities outgoing from the current state, then decides the | 212 | * probabilities outgoing from the current state, then decides the |
| 206 | * next state and if the next packet has to be transmitted or lost. | 213 | * next state and if the next packet has to be transmitted or lost. |
| 207 | * The four states correspond to: | 214 | * The four states correspond to: |
| 208 | * 1 => successfully transmitted packets within a gap period | 215 | * TX_IN_GAP_PERIOD => successfully transmitted packets within a gap period |
| 209 | * 4 => isolated losses within a gap period | 216 | * LOST_IN_BURST_PERIOD => isolated losses within a gap period |
| 210 | * 3 => lost packets within a burst period | 217 | * LOST_IN_GAP_PERIOD => lost packets within a burst period |
| 211 | * 2 => successfully transmitted packets within a burst period | 218 | * TX_IN_GAP_PERIOD => successfully transmitted packets within a burst period |
| 212 | */ | 219 | */ |
| 213 | switch (clg->state) { | 220 | switch (clg->state) { |
| 214 | case 1: | 221 | case TX_IN_GAP_PERIOD: |
| 215 | if (rnd < clg->a4) { | 222 | if (rnd < clg->a4) { |
| 216 | clg->state = 4; | 223 | clg->state = LOST_IN_BURST_PERIOD; |
| 217 | return true; | 224 | return true; |
| 218 | } else if (clg->a4 < rnd && rnd < clg->a1 + clg->a4) { | 225 | } else if (clg->a4 < rnd && rnd < clg->a1 + clg->a4) { |
| 219 | clg->state = 3; | 226 | clg->state = LOST_IN_GAP_PERIOD; |
| 220 | return true; | 227 | return true; |
| 221 | } else if (clg->a1 + clg->a4 < rnd) | 228 | } else if (clg->a1 + clg->a4 < rnd) { |
| 222 | clg->state = 1; | 229 | clg->state = TX_IN_GAP_PERIOD; |
| 230 | } | ||
| 223 | 231 | ||
| 224 | break; | 232 | break; |
| 225 | case 2: | 233 | case TX_IN_BURST_PERIOD: |
| 226 | if (rnd < clg->a5) { | 234 | if (rnd < clg->a5) { |
| 227 | clg->state = 3; | 235 | clg->state = LOST_IN_GAP_PERIOD; |
| 228 | return true; | 236 | return true; |
| 229 | } else | 237 | } else { |
| 230 | clg->state = 2; | 238 | clg->state = TX_IN_BURST_PERIOD; |
| 239 | } | ||
| 231 | 240 | ||
| 232 | break; | 241 | break; |
| 233 | case 3: | 242 | case LOST_IN_GAP_PERIOD: |
| 234 | if (rnd < clg->a3) | 243 | if (rnd < clg->a3) |
| 235 | clg->state = 2; | 244 | clg->state = TX_IN_BURST_PERIOD; |
| 236 | else if (clg->a3 < rnd && rnd < clg->a2 + clg->a3) { | 245 | else if (clg->a3 < rnd && rnd < clg->a2 + clg->a3) { |
| 237 | clg->state = 1; | 246 | clg->state = TX_IN_GAP_PERIOD; |
| 238 | } else if (clg->a2 + clg->a3 < rnd) { | 247 | } else if (clg->a2 + clg->a3 < rnd) { |
| 239 | clg->state = 3; | 248 | clg->state = LOST_IN_GAP_PERIOD; |
| 240 | return true; | 249 | return true; |
| 241 | } | 250 | } |
| 242 | break; | 251 | break; |
| 243 | case 4: | 252 | case LOST_IN_BURST_PERIOD: |
| 244 | clg->state = 1; | 253 | clg->state = TX_IN_GAP_PERIOD; |
| 245 | break; | 254 | break; |
| 246 | } | 255 | } |
| 247 | 256 | ||
| @@ -264,15 +273,15 @@ static bool loss_gilb_ell(struct netem_sched_data *q) | |||
| 264 | 273 | ||
| 265 | switch (clg->state) { | 274 | switch (clg->state) { |
| 266 | case 1: | 275 | case 1: |
| 267 | if (net_random() < clg->a1) | 276 | if (prandom_u32() < clg->a1) |
| 268 | clg->state = 2; | 277 | clg->state = 2; |
| 269 | if (net_random() < clg->a4) | 278 | if (prandom_u32() < clg->a4) |
| 270 | return true; | 279 | return true; |
| 271 | break; | 280 | break; |
| 272 | case 2: | 281 | case 2: |
| 273 | if (net_random() < clg->a2) | 282 | if (prandom_u32() < clg->a2) |
| 274 | clg->state = 1; | 283 | clg->state = 1; |
| 275 | if (net_random() > clg->a3) | 284 | if (prandom_u32() > clg->a3) |
| 276 | return true; | 285 | return true; |
| 277 | } | 286 | } |
| 278 | 287 | ||
| @@ -457,7 +466,8 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch) | |||
| 457 | skb_checksum_help(skb))) | 466 | skb_checksum_help(skb))) |
| 458 | return qdisc_drop(skb, sch); | 467 | return qdisc_drop(skb, sch); |
| 459 | 468 | ||
| 460 | skb->data[net_random() % skb_headlen(skb)] ^= 1<<(net_random() % 8); | 469 | skb->data[prandom_u32() % skb_headlen(skb)] ^= |
| 470 | 1<<(prandom_u32() % 8); | ||
| 461 | } | 471 | } |
| 462 | 472 | ||
| 463 | if (unlikely(skb_queue_len(&sch->q) >= sch->limit)) | 473 | if (unlikely(skb_queue_len(&sch->q) >= sch->limit)) |
| @@ -495,7 +505,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch) | |||
| 495 | now = netem_skb_cb(last)->time_to_send; | 505 | now = netem_skb_cb(last)->time_to_send; |
| 496 | } | 506 | } |
| 497 | 507 | ||
| 498 | delay += packet_len_2_sched_time(skb->len, q); | 508 | delay += packet_len_2_sched_time(qdisc_pkt_len(skb), q); |
| 499 | } | 509 | } |
| 500 | 510 | ||
| 501 | cb->time_to_send = now + delay; | 511 | cb->time_to_send = now + delay; |
| @@ -715,9 +725,11 @@ static void get_rate(struct Qdisc *sch, const struct nlattr *attr) | |||
| 715 | q->rate = r->rate; | 725 | q->rate = r->rate; |
| 716 | q->packet_overhead = r->packet_overhead; | 726 | q->packet_overhead = r->packet_overhead; |
| 717 | q->cell_size = r->cell_size; | 727 | q->cell_size = r->cell_size; |
| 728 | q->cell_overhead = r->cell_overhead; | ||
| 718 | if (q->cell_size) | 729 | if (q->cell_size) |
| 719 | q->cell_size_reciprocal = reciprocal_value(q->cell_size); | 730 | q->cell_size_reciprocal = reciprocal_value(q->cell_size); |
| 720 | q->cell_overhead = r->cell_overhead; | 731 | else |
| 732 | q->cell_size_reciprocal = (struct reciprocal_value) { 0 }; | ||
| 721 | } | 733 | } |
| 722 | 734 | ||
| 723 | static int get_loss_clg(struct Qdisc *sch, const struct nlattr *attr) | 735 | static int get_loss_clg(struct Qdisc *sch, const struct nlattr *attr) |
| @@ -729,7 +741,7 @@ static int get_loss_clg(struct Qdisc *sch, const struct nlattr *attr) | |||
| 729 | nla_for_each_nested(la, attr, rem) { | 741 | nla_for_each_nested(la, attr, rem) { |
| 730 | u16 type = nla_type(la); | 742 | u16 type = nla_type(la); |
| 731 | 743 | ||
| 732 | switch(type) { | 744 | switch (type) { |
| 733 | case NETEM_LOSS_GI: { | 745 | case NETEM_LOSS_GI: { |
| 734 | const struct tc_netem_gimodel *gi = nla_data(la); | 746 | const struct tc_netem_gimodel *gi = nla_data(la); |
| 735 | 747 | ||
| @@ -782,6 +794,7 @@ static const struct nla_policy netem_policy[TCA_NETEM_MAX + 1] = { | |||
| 782 | [TCA_NETEM_RATE] = { .len = sizeof(struct tc_netem_rate) }, | 794 | [TCA_NETEM_RATE] = { .len = sizeof(struct tc_netem_rate) }, |
| 783 | [TCA_NETEM_LOSS] = { .type = NLA_NESTED }, | 795 | [TCA_NETEM_LOSS] = { .type = NLA_NESTED }, |
| 784 | [TCA_NETEM_ECN] = { .type = NLA_U32 }, | 796 | [TCA_NETEM_ECN] = { .type = NLA_U32 }, |
| 797 | [TCA_NETEM_RATE64] = { .type = NLA_U64 }, | ||
| 785 | }; | 798 | }; |
| 786 | 799 | ||
| 787 | static int parse_attr(struct nlattr *tb[], int maxtype, struct nlattr *nla, | 800 | static int parse_attr(struct nlattr *tb[], int maxtype, struct nlattr *nla, |
| @@ -852,6 +865,10 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt) | |||
| 852 | if (tb[TCA_NETEM_RATE]) | 865 | if (tb[TCA_NETEM_RATE]) |
| 853 | get_rate(sch, tb[TCA_NETEM_RATE]); | 866 | get_rate(sch, tb[TCA_NETEM_RATE]); |
| 854 | 867 | ||
| 868 | if (tb[TCA_NETEM_RATE64]) | ||
| 869 | q->rate = max_t(u64, q->rate, | ||
| 870 | nla_get_u64(tb[TCA_NETEM_RATE64])); | ||
| 871 | |||
| 855 | if (tb[TCA_NETEM_ECN]) | 872 | if (tb[TCA_NETEM_ECN]) |
| 856 | q->ecn = nla_get_u32(tb[TCA_NETEM_ECN]); | 873 | q->ecn = nla_get_u32(tb[TCA_NETEM_ECN]); |
| 857 | 874 | ||
| @@ -974,7 +991,13 @@ static int netem_dump(struct Qdisc *sch, struct sk_buff *skb) | |||
| 974 | if (nla_put(skb, TCA_NETEM_CORRUPT, sizeof(corrupt), &corrupt)) | 991 | if (nla_put(skb, TCA_NETEM_CORRUPT, sizeof(corrupt), &corrupt)) |
| 975 | goto nla_put_failure; | 992 | goto nla_put_failure; |
| 976 | 993 | ||
| 977 | rate.rate = q->rate; | 994 | if (q->rate >= (1ULL << 32)) { |
| 995 | if (nla_put_u64(skb, TCA_NETEM_RATE64, q->rate)) | ||
| 996 | goto nla_put_failure; | ||
| 997 | rate.rate = ~0U; | ||
| 998 | } else { | ||
| 999 | rate.rate = q->rate; | ||
| 1000 | } | ||
| 978 | rate.packet_overhead = q->packet_overhead; | 1001 | rate.packet_overhead = q->packet_overhead; |
| 979 | rate.cell_size = q->cell_size; | 1002 | rate.cell_size = q->cell_size; |
| 980 | rate.cell_overhead = q->cell_overhead; | 1003 | rate.cell_overhead = q->cell_overhead; |
diff --git a/net/sched/sch_pie.c b/net/sched/sch_pie.c new file mode 100644 index 000000000000..a255d0200a59 --- /dev/null +++ b/net/sched/sch_pie.c | |||
| @@ -0,0 +1,555 @@ | |||
| 1 | /* Copyright (C) 2013 Cisco Systems, Inc, 2013. | ||
| 2 | * | ||
| 3 | * This program is free software; you can redistribute it and/or | ||
| 4 | * modify it under the terms of the GNU General Public License | ||
| 5 | * as published by the Free Software Foundation; either version 2 | ||
| 6 | * of the License. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * Author: Vijay Subramanian <vijaynsu@cisco.com> | ||
| 14 | * Author: Mythili Prabhu <mysuryan@cisco.com> | ||
| 15 | * | ||
| 16 | * ECN support is added by Naeem Khademi <naeemk@ifi.uio.no> | ||
| 17 | * University of Oslo, Norway. | ||
| 18 | */ | ||
| 19 | |||
| 20 | #include <linux/module.h> | ||
| 21 | #include <linux/slab.h> | ||
| 22 | #include <linux/types.h> | ||
| 23 | #include <linux/kernel.h> | ||
| 24 | #include <linux/errno.h> | ||
| 25 | #include <linux/skbuff.h> | ||
| 26 | #include <net/pkt_sched.h> | ||
| 27 | #include <net/inet_ecn.h> | ||
| 28 | |||
| 29 | #define QUEUE_THRESHOLD 10000 | ||
| 30 | #define DQCOUNT_INVALID -1 | ||
| 31 | #define MAX_PROB 0xffffffff | ||
| 32 | #define PIE_SCALE 8 | ||
| 33 | |||
| 34 | /* parameters used */ | ||
| 35 | struct pie_params { | ||
| 36 | psched_time_t target; /* user specified target delay in pschedtime */ | ||
| 37 | u32 tupdate; /* timer frequency (in jiffies) */ | ||
| 38 | u32 limit; /* number of packets that can be enqueued */ | ||
| 39 | u32 alpha; /* alpha and beta are between -4 and 4 */ | ||
| 40 | u32 beta; /* and are used for shift relative to 1 */ | ||
| 41 | bool ecn; /* true if ecn is enabled */ | ||
| 42 | bool bytemode; /* to scale drop early prob based on pkt size */ | ||
| 43 | }; | ||
| 44 | |||
| 45 | /* variables used */ | ||
| 46 | struct pie_vars { | ||
| 47 | u32 prob; /* probability but scaled by u32 limit. */ | ||
| 48 | psched_time_t burst_time; | ||
| 49 | psched_time_t qdelay; | ||
| 50 | psched_time_t qdelay_old; | ||
| 51 | u64 dq_count; /* measured in bytes */ | ||
| 52 | psched_time_t dq_tstamp; /* drain rate */ | ||
| 53 | u32 avg_dq_rate; /* bytes per pschedtime tick,scaled */ | ||
| 54 | u32 qlen_old; /* in bytes */ | ||
| 55 | }; | ||
| 56 | |||
| 57 | /* statistics gathering */ | ||
| 58 | struct pie_stats { | ||
| 59 | u32 packets_in; /* total number of packets enqueued */ | ||
| 60 | u32 dropped; /* packets dropped due to pie_action */ | ||
| 61 | u32 overlimit; /* dropped due to lack of space in queue */ | ||
| 62 | u32 maxq; /* maximum queue size */ | ||
| 63 | u32 ecn_mark; /* packets marked with ECN */ | ||
| 64 | }; | ||
| 65 | |||
| 66 | /* private data for the Qdisc */ | ||
| 67 | struct pie_sched_data { | ||
| 68 | struct pie_params params; | ||
| 69 | struct pie_vars vars; | ||
| 70 | struct pie_stats stats; | ||
| 71 | struct timer_list adapt_timer; | ||
| 72 | }; | ||
| 73 | |||
| 74 | static void pie_params_init(struct pie_params *params) | ||
| 75 | { | ||
| 76 | params->alpha = 2; | ||
| 77 | params->beta = 20; | ||
| 78 | params->tupdate = usecs_to_jiffies(30 * USEC_PER_MSEC); /* 30 ms */ | ||
| 79 | params->limit = 1000; /* default of 1000 packets */ | ||
| 80 | params->target = PSCHED_NS2TICKS(20 * NSEC_PER_MSEC); /* 20 ms */ | ||
| 81 | params->ecn = false; | ||
| 82 | params->bytemode = false; | ||
| 83 | } | ||
| 84 | |||
| 85 | static void pie_vars_init(struct pie_vars *vars) | ||
| 86 | { | ||
| 87 | vars->dq_count = DQCOUNT_INVALID; | ||
| 88 | vars->avg_dq_rate = 0; | ||
| 89 | /* default of 100 ms in pschedtime */ | ||
| 90 | vars->burst_time = PSCHED_NS2TICKS(100 * NSEC_PER_MSEC); | ||
| 91 | } | ||
| 92 | |||
| 93 | static bool drop_early(struct Qdisc *sch, u32 packet_size) | ||
| 94 | { | ||
| 95 | struct pie_sched_data *q = qdisc_priv(sch); | ||
| 96 | u32 rnd; | ||
| 97 | u32 local_prob = q->vars.prob; | ||
| 98 | u32 mtu = psched_mtu(qdisc_dev(sch)); | ||
| 99 | |||
| 100 | /* If there is still burst allowance left skip random early drop */ | ||
| 101 | if (q->vars.burst_time > 0) | ||
| 102 | return false; | ||
| 103 | |||
| 104 | /* If current delay is less than half of target, and | ||
| 105 | * if drop prob is low already, disable early_drop | ||
| 106 | */ | ||
| 107 | if ((q->vars.qdelay < q->params.target / 2) | ||
| 108 | && (q->vars.prob < MAX_PROB / 5)) | ||
| 109 | return false; | ||
| 110 | |||
| 111 | /* If we have fewer than 2 mtu-sized packets, disable drop_early, | ||
| 112 | * similar to min_th in RED | ||
| 113 | */ | ||
| 114 | if (sch->qstats.backlog < 2 * mtu) | ||
| 115 | return false; | ||
| 116 | |||
| 117 | /* If bytemode is turned on, use packet size to compute new | ||
| 118 | * probablity. Smaller packets will have lower drop prob in this case | ||
| 119 | */ | ||
| 120 | if (q->params.bytemode && packet_size <= mtu) | ||
| 121 | local_prob = (local_prob / mtu) * packet_size; | ||
| 122 | else | ||
| 123 | local_prob = q->vars.prob; | ||
| 124 | |||
| 125 | rnd = prandom_u32(); | ||
| 126 | if (rnd < local_prob) | ||
| 127 | return true; | ||
| 128 | |||
| 129 | return false; | ||
| 130 | } | ||
| 131 | |||
| 132 | static int pie_qdisc_enqueue(struct sk_buff *skb, struct Qdisc *sch) | ||
| 133 | { | ||
| 134 | struct pie_sched_data *q = qdisc_priv(sch); | ||
| 135 | bool enqueue = false; | ||
| 136 | |||
| 137 | if (unlikely(qdisc_qlen(sch) >= sch->limit)) { | ||
| 138 | q->stats.overlimit++; | ||
| 139 | goto out; | ||
| 140 | } | ||
| 141 | |||
| 142 | if (!drop_early(sch, skb->len)) { | ||
| 143 | enqueue = true; | ||
| 144 | } else if (q->params.ecn && (q->vars.prob <= MAX_PROB / 10) && | ||
| 145 | INET_ECN_set_ce(skb)) { | ||
| 146 | /* If packet is ecn capable, mark it if drop probability | ||
| 147 | * is lower than 10%, else drop it. | ||
| 148 | */ | ||
| 149 | q->stats.ecn_mark++; | ||
| 150 | enqueue = true; | ||
| 151 | } | ||
| 152 | |||
| 153 | /* we can enqueue the packet */ | ||
| 154 | if (enqueue) { | ||
| 155 | q->stats.packets_in++; | ||
| 156 | if (qdisc_qlen(sch) > q->stats.maxq) | ||
| 157 | q->stats.maxq = qdisc_qlen(sch); | ||
| 158 | |||
| 159 | return qdisc_enqueue_tail(skb, sch); | ||
| 160 | } | ||
| 161 | |||
| 162 | out: | ||
| 163 | q->stats.dropped++; | ||
| 164 | return qdisc_drop(skb, sch); | ||
| 165 | } | ||
| 166 | |||
| 167 | static const struct nla_policy pie_policy[TCA_PIE_MAX + 1] = { | ||
| 168 | [TCA_PIE_TARGET] = {.type = NLA_U32}, | ||
| 169 | [TCA_PIE_LIMIT] = {.type = NLA_U32}, | ||
| 170 | [TCA_PIE_TUPDATE] = {.type = NLA_U32}, | ||
| 171 | [TCA_PIE_ALPHA] = {.type = NLA_U32}, | ||
| 172 | [TCA_PIE_BETA] = {.type = NLA_U32}, | ||
| 173 | [TCA_PIE_ECN] = {.type = NLA_U32}, | ||
| 174 | [TCA_PIE_BYTEMODE] = {.type = NLA_U32}, | ||
| 175 | }; | ||
| 176 | |||
| 177 | static int pie_change(struct Qdisc *sch, struct nlattr *opt) | ||
| 178 | { | ||
| 179 | struct pie_sched_data *q = qdisc_priv(sch); | ||
| 180 | struct nlattr *tb[TCA_PIE_MAX + 1]; | ||
| 181 | unsigned int qlen; | ||
| 182 | int err; | ||
| 183 | |||
| 184 | if (!opt) | ||
| 185 | return -EINVAL; | ||
| 186 | |||
| 187 | err = nla_parse_nested(tb, TCA_PIE_MAX, opt, pie_policy); | ||
| 188 | if (err < 0) | ||
| 189 | return err; | ||
| 190 | |||
| 191 | sch_tree_lock(sch); | ||
| 192 | |||
| 193 | /* convert from microseconds to pschedtime */ | ||
| 194 | if (tb[TCA_PIE_TARGET]) { | ||
| 195 | /* target is in us */ | ||
| 196 | u32 target = nla_get_u32(tb[TCA_PIE_TARGET]); | ||
| 197 | |||
| 198 | /* convert to pschedtime */ | ||
| 199 | q->params.target = PSCHED_NS2TICKS((u64)target * NSEC_PER_USEC); | ||
| 200 | } | ||
| 201 | |||
| 202 | /* tupdate is in jiffies */ | ||
| 203 | if (tb[TCA_PIE_TUPDATE]) | ||
| 204 | q->params.tupdate = usecs_to_jiffies(nla_get_u32(tb[TCA_PIE_TUPDATE])); | ||
| 205 | |||
| 206 | if (tb[TCA_PIE_LIMIT]) { | ||
| 207 | u32 limit = nla_get_u32(tb[TCA_PIE_LIMIT]); | ||
| 208 | |||
| 209 | q->params.limit = limit; | ||
| 210 | sch->limit = limit; | ||
| 211 | } | ||
| 212 | |||
| 213 | if (tb[TCA_PIE_ALPHA]) | ||
| 214 | q->params.alpha = nla_get_u32(tb[TCA_PIE_ALPHA]); | ||
| 215 | |||
| 216 | if (tb[TCA_PIE_BETA]) | ||
| 217 | q->params.beta = nla_get_u32(tb[TCA_PIE_BETA]); | ||
| 218 | |||
| 219 | if (tb[TCA_PIE_ECN]) | ||
| 220 | q->params.ecn = nla_get_u32(tb[TCA_PIE_ECN]); | ||
| 221 | |||
| 222 | if (tb[TCA_PIE_BYTEMODE]) | ||
| 223 | q->params.bytemode = nla_get_u32(tb[TCA_PIE_BYTEMODE]); | ||
| 224 | |||
| 225 | /* Drop excess packets if new limit is lower */ | ||
| 226 | qlen = sch->q.qlen; | ||
| 227 | while (sch->q.qlen > sch->limit) { | ||
| 228 | struct sk_buff *skb = __skb_dequeue(&sch->q); | ||
| 229 | |||
| 230 | sch->qstats.backlog -= qdisc_pkt_len(skb); | ||
| 231 | qdisc_drop(skb, sch); | ||
| 232 | } | ||
| 233 | qdisc_tree_decrease_qlen(sch, qlen - sch->q.qlen); | ||
| 234 | |||
| 235 | sch_tree_unlock(sch); | ||
| 236 | return 0; | ||
| 237 | } | ||
| 238 | |||
| 239 | static void pie_process_dequeue(struct Qdisc *sch, struct sk_buff *skb) | ||
| 240 | { | ||
| 241 | |||
| 242 | struct pie_sched_data *q = qdisc_priv(sch); | ||
| 243 | int qlen = sch->qstats.backlog; /* current queue size in bytes */ | ||
| 244 | |||
| 245 | /* If current queue is about 10 packets or more and dq_count is unset | ||
| 246 | * we have enough packets to calculate the drain rate. Save | ||
| 247 | * current time as dq_tstamp and start measurement cycle. | ||
| 248 | */ | ||
| 249 | if (qlen >= QUEUE_THRESHOLD && q->vars.dq_count == DQCOUNT_INVALID) { | ||
| 250 | q->vars.dq_tstamp = psched_get_time(); | ||
| 251 | q->vars.dq_count = 0; | ||
| 252 | } | ||
| 253 | |||
| 254 | /* Calculate the average drain rate from this value. If queue length | ||
| 255 | * has receded to a small value viz., <= QUEUE_THRESHOLD bytes,reset | ||
| 256 | * the dq_count to -1 as we don't have enough packets to calculate the | ||
| 257 | * drain rate anymore The following if block is entered only when we | ||
| 258 | * have a substantial queue built up (QUEUE_THRESHOLD bytes or more) | ||
| 259 | * and we calculate the drain rate for the threshold here. dq_count is | ||
| 260 | * in bytes, time difference in psched_time, hence rate is in | ||
| 261 | * bytes/psched_time. | ||
| 262 | */ | ||
| 263 | if (q->vars.dq_count != DQCOUNT_INVALID) { | ||
| 264 | q->vars.dq_count += skb->len; | ||
| 265 | |||
| 266 | if (q->vars.dq_count >= QUEUE_THRESHOLD) { | ||
| 267 | psched_time_t now = psched_get_time(); | ||
| 268 | u32 dtime = now - q->vars.dq_tstamp; | ||
| 269 | u32 count = q->vars.dq_count << PIE_SCALE; | ||
| 270 | |||
| 271 | if (dtime == 0) | ||
| 272 | return; | ||
| 273 | |||
| 274 | count = count / dtime; | ||
| 275 | |||
| 276 | if (q->vars.avg_dq_rate == 0) | ||
| 277 | q->vars.avg_dq_rate = count; | ||
| 278 | else | ||
| 279 | q->vars.avg_dq_rate = | ||
| 280 | (q->vars.avg_dq_rate - | ||
| 281 | (q->vars.avg_dq_rate >> 3)) + (count >> 3); | ||
| 282 | |||
| 283 | /* If the queue has receded below the threshold, we hold | ||
| 284 | * on to the last drain rate calculated, else we reset | ||
| 285 | * dq_count to 0 to re-enter the if block when the next | ||
| 286 | * packet is dequeued | ||
| 287 | */ | ||
| 288 | if (qlen < QUEUE_THRESHOLD) | ||
| 289 | q->vars.dq_count = DQCOUNT_INVALID; | ||
| 290 | else { | ||
| 291 | q->vars.dq_count = 0; | ||
| 292 | q->vars.dq_tstamp = psched_get_time(); | ||
| 293 | } | ||
| 294 | |||
| 295 | if (q->vars.burst_time > 0) { | ||
| 296 | if (q->vars.burst_time > dtime) | ||
| 297 | q->vars.burst_time -= dtime; | ||
| 298 | else | ||
| 299 | q->vars.burst_time = 0; | ||
| 300 | } | ||
| 301 | } | ||
| 302 | } | ||
| 303 | } | ||
| 304 | |||
| 305 | static void calculate_probability(struct Qdisc *sch) | ||
| 306 | { | ||
| 307 | struct pie_sched_data *q = qdisc_priv(sch); | ||
| 308 | u32 qlen = sch->qstats.backlog; /* queue size in bytes */ | ||
| 309 | psched_time_t qdelay = 0; /* in pschedtime */ | ||
| 310 | psched_time_t qdelay_old = q->vars.qdelay; /* in pschedtime */ | ||
| 311 | s32 delta = 0; /* determines the change in probability */ | ||
| 312 | u32 oldprob; | ||
| 313 | u32 alpha, beta; | ||
| 314 | bool update_prob = true; | ||
| 315 | |||
| 316 | q->vars.qdelay_old = q->vars.qdelay; | ||
| 317 | |||
| 318 | if (q->vars.avg_dq_rate > 0) | ||
| 319 | qdelay = (qlen << PIE_SCALE) / q->vars.avg_dq_rate; | ||
| 320 | else | ||
| 321 | qdelay = 0; | ||
| 322 | |||
| 323 | /* If qdelay is zero and qlen is not, it means qlen is very small, less | ||
| 324 | * than dequeue_rate, so we do not update probabilty in this round | ||
| 325 | */ | ||
| 326 | if (qdelay == 0 && qlen != 0) | ||
| 327 | update_prob = false; | ||
| 328 | |||
| 329 | /* Add ranges for alpha and beta, more aggressive for high dropping | ||
| 330 | * mode and gentle steps for light dropping mode | ||
| 331 | * In light dropping mode, take gentle steps; in medium dropping mode, | ||
| 332 | * take medium steps; in high dropping mode, take big steps. | ||
| 333 | */ | ||
| 334 | if (q->vars.prob < MAX_PROB / 100) { | ||
| 335 | alpha = | ||
| 336 | (q->params.alpha * (MAX_PROB / PSCHED_TICKS_PER_SEC)) >> 7; | ||
| 337 | beta = | ||
| 338 | (q->params.beta * (MAX_PROB / PSCHED_TICKS_PER_SEC)) >> 7; | ||
| 339 | } else if (q->vars.prob < MAX_PROB / 10) { | ||
| 340 | alpha = | ||
| 341 | (q->params.alpha * (MAX_PROB / PSCHED_TICKS_PER_SEC)) >> 5; | ||
| 342 | beta = | ||
| 343 | (q->params.beta * (MAX_PROB / PSCHED_TICKS_PER_SEC)) >> 5; | ||
| 344 | } else { | ||
| 345 | alpha = | ||
| 346 | (q->params.alpha * (MAX_PROB / PSCHED_TICKS_PER_SEC)) >> 4; | ||
| 347 | beta = | ||
| 348 | (q->params.beta * (MAX_PROB / PSCHED_TICKS_PER_SEC)) >> 4; | ||
| 349 | } | ||
| 350 | |||
| 351 | /* alpha and beta should be between 0 and 32, in multiples of 1/16 */ | ||
| 352 | delta += alpha * ((qdelay - q->params.target)); | ||
| 353 | delta += beta * ((qdelay - qdelay_old)); | ||
| 354 | |||
| 355 | oldprob = q->vars.prob; | ||
| 356 | |||
| 357 | /* to ensure we increase probability in steps of no more than 2% */ | ||
| 358 | if (delta > (s32) (MAX_PROB / (100 / 2)) && | ||
| 359 | q->vars.prob >= MAX_PROB / 10) | ||
| 360 | delta = (MAX_PROB / 100) * 2; | ||
| 361 | |||
| 362 | /* Non-linear drop: | ||
| 363 | * Tune drop probability to increase quickly for high delays(>= 250ms) | ||
| 364 | * 250ms is derived through experiments and provides error protection | ||
| 365 | */ | ||
| 366 | |||
| 367 | if (qdelay > (PSCHED_NS2TICKS(250 * NSEC_PER_MSEC))) | ||
| 368 | delta += MAX_PROB / (100 / 2); | ||
| 369 | |||
| 370 | q->vars.prob += delta; | ||
| 371 | |||
| 372 | if (delta > 0) { | ||
| 373 | /* prevent overflow */ | ||
| 374 | if (q->vars.prob < oldprob) { | ||
| 375 | q->vars.prob = MAX_PROB; | ||
| 376 | /* Prevent normalization error. If probability is at | ||
| 377 | * maximum value already, we normalize it here, and | ||
| 378 | * skip the check to do a non-linear drop in the next | ||
| 379 | * section. | ||
| 380 | */ | ||
| 381 | update_prob = false; | ||
| 382 | } | ||
| 383 | } else { | ||
| 384 | /* prevent underflow */ | ||
| 385 | if (q->vars.prob > oldprob) | ||
| 386 | q->vars.prob = 0; | ||
| 387 | } | ||
| 388 | |||
| 389 | /* Non-linear drop in probability: Reduce drop probability quickly if | ||
| 390 | * delay is 0 for 2 consecutive Tupdate periods. | ||
| 391 | */ | ||
| 392 | |||
| 393 | if ((qdelay == 0) && (qdelay_old == 0) && update_prob) | ||
| 394 | q->vars.prob = (q->vars.prob * 98) / 100; | ||
| 395 | |||
| 396 | q->vars.qdelay = qdelay; | ||
| 397 | q->vars.qlen_old = qlen; | ||
| 398 | |||
| 399 | /* We restart the measurement cycle if the following conditions are met | ||
| 400 | * 1. If the delay has been low for 2 consecutive Tupdate periods | ||
| 401 | * 2. Calculated drop probability is zero | ||
| 402 | * 3. We have atleast one estimate for the avg_dq_rate ie., | ||
| 403 | * is a non-zero value | ||
| 404 | */ | ||
| 405 | if ((q->vars.qdelay < q->params.target / 2) && | ||
| 406 | (q->vars.qdelay_old < q->params.target / 2) && | ||
| 407 | (q->vars.prob == 0) && | ||
| 408 | (q->vars.avg_dq_rate > 0)) | ||
| 409 | pie_vars_init(&q->vars); | ||
| 410 | } | ||
| 411 | |||
| 412 | static void pie_timer(unsigned long arg) | ||
| 413 | { | ||
| 414 | struct Qdisc *sch = (struct Qdisc *)arg; | ||
| 415 | struct pie_sched_data *q = qdisc_priv(sch); | ||
| 416 | spinlock_t *root_lock = qdisc_lock(qdisc_root_sleeping(sch)); | ||
| 417 | |||
| 418 | spin_lock(root_lock); | ||
| 419 | calculate_probability(sch); | ||
| 420 | |||
| 421 | /* reset the timer to fire after 'tupdate'. tupdate is in jiffies. */ | ||
| 422 | if (q->params.tupdate) | ||
| 423 | mod_timer(&q->adapt_timer, jiffies + q->params.tupdate); | ||
| 424 | spin_unlock(root_lock); | ||
| 425 | |||
| 426 | } | ||
| 427 | |||
| 428 | static int pie_init(struct Qdisc *sch, struct nlattr *opt) | ||
| 429 | { | ||
| 430 | struct pie_sched_data *q = qdisc_priv(sch); | ||
| 431 | |||
| 432 | pie_params_init(&q->params); | ||
| 433 | pie_vars_init(&q->vars); | ||
| 434 | sch->limit = q->params.limit; | ||
| 435 | |||
| 436 | setup_timer(&q->adapt_timer, pie_timer, (unsigned long)sch); | ||
| 437 | mod_timer(&q->adapt_timer, jiffies + HZ / 2); | ||
| 438 | |||
| 439 | if (opt) { | ||
| 440 | int err = pie_change(sch, opt); | ||
| 441 | |||
| 442 | if (err) | ||
| 443 | return err; | ||
| 444 | } | ||
| 445 | |||
| 446 | return 0; | ||
| 447 | } | ||
| 448 | |||
| 449 | static int pie_dump(struct Qdisc *sch, struct sk_buff *skb) | ||
| 450 | { | ||
| 451 | struct pie_sched_data *q = qdisc_priv(sch); | ||
| 452 | struct nlattr *opts; | ||
| 453 | |||
| 454 | opts = nla_nest_start(skb, TCA_OPTIONS); | ||
| 455 | if (opts == NULL) | ||
| 456 | goto nla_put_failure; | ||
| 457 | |||
| 458 | /* convert target from pschedtime to us */ | ||
| 459 | if (nla_put_u32(skb, TCA_PIE_TARGET, | ||
| 460 | ((u32) PSCHED_TICKS2NS(q->params.target)) / | ||
| 461 | NSEC_PER_USEC) || | ||
| 462 | nla_put_u32(skb, TCA_PIE_LIMIT, sch->limit) || | ||
| 463 | nla_put_u32(skb, TCA_PIE_TUPDATE, jiffies_to_usecs(q->params.tupdate)) || | ||
| 464 | nla_put_u32(skb, TCA_PIE_ALPHA, q->params.alpha) || | ||
| 465 | nla_put_u32(skb, TCA_PIE_BETA, q->params.beta) || | ||
| 466 | nla_put_u32(skb, TCA_PIE_ECN, q->params.ecn) || | ||
| 467 | nla_put_u32(skb, TCA_PIE_BYTEMODE, q->params.bytemode)) | ||
| 468 | goto nla_put_failure; | ||
| 469 | |||
| 470 | return nla_nest_end(skb, opts); | ||
| 471 | |||
| 472 | nla_put_failure: | ||
| 473 | nla_nest_cancel(skb, opts); | ||
| 474 | return -1; | ||
| 475 | |||
| 476 | } | ||
| 477 | |||
| 478 | static int pie_dump_stats(struct Qdisc *sch, struct gnet_dump *d) | ||
| 479 | { | ||
| 480 | struct pie_sched_data *q = qdisc_priv(sch); | ||
| 481 | struct tc_pie_xstats st = { | ||
| 482 | .prob = q->vars.prob, | ||
| 483 | .delay = ((u32) PSCHED_TICKS2NS(q->vars.qdelay)) / | ||
| 484 | NSEC_PER_USEC, | ||
| 485 | /* unscale and return dq_rate in bytes per sec */ | ||
| 486 | .avg_dq_rate = q->vars.avg_dq_rate * | ||
| 487 | (PSCHED_TICKS_PER_SEC) >> PIE_SCALE, | ||
| 488 | .packets_in = q->stats.packets_in, | ||
| 489 | .overlimit = q->stats.overlimit, | ||
| 490 | .maxq = q->stats.maxq, | ||
| 491 | .dropped = q->stats.dropped, | ||
| 492 | .ecn_mark = q->stats.ecn_mark, | ||
| 493 | }; | ||
| 494 | |||
| 495 | return gnet_stats_copy_app(d, &st, sizeof(st)); | ||
| 496 | } | ||
| 497 | |||
| 498 | static struct sk_buff *pie_qdisc_dequeue(struct Qdisc *sch) | ||
| 499 | { | ||
| 500 | struct sk_buff *skb; | ||
| 501 | skb = __qdisc_dequeue_head(sch, &sch->q); | ||
| 502 | |||
| 503 | if (!skb) | ||
| 504 | return NULL; | ||
| 505 | |||
| 506 | pie_process_dequeue(sch, skb); | ||
| 507 | return skb; | ||
| 508 | } | ||
| 509 | |||
| 510 | static void pie_reset(struct Qdisc *sch) | ||
| 511 | { | ||
| 512 | struct pie_sched_data *q = qdisc_priv(sch); | ||
| 513 | qdisc_reset_queue(sch); | ||
| 514 | pie_vars_init(&q->vars); | ||
| 515 | } | ||
| 516 | |||
| 517 | static void pie_destroy(struct Qdisc *sch) | ||
| 518 | { | ||
| 519 | struct pie_sched_data *q = qdisc_priv(sch); | ||
| 520 | q->params.tupdate = 0; | ||
| 521 | del_timer_sync(&q->adapt_timer); | ||
| 522 | } | ||
| 523 | |||
| 524 | static struct Qdisc_ops pie_qdisc_ops __read_mostly = { | ||
| 525 | .id = "pie", | ||
| 526 | .priv_size = sizeof(struct pie_sched_data), | ||
| 527 | .enqueue = pie_qdisc_enqueue, | ||
| 528 | .dequeue = pie_qdisc_dequeue, | ||
| 529 | .peek = qdisc_peek_dequeued, | ||
| 530 | .init = pie_init, | ||
| 531 | .destroy = pie_destroy, | ||
| 532 | .reset = pie_reset, | ||
| 533 | .change = pie_change, | ||
| 534 | .dump = pie_dump, | ||
| 535 | .dump_stats = pie_dump_stats, | ||
| 536 | .owner = THIS_MODULE, | ||
| 537 | }; | ||
| 538 | |||
| 539 | static int __init pie_module_init(void) | ||
| 540 | { | ||
| 541 | return register_qdisc(&pie_qdisc_ops); | ||
| 542 | } | ||
| 543 | |||
| 544 | static void __exit pie_module_exit(void) | ||
| 545 | { | ||
| 546 | unregister_qdisc(&pie_qdisc_ops); | ||
| 547 | } | ||
| 548 | |||
| 549 | module_init(pie_module_init); | ||
| 550 | module_exit(pie_module_exit); | ||
| 551 | |||
| 552 | MODULE_DESCRIPTION("Proportional Integral controller Enhanced (PIE) scheduler"); | ||
| 553 | MODULE_AUTHOR("Vijay Subramanian"); | ||
| 554 | MODULE_AUTHOR("Mythili Prabhu"); | ||
| 555 | MODULE_LICENSE("GPL"); | ||
diff --git a/net/sched/sch_sfb.c b/net/sched/sch_sfb.c index 30ea4674cabd..9b0f7093d970 100644 --- a/net/sched/sch_sfb.c +++ b/net/sched/sch_sfb.c | |||
| @@ -220,7 +220,7 @@ static u32 sfb_compute_qlen(u32 *prob_r, u32 *avgpm_r, const struct sfb_sched_da | |||
| 220 | 220 | ||
| 221 | static void sfb_init_perturbation(u32 slot, struct sfb_sched_data *q) | 221 | static void sfb_init_perturbation(u32 slot, struct sfb_sched_data *q) |
| 222 | { | 222 | { |
| 223 | q->bins[slot].perturbation = net_random(); | 223 | q->bins[slot].perturbation = prandom_u32(); |
| 224 | } | 224 | } |
| 225 | 225 | ||
| 226 | static void sfb_swap_slot(struct sfb_sched_data *q) | 226 | static void sfb_swap_slot(struct sfb_sched_data *q) |
| @@ -381,7 +381,7 @@ static int sfb_enqueue(struct sk_buff *skb, struct Qdisc *sch) | |||
| 381 | goto enqueue; | 381 | goto enqueue; |
| 382 | } | 382 | } |
| 383 | 383 | ||
| 384 | r = net_random() & SFB_MAX_PROB; | 384 | r = prandom_u32() & SFB_MAX_PROB; |
| 385 | 385 | ||
| 386 | if (unlikely(r < p_min)) { | 386 | if (unlikely(r < p_min)) { |
| 387 | if (unlikely(p_min > SFB_MAX_PROB / 2)) { | 387 | if (unlikely(p_min > SFB_MAX_PROB / 2)) { |
diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c index d3a1bc26dbfc..87317ff0b4ec 100644 --- a/net/sched/sch_sfq.c +++ b/net/sched/sch_sfq.c | |||
| @@ -237,10 +237,12 @@ static inline void sfq_link(struct sfq_sched_data *q, sfq_index x) | |||
| 237 | } | 237 | } |
| 238 | 238 | ||
| 239 | #define sfq_unlink(q, x, n, p) \ | 239 | #define sfq_unlink(q, x, n, p) \ |
| 240 | n = q->slots[x].dep.next; \ | 240 | do { \ |
| 241 | p = q->slots[x].dep.prev; \ | 241 | n = q->slots[x].dep.next; \ |
| 242 | sfq_dep_head(q, p)->next = n; \ | 242 | p = q->slots[x].dep.prev; \ |
| 243 | sfq_dep_head(q, n)->prev = p | 243 | sfq_dep_head(q, p)->next = n; \ |
| 244 | sfq_dep_head(q, n)->prev = p; \ | ||
| 245 | } while (0) | ||
| 244 | 246 | ||
| 245 | 247 | ||
| 246 | static inline void sfq_dec(struct sfq_sched_data *q, sfq_index x) | 248 | static inline void sfq_dec(struct sfq_sched_data *q, sfq_index x) |
| @@ -627,7 +629,7 @@ static void sfq_perturbation(unsigned long arg) | |||
| 627 | spinlock_t *root_lock = qdisc_lock(qdisc_root_sleeping(sch)); | 629 | spinlock_t *root_lock = qdisc_lock(qdisc_root_sleeping(sch)); |
| 628 | 630 | ||
| 629 | spin_lock(root_lock); | 631 | spin_lock(root_lock); |
| 630 | q->perturbation = net_random(); | 632 | q->perturbation = prandom_u32(); |
| 631 | if (!q->filter_list && q->tail) | 633 | if (!q->filter_list && q->tail) |
| 632 | sfq_rehash(sch); | 634 | sfq_rehash(sch); |
| 633 | spin_unlock(root_lock); | 635 | spin_unlock(root_lock); |
| @@ -696,7 +698,7 @@ static int sfq_change(struct Qdisc *sch, struct nlattr *opt) | |||
| 696 | del_timer(&q->perturb_timer); | 698 | del_timer(&q->perturb_timer); |
| 697 | if (q->perturb_period) { | 699 | if (q->perturb_period) { |
| 698 | mod_timer(&q->perturb_timer, jiffies + q->perturb_period); | 700 | mod_timer(&q->perturb_timer, jiffies + q->perturb_period); |
| 699 | q->perturbation = net_random(); | 701 | q->perturbation = prandom_u32(); |
| 700 | } | 702 | } |
| 701 | sch_tree_unlock(sch); | 703 | sch_tree_unlock(sch); |
| 702 | kfree(p); | 704 | kfree(p); |
| @@ -757,7 +759,7 @@ static int sfq_init(struct Qdisc *sch, struct nlattr *opt) | |||
| 757 | q->quantum = psched_mtu(qdisc_dev(sch)); | 759 | q->quantum = psched_mtu(qdisc_dev(sch)); |
| 758 | q->scaled_quantum = SFQ_ALLOT_SIZE(q->quantum); | 760 | q->scaled_quantum = SFQ_ALLOT_SIZE(q->quantum); |
| 759 | q->perturb_period = 0; | 761 | q->perturb_period = 0; |
| 760 | q->perturbation = net_random(); | 762 | q->perturbation = prandom_u32(); |
| 761 | 763 | ||
| 762 | if (opt) { | 764 | if (opt) { |
| 763 | int err = sfq_change(sch, opt); | 765 | int err = sfq_change(sch, opt); |
diff --git a/net/sched/sch_tbf.c b/net/sched/sch_tbf.c index 887e672f9d7d..1cb413fead89 100644 --- a/net/sched/sch_tbf.c +++ b/net/sched/sch_tbf.c | |||
| @@ -21,7 +21,6 @@ | |||
| 21 | #include <net/netlink.h> | 21 | #include <net/netlink.h> |
| 22 | #include <net/sch_generic.h> | 22 | #include <net/sch_generic.h> |
| 23 | #include <net/pkt_sched.h> | 23 | #include <net/pkt_sched.h> |
| 24 | #include <net/tcp.h> | ||
| 25 | 24 | ||
| 26 | 25 | ||
| 27 | /* Simple Token Bucket Filter. | 26 | /* Simple Token Bucket Filter. |
| @@ -148,16 +147,10 @@ static u64 psched_ns_t2l(const struct psched_ratecfg *r, | |||
| 148 | * Return length of individual segments of a gso packet, | 147 | * Return length of individual segments of a gso packet, |
| 149 | * including all headers (MAC, IP, TCP/UDP) | 148 | * including all headers (MAC, IP, TCP/UDP) |
| 150 | */ | 149 | */ |
| 151 | static unsigned int skb_gso_seglen(const struct sk_buff *skb) | 150 | static unsigned int skb_gso_mac_seglen(const struct sk_buff *skb) |
| 152 | { | 151 | { |
| 153 | unsigned int hdr_len = skb_transport_header(skb) - skb_mac_header(skb); | 152 | unsigned int hdr_len = skb_transport_header(skb) - skb_mac_header(skb); |
| 154 | const struct skb_shared_info *shinfo = skb_shinfo(skb); | 153 | return hdr_len + skb_gso_transport_seglen(skb); |
| 155 | |||
| 156 | if (likely(shinfo->gso_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6))) | ||
| 157 | hdr_len += tcp_hdrlen(skb); | ||
| 158 | else | ||
| 159 | hdr_len += sizeof(struct udphdr); | ||
| 160 | return hdr_len + shinfo->gso_size; | ||
| 161 | } | 154 | } |
| 162 | 155 | ||
| 163 | /* GSO packet is too big, segment it so that tbf can transmit | 156 | /* GSO packet is too big, segment it so that tbf can transmit |
| @@ -202,7 +195,7 @@ static int tbf_enqueue(struct sk_buff *skb, struct Qdisc *sch) | |||
| 202 | int ret; | 195 | int ret; |
| 203 | 196 | ||
| 204 | if (qdisc_pkt_len(skb) > q->max_size) { | 197 | if (qdisc_pkt_len(skb) > q->max_size) { |
| 205 | if (skb_is_gso(skb) && skb_gso_seglen(skb) <= q->max_size) | 198 | if (skb_is_gso(skb) && skb_gso_mac_seglen(skb) <= q->max_size) |
| 206 | return tbf_segment(skb, sch); | 199 | return tbf_segment(skb, sch); |
| 207 | return qdisc_reshape_fail(skb, sch); | 200 | return qdisc_reshape_fail(skb, sch); |
| 208 | } | 201 | } |
| @@ -307,6 +300,8 @@ static const struct nla_policy tbf_policy[TCA_TBF_MAX + 1] = { | |||
| 307 | [TCA_TBF_PTAB] = { .type = NLA_BINARY, .len = TC_RTAB_SIZE }, | 300 | [TCA_TBF_PTAB] = { .type = NLA_BINARY, .len = TC_RTAB_SIZE }, |
| 308 | [TCA_TBF_RATE64] = { .type = NLA_U64 }, | 301 | [TCA_TBF_RATE64] = { .type = NLA_U64 }, |
| 309 | [TCA_TBF_PRATE64] = { .type = NLA_U64 }, | 302 | [TCA_TBF_PRATE64] = { .type = NLA_U64 }, |
| 303 | [TCA_TBF_BURST] = { .type = NLA_U32 }, | ||
| 304 | [TCA_TBF_PBURST] = { .type = NLA_U32 }, | ||
| 310 | }; | 305 | }; |
| 311 | 306 | ||
| 312 | static int tbf_change(struct Qdisc *sch, struct nlattr *opt) | 307 | static int tbf_change(struct Qdisc *sch, struct nlattr *opt) |
| @@ -358,7 +353,12 @@ static int tbf_change(struct Qdisc *sch, struct nlattr *opt) | |||
| 358 | rate64 = nla_get_u64(tb[TCA_TBF_RATE64]); | 353 | rate64 = nla_get_u64(tb[TCA_TBF_RATE64]); |
| 359 | psched_ratecfg_precompute(&rate, &qopt->rate, rate64); | 354 | psched_ratecfg_precompute(&rate, &qopt->rate, rate64); |
| 360 | 355 | ||
| 361 | max_size = min_t(u64, psched_ns_t2l(&rate, buffer), ~0U); | 356 | if (tb[TCA_TBF_BURST]) { |
| 357 | max_size = nla_get_u32(tb[TCA_TBF_BURST]); | ||
| 358 | buffer = psched_l2t_ns(&rate, max_size); | ||
| 359 | } else { | ||
| 360 | max_size = min_t(u64, psched_ns_t2l(&rate, buffer), ~0U); | ||
| 361 | } | ||
| 362 | 362 | ||
| 363 | if (qopt->peakrate.rate) { | 363 | if (qopt->peakrate.rate) { |
| 364 | if (tb[TCA_TBF_PRATE64]) | 364 | if (tb[TCA_TBF_PRATE64]) |
| @@ -366,12 +366,18 @@ static int tbf_change(struct Qdisc *sch, struct nlattr *opt) | |||
| 366 | psched_ratecfg_precompute(&peak, &qopt->peakrate, prate64); | 366 | psched_ratecfg_precompute(&peak, &qopt->peakrate, prate64); |
| 367 | if (peak.rate_bytes_ps <= rate.rate_bytes_ps) { | 367 | if (peak.rate_bytes_ps <= rate.rate_bytes_ps) { |
| 368 | pr_warn_ratelimited("sch_tbf: peakrate %llu is lower than or equals to rate %llu !\n", | 368 | pr_warn_ratelimited("sch_tbf: peakrate %llu is lower than or equals to rate %llu !\n", |
| 369 | peak.rate_bytes_ps, rate.rate_bytes_ps); | 369 | peak.rate_bytes_ps, rate.rate_bytes_ps); |
| 370 | err = -EINVAL; | 370 | err = -EINVAL; |
| 371 | goto done; | 371 | goto done; |
| 372 | } | 372 | } |
| 373 | 373 | ||
| 374 | max_size = min_t(u64, max_size, psched_ns_t2l(&peak, mtu)); | 374 | if (tb[TCA_TBF_PBURST]) { |
| 375 | u32 pburst = nla_get_u32(tb[TCA_TBF_PBURST]); | ||
| 376 | max_size = min_t(u32, max_size, pburst); | ||
| 377 | mtu = psched_l2t_ns(&peak, pburst); | ||
| 378 | } else { | ||
| 379 | max_size = min_t(u64, max_size, psched_ns_t2l(&peak, mtu)); | ||
| 380 | } | ||
| 375 | } | 381 | } |
| 376 | 382 | ||
| 377 | if (max_size < psched_mtu(qdisc_dev(sch))) | 383 | if (max_size < psched_mtu(qdisc_dev(sch))) |
| @@ -391,9 +397,15 @@ static int tbf_change(struct Qdisc *sch, struct nlattr *opt) | |||
| 391 | q->qdisc = child; | 397 | q->qdisc = child; |
| 392 | } | 398 | } |
| 393 | q->limit = qopt->limit; | 399 | q->limit = qopt->limit; |
| 394 | q->mtu = PSCHED_TICKS2NS(qopt->mtu); | 400 | if (tb[TCA_TBF_PBURST]) |
| 401 | q->mtu = mtu; | ||
| 402 | else | ||
| 403 | q->mtu = PSCHED_TICKS2NS(qopt->mtu); | ||
| 395 | q->max_size = max_size; | 404 | q->max_size = max_size; |
| 396 | q->buffer = PSCHED_TICKS2NS(qopt->buffer); | 405 | if (tb[TCA_TBF_BURST]) |
| 406 | q->buffer = buffer; | ||
| 407 | else | ||
| 408 | q->buffer = PSCHED_TICKS2NS(qopt->buffer); | ||
| 397 | q->tokens = q->buffer; | 409 | q->tokens = q->buffer; |
| 398 | q->ptokens = q->mtu; | 410 | q->ptokens = q->mtu; |
| 399 | 411 | ||
diff --git a/net/sctp/associola.c b/net/sctp/associola.c index 31ed008c8e13..5ae609200674 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c | |||
| @@ -22,9 +22,8 @@ | |||
| 22 | * See the GNU General Public License for more details. | 22 | * See the GNU General Public License for more details. |
| 23 | * | 23 | * |
| 24 | * You should have received a copy of the GNU General Public License | 24 | * You should have received a copy of the GNU General Public License |
| 25 | * along with GNU CC; see the file COPYING. If not, write to | 25 | * along with GNU CC; see the file COPYING. If not, see |
| 26 | * the Free Software Foundation, 59 Temple Place - Suite 330, | 26 | * <http://www.gnu.org/licenses/>. |
| 27 | * Boston, MA 02111-1307, USA. | ||
| 28 | * | 27 | * |
| 29 | * Please send any bug reports or fixes you make to the | 28 | * Please send any bug reports or fixes you make to the |
| 30 | * email address(es): | 29 | * email address(es): |
| @@ -90,14 +89,12 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a | |||
| 90 | 89 | ||
| 91 | /* Initialize the object handling fields. */ | 90 | /* Initialize the object handling fields. */ |
| 92 | atomic_set(&asoc->base.refcnt, 1); | 91 | atomic_set(&asoc->base.refcnt, 1); |
| 93 | asoc->base.dead = false; | ||
| 94 | 92 | ||
| 95 | /* Initialize the bind addr area. */ | 93 | /* Initialize the bind addr area. */ |
| 96 | sctp_bind_addr_init(&asoc->base.bind_addr, ep->base.bind_addr.port); | 94 | sctp_bind_addr_init(&asoc->base.bind_addr, ep->base.bind_addr.port); |
| 97 | 95 | ||
| 98 | asoc->state = SCTP_STATE_CLOSED; | 96 | asoc->state = SCTP_STATE_CLOSED; |
| 99 | asoc->cookie_life = ms_to_ktime(sp->assocparams.sasoc_cookie_life); | 97 | asoc->cookie_life = ms_to_ktime(sp->assocparams.sasoc_cookie_life); |
| 100 | asoc->frag_point = 0; | ||
| 101 | asoc->user_frag = sp->user_frag; | 98 | asoc->user_frag = sp->user_frag; |
| 102 | 99 | ||
| 103 | /* Set the association max_retrans and RTO values from the | 100 | /* Set the association max_retrans and RTO values from the |
| @@ -110,8 +107,6 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a | |||
| 110 | asoc->rto_max = msecs_to_jiffies(sp->rtoinfo.srto_max); | 107 | asoc->rto_max = msecs_to_jiffies(sp->rtoinfo.srto_max); |
| 111 | asoc->rto_min = msecs_to_jiffies(sp->rtoinfo.srto_min); | 108 | asoc->rto_min = msecs_to_jiffies(sp->rtoinfo.srto_min); |
| 112 | 109 | ||
| 113 | asoc->overall_error_count = 0; | ||
| 114 | |||
| 115 | /* Initialize the association's heartbeat interval based on the | 110 | /* Initialize the association's heartbeat interval based on the |
| 116 | * sock configured value. | 111 | * sock configured value. |
| 117 | */ | 112 | */ |
| @@ -132,18 +127,15 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a | |||
| 132 | */ | 127 | */ |
| 133 | asoc->param_flags = sp->param_flags; | 128 | asoc->param_flags = sp->param_flags; |
| 134 | 129 | ||
| 135 | /* Initialize the maximum mumber of new data packets that can be sent | 130 | /* Initialize the maximum number of new data packets that can be sent |
| 136 | * in a burst. | 131 | * in a burst. |
| 137 | */ | 132 | */ |
| 138 | asoc->max_burst = sp->max_burst; | 133 | asoc->max_burst = sp->max_burst; |
| 139 | 134 | ||
| 140 | /* initialize association timers */ | 135 | /* initialize association timers */ |
| 141 | asoc->timeouts[SCTP_EVENT_TIMEOUT_NONE] = 0; | ||
| 142 | asoc->timeouts[SCTP_EVENT_TIMEOUT_T1_COOKIE] = asoc->rto_initial; | 136 | asoc->timeouts[SCTP_EVENT_TIMEOUT_T1_COOKIE] = asoc->rto_initial; |
| 143 | asoc->timeouts[SCTP_EVENT_TIMEOUT_T1_INIT] = asoc->rto_initial; | 137 | asoc->timeouts[SCTP_EVENT_TIMEOUT_T1_INIT] = asoc->rto_initial; |
| 144 | asoc->timeouts[SCTP_EVENT_TIMEOUT_T2_SHUTDOWN] = asoc->rto_initial; | 138 | asoc->timeouts[SCTP_EVENT_TIMEOUT_T2_SHUTDOWN] = asoc->rto_initial; |
| 145 | asoc->timeouts[SCTP_EVENT_TIMEOUT_T3_RTX] = 0; | ||
| 146 | asoc->timeouts[SCTP_EVENT_TIMEOUT_T4_RTO] = 0; | ||
| 147 | 139 | ||
| 148 | /* sctpimpguide Section 2.12.2 | 140 | /* sctpimpguide Section 2.12.2 |
| 149 | * If the 'T5-shutdown-guard' timer is used, it SHOULD be set to the | 141 | * If the 'T5-shutdown-guard' timer is used, it SHOULD be set to the |
| @@ -152,7 +144,6 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a | |||
| 152 | asoc->timeouts[SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD] | 144 | asoc->timeouts[SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD] |
| 153 | = 5 * asoc->rto_max; | 145 | = 5 * asoc->rto_max; |
| 154 | 146 | ||
| 155 | asoc->timeouts[SCTP_EVENT_TIMEOUT_HEARTBEAT] = 0; | ||
| 156 | asoc->timeouts[SCTP_EVENT_TIMEOUT_SACK] = asoc->sackdelay; | 147 | asoc->timeouts[SCTP_EVENT_TIMEOUT_SACK] = asoc->sackdelay; |
| 157 | asoc->timeouts[SCTP_EVENT_TIMEOUT_AUTOCLOSE] = sp->autoclose * HZ; | 148 | asoc->timeouts[SCTP_EVENT_TIMEOUT_AUTOCLOSE] = sp->autoclose * HZ; |
| 158 | 149 | ||
| @@ -172,11 +163,6 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a | |||
| 172 | asoc->max_init_timeo = | 163 | asoc->max_init_timeo = |
| 173 | msecs_to_jiffies(sp->initmsg.sinit_max_init_timeo); | 164 | msecs_to_jiffies(sp->initmsg.sinit_max_init_timeo); |
| 174 | 165 | ||
| 175 | /* Allocate storage for the ssnmap after the inbound and outbound | ||
| 176 | * streams have been negotiated during Init. | ||
| 177 | */ | ||
| 178 | asoc->ssnmap = NULL; | ||
| 179 | |||
| 180 | /* Set the local window size for receive. | 166 | /* Set the local window size for receive. |
| 181 | * This is also the rcvbuf space per association. | 167 | * This is also the rcvbuf space per association. |
| 182 | * RFC 6 - A SCTP receiver MUST be able to receive a minimum of | 168 | * RFC 6 - A SCTP receiver MUST be able to receive a minimum of |
| @@ -189,25 +175,15 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a | |||
| 189 | 175 | ||
| 190 | asoc->a_rwnd = asoc->rwnd; | 176 | asoc->a_rwnd = asoc->rwnd; |
| 191 | 177 | ||
| 192 | asoc->rwnd_over = 0; | ||
| 193 | asoc->rwnd_press = 0; | ||
| 194 | |||
| 195 | /* Use my own max window until I learn something better. */ | 178 | /* Use my own max window until I learn something better. */ |
| 196 | asoc->peer.rwnd = SCTP_DEFAULT_MAXWINDOW; | 179 | asoc->peer.rwnd = SCTP_DEFAULT_MAXWINDOW; |
| 197 | 180 | ||
| 198 | /* Set the sndbuf size for transmit. */ | ||
| 199 | asoc->sndbuf_used = 0; | ||
| 200 | |||
| 201 | /* Initialize the receive memory counter */ | 181 | /* Initialize the receive memory counter */ |
| 202 | atomic_set(&asoc->rmem_alloc, 0); | 182 | atomic_set(&asoc->rmem_alloc, 0); |
| 203 | 183 | ||
| 204 | init_waitqueue_head(&asoc->wait); | 184 | init_waitqueue_head(&asoc->wait); |
| 205 | 185 | ||
| 206 | asoc->c.my_vtag = sctp_generate_tag(ep); | 186 | asoc->c.my_vtag = sctp_generate_tag(ep); |
| 207 | asoc->peer.i.init_tag = 0; /* INIT needs a vtag of 0. */ | ||
| 208 | asoc->c.peer_vtag = 0; | ||
| 209 | asoc->c.my_ttag = 0; | ||
| 210 | asoc->c.peer_ttag = 0; | ||
| 211 | asoc->c.my_port = ep->base.bind_addr.port; | 187 | asoc->c.my_port = ep->base.bind_addr.port; |
| 212 | 188 | ||
| 213 | asoc->c.initial_tsn = sctp_generate_tsn(ep); | 189 | asoc->c.initial_tsn = sctp_generate_tsn(ep); |
| @@ -218,7 +194,6 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a | |||
| 218 | asoc->adv_peer_ack_point = asoc->ctsn_ack_point; | 194 | asoc->adv_peer_ack_point = asoc->ctsn_ack_point; |
| 219 | asoc->highest_sacked = asoc->ctsn_ack_point; | 195 | asoc->highest_sacked = asoc->ctsn_ack_point; |
| 220 | asoc->last_cwr_tsn = asoc->ctsn_ack_point; | 196 | asoc->last_cwr_tsn = asoc->ctsn_ack_point; |
| 221 | asoc->unack_data = 0; | ||
| 222 | 197 | ||
| 223 | /* ADDIP Section 4.1 Asconf Chunk Procedures | 198 | /* ADDIP Section 4.1 Asconf Chunk Procedures |
| 224 | * | 199 | * |
| @@ -237,7 +212,6 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a | |||
| 237 | 212 | ||
| 238 | /* Make an empty list of remote transport addresses. */ | 213 | /* Make an empty list of remote transport addresses. */ |
| 239 | INIT_LIST_HEAD(&asoc->peer.transport_addr_list); | 214 | INIT_LIST_HEAD(&asoc->peer.transport_addr_list); |
| 240 | asoc->peer.transport_count = 0; | ||
| 241 | 215 | ||
| 242 | /* RFC 2960 5.1 Normal Establishment of an Association | 216 | /* RFC 2960 5.1 Normal Establishment of an Association |
| 243 | * | 217 | * |
| @@ -251,20 +225,15 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a | |||
| 251 | * already received one packet.] | 225 | * already received one packet.] |
| 252 | */ | 226 | */ |
| 253 | asoc->peer.sack_needed = 1; | 227 | asoc->peer.sack_needed = 1; |
| 254 | asoc->peer.sack_cnt = 0; | ||
| 255 | asoc->peer.sack_generation = 1; | 228 | asoc->peer.sack_generation = 1; |
| 256 | 229 | ||
| 257 | /* Assume that the peer will tell us if he recognizes ASCONF | 230 | /* Assume that the peer will tell us if he recognizes ASCONF |
| 258 | * as part of INIT exchange. | 231 | * as part of INIT exchange. |
| 259 | * The sctp_addip_noauth option is there for backward compatibilty | 232 | * The sctp_addip_noauth option is there for backward compatibility |
| 260 | * and will revert old behavior. | 233 | * and will revert old behavior. |
| 261 | */ | 234 | */ |
| 262 | asoc->peer.asconf_capable = 0; | ||
| 263 | if (net->sctp.addip_noauth) | 235 | if (net->sctp.addip_noauth) |
| 264 | asoc->peer.asconf_capable = 1; | 236 | asoc->peer.asconf_capable = 1; |
| 265 | asoc->asconf_addr_del_pending = NULL; | ||
| 266 | asoc->src_out_of_asoc_ok = 0; | ||
| 267 | asoc->new_transport = NULL; | ||
| 268 | 237 | ||
| 269 | /* Create an input queue. */ | 238 | /* Create an input queue. */ |
| 270 | sctp_inq_init(&asoc->base.inqueue); | 239 | sctp_inq_init(&asoc->base.inqueue); |
| @@ -276,12 +245,6 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a | |||
| 276 | if (!sctp_ulpq_init(&asoc->ulpq, asoc)) | 245 | if (!sctp_ulpq_init(&asoc->ulpq, asoc)) |
| 277 | goto fail_init; | 246 | goto fail_init; |
| 278 | 247 | ||
| 279 | memset(&asoc->peer.tsn_map, 0, sizeof(struct sctp_tsnmap)); | ||
| 280 | |||
| 281 | asoc->need_ecne = 0; | ||
| 282 | |||
| 283 | asoc->assoc_id = 0; | ||
| 284 | |||
| 285 | /* Assume that peer would support both address types unless we are | 248 | /* Assume that peer would support both address types unless we are |
| 286 | * told otherwise. | 249 | * told otherwise. |
| 287 | */ | 250 | */ |
| @@ -297,9 +260,6 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a | |||
| 297 | asoc->default_timetolive = sp->default_timetolive; | 260 | asoc->default_timetolive = sp->default_timetolive; |
| 298 | asoc->default_rcv_context = sp->default_rcv_context; | 261 | asoc->default_rcv_context = sp->default_rcv_context; |
| 299 | 262 | ||
| 300 | /* SCTP_GET_ASSOC_STATS COUNTERS */ | ||
| 301 | memset(&asoc->stats, 0, sizeof(struct sctp_priv_assoc_stats)); | ||
| 302 | |||
| 303 | /* AUTH related initializations */ | 263 | /* AUTH related initializations */ |
| 304 | INIT_LIST_HEAD(&asoc->endpoint_shared_keys); | 264 | INIT_LIST_HEAD(&asoc->endpoint_shared_keys); |
| 305 | err = sctp_auth_asoc_copy_shkeys(ep, asoc, gfp); | 265 | err = sctp_auth_asoc_copy_shkeys(ep, asoc, gfp); |
| @@ -307,9 +267,7 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a | |||
| 307 | goto fail_init; | 267 | goto fail_init; |
| 308 | 268 | ||
| 309 | asoc->active_key_id = ep->active_key_id; | 269 | asoc->active_key_id = ep->active_key_id; |
| 310 | asoc->asoc_shared_key = NULL; | ||
| 311 | 270 | ||
| 312 | asoc->default_hmac_id = 0; | ||
| 313 | /* Save the hmacs and chunks list into this association */ | 271 | /* Save the hmacs and chunks list into this association */ |
| 314 | if (ep->auth_hmacs_list) | 272 | if (ep->auth_hmacs_list) |
| 315 | memcpy(asoc->c.auth_hmacs, ep->auth_hmacs_list, | 273 | memcpy(asoc->c.auth_hmacs, ep->auth_hmacs_list, |
| @@ -994,17 +952,13 @@ int sctp_cmp_addr_exact(const union sctp_addr *ss1, | |||
| 994 | */ | 952 | */ |
| 995 | struct sctp_chunk *sctp_get_ecne_prepend(struct sctp_association *asoc) | 953 | struct sctp_chunk *sctp_get_ecne_prepend(struct sctp_association *asoc) |
| 996 | { | 954 | { |
| 997 | struct sctp_chunk *chunk; | 955 | if (!asoc->need_ecne) |
| 956 | return NULL; | ||
| 998 | 957 | ||
| 999 | /* Send ECNE if needed. | 958 | /* Send ECNE if needed. |
| 1000 | * Not being able to allocate a chunk here is not deadly. | 959 | * Not being able to allocate a chunk here is not deadly. |
| 1001 | */ | 960 | */ |
| 1002 | if (asoc->need_ecne) | 961 | return sctp_make_ecne(asoc, asoc->last_ecne_tsn); |
| 1003 | chunk = sctp_make_ecne(asoc, asoc->last_ecne_tsn); | ||
| 1004 | else | ||
| 1005 | chunk = NULL; | ||
| 1006 | |||
| 1007 | return chunk; | ||
| 1008 | } | 962 | } |
| 1009 | 963 | ||
| 1010 | /* | 964 | /* |
| @@ -1265,7 +1219,7 @@ void sctp_assoc_update(struct sctp_association *asoc, | |||
| 1265 | } | 1219 | } |
| 1266 | } | 1220 | } |
| 1267 | 1221 | ||
| 1268 | /* SCTP-AUTH: Save the peer parameters from the new assocaitions | 1222 | /* SCTP-AUTH: Save the peer parameters from the new associations |
| 1269 | * and also move the association shared keys over | 1223 | * and also move the association shared keys over |
| 1270 | */ | 1224 | */ |
| 1271 | kfree(asoc->peer.peer_random); | 1225 | kfree(asoc->peer.peer_random); |
| @@ -1393,7 +1347,7 @@ void sctp_assoc_sync_pmtu(struct sock *sk, struct sctp_association *asoc) | |||
| 1393 | } | 1347 | } |
| 1394 | 1348 | ||
| 1395 | /* Should we send a SACK to update our peer? */ | 1349 | /* Should we send a SACK to update our peer? */ |
| 1396 | static inline int sctp_peer_needs_update(struct sctp_association *asoc) | 1350 | static inline bool sctp_peer_needs_update(struct sctp_association *asoc) |
| 1397 | { | 1351 | { |
| 1398 | struct net *net = sock_net(asoc->base.sk); | 1352 | struct net *net = sock_net(asoc->base.sk); |
| 1399 | switch (asoc->state) { | 1353 | switch (asoc->state) { |
| @@ -1405,12 +1359,12 @@ static inline int sctp_peer_needs_update(struct sctp_association *asoc) | |||
| 1405 | ((asoc->rwnd - asoc->a_rwnd) >= max_t(__u32, | 1359 | ((asoc->rwnd - asoc->a_rwnd) >= max_t(__u32, |
| 1406 | (asoc->base.sk->sk_rcvbuf >> net->sctp.rwnd_upd_shift), | 1360 | (asoc->base.sk->sk_rcvbuf >> net->sctp.rwnd_upd_shift), |
| 1407 | asoc->pathmtu))) | 1361 | asoc->pathmtu))) |
| 1408 | return 1; | 1362 | return true; |
| 1409 | break; | 1363 | break; |
| 1410 | default: | 1364 | default: |
| 1411 | break; | 1365 | break; |
| 1412 | } | 1366 | } |
| 1413 | return 0; | 1367 | return false; |
| 1414 | } | 1368 | } |
| 1415 | 1369 | ||
| 1416 | /* Increase asoc's rwnd by len and send any window update SACK if needed. */ | 1370 | /* Increase asoc's rwnd by len and send any window update SACK if needed. */ |
| @@ -1490,7 +1444,7 @@ void sctp_assoc_rwnd_decrease(struct sctp_association *asoc, unsigned int len) | |||
| 1490 | 1444 | ||
| 1491 | /* If we've reached or overflowed our receive buffer, announce | 1445 | /* If we've reached or overflowed our receive buffer, announce |
| 1492 | * a 0 rwnd if rwnd would still be positive. Store the | 1446 | * a 0 rwnd if rwnd would still be positive. Store the |
| 1493 | * the pottential pressure overflow so that the window can be restored | 1447 | * the potential pressure overflow so that the window can be restored |
| 1494 | * back to original value. | 1448 | * back to original value. |
| 1495 | */ | 1449 | */ |
| 1496 | if (rx_count >= asoc->base.sk->sk_rcvbuf) | 1450 | if (rx_count >= asoc->base.sk->sk_rcvbuf) |
diff --git a/net/sctp/auth.c b/net/sctp/auth.c index 46b5977978a1..683c7d1b1306 100644 --- a/net/sctp/auth.c +++ b/net/sctp/auth.c | |||
| @@ -16,9 +16,8 @@ | |||
| 16 | * See the GNU General Public License for more details. | 16 | * See the GNU General Public License for more details. |
| 17 | * | 17 | * |
| 18 | * You should have received a copy of the GNU General Public License | 18 | * You should have received a copy of the GNU General Public License |
| 19 | * along with GNU CC; see the file COPYING. If not, write to | 19 | * along with GNU CC; see the file COPYING. If not, see |
| 20 | * the Free Software Foundation, 59 Temple Place - Suite 330, | 20 | * <http://www.gnu.org/licenses/>. |
| 21 | * Boston, MA 02111-1307, USA. | ||
| 22 | * | 21 | * |
| 23 | * Please send any bug reports or fixes you make to the | 22 | * Please send any bug reports or fixes you make to the |
| 24 | * email address(es): | 23 | * email address(es): |
| @@ -42,7 +41,7 @@ static struct sctp_hmac sctp_hmac_list[SCTP_AUTH_NUM_HMACS] = { | |||
| 42 | }, | 41 | }, |
| 43 | { | 42 | { |
| 44 | .hmac_id = SCTP_AUTH_HMAC_ID_SHA1, | 43 | .hmac_id = SCTP_AUTH_HMAC_ID_SHA1, |
| 45 | .hmac_name="hmac(sha1)", | 44 | .hmac_name = "hmac(sha1)", |
| 46 | .hmac_len = SCTP_SHA1_SIG_SIZE, | 45 | .hmac_len = SCTP_SHA1_SIG_SIZE, |
| 47 | }, | 46 | }, |
| 48 | { | 47 | { |
| @@ -52,7 +51,7 @@ static struct sctp_hmac sctp_hmac_list[SCTP_AUTH_NUM_HMACS] = { | |||
| 52 | #if defined (CONFIG_CRYPTO_SHA256) || defined (CONFIG_CRYPTO_SHA256_MODULE) | 51 | #if defined (CONFIG_CRYPTO_SHA256) || defined (CONFIG_CRYPTO_SHA256_MODULE) |
| 53 | { | 52 | { |
| 54 | .hmac_id = SCTP_AUTH_HMAC_ID_SHA256, | 53 | .hmac_id = SCTP_AUTH_HMAC_ID_SHA256, |
| 55 | .hmac_name="hmac(sha256)", | 54 | .hmac_name = "hmac(sha256)", |
| 56 | .hmac_len = SCTP_SHA256_SIG_SIZE, | 55 | .hmac_len = SCTP_SHA256_SIG_SIZE, |
| 57 | } | 56 | } |
| 58 | #endif | 57 | #endif |
| @@ -164,7 +163,7 @@ static int sctp_auth_compare_vectors(struct sctp_auth_bytes *vector1, | |||
| 164 | * lead-zero padded. If it is not, it | 163 | * lead-zero padded. If it is not, it |
| 165 | * is automatically larger numerically. | 164 | * is automatically larger numerically. |
| 166 | */ | 165 | */ |
| 167 | for (i = 0; i < abs(diff); i++ ) { | 166 | for (i = 0; i < abs(diff); i++) { |
| 168 | if (longer[i] != 0) | 167 | if (longer[i] != 0) |
| 169 | return diff; | 168 | return diff; |
| 170 | } | 169 | } |
| @@ -227,9 +226,9 @@ static struct sctp_auth_bytes *sctp_auth_make_local_vector( | |||
| 227 | gfp_t gfp) | 226 | gfp_t gfp) |
| 228 | { | 227 | { |
| 229 | return sctp_auth_make_key_vector( | 228 | return sctp_auth_make_key_vector( |
| 230 | (sctp_random_param_t*)asoc->c.auth_random, | 229 | (sctp_random_param_t *)asoc->c.auth_random, |
| 231 | (sctp_chunks_param_t*)asoc->c.auth_chunks, | 230 | (sctp_chunks_param_t *)asoc->c.auth_chunks, |
| 232 | (sctp_hmac_algo_param_t*)asoc->c.auth_hmacs, | 231 | (sctp_hmac_algo_param_t *)asoc->c.auth_hmacs, |
| 233 | gfp); | 232 | gfp); |
| 234 | } | 233 | } |
| 235 | 234 | ||
| @@ -500,8 +499,7 @@ void sctp_auth_destroy_hmacs(struct crypto_hash *auth_hmacs[]) | |||
| 500 | if (!auth_hmacs) | 499 | if (!auth_hmacs) |
| 501 | return; | 500 | return; |
| 502 | 501 | ||
| 503 | for (i = 0; i < SCTP_AUTH_NUM_HMACS; i++) | 502 | for (i = 0; i < SCTP_AUTH_NUM_HMACS; i++) { |
| 504 | { | ||
| 505 | if (auth_hmacs[i]) | 503 | if (auth_hmacs[i]) |
| 506 | crypto_free_hash(auth_hmacs[i]); | 504 | crypto_free_hash(auth_hmacs[i]); |
| 507 | } | 505 | } |
| @@ -648,15 +646,15 @@ static int __sctp_auth_cid(sctp_cid_t chunk, struct sctp_chunks_param *param) | |||
| 648 | */ | 646 | */ |
| 649 | for (i = 0; !found && i < len; i++) { | 647 | for (i = 0; !found && i < len; i++) { |
| 650 | switch (param->chunks[i]) { | 648 | switch (param->chunks[i]) { |
| 651 | case SCTP_CID_INIT: | 649 | case SCTP_CID_INIT: |
| 652 | case SCTP_CID_INIT_ACK: | 650 | case SCTP_CID_INIT_ACK: |
| 653 | case SCTP_CID_SHUTDOWN_COMPLETE: | 651 | case SCTP_CID_SHUTDOWN_COMPLETE: |
| 654 | case SCTP_CID_AUTH: | 652 | case SCTP_CID_AUTH: |
| 655 | break; | 653 | break; |
| 656 | 654 | ||
| 657 | default: | 655 | default: |
| 658 | if (param->chunks[i] == chunk) | 656 | if (param->chunks[i] == chunk) |
| 659 | found = 1; | 657 | found = 1; |
| 660 | break; | 658 | break; |
| 661 | } | 659 | } |
| 662 | } | 660 | } |
diff --git a/net/sctp/bind_addr.c b/net/sctp/bind_addr.c index 077bb070052b..871cdf9567e6 100644 --- a/net/sctp/bind_addr.c +++ b/net/sctp/bind_addr.c | |||
| @@ -21,9 +21,8 @@ | |||
| 21 | * See the GNU General Public License for more details. | 21 | * See the GNU General Public License for more details. |
| 22 | * | 22 | * |
| 23 | * You should have received a copy of the GNU General Public License | 23 | * You should have received a copy of the GNU General Public License |
| 24 | * along with GNU CC; see the file COPYING. If not, write to | 24 | * along with GNU CC; see the file COPYING. If not, see |
| 25 | * the Free Software Foundation, 59 Temple Place - Suite 330, | 25 | * <http://www.gnu.org/licenses/>. |
| 26 | * Boston, MA 02111-1307, USA. | ||
| 27 | * | 26 | * |
| 28 | * Please send any bug reports or fixes you make to the | 27 | * Please send any bug reports or fixes you make to the |
| 29 | * email address(es): | 28 | * email address(es): |
diff --git a/net/sctp/chunk.c b/net/sctp/chunk.c index f2044fcb9dd1..158701da2d31 100644 --- a/net/sctp/chunk.c +++ b/net/sctp/chunk.c | |||
| @@ -18,9 +18,8 @@ | |||
| 18 | * See the GNU General Public License for more details. | 18 | * See the GNU General Public License for more details. |
| 19 | * | 19 | * |
| 20 | * You should have received a copy of the GNU General Public License | 20 | * You should have received a copy of the GNU General Public License |
| 21 | * along with GNU CC; see the file COPYING. If not, write to | 21 | * along with GNU CC; see the file COPYING. If not, see |
| 22 | * the Free Software Foundation, 59 Temple Place - Suite 330, | 22 | * <http://www.gnu.org/licenses/>. |
| 23 | * Boston, MA 02111-1307, USA. | ||
| 24 | * | 23 | * |
| 25 | * Please send any bug reports or fixes you make to the | 24 | * Please send any bug reports or fixes you make to the |
| 26 | * email address(es): | 25 | * email address(es): |
| @@ -255,7 +254,7 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc, | |||
| 255 | SCTP_INC_STATS_USER(sock_net(asoc->base.sk), SCTP_MIB_FRAGUSRMSGS); | 254 | SCTP_INC_STATS_USER(sock_net(asoc->base.sk), SCTP_MIB_FRAGUSRMSGS); |
| 256 | 255 | ||
| 257 | /* Create chunks for all the full sized DATA chunks. */ | 256 | /* Create chunks for all the full sized DATA chunks. */ |
| 258 | for (i=0, len=first_len; i < whole; i++) { | 257 | for (i = 0, len = first_len; i < whole; i++) { |
| 259 | frag = SCTP_DATA_MIDDLE_FRAG; | 258 | frag = SCTP_DATA_MIDDLE_FRAG; |
| 260 | 259 | ||
| 261 | if (0 == i) | 260 | if (0 == i) |
| @@ -318,7 +317,7 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc, | |||
| 318 | goto errout; | 317 | goto errout; |
| 319 | } | 318 | } |
| 320 | 319 | ||
| 321 | err = sctp_user_addto_chunk(chunk, offset, over,msgh->msg_iov); | 320 | err = sctp_user_addto_chunk(chunk, offset, over, msgh->msg_iov); |
| 322 | 321 | ||
| 323 | /* Put the chunk->skb back into the form expected by send. */ | 322 | /* Put the chunk->skb back into the form expected by send. */ |
| 324 | __skb_pull(chunk->skb, (__u8 *)chunk->chunk_hdr | 323 | __skb_pull(chunk->skb, (__u8 *)chunk->chunk_hdr |
diff --git a/net/sctp/command.c b/net/sctp/command.c index 3d9a9ff69c03..dd7375851618 100644 --- a/net/sctp/command.c +++ b/net/sctp/command.c | |||
| @@ -19,9 +19,8 @@ | |||
| 19 | * See the GNU General Public License for more details. | 19 | * See the GNU General Public License for more details. |
| 20 | * | 20 | * |
| 21 | * You should have received a copy of the GNU General Public License | 21 | * You should have received a copy of the GNU General Public License |
| 22 | * along with GNU CC; see the file COPYING. If not, write to | 22 | * along with GNU CC; see the file COPYING. If not, see |
| 23 | * the Free Software Foundation, 59 Temple Place - Suite 330, | 23 | * <http://www.gnu.org/licenses/>. |
| 24 | * Boston, MA 02111-1307, USA. | ||
| 25 | * | 24 | * |
| 26 | * Please send any bug reports or fixes you make to the | 25 | * Please send any bug reports or fixes you make to the |
| 27 | * email address(es): | 26 | * email address(es): |
diff --git a/net/sctp/debug.c b/net/sctp/debug.c index e89015d8935a..95d7b15dad21 100644 --- a/net/sctp/debug.c +++ b/net/sctp/debug.c | |||
| @@ -22,9 +22,8 @@ | |||
| 22 | * See the GNU General Public License for more details. | 22 | * See the GNU General Public License for more details. |
| 23 | * | 23 | * |
| 24 | * You should have received a copy of the GNU General Public License | 24 | * You should have received a copy of the GNU General Public License |
| 25 | * along with GNU CC; see the file COPYING. If not, write to | 25 | * along with GNU CC; see the file COPYING. If not, see |
| 26 | * the Free Software Foundation, 59 Temple Place - Suite 330, | 26 | * <http://www.gnu.org/licenses/>. |
| 27 | * Boston, MA 02111-1307, USA. | ||
| 28 | * | 27 | * |
| 29 | * Please send any bug reports or fixes you make to the | 28 | * Please send any bug reports or fixes you make to the |
| 30 | * email address(es): | 29 | * email address(es): |
diff --git a/net/sctp/endpointola.c b/net/sctp/endpointola.c index 09b8daac87c8..8e5fdea05216 100644 --- a/net/sctp/endpointola.c +++ b/net/sctp/endpointola.c | |||
| @@ -23,9 +23,8 @@ | |||
| 23 | * See the GNU General Public License for more details. | 23 | * See the GNU General Public License for more details. |
| 24 | * | 24 | * |
| 25 | * You should have received a copy of the GNU General Public License | 25 | * You should have received a copy of the GNU General Public License |
| 26 | * along with GNU CC; see the file COPYING. If not, write to | 26 | * along with GNU CC; see the file COPYING. If not, see |
| 27 | * the Free Software Foundation, 59 Temple Place - Suite 330, | 27 | * <http://www.gnu.org/licenses/>. |
| 28 | * Boston, MA 02111-1307, USA. | ||
| 29 | * | 28 | * |
| 30 | * Please send any bug reports or fixes you make to the | 29 | * Please send any bug reports or fixes you make to the |
| 31 | * email address(es): | 30 | * email address(es): |
| @@ -369,9 +368,9 @@ struct sctp_association *sctp_endpoint_lookup_assoc( | |||
| 369 | { | 368 | { |
| 370 | struct sctp_association *asoc; | 369 | struct sctp_association *asoc; |
| 371 | 370 | ||
| 372 | sctp_local_bh_disable(); | 371 | local_bh_disable(); |
| 373 | asoc = __sctp_endpoint_lookup_assoc(ep, paddr, transport); | 372 | asoc = __sctp_endpoint_lookup_assoc(ep, paddr, transport); |
| 374 | sctp_local_bh_enable(); | 373 | local_bh_enable(); |
| 375 | 374 | ||
| 376 | return asoc; | 375 | return asoc; |
| 377 | } | 376 | } |
diff --git a/net/sctp/input.c b/net/sctp/input.c index 98b69bbecdd9..f2e2cbd2d750 100644 --- a/net/sctp/input.c +++ b/net/sctp/input.c | |||
| @@ -23,9 +23,8 @@ | |||
| 23 | * See the GNU General Public License for more details. | 23 | * See the GNU General Public License for more details. |
| 24 | * | 24 | * |
| 25 | * You should have received a copy of the GNU General Public License | 25 | * You should have received a copy of the GNU General Public License |
| 26 | * along with GNU CC; see the file COPYING. If not, write to | 26 | * along with GNU CC; see the file COPYING. If not, see |
| 27 | * the Free Software Foundation, 59 Temple Place - Suite 330, | 27 | * <http://www.gnu.org/licenses/>. |
| 28 | * Boston, MA 02111-1307, USA. | ||
| 29 | * | 28 | * |
| 30 | * Please send any bug reports or fixes you make to the | 29 | * Please send any bug reports or fixes you make to the |
| 31 | * email address(es): | 30 | * email address(es): |
| @@ -120,7 +119,7 @@ int sctp_rcv(struct sk_buff *skb) | |||
| 120 | struct sctp_af *af; | 119 | struct sctp_af *af; |
| 121 | struct net *net = dev_net(skb->dev); | 120 | struct net *net = dev_net(skb->dev); |
| 122 | 121 | ||
| 123 | if (skb->pkt_type!=PACKET_HOST) | 122 | if (skb->pkt_type != PACKET_HOST) |
| 124 | goto discard_it; | 123 | goto discard_it; |
| 125 | 124 | ||
| 126 | SCTP_INC_STATS_BH(net, SCTP_MIB_INSCTPPACKS); | 125 | SCTP_INC_STATS_BH(net, SCTP_MIB_INSCTPPACKS); |
| @@ -181,8 +180,7 @@ int sctp_rcv(struct sk_buff *skb) | |||
| 181 | * If a frame arrives on an interface and the receiving socket is | 180 | * If a frame arrives on an interface and the receiving socket is |
| 182 | * bound to another interface, via SO_BINDTODEVICE, treat it as OOTB | 181 | * bound to another interface, via SO_BINDTODEVICE, treat it as OOTB |
| 183 | */ | 182 | */ |
| 184 | if (sk->sk_bound_dev_if && (sk->sk_bound_dev_if != af->skb_iif(skb))) | 183 | if (sk->sk_bound_dev_if && (sk->sk_bound_dev_if != af->skb_iif(skb))) { |
| 185 | { | ||
| 186 | if (asoc) { | 184 | if (asoc) { |
| 187 | sctp_association_put(asoc); | 185 | sctp_association_put(asoc); |
| 188 | asoc = NULL; | 186 | asoc = NULL; |
| @@ -240,7 +238,7 @@ int sctp_rcv(struct sk_buff *skb) | |||
| 240 | * bottom halves on this lock, but a user may be in the lock too, | 238 | * bottom halves on this lock, but a user may be in the lock too, |
| 241 | * so check if it is busy. | 239 | * so check if it is busy. |
| 242 | */ | 240 | */ |
| 243 | sctp_bh_lock_sock(sk); | 241 | bh_lock_sock(sk); |
| 244 | 242 | ||
| 245 | if (sk != rcvr->sk) { | 243 | if (sk != rcvr->sk) { |
| 246 | /* Our cached sk is different from the rcvr->sk. This is | 244 | /* Our cached sk is different from the rcvr->sk. This is |
| @@ -250,14 +248,14 @@ int sctp_rcv(struct sk_buff *skb) | |||
| 250 | * be doing something with the new socket. Switch our veiw | 248 | * be doing something with the new socket. Switch our veiw |
| 251 | * of the current sk. | 249 | * of the current sk. |
| 252 | */ | 250 | */ |
| 253 | sctp_bh_unlock_sock(sk); | 251 | bh_unlock_sock(sk); |
| 254 | sk = rcvr->sk; | 252 | sk = rcvr->sk; |
| 255 | sctp_bh_lock_sock(sk); | 253 | bh_lock_sock(sk); |
| 256 | } | 254 | } |
| 257 | 255 | ||
| 258 | if (sock_owned_by_user(sk)) { | 256 | if (sock_owned_by_user(sk)) { |
| 259 | if (sctp_add_backlog(sk, skb)) { | 257 | if (sctp_add_backlog(sk, skb)) { |
| 260 | sctp_bh_unlock_sock(sk); | 258 | bh_unlock_sock(sk); |
| 261 | sctp_chunk_free(chunk); | 259 | sctp_chunk_free(chunk); |
| 262 | skb = NULL; /* sctp_chunk_free already freed the skb */ | 260 | skb = NULL; /* sctp_chunk_free already freed the skb */ |
| 263 | goto discard_release; | 261 | goto discard_release; |
| @@ -268,7 +266,7 @@ int sctp_rcv(struct sk_buff *skb) | |||
| 268 | sctp_inq_push(&chunk->rcvr->inqueue, chunk); | 266 | sctp_inq_push(&chunk->rcvr->inqueue, chunk); |
| 269 | } | 267 | } |
| 270 | 268 | ||
| 271 | sctp_bh_unlock_sock(sk); | 269 | bh_unlock_sock(sk); |
| 272 | 270 | ||
| 273 | /* Release the asoc/ep ref we took in the lookup calls. */ | 271 | /* Release the asoc/ep ref we took in the lookup calls. */ |
| 274 | if (asoc) | 272 | if (asoc) |
| @@ -329,7 +327,7 @@ int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb) | |||
| 329 | */ | 327 | */ |
| 330 | 328 | ||
| 331 | sk = rcvr->sk; | 329 | sk = rcvr->sk; |
| 332 | sctp_bh_lock_sock(sk); | 330 | bh_lock_sock(sk); |
| 333 | 331 | ||
| 334 | if (sock_owned_by_user(sk)) { | 332 | if (sock_owned_by_user(sk)) { |
| 335 | if (sk_add_backlog(sk, skb, sk->sk_rcvbuf)) | 333 | if (sk_add_backlog(sk, skb, sk->sk_rcvbuf)) |
| @@ -339,7 +337,7 @@ int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb) | |||
| 339 | } else | 337 | } else |
| 340 | sctp_inq_push(inqueue, chunk); | 338 | sctp_inq_push(inqueue, chunk); |
| 341 | 339 | ||
| 342 | sctp_bh_unlock_sock(sk); | 340 | bh_unlock_sock(sk); |
| 343 | 341 | ||
| 344 | /* If the chunk was backloged again, don't drop refs */ | 342 | /* If the chunk was backloged again, don't drop refs */ |
| 345 | if (backloged) | 343 | if (backloged) |
| @@ -524,7 +522,7 @@ struct sock *sctp_err_lookup(struct net *net, int family, struct sk_buff *skb, | |||
| 524 | goto out; | 522 | goto out; |
| 525 | } | 523 | } |
| 526 | 524 | ||
| 527 | sctp_bh_lock_sock(sk); | 525 | bh_lock_sock(sk); |
| 528 | 526 | ||
| 529 | /* If too many ICMPs get dropped on busy | 527 | /* If too many ICMPs get dropped on busy |
| 530 | * servers this needs to be solved differently. | 528 | * servers this needs to be solved differently. |
| @@ -537,17 +535,15 @@ struct sock *sctp_err_lookup(struct net *net, int family, struct sk_buff *skb, | |||
| 537 | return sk; | 535 | return sk; |
| 538 | 536 | ||
| 539 | out: | 537 | out: |
| 540 | if (asoc) | 538 | sctp_association_put(asoc); |
| 541 | sctp_association_put(asoc); | ||
| 542 | return NULL; | 539 | return NULL; |
| 543 | } | 540 | } |
| 544 | 541 | ||
| 545 | /* Common cleanup code for icmp/icmpv6 error handler. */ | 542 | /* Common cleanup code for icmp/icmpv6 error handler. */ |
| 546 | void sctp_err_finish(struct sock *sk, struct sctp_association *asoc) | 543 | void sctp_err_finish(struct sock *sk, struct sctp_association *asoc) |
| 547 | { | 544 | { |
| 548 | sctp_bh_unlock_sock(sk); | 545 | bh_unlock_sock(sk); |
| 549 | if (asoc) | 546 | sctp_association_put(asoc); |
| 550 | sctp_association_put(asoc); | ||
| 551 | } | 547 | } |
| 552 | 548 | ||
| 553 | /* | 549 | /* |
| @@ -613,8 +609,7 @@ void sctp_v4_err(struct sk_buff *skb, __u32 info) | |||
| 613 | if (ICMP_FRAG_NEEDED == code) { | 609 | if (ICMP_FRAG_NEEDED == code) { |
| 614 | sctp_icmp_frag_needed(sk, asoc, transport, info); | 610 | sctp_icmp_frag_needed(sk, asoc, transport, info); |
| 615 | goto out_unlock; | 611 | goto out_unlock; |
| 616 | } | 612 | } else { |
| 617 | else { | ||
| 618 | if (ICMP_PROT_UNREACH == code) { | 613 | if (ICMP_PROT_UNREACH == code) { |
| 619 | sctp_icmp_proto_unreachable(sk, asoc, | 614 | sctp_icmp_proto_unreachable(sk, asoc, |
| 620 | transport); | 615 | transport); |
| @@ -723,17 +718,17 @@ static void __sctp_hash_endpoint(struct sctp_endpoint *ep) | |||
| 723 | epb->hashent = sctp_ep_hashfn(net, epb->bind_addr.port); | 718 | epb->hashent = sctp_ep_hashfn(net, epb->bind_addr.port); |
| 724 | head = &sctp_ep_hashtable[epb->hashent]; | 719 | head = &sctp_ep_hashtable[epb->hashent]; |
| 725 | 720 | ||
| 726 | sctp_write_lock(&head->lock); | 721 | write_lock(&head->lock); |
| 727 | hlist_add_head(&epb->node, &head->chain); | 722 | hlist_add_head(&epb->node, &head->chain); |
| 728 | sctp_write_unlock(&head->lock); | 723 | write_unlock(&head->lock); |
| 729 | } | 724 | } |
| 730 | 725 | ||
| 731 | /* Add an endpoint to the hash. Local BH-safe. */ | 726 | /* Add an endpoint to the hash. Local BH-safe. */ |
| 732 | void sctp_hash_endpoint(struct sctp_endpoint *ep) | 727 | void sctp_hash_endpoint(struct sctp_endpoint *ep) |
| 733 | { | 728 | { |
| 734 | sctp_local_bh_disable(); | 729 | local_bh_disable(); |
| 735 | __sctp_hash_endpoint(ep); | 730 | __sctp_hash_endpoint(ep); |
| 736 | sctp_local_bh_enable(); | 731 | local_bh_enable(); |
| 737 | } | 732 | } |
| 738 | 733 | ||
| 739 | /* Remove endpoint from the hash table. */ | 734 | /* Remove endpoint from the hash table. */ |
| @@ -749,17 +744,17 @@ static void __sctp_unhash_endpoint(struct sctp_endpoint *ep) | |||
| 749 | 744 | ||
| 750 | head = &sctp_ep_hashtable[epb->hashent]; | 745 | head = &sctp_ep_hashtable[epb->hashent]; |
| 751 | 746 | ||
| 752 | sctp_write_lock(&head->lock); | 747 | write_lock(&head->lock); |
| 753 | hlist_del_init(&epb->node); | 748 | hlist_del_init(&epb->node); |
| 754 | sctp_write_unlock(&head->lock); | 749 | write_unlock(&head->lock); |
| 755 | } | 750 | } |
| 756 | 751 | ||
| 757 | /* Remove endpoint from the hash. Local BH-safe. */ | 752 | /* Remove endpoint from the hash. Local BH-safe. */ |
| 758 | void sctp_unhash_endpoint(struct sctp_endpoint *ep) | 753 | void sctp_unhash_endpoint(struct sctp_endpoint *ep) |
| 759 | { | 754 | { |
| 760 | sctp_local_bh_disable(); | 755 | local_bh_disable(); |
| 761 | __sctp_unhash_endpoint(ep); | 756 | __sctp_unhash_endpoint(ep); |
| 762 | sctp_local_bh_enable(); | 757 | local_bh_enable(); |
| 763 | } | 758 | } |
| 764 | 759 | ||
| 765 | /* Look up an endpoint. */ | 760 | /* Look up an endpoint. */ |
| @@ -803,9 +798,9 @@ static void __sctp_hash_established(struct sctp_association *asoc) | |||
| 803 | 798 | ||
| 804 | head = &sctp_assoc_hashtable[epb->hashent]; | 799 | head = &sctp_assoc_hashtable[epb->hashent]; |
| 805 | 800 | ||
| 806 | sctp_write_lock(&head->lock); | 801 | write_lock(&head->lock); |
| 807 | hlist_add_head(&epb->node, &head->chain); | 802 | hlist_add_head(&epb->node, &head->chain); |
| 808 | sctp_write_unlock(&head->lock); | 803 | write_unlock(&head->lock); |
| 809 | } | 804 | } |
| 810 | 805 | ||
| 811 | /* Add an association to the hash. Local BH-safe. */ | 806 | /* Add an association to the hash. Local BH-safe. */ |
| @@ -814,9 +809,9 @@ void sctp_hash_established(struct sctp_association *asoc) | |||
| 814 | if (asoc->temp) | 809 | if (asoc->temp) |
| 815 | return; | 810 | return; |
| 816 | 811 | ||
| 817 | sctp_local_bh_disable(); | 812 | local_bh_disable(); |
| 818 | __sctp_hash_established(asoc); | 813 | __sctp_hash_established(asoc); |
| 819 | sctp_local_bh_enable(); | 814 | local_bh_enable(); |
| 820 | } | 815 | } |
| 821 | 816 | ||
| 822 | /* Remove association from the hash table. */ | 817 | /* Remove association from the hash table. */ |
| @@ -833,9 +828,9 @@ static void __sctp_unhash_established(struct sctp_association *asoc) | |||
| 833 | 828 | ||
| 834 | head = &sctp_assoc_hashtable[epb->hashent]; | 829 | head = &sctp_assoc_hashtable[epb->hashent]; |
| 835 | 830 | ||
| 836 | sctp_write_lock(&head->lock); | 831 | write_lock(&head->lock); |
| 837 | hlist_del_init(&epb->node); | 832 | hlist_del_init(&epb->node); |
| 838 | sctp_write_unlock(&head->lock); | 833 | write_unlock(&head->lock); |
| 839 | } | 834 | } |
| 840 | 835 | ||
| 841 | /* Remove association from the hash table. Local BH-safe. */ | 836 | /* Remove association from the hash table. Local BH-safe. */ |
| @@ -844,9 +839,9 @@ void sctp_unhash_established(struct sctp_association *asoc) | |||
| 844 | if (asoc->temp) | 839 | if (asoc->temp) |
| 845 | return; | 840 | return; |
| 846 | 841 | ||
| 847 | sctp_local_bh_disable(); | 842 | local_bh_disable(); |
| 848 | __sctp_unhash_established(asoc); | 843 | __sctp_unhash_established(asoc); |
| 849 | sctp_local_bh_enable(); | 844 | local_bh_enable(); |
| 850 | } | 845 | } |
| 851 | 846 | ||
| 852 | /* Look up an association. */ | 847 | /* Look up an association. */ |
| @@ -896,9 +891,9 @@ struct sctp_association *sctp_lookup_association(struct net *net, | |||
| 896 | { | 891 | { |
| 897 | struct sctp_association *asoc; | 892 | struct sctp_association *asoc; |
| 898 | 893 | ||
| 899 | sctp_local_bh_disable(); | 894 | local_bh_disable(); |
| 900 | asoc = __sctp_lookup_association(net, laddr, paddr, transportp); | 895 | asoc = __sctp_lookup_association(net, laddr, paddr, transportp); |
| 901 | sctp_local_bh_enable(); | 896 | local_bh_enable(); |
| 902 | 897 | ||
| 903 | return asoc; | 898 | return asoc; |
| 904 | } | 899 | } |
| @@ -1058,31 +1053,31 @@ static struct sctp_association *__sctp_rcv_walk_lookup(struct net *net, | |||
| 1058 | if (ch_end > skb_tail_pointer(skb)) | 1053 | if (ch_end > skb_tail_pointer(skb)) |
| 1059 | break; | 1054 | break; |
| 1060 | 1055 | ||
| 1061 | switch(ch->type) { | 1056 | switch (ch->type) { |
| 1062 | case SCTP_CID_AUTH: | 1057 | case SCTP_CID_AUTH: |
| 1063 | have_auth = chunk_num; | 1058 | have_auth = chunk_num; |
| 1064 | break; | 1059 | break; |
| 1065 | 1060 | ||
| 1066 | case SCTP_CID_COOKIE_ECHO: | 1061 | case SCTP_CID_COOKIE_ECHO: |
| 1067 | /* If a packet arrives containing an AUTH chunk as | 1062 | /* If a packet arrives containing an AUTH chunk as |
| 1068 | * a first chunk, a COOKIE-ECHO chunk as the second | 1063 | * a first chunk, a COOKIE-ECHO chunk as the second |
| 1069 | * chunk, and possibly more chunks after them, and | 1064 | * chunk, and possibly more chunks after them, and |
| 1070 | * the receiver does not have an STCB for that | 1065 | * the receiver does not have an STCB for that |
| 1071 | * packet, then authentication is based on | 1066 | * packet, then authentication is based on |
| 1072 | * the contents of the COOKIE- ECHO chunk. | 1067 | * the contents of the COOKIE- ECHO chunk. |
| 1073 | */ | 1068 | */ |
| 1074 | if (have_auth == 1 && chunk_num == 2) | 1069 | if (have_auth == 1 && chunk_num == 2) |
| 1075 | return NULL; | 1070 | return NULL; |
| 1076 | break; | 1071 | break; |
| 1077 | 1072 | ||
| 1078 | case SCTP_CID_ASCONF: | 1073 | case SCTP_CID_ASCONF: |
| 1079 | if (have_auth || net->sctp.addip_noauth) | 1074 | if (have_auth || net->sctp.addip_noauth) |
| 1080 | asoc = __sctp_rcv_asconf_lookup( | 1075 | asoc = __sctp_rcv_asconf_lookup( |
| 1081 | net, ch, laddr, | 1076 | net, ch, laddr, |
| 1082 | sctp_hdr(skb)->source, | 1077 | sctp_hdr(skb)->source, |
| 1083 | transportp); | 1078 | transportp); |
| 1084 | default: | 1079 | default: |
| 1085 | break; | 1080 | break; |
| 1086 | } | 1081 | } |
| 1087 | 1082 | ||
| 1088 | if (asoc) | 1083 | if (asoc) |
| @@ -1119,19 +1114,10 @@ static struct sctp_association *__sctp_rcv_lookup_harder(struct net *net, | |||
| 1119 | return NULL; | 1114 | return NULL; |
| 1120 | 1115 | ||
| 1121 | /* If this is INIT/INIT-ACK look inside the chunk too. */ | 1116 | /* If this is INIT/INIT-ACK look inside the chunk too. */ |
| 1122 | switch (ch->type) { | 1117 | if (ch->type == SCTP_CID_INIT || ch->type == SCTP_CID_INIT_ACK) |
| 1123 | case SCTP_CID_INIT: | ||
| 1124 | case SCTP_CID_INIT_ACK: | ||
| 1125 | return __sctp_rcv_init_lookup(net, skb, laddr, transportp); | 1118 | return __sctp_rcv_init_lookup(net, skb, laddr, transportp); |
| 1126 | break; | ||
| 1127 | 1119 | ||
| 1128 | default: | 1120 | return __sctp_rcv_walk_lookup(net, skb, laddr, transportp); |
| 1129 | return __sctp_rcv_walk_lookup(net, skb, laddr, transportp); | ||
| 1130 | break; | ||
| 1131 | } | ||
| 1132 | |||
| 1133 | |||
| 1134 | return NULL; | ||
| 1135 | } | 1121 | } |
| 1136 | 1122 | ||
| 1137 | /* Lookup an association for an inbound skb. */ | 1123 | /* Lookup an association for an inbound skb. */ |
diff --git a/net/sctp/inqueue.c b/net/sctp/inqueue.c index 5856932fdc38..4de12afa13d4 100644 --- a/net/sctp/inqueue.c +++ b/net/sctp/inqueue.c | |||
| @@ -24,9 +24,8 @@ | |||
| 24 | * See the GNU General Public License for more details. | 24 | * See the GNU General Public License for more details. |
| 25 | * | 25 | * |
| 26 | * You should have received a copy of the GNU General Public License | 26 | * You should have received a copy of the GNU General Public License |
| 27 | * along with GNU CC; see the file COPYING. If not, write to | 27 | * along with GNU CC; see the file COPYING. If not, see |
| 28 | * the Free Software Foundation, 59 Temple Place - Suite 330, | 28 | * <http://www.gnu.org/licenses/>. |
| 29 | * Boston, MA 02111-1307, USA. | ||
| 30 | * | 29 | * |
| 31 | * Please send any bug reports or fixes you make to the | 30 | * Please send any bug reports or fixes you make to the |
| 32 | * email address(es): | 31 | * email address(es): |
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index 7567e6f1a920..0f6259a6a932 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c | |||
| @@ -21,9 +21,8 @@ | |||
| 21 | * See the GNU General Public License for more details. | 21 | * See the GNU General Public License for more details. |
| 22 | * | 22 | * |
| 23 | * You should have received a copy of the GNU General Public License | 23 | * You should have received a copy of the GNU General Public License |
| 24 | * along with GNU CC; see the file COPYING. If not, write to | 24 | * along with GNU CC; see the file COPYING. If not, see |
| 25 | * the Free Software Foundation, 59 Temple Place - Suite 330, | 25 | * <http://www.gnu.org/licenses/>. |
| 26 | * Boston, MA 02111-1307, USA. | ||
| 27 | * | 26 | * |
| 28 | * Please send any bug reports or fixes you make to the | 27 | * Please send any bug reports or fixes you make to the |
| 29 | * email address(es): | 28 | * email address(es): |
| @@ -173,7 +172,8 @@ static void sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
| 173 | 172 | ||
| 174 | switch (type) { | 173 | switch (type) { |
| 175 | case ICMPV6_PKT_TOOBIG: | 174 | case ICMPV6_PKT_TOOBIG: |
| 176 | sctp_icmp_frag_needed(sk, asoc, transport, ntohl(info)); | 175 | if (ip6_sk_accept_pmtu(sk)) |
| 176 | sctp_icmp_frag_needed(sk, asoc, transport, ntohl(info)); | ||
| 177 | goto out_unlock; | 177 | goto out_unlock; |
| 178 | case ICMPV6_PARAMPROB: | 178 | case ICMPV6_PARAMPROB: |
| 179 | if (ICMPV6_UNK_NEXTHDR == code) { | 179 | if (ICMPV6_UNK_NEXTHDR == code) { |
| @@ -263,7 +263,7 @@ static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr, | |||
| 263 | } | 263 | } |
| 264 | 264 | ||
| 265 | final_p = fl6_update_dst(fl6, np->opt, &final); | 265 | final_p = fl6_update_dst(fl6, np->opt, &final); |
| 266 | dst = ip6_dst_lookup_flow(sk, fl6, final_p, false); | 266 | dst = ip6_dst_lookup_flow(sk, fl6, final_p); |
| 267 | if (!asoc || saddr) | 267 | if (!asoc || saddr) |
| 268 | goto out; | 268 | goto out; |
| 269 | 269 | ||
| @@ -322,7 +322,7 @@ static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr, | |||
| 322 | fl6->saddr = baddr->v6.sin6_addr; | 322 | fl6->saddr = baddr->v6.sin6_addr; |
| 323 | fl6->fl6_sport = baddr->v6.sin6_port; | 323 | fl6->fl6_sport = baddr->v6.sin6_port; |
| 324 | final_p = fl6_update_dst(fl6, np->opt, &final); | 324 | final_p = fl6_update_dst(fl6, np->opt, &final); |
| 325 | dst = ip6_dst_lookup_flow(sk, fl6, final_p, false); | 325 | dst = ip6_dst_lookup_flow(sk, fl6, final_p); |
| 326 | } | 326 | } |
| 327 | 327 | ||
| 328 | out: | 328 | out: |
| @@ -402,7 +402,7 @@ static void sctp_v6_copy_addrlist(struct list_head *addrlist, | |||
| 402 | } | 402 | } |
| 403 | 403 | ||
| 404 | /* Initialize a sockaddr_storage from in incoming skb. */ | 404 | /* Initialize a sockaddr_storage from in incoming skb. */ |
| 405 | static void sctp_v6_from_skb(union sctp_addr *addr,struct sk_buff *skb, | 405 | static void sctp_v6_from_skb(union sctp_addr *addr, struct sk_buff *skb, |
| 406 | int is_saddr) | 406 | int is_saddr) |
| 407 | { | 407 | { |
| 408 | __be16 *port; | 408 | __be16 *port; |
diff --git a/net/sctp/objcnt.c b/net/sctp/objcnt.c index 647396baa56f..40e7fac96c41 100644 --- a/net/sctp/objcnt.c +++ b/net/sctp/objcnt.c | |||
| @@ -20,9 +20,8 @@ | |||
| 20 | * See the GNU General Public License for more details. | 20 | * See the GNU General Public License for more details. |
| 21 | * | 21 | * |
| 22 | * You should have received a copy of the GNU General Public License | 22 | * You should have received a copy of the GNU General Public License |
| 23 | * along with GNU CC; see the file COPYING. If not, write to | 23 | * along with GNU CC; see the file COPYING. If not, see |
| 24 | * the Free Software Foundation, 59 Temple Place - Suite 330, | 24 | * <http://www.gnu.org/licenses/>. |
| 25 | * Boston, MA 02111-1307, USA. | ||
| 26 | * | 25 | * |
| 27 | * Please send any bug reports or fixes you make to the | 26 | * Please send any bug reports or fixes you make to the |
| 28 | * email address(es): | 27 | * email address(es): |
| @@ -98,7 +97,7 @@ static void sctp_objcnt_seq_stop(struct seq_file *seq, void *v) | |||
| 98 | { | 97 | { |
| 99 | } | 98 | } |
| 100 | 99 | ||
| 101 | static void * sctp_objcnt_seq_next(struct seq_file *seq, void *v, loff_t *pos) | 100 | static void *sctp_objcnt_seq_next(struct seq_file *seq, void *v, loff_t *pos) |
| 102 | { | 101 | { |
| 103 | ++*pos; | 102 | ++*pos; |
| 104 | return (*pos >= ARRAY_SIZE(sctp_dbg_objcnt)) ? NULL : (void *)pos; | 103 | return (*pos >= ARRAY_SIZE(sctp_dbg_objcnt)) ? NULL : (void *)pos; |
diff --git a/net/sctp/output.c b/net/sctp/output.c index 0fb140f8f088..0f4d15fc2627 100644 --- a/net/sctp/output.c +++ b/net/sctp/output.c | |||
| @@ -20,9 +20,8 @@ | |||
| 20 | * See the GNU General Public License for more details. | 20 | * See the GNU General Public License for more details. |
| 21 | * | 21 | * |
| 22 | * You should have received a copy of the GNU General Public License | 22 | * You should have received a copy of the GNU General Public License |
| 23 | * along with GNU CC; see the file COPYING. If not, write to | 23 | * along with GNU CC; see the file COPYING. If not, see |
| 24 | * the Free Software Foundation, 59 Temple Place - Suite 330, | 24 | * <http://www.gnu.org/licenses/>. |
| 25 | * Boston, MA 02111-1307, USA. | ||
| 26 | * | 25 | * |
| 27 | * Please send any bug reports or fixes you make to the | 26 | * Please send any bug reports or fixes you make to the |
| 28 | * email address(es): | 27 | * email address(es): |
| @@ -281,7 +280,7 @@ static sctp_xmit_t __sctp_packet_append_chunk(struct sctp_packet *packet, | |||
| 281 | 280 | ||
| 282 | /* We believe that this chunk is OK to add to the packet */ | 281 | /* We believe that this chunk is OK to add to the packet */ |
| 283 | switch (chunk->chunk_hdr->type) { | 282 | switch (chunk->chunk_hdr->type) { |
| 284 | case SCTP_CID_DATA: | 283 | case SCTP_CID_DATA: |
| 285 | /* Account for the data being in the packet */ | 284 | /* Account for the data being in the packet */ |
| 286 | sctp_packet_append_data(packet, chunk); | 285 | sctp_packet_append_data(packet, chunk); |
| 287 | /* Disallow SACK bundling after DATA. */ | 286 | /* Disallow SACK bundling after DATA. */ |
| @@ -293,17 +292,17 @@ static sctp_xmit_t __sctp_packet_append_chunk(struct sctp_packet *packet, | |||
| 293 | /* timestamp the chunk for rtx purposes */ | 292 | /* timestamp the chunk for rtx purposes */ |
| 294 | chunk->sent_at = jiffies; | 293 | chunk->sent_at = jiffies; |
| 295 | break; | 294 | break; |
| 296 | case SCTP_CID_COOKIE_ECHO: | 295 | case SCTP_CID_COOKIE_ECHO: |
| 297 | packet->has_cookie_echo = 1; | 296 | packet->has_cookie_echo = 1; |
| 298 | break; | 297 | break; |
| 299 | 298 | ||
| 300 | case SCTP_CID_SACK: | 299 | case SCTP_CID_SACK: |
| 301 | packet->has_sack = 1; | 300 | packet->has_sack = 1; |
| 302 | if (chunk->asoc) | 301 | if (chunk->asoc) |
| 303 | chunk->asoc->stats.osacks++; | 302 | chunk->asoc->stats.osacks++; |
| 304 | break; | 303 | break; |
| 305 | 304 | ||
| 306 | case SCTP_CID_AUTH: | 305 | case SCTP_CID_AUTH: |
| 307 | packet->has_auth = 1; | 306 | packet->has_auth = 1; |
| 308 | packet->auth = chunk; | 307 | packet->auth = chunk; |
| 309 | break; | 308 | break; |
| @@ -388,7 +387,7 @@ int sctp_packet_transmit(struct sctp_packet *packet) | |||
| 388 | int err = 0; | 387 | int err = 0; |
| 389 | int padding; /* How much padding do we need? */ | 388 | int padding; /* How much padding do we need? */ |
| 390 | __u8 has_data = 0; | 389 | __u8 has_data = 0; |
| 391 | struct dst_entry *dst = tp->dst; | 390 | struct dst_entry *dst; |
| 392 | unsigned char *auth = NULL; /* pointer to auth in skb data */ | 391 | unsigned char *auth = NULL; /* pointer to auth in skb data */ |
| 393 | 392 | ||
| 394 | pr_debug("%s: packet:%p\n", __func__, packet); | 393 | pr_debug("%s: packet:%p\n", __func__, packet); |
| @@ -421,9 +420,9 @@ int sctp_packet_transmit(struct sctp_packet *packet) | |||
| 421 | } | 420 | } |
| 422 | } | 421 | } |
| 423 | dst = dst_clone(tp->dst); | 422 | dst = dst_clone(tp->dst); |
| 424 | skb_dst_set(nskb, dst); | ||
| 425 | if (!dst) | 423 | if (!dst) |
| 426 | goto no_route; | 424 | goto no_route; |
| 425 | skb_dst_set(nskb, dst); | ||
| 427 | 426 | ||
| 428 | /* Build the SCTP header. */ | 427 | /* Build the SCTP header. */ |
| 429 | sh = (struct sctphdr *)skb_push(nskb, sizeof(struct sctphdr)); | 428 | sh = (struct sctphdr *)skb_push(nskb, sizeof(struct sctphdr)); |
| @@ -541,8 +540,7 @@ int sctp_packet_transmit(struct sctp_packet *packet) | |||
| 541 | } else { | 540 | } else { |
| 542 | /* no need to seed pseudo checksum for SCTP */ | 541 | /* no need to seed pseudo checksum for SCTP */ |
| 543 | nskb->ip_summed = CHECKSUM_PARTIAL; | 542 | nskb->ip_summed = CHECKSUM_PARTIAL; |
| 544 | nskb->csum_start = (skb_transport_header(nskb) - | 543 | nskb->csum_start = skb_transport_header(nskb) - nskb->head; |
| 545 | nskb->head); | ||
| 546 | nskb->csum_offset = offsetof(struct sctphdr, checksum); | 544 | nskb->csum_offset = offsetof(struct sctphdr, checksum); |
| 547 | } | 545 | } |
| 548 | } | 546 | } |
| @@ -559,7 +557,7 @@ int sctp_packet_transmit(struct sctp_packet *packet) | |||
| 559 | * Note: The works for IPv6 layer checks this bit too later | 557 | * Note: The works for IPv6 layer checks this bit too later |
| 560 | * in transmission. See IP6_ECN_flow_xmit(). | 558 | * in transmission. See IP6_ECN_flow_xmit(). |
| 561 | */ | 559 | */ |
| 562 | (*tp->af_specific->ecn_capable)(nskb->sk); | 560 | tp->af_specific->ecn_capable(nskb->sk); |
| 563 | 561 | ||
| 564 | /* Set up the IP options. */ | 562 | /* Set up the IP options. */ |
| 565 | /* BUG: not implemented | 563 | /* BUG: not implemented |
| @@ -594,7 +592,7 @@ int sctp_packet_transmit(struct sctp_packet *packet) | |||
| 594 | pr_debug("***sctp_transmit_packet*** skb->len:%d\n", nskb->len); | 592 | pr_debug("***sctp_transmit_packet*** skb->len:%d\n", nskb->len); |
| 595 | 593 | ||
| 596 | nskb->local_df = packet->ipfragok; | 594 | nskb->local_df = packet->ipfragok; |
| 597 | (*tp->af_specific->sctp_xmit)(nskb, tp); | 595 | tp->af_specific->sctp_xmit(nskb, tp); |
| 598 | 596 | ||
| 599 | out: | 597 | out: |
| 600 | sctp_packet_reset(packet); | 598 | sctp_packet_reset(packet); |
diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c index 59268f6e2c36..9c77947c0597 100644 --- a/net/sctp/outqueue.c +++ b/net/sctp/outqueue.c | |||
| @@ -22,9 +22,8 @@ | |||
| 22 | * See the GNU General Public License for more details. | 22 | * See the GNU General Public License for more details. |
| 23 | * | 23 | * |
| 24 | * You should have received a copy of the GNU General Public License | 24 | * You should have received a copy of the GNU General Public License |
| 25 | * along with GNU CC; see the file COPYING. If not, write to | 25 | * along with GNU CC; see the file COPYING. If not, see |
| 26 | * the Free Software Foundation, 59 Temple Place - Suite 330, | 26 | * <http://www.gnu.org/licenses/>. |
| 27 | * Boston, MA 02111-1307, USA. | ||
| 28 | * | 27 | * |
| 29 | * Please send any bug reports or fixes you make to the | 28 | * Please send any bug reports or fixes you make to the |
| 30 | * email address(es): | 29 | * email address(es): |
| @@ -111,7 +110,7 @@ static inline int sctp_cacc_skip_3_1_d(struct sctp_transport *primary, | |||
| 111 | struct sctp_transport *transport, | 110 | struct sctp_transport *transport, |
| 112 | int count_of_newacks) | 111 | int count_of_newacks) |
| 113 | { | 112 | { |
| 114 | if (count_of_newacks >=2 && transport != primary) | 113 | if (count_of_newacks >= 2 && transport != primary) |
| 115 | return 1; | 114 | return 1; |
| 116 | return 0; | 115 | return 0; |
| 117 | } | 116 | } |
| @@ -468,7 +467,7 @@ void sctp_retransmit(struct sctp_outq *q, struct sctp_transport *transport, | |||
| 468 | struct net *net = sock_net(q->asoc->base.sk); | 467 | struct net *net = sock_net(q->asoc->base.sk); |
| 469 | int error = 0; | 468 | int error = 0; |
| 470 | 469 | ||
| 471 | switch(reason) { | 470 | switch (reason) { |
| 472 | case SCTP_RTXR_T3_RTX: | 471 | case SCTP_RTXR_T3_RTX: |
| 473 | SCTP_INC_STATS(net, SCTP_MIB_T3_RETRANSMITS); | 472 | SCTP_INC_STATS(net, SCTP_MIB_T3_RETRANSMITS); |
| 474 | sctp_transport_lower_cwnd(transport, SCTP_LOWER_CWND_T3_RTX); | 473 | sctp_transport_lower_cwnd(transport, SCTP_LOWER_CWND_T3_RTX); |
| @@ -1083,7 +1082,7 @@ sctp_flush_out: | |||
| 1083 | * | 1082 | * |
| 1084 | * --xguo | 1083 | * --xguo |
| 1085 | */ | 1084 | */ |
| 1086 | while ((ltransport = sctp_list_dequeue(&transport_list)) != NULL ) { | 1085 | while ((ltransport = sctp_list_dequeue(&transport_list)) != NULL) { |
| 1087 | struct sctp_transport *t = list_entry(ltransport, | 1086 | struct sctp_transport *t = list_entry(ltransport, |
| 1088 | struct sctp_transport, | 1087 | struct sctp_transport, |
| 1089 | send_ready); | 1088 | send_ready); |
| @@ -1212,7 +1211,7 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_chunk *chunk) | |||
| 1212 | * destinations for which cacc_saw_newack is set. | 1211 | * destinations for which cacc_saw_newack is set. |
| 1213 | */ | 1212 | */ |
| 1214 | if (transport->cacc.cacc_saw_newack) | 1213 | if (transport->cacc.cacc_saw_newack) |
| 1215 | count_of_newacks ++; | 1214 | count_of_newacks++; |
| 1216 | } | 1215 | } |
| 1217 | 1216 | ||
| 1218 | /* Move the Cumulative TSN Ack Point if appropriate. */ | 1217 | /* Move the Cumulative TSN Ack Point if appropriate. */ |
diff --git a/net/sctp/primitive.c b/net/sctp/primitive.c index ce1ffd811775..ab8d9f96a177 100644 --- a/net/sctp/primitive.c +++ b/net/sctp/primitive.c | |||
| @@ -23,9 +23,8 @@ | |||
| 23 | * See the GNU General Public License for more details. | 23 | * See the GNU General Public License for more details. |
| 24 | * | 24 | * |
| 25 | * You should have received a copy of the GNU General Public License | 25 | * You should have received a copy of the GNU General Public License |
| 26 | * along with GNU CC; see the file COPYING. If not, write to | 26 | * along with GNU CC; see the file COPYING. If not, see |
| 27 | * the Free Software Foundation, 59 Temple Place - Suite 330, | 27 | * <http://www.gnu.org/licenses/>. |
| 28 | * Boston, MA 02111-1307, USA. | ||
| 29 | * | 28 | * |
| 30 | * Please send any bug reports or fixes you make to the | 29 | * Please send any bug reports or fixes you make to the |
| 31 | * email address(es): | 30 | * email address(es): |
diff --git a/net/sctp/proc.c b/net/sctp/proc.c index 0c0642156842..0947f1e15eb8 100644 --- a/net/sctp/proc.c +++ b/net/sctp/proc.c | |||
| @@ -16,9 +16,8 @@ | |||
| 16 | * See the GNU General Public License for more details. | 16 | * See the GNU General Public License for more details. |
| 17 | * | 17 | * |
| 18 | * You should have received a copy of the GNU General Public License | 18 | * You should have received a copy of the GNU General Public License |
| 19 | * along with GNU CC; see the file COPYING. If not, write to | 19 | * along with GNU CC; see the file COPYING. If not, see |
| 20 | * the Free Software Foundation, 59 Temple Place - Suite 330, | 20 | * <http://www.gnu.org/licenses/>. |
| 21 | * Boston, MA 02111-1307, USA. | ||
| 22 | * | 21 | * |
| 23 | * Please send any bug reports or fixes you make to the | 22 | * Please send any bug reports or fixes you make to the |
| 24 | * email address(es): | 23 | * email address(es): |
| @@ -178,7 +177,7 @@ static void sctp_seq_dump_remote_addrs(struct seq_file *seq, struct sctp_associa | |||
| 178 | rcu_read_unlock(); | 177 | rcu_read_unlock(); |
| 179 | } | 178 | } |
| 180 | 179 | ||
| 181 | static void * sctp_eps_seq_start(struct seq_file *seq, loff_t *pos) | 180 | static void *sctp_eps_seq_start(struct seq_file *seq, loff_t *pos) |
| 182 | { | 181 | { |
| 183 | if (*pos >= sctp_ep_hashsize) | 182 | if (*pos >= sctp_ep_hashsize) |
| 184 | return NULL; | 183 | return NULL; |
| @@ -197,7 +196,7 @@ static void sctp_eps_seq_stop(struct seq_file *seq, void *v) | |||
| 197 | } | 196 | } |
| 198 | 197 | ||
| 199 | 198 | ||
| 200 | static void * sctp_eps_seq_next(struct seq_file *seq, void *v, loff_t *pos) | 199 | static void *sctp_eps_seq_next(struct seq_file *seq, void *v, loff_t *pos) |
| 201 | { | 200 | { |
| 202 | if (++*pos >= sctp_ep_hashsize) | 201 | if (++*pos >= sctp_ep_hashsize) |
| 203 | return NULL; | 202 | return NULL; |
| @@ -219,7 +218,7 @@ static int sctp_eps_seq_show(struct seq_file *seq, void *v) | |||
| 219 | return -ENOMEM; | 218 | return -ENOMEM; |
| 220 | 219 | ||
| 221 | head = &sctp_ep_hashtable[hash]; | 220 | head = &sctp_ep_hashtable[hash]; |
| 222 | sctp_local_bh_disable(); | 221 | local_bh_disable(); |
| 223 | read_lock(&head->lock); | 222 | read_lock(&head->lock); |
| 224 | sctp_for_each_hentry(epb, &head->chain) { | 223 | sctp_for_each_hentry(epb, &head->chain) { |
| 225 | ep = sctp_ep(epb); | 224 | ep = sctp_ep(epb); |
| @@ -236,7 +235,7 @@ static int sctp_eps_seq_show(struct seq_file *seq, void *v) | |||
| 236 | seq_printf(seq, "\n"); | 235 | seq_printf(seq, "\n"); |
| 237 | } | 236 | } |
| 238 | read_unlock(&head->lock); | 237 | read_unlock(&head->lock); |
| 239 | sctp_local_bh_enable(); | 238 | local_bh_enable(); |
| 240 | 239 | ||
| 241 | return 0; | 240 | return 0; |
| 242 | } | 241 | } |
| @@ -283,7 +282,7 @@ void sctp_eps_proc_exit(struct net *net) | |||
| 283 | } | 282 | } |
| 284 | 283 | ||
| 285 | 284 | ||
| 286 | static void * sctp_assocs_seq_start(struct seq_file *seq, loff_t *pos) | 285 | static void *sctp_assocs_seq_start(struct seq_file *seq, loff_t *pos) |
| 287 | { | 286 | { |
| 288 | if (*pos >= sctp_assoc_hashsize) | 287 | if (*pos >= sctp_assoc_hashsize) |
| 289 | return NULL; | 288 | return NULL; |
| @@ -306,7 +305,7 @@ static void sctp_assocs_seq_stop(struct seq_file *seq, void *v) | |||
| 306 | } | 305 | } |
| 307 | 306 | ||
| 308 | 307 | ||
| 309 | static void * sctp_assocs_seq_next(struct seq_file *seq, void *v, loff_t *pos) | 308 | static void *sctp_assocs_seq_next(struct seq_file *seq, void *v, loff_t *pos) |
| 310 | { | 309 | { |
| 311 | if (++*pos >= sctp_assoc_hashsize) | 310 | if (++*pos >= sctp_assoc_hashsize) |
| 312 | return NULL; | 311 | return NULL; |
| @@ -327,7 +326,7 @@ static int sctp_assocs_seq_show(struct seq_file *seq, void *v) | |||
| 327 | return -ENOMEM; | 326 | return -ENOMEM; |
| 328 | 327 | ||
| 329 | head = &sctp_assoc_hashtable[hash]; | 328 | head = &sctp_assoc_hashtable[hash]; |
| 330 | sctp_local_bh_disable(); | 329 | local_bh_disable(); |
| 331 | read_lock(&head->lock); | 330 | read_lock(&head->lock); |
| 332 | sctp_for_each_hentry(epb, &head->chain) { | 331 | sctp_for_each_hentry(epb, &head->chain) { |
| 333 | assoc = sctp_assoc(epb); | 332 | assoc = sctp_assoc(epb); |
| @@ -363,7 +362,7 @@ static int sctp_assocs_seq_show(struct seq_file *seq, void *v) | |||
| 363 | seq_printf(seq, "\n"); | 362 | seq_printf(seq, "\n"); |
| 364 | } | 363 | } |
| 365 | read_unlock(&head->lock); | 364 | read_unlock(&head->lock); |
| 366 | sctp_local_bh_enable(); | 365 | local_bh_enable(); |
| 367 | 366 | ||
| 368 | return 0; | 367 | return 0; |
| 369 | } | 368 | } |
| @@ -447,7 +446,7 @@ static int sctp_remaddr_seq_show(struct seq_file *seq, void *v) | |||
| 447 | return -ENOMEM; | 446 | return -ENOMEM; |
| 448 | 447 | ||
| 449 | head = &sctp_assoc_hashtable[hash]; | 448 | head = &sctp_assoc_hashtable[hash]; |
| 450 | sctp_local_bh_disable(); | 449 | local_bh_disable(); |
| 451 | read_lock(&head->lock); | 450 | read_lock(&head->lock); |
| 452 | rcu_read_lock(); | 451 | rcu_read_lock(); |
| 453 | sctp_for_each_hentry(epb, &head->chain) { | 452 | sctp_for_each_hentry(epb, &head->chain) { |
| @@ -506,7 +505,7 @@ static int sctp_remaddr_seq_show(struct seq_file *seq, void *v) | |||
| 506 | 505 | ||
| 507 | rcu_read_unlock(); | 506 | rcu_read_unlock(); |
| 508 | read_unlock(&head->lock); | 507 | read_unlock(&head->lock); |
| 509 | sctp_local_bh_enable(); | 508 | local_bh_enable(); |
| 510 | 509 | ||
| 511 | return 0; | 510 | return 0; |
| 512 | 511 | ||
diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 5e17092f4ada..4e1d0fcb028e 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c | |||
| @@ -23,9 +23,8 @@ | |||
| 23 | * See the GNU General Public License for more details. | 23 | * See the GNU General Public License for more details. |
| 24 | * | 24 | * |
| 25 | * You should have received a copy of the GNU General Public License | 25 | * You should have received a copy of the GNU General Public License |
| 26 | * along with GNU CC; see the file COPYING. If not, write to | 26 | * along with GNU CC; see the file COPYING. If not, see |
| 27 | * the Free Software Foundation, 59 Temple Place - Suite 330, | 27 | * <http://www.gnu.org/licenses/>. |
| 28 | * Boston, MA 02111-1307, USA. | ||
| 29 | * | 28 | * |
| 30 | * Please send any bug reports or fixes you make to the | 29 | * Please send any bug reports or fixes you make to the |
| 31 | * email address(es): | 30 | * email address(es): |
| @@ -635,10 +634,10 @@ static void sctp_addr_wq_timeout_handler(unsigned long arg) | |||
| 635 | /* ignore bound-specific endpoints */ | 634 | /* ignore bound-specific endpoints */ |
| 636 | if (!sctp_is_ep_boundall(sk)) | 635 | if (!sctp_is_ep_boundall(sk)) |
| 637 | continue; | 636 | continue; |
| 638 | sctp_bh_lock_sock(sk); | 637 | bh_lock_sock(sk); |
| 639 | if (sctp_asconf_mgmt(sp, addrw) < 0) | 638 | if (sctp_asconf_mgmt(sp, addrw) < 0) |
| 640 | pr_debug("%s: sctp_asconf_mgmt failed\n", __func__); | 639 | pr_debug("%s: sctp_asconf_mgmt failed\n", __func__); |
| 641 | sctp_bh_unlock_sock(sk); | 640 | bh_unlock_sock(sk); |
| 642 | } | 641 | } |
| 643 | #if IS_ENABLED(CONFIG_IPV6) | 642 | #if IS_ENABLED(CONFIG_IPV6) |
| 644 | free_next: | 643 | free_next: |
| @@ -1031,6 +1030,7 @@ static const struct net_protocol sctp_protocol = { | |||
| 1031 | .err_handler = sctp_v4_err, | 1030 | .err_handler = sctp_v4_err, |
| 1032 | .no_policy = 1, | 1031 | .no_policy = 1, |
| 1033 | .netns_ok = 1, | 1032 | .netns_ok = 1, |
| 1033 | .icmp_strict_tag_validation = 1, | ||
| 1034 | }; | 1034 | }; |
| 1035 | 1035 | ||
| 1036 | /* IPv4 address related functions. */ | 1036 | /* IPv4 address related functions. */ |
| @@ -1066,8 +1066,8 @@ static struct sctp_af sctp_af_inet = { | |||
| 1066 | #endif | 1066 | #endif |
| 1067 | }; | 1067 | }; |
| 1068 | 1068 | ||
| 1069 | struct sctp_pf *sctp_get_pf_specific(sa_family_t family) { | 1069 | struct sctp_pf *sctp_get_pf_specific(sa_family_t family) |
| 1070 | 1070 | { | |
| 1071 | switch (family) { | 1071 | switch (family) { |
| 1072 | case PF_INET: | 1072 | case PF_INET: |
| 1073 | return sctp_pf_inet_specific; | 1073 | return sctp_pf_inet_specific; |
| @@ -1461,7 +1461,6 @@ static __init int sctp_init(void) | |||
| 1461 | if (status) | 1461 | if (status) |
| 1462 | goto err_v6_add_protocol; | 1462 | goto err_v6_add_protocol; |
| 1463 | 1463 | ||
| 1464 | status = 0; | ||
| 1465 | out: | 1464 | out: |
| 1466 | return status; | 1465 | return status; |
| 1467 | err_v6_add_protocol: | 1466 | err_v6_add_protocol: |
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index fe690320b1e4..632090b961c3 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c | |||
| @@ -23,9 +23,8 @@ | |||
| 23 | * See the GNU General Public License for more details. | 23 | * See the GNU General Public License for more details. |
| 24 | * | 24 | * |
| 25 | * You should have received a copy of the GNU General Public License | 25 | * You should have received a copy of the GNU General Public License |
| 26 | * along with GNU CC; see the file COPYING. If not, write to | 26 | * along with GNU CC; see the file COPYING. If not, see |
| 27 | * the Free Software Foundation, 59 Temple Place - Suite 330, | 27 | * <http://www.gnu.org/licenses/>. |
| 28 | * Boston, MA 02111-1307, USA. | ||
| 29 | * | 28 | * |
| 30 | * Please send any bug reports or fixes you make to the | 29 | * Please send any bug reports or fixes you make to the |
| 31 | * email address(es): | 30 | * email address(es): |
| @@ -79,6 +78,8 @@ static int sctp_process_param(struct sctp_association *asoc, | |||
| 79 | gfp_t gfp); | 78 | gfp_t gfp); |
| 80 | static void *sctp_addto_param(struct sctp_chunk *chunk, int len, | 79 | static void *sctp_addto_param(struct sctp_chunk *chunk, int len, |
| 81 | const void *data); | 80 | const void *data); |
| 81 | static void *sctp_addto_chunk_fixed(struct sctp_chunk *, int len, | ||
| 82 | const void *data); | ||
| 82 | 83 | ||
| 83 | /* Control chunk destructor */ | 84 | /* Control chunk destructor */ |
| 84 | static void sctp_control_release_owner(struct sk_buff *skb) | 85 | static void sctp_control_release_owner(struct sk_buff *skb) |
| @@ -1476,8 +1477,8 @@ void *sctp_addto_chunk(struct sctp_chunk *chunk, int len, const void *data) | |||
| 1476 | /* Append bytes to the end of a chunk. Returns NULL if there isn't sufficient | 1477 | /* Append bytes to the end of a chunk. Returns NULL if there isn't sufficient |
| 1477 | * space in the chunk | 1478 | * space in the chunk |
| 1478 | */ | 1479 | */ |
| 1479 | void *sctp_addto_chunk_fixed(struct sctp_chunk *chunk, | 1480 | static void *sctp_addto_chunk_fixed(struct sctp_chunk *chunk, |
| 1480 | int len, const void *data) | 1481 | int len, const void *data) |
| 1481 | { | 1482 | { |
| 1482 | if (skb_tailroom(chunk->skb) >= len) | 1483 | if (skb_tailroom(chunk->skb) >= len) |
| 1483 | return sctp_addto_chunk(chunk, len, data); | 1484 | return sctp_addto_chunk(chunk, len, data); |
| @@ -1968,13 +1969,13 @@ static int sctp_verify_ext_param(struct net *net, union sctp_params param) | |||
| 1968 | 1969 | ||
| 1969 | for (i = 0; i < num_ext; i++) { | 1970 | for (i = 0; i < num_ext; i++) { |
| 1970 | switch (param.ext->chunks[i]) { | 1971 | switch (param.ext->chunks[i]) { |
| 1971 | case SCTP_CID_AUTH: | 1972 | case SCTP_CID_AUTH: |
| 1972 | have_auth = 1; | 1973 | have_auth = 1; |
| 1973 | break; | 1974 | break; |
| 1974 | case SCTP_CID_ASCONF: | 1975 | case SCTP_CID_ASCONF: |
| 1975 | case SCTP_CID_ASCONF_ACK: | 1976 | case SCTP_CID_ASCONF_ACK: |
| 1976 | have_asconf = 1; | 1977 | have_asconf = 1; |
| 1977 | break; | 1978 | break; |
| 1978 | } | 1979 | } |
| 1979 | } | 1980 | } |
| 1980 | 1981 | ||
| @@ -2001,25 +2002,24 @@ static void sctp_process_ext_param(struct sctp_association *asoc, | |||
| 2001 | 2002 | ||
| 2002 | for (i = 0; i < num_ext; i++) { | 2003 | for (i = 0; i < num_ext; i++) { |
| 2003 | switch (param.ext->chunks[i]) { | 2004 | switch (param.ext->chunks[i]) { |
| 2004 | case SCTP_CID_FWD_TSN: | 2005 | case SCTP_CID_FWD_TSN: |
| 2005 | if (net->sctp.prsctp_enable && | 2006 | if (net->sctp.prsctp_enable && !asoc->peer.prsctp_capable) |
| 2006 | !asoc->peer.prsctp_capable) | ||
| 2007 | asoc->peer.prsctp_capable = 1; | 2007 | asoc->peer.prsctp_capable = 1; |
| 2008 | break; | 2008 | break; |
| 2009 | case SCTP_CID_AUTH: | 2009 | case SCTP_CID_AUTH: |
| 2010 | /* if the peer reports AUTH, assume that he | 2010 | /* if the peer reports AUTH, assume that he |
| 2011 | * supports AUTH. | 2011 | * supports AUTH. |
| 2012 | */ | 2012 | */ |
| 2013 | if (net->sctp.auth_enable) | 2013 | if (net->sctp.auth_enable) |
| 2014 | asoc->peer.auth_capable = 1; | 2014 | asoc->peer.auth_capable = 1; |
| 2015 | break; | 2015 | break; |
| 2016 | case SCTP_CID_ASCONF: | 2016 | case SCTP_CID_ASCONF: |
| 2017 | case SCTP_CID_ASCONF_ACK: | 2017 | case SCTP_CID_ASCONF_ACK: |
| 2018 | if (net->sctp.addip_enable) | 2018 | if (net->sctp.addip_enable) |
| 2019 | asoc->peer.asconf_capable = 1; | 2019 | asoc->peer.asconf_capable = 1; |
| 2020 | break; | 2020 | break; |
| 2021 | default: | 2021 | default: |
| 2022 | break; | 2022 | break; |
| 2023 | } | 2023 | } |
| 2024 | } | 2024 | } |
| 2025 | } | 2025 | } |
| @@ -2252,7 +2252,7 @@ int sctp_verify_init(struct net *net, const struct sctp_association *asoc, | |||
| 2252 | * VIOLATION error. We build the ERROR chunk here and let the normal | 2252 | * VIOLATION error. We build the ERROR chunk here and let the normal |
| 2253 | * error handling code build and send the packet. | 2253 | * error handling code build and send the packet. |
| 2254 | */ | 2254 | */ |
| 2255 | if (param.v != (void*)chunk->chunk_end) | 2255 | if (param.v != (void *)chunk->chunk_end) |
| 2256 | return sctp_process_inv_paramlength(asoc, param.p, chunk, errp); | 2256 | return sctp_process_inv_paramlength(asoc, param.p, chunk, errp); |
| 2257 | 2257 | ||
| 2258 | /* The only missing mandatory param possible today is | 2258 | /* The only missing mandatory param possible today is |
| @@ -2267,14 +2267,14 @@ int sctp_verify_init(struct net *net, const struct sctp_association *asoc, | |||
| 2267 | 2267 | ||
| 2268 | result = sctp_verify_param(net, asoc, param, cid, chunk, errp); | 2268 | result = sctp_verify_param(net, asoc, param, cid, chunk, errp); |
| 2269 | switch (result) { | 2269 | switch (result) { |
| 2270 | case SCTP_IERROR_ABORT: | 2270 | case SCTP_IERROR_ABORT: |
| 2271 | case SCTP_IERROR_NOMEM: | 2271 | case SCTP_IERROR_NOMEM: |
| 2272 | return 0; | 2272 | return 0; |
| 2273 | case SCTP_IERROR_ERROR: | 2273 | case SCTP_IERROR_ERROR: |
| 2274 | return 1; | 2274 | return 1; |
| 2275 | case SCTP_IERROR_NO_ERROR: | 2275 | case SCTP_IERROR_NO_ERROR: |
| 2276 | default: | 2276 | default: |
| 2277 | break; | 2277 | break; |
| 2278 | } | 2278 | } |
| 2279 | 2279 | ||
| 2280 | } /* for (loop through all parameters) */ | 2280 | } /* for (loop through all parameters) */ |
| @@ -2309,7 +2309,7 @@ int sctp_process_init(struct sctp_association *asoc, struct sctp_chunk *chunk, | |||
| 2309 | * added as the primary transport. The source address seems to | 2309 | * added as the primary transport. The source address seems to |
| 2310 | * be a a better choice than any of the embedded addresses. | 2310 | * be a a better choice than any of the embedded addresses. |
| 2311 | */ | 2311 | */ |
| 2312 | if(!sctp_assoc_add_peer(asoc, peer_addr, gfp, SCTP_ACTIVE)) | 2312 | if (!sctp_assoc_add_peer(asoc, peer_addr, gfp, SCTP_ACTIVE)) |
| 2313 | goto nomem; | 2313 | goto nomem; |
| 2314 | 2314 | ||
| 2315 | if (sctp_cmp_addr_exact(sctp_source(chunk), peer_addr)) | 2315 | if (sctp_cmp_addr_exact(sctp_source(chunk), peer_addr)) |
| @@ -3335,7 +3335,7 @@ static __be16 sctp_get_asconf_response(struct sctp_chunk *asconf_ack, | |||
| 3335 | 3335 | ||
| 3336 | while (asconf_ack_len > 0) { | 3336 | while (asconf_ack_len > 0) { |
| 3337 | if (asconf_ack_param->crr_id == asconf_param->crr_id) { | 3337 | if (asconf_ack_param->crr_id == asconf_param->crr_id) { |
| 3338 | switch(asconf_ack_param->param_hdr.type) { | 3338 | switch (asconf_ack_param->param_hdr.type) { |
| 3339 | case SCTP_PARAM_SUCCESS_REPORT: | 3339 | case SCTP_PARAM_SUCCESS_REPORT: |
| 3340 | return SCTP_ERROR_NO_ERROR; | 3340 | return SCTP_ERROR_NO_ERROR; |
| 3341 | case SCTP_PARAM_ERR_CAUSE: | 3341 | case SCTP_PARAM_ERR_CAUSE: |
diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c index 1a6eef39ab2f..bd859154000e 100644 --- a/net/sctp/sm_sideeffect.c +++ b/net/sctp/sm_sideeffect.c | |||
| @@ -22,9 +22,8 @@ | |||
| 22 | * See the GNU General Public License for more details. | 22 | * See the GNU General Public License for more details. |
| 23 | * | 23 | * |
| 24 | * You should have received a copy of the GNU General Public License | 24 | * You should have received a copy of the GNU General Public License |
| 25 | * along with GNU CC; see the file COPYING. If not, write to | 25 | * along with GNU CC; see the file COPYING. If not, see |
| 26 | * the Free Software Foundation, 59 Temple Place - Suite 330, | 26 | * <http://www.gnu.org/licenses/>. |
| 27 | * Boston, MA 02111-1307, USA. | ||
| 28 | * | 27 | * |
| 29 | * Please send any bug reports or fixes you make to the | 28 | * Please send any bug reports or fixes you make to the |
| 30 | * email address(es): | 29 | * email address(es): |
| @@ -249,7 +248,7 @@ void sctp_generate_t3_rtx_event(unsigned long peer) | |||
| 249 | 248 | ||
| 250 | /* Check whether a task is in the sock. */ | 249 | /* Check whether a task is in the sock. */ |
| 251 | 250 | ||
| 252 | sctp_bh_lock_sock(asoc->base.sk); | 251 | bh_lock_sock(asoc->base.sk); |
| 253 | if (sock_owned_by_user(asoc->base.sk)) { | 252 | if (sock_owned_by_user(asoc->base.sk)) { |
| 254 | pr_debug("%s: sock is busy\n", __func__); | 253 | pr_debug("%s: sock is busy\n", __func__); |
| 255 | 254 | ||
| @@ -276,7 +275,7 @@ void sctp_generate_t3_rtx_event(unsigned long peer) | |||
| 276 | asoc->base.sk->sk_err = -error; | 275 | asoc->base.sk->sk_err = -error; |
| 277 | 276 | ||
| 278 | out_unlock: | 277 | out_unlock: |
| 279 | sctp_bh_unlock_sock(asoc->base.sk); | 278 | bh_unlock_sock(asoc->base.sk); |
| 280 | sctp_transport_put(transport); | 279 | sctp_transport_put(transport); |
| 281 | } | 280 | } |
| 282 | 281 | ||
| @@ -289,7 +288,7 @@ static void sctp_generate_timeout_event(struct sctp_association *asoc, | |||
| 289 | struct net *net = sock_net(asoc->base.sk); | 288 | struct net *net = sock_net(asoc->base.sk); |
| 290 | int error = 0; | 289 | int error = 0; |
| 291 | 290 | ||
| 292 | sctp_bh_lock_sock(asoc->base.sk); | 291 | bh_lock_sock(asoc->base.sk); |
| 293 | if (sock_owned_by_user(asoc->base.sk)) { | 292 | if (sock_owned_by_user(asoc->base.sk)) { |
| 294 | pr_debug("%s: sock is busy: timer %d\n", __func__, | 293 | pr_debug("%s: sock is busy: timer %d\n", __func__, |
| 295 | timeout_type); | 294 | timeout_type); |
| @@ -316,7 +315,7 @@ static void sctp_generate_timeout_event(struct sctp_association *asoc, | |||
| 316 | asoc->base.sk->sk_err = -error; | 315 | asoc->base.sk->sk_err = -error; |
| 317 | 316 | ||
| 318 | out_unlock: | 317 | out_unlock: |
| 319 | sctp_bh_unlock_sock(asoc->base.sk); | 318 | bh_unlock_sock(asoc->base.sk); |
| 320 | sctp_association_put(asoc); | 319 | sctp_association_put(asoc); |
| 321 | } | 320 | } |
| 322 | 321 | ||
| @@ -368,7 +367,7 @@ void sctp_generate_heartbeat_event(unsigned long data) | |||
| 368 | struct sctp_association *asoc = transport->asoc; | 367 | struct sctp_association *asoc = transport->asoc; |
| 369 | struct net *net = sock_net(asoc->base.sk); | 368 | struct net *net = sock_net(asoc->base.sk); |
| 370 | 369 | ||
| 371 | sctp_bh_lock_sock(asoc->base.sk); | 370 | bh_lock_sock(asoc->base.sk); |
| 372 | if (sock_owned_by_user(asoc->base.sk)) { | 371 | if (sock_owned_by_user(asoc->base.sk)) { |
| 373 | pr_debug("%s: sock is busy\n", __func__); | 372 | pr_debug("%s: sock is busy\n", __func__); |
| 374 | 373 | ||
| @@ -393,7 +392,7 @@ void sctp_generate_heartbeat_event(unsigned long data) | |||
| 393 | asoc->base.sk->sk_err = -error; | 392 | asoc->base.sk->sk_err = -error; |
| 394 | 393 | ||
| 395 | out_unlock: | 394 | out_unlock: |
| 396 | sctp_bh_unlock_sock(asoc->base.sk); | 395 | bh_unlock_sock(asoc->base.sk); |
| 397 | sctp_transport_put(transport); | 396 | sctp_transport_put(transport); |
| 398 | } | 397 | } |
| 399 | 398 | ||
| @@ -405,8 +404,8 @@ void sctp_generate_proto_unreach_event(unsigned long data) | |||
| 405 | struct sctp_transport *transport = (struct sctp_transport *) data; | 404 | struct sctp_transport *transport = (struct sctp_transport *) data; |
| 406 | struct sctp_association *asoc = transport->asoc; | 405 | struct sctp_association *asoc = transport->asoc; |
| 407 | struct net *net = sock_net(asoc->base.sk); | 406 | struct net *net = sock_net(asoc->base.sk); |
| 408 | 407 | ||
| 409 | sctp_bh_lock_sock(asoc->base.sk); | 408 | bh_lock_sock(asoc->base.sk); |
| 410 | if (sock_owned_by_user(asoc->base.sk)) { | 409 | if (sock_owned_by_user(asoc->base.sk)) { |
| 411 | pr_debug("%s: sock is busy\n", __func__); | 410 | pr_debug("%s: sock is busy\n", __func__); |
| 412 | 411 | ||
| @@ -428,7 +427,7 @@ void sctp_generate_proto_unreach_event(unsigned long data) | |||
| 428 | asoc->state, asoc->ep, asoc, transport, GFP_ATOMIC); | 427 | asoc->state, asoc->ep, asoc, transport, GFP_ATOMIC); |
| 429 | 428 | ||
| 430 | out_unlock: | 429 | out_unlock: |
| 431 | sctp_bh_unlock_sock(asoc->base.sk); | 430 | bh_unlock_sock(asoc->base.sk); |
| 432 | sctp_association_put(asoc); | 431 | sctp_association_put(asoc); |
| 433 | } | 432 | } |
| 434 | 433 | ||
| @@ -544,7 +543,7 @@ static void sctp_cmd_init_failed(sctp_cmd_seq_t *commands, | |||
| 544 | { | 543 | { |
| 545 | struct sctp_ulpevent *event; | 544 | struct sctp_ulpevent *event; |
| 546 | 545 | ||
| 547 | event = sctp_ulpevent_make_assoc_change(asoc,0, SCTP_CANT_STR_ASSOC, | 546 | event = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_CANT_STR_ASSOC, |
| 548 | (__u16)error, 0, 0, NULL, | 547 | (__u16)error, 0, 0, NULL, |
| 549 | GFP_ATOMIC); | 548 | GFP_ATOMIC); |
| 550 | 549 | ||
| @@ -1116,7 +1115,7 @@ int sctp_do_sm(struct net *net, sctp_event_t event_type, sctp_subtype_t subtype, | |||
| 1116 | sctp_init_cmd_seq(&commands); | 1115 | sctp_init_cmd_seq(&commands); |
| 1117 | 1116 | ||
| 1118 | debug_pre_sfn(); | 1117 | debug_pre_sfn(); |
| 1119 | status = (*state_fn->fn)(net, ep, asoc, subtype, event_arg, &commands); | 1118 | status = state_fn->fn(net, ep, asoc, subtype, event_arg, &commands); |
| 1120 | debug_post_sfn(); | 1119 | debug_post_sfn(); |
| 1121 | 1120 | ||
| 1122 | error = sctp_side_effects(event_type, subtype, state, | 1121 | error = sctp_side_effects(event_type, subtype, state, |
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index a26065be7289..483dcd71b3c5 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c | |||
| @@ -22,9 +22,8 @@ | |||
| 22 | * See the GNU General Public License for more details. | 22 | * See the GNU General Public License for more details. |
| 23 | * | 23 | * |
| 24 | * You should have received a copy of the GNU General Public License | 24 | * You should have received a copy of the GNU General Public License |
| 25 | * along with GNU CC; see the file COPYING. If not, write to | 25 | * along with GNU CC; see the file COPYING. If not, see |
| 26 | * the Free Software Foundation, 59 Temple Place - Suite 330, | 26 | * <http://www.gnu.org/licenses/>. |
| 27 | * Boston, MA 02111-1307, USA. | ||
| 28 | * | 27 | * |
| 29 | * Please send any bug reports or fixes you make to the | 28 | * Please send any bug reports or fixes you make to the |
| 30 | * email address(es): | 29 | * email address(es): |
| @@ -2946,7 +2945,7 @@ sctp_disposition_t sctp_sf_eat_data_6_2(struct net *net, | |||
| 2946 | return sctp_sf_violation_chunklen(net, ep, asoc, type, arg, | 2945 | return sctp_sf_violation_chunklen(net, ep, asoc, type, arg, |
| 2947 | commands); | 2946 | commands); |
| 2948 | 2947 | ||
| 2949 | error = sctp_eat_data(asoc, chunk, commands ); | 2948 | error = sctp_eat_data(asoc, chunk, commands); |
| 2950 | switch (error) { | 2949 | switch (error) { |
| 2951 | case SCTP_IERROR_NO_ERROR: | 2950 | case SCTP_IERROR_NO_ERROR: |
| 2952 | break; | 2951 | break; |
| @@ -3067,7 +3066,7 @@ sctp_disposition_t sctp_sf_eat_data_fast_4_4(struct net *net, | |||
| 3067 | return sctp_sf_violation_chunklen(net, ep, asoc, type, arg, | 3066 | return sctp_sf_violation_chunklen(net, ep, asoc, type, arg, |
| 3068 | commands); | 3067 | commands); |
| 3069 | 3068 | ||
| 3070 | error = sctp_eat_data(asoc, chunk, commands ); | 3069 | error = sctp_eat_data(asoc, chunk, commands); |
| 3071 | switch (error) { | 3070 | switch (error) { |
| 3072 | case SCTP_IERROR_NO_ERROR: | 3071 | case SCTP_IERROR_NO_ERROR: |
| 3073 | case SCTP_IERROR_HIGH_TSN: | 3072 | case SCTP_IERROR_HIGH_TSN: |
| @@ -3682,8 +3681,7 @@ sctp_disposition_t sctp_sf_do_asconf(struct net *net, | |||
| 3682 | asconf_ack->dest = chunk->source; | 3681 | asconf_ack->dest = chunk->source; |
| 3683 | sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(asconf_ack)); | 3682 | sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(asconf_ack)); |
| 3684 | if (asoc->new_transport) { | 3683 | if (asoc->new_transport) { |
| 3685 | sctp_sf_heartbeat(ep, asoc, type, asoc->new_transport, | 3684 | sctp_sf_heartbeat(ep, asoc, type, asoc->new_transport, commands); |
| 3686 | commands); | ||
| 3687 | ((struct sctp_association *)asoc)->new_transport = NULL; | 3685 | ((struct sctp_association *)asoc)->new_transport = NULL; |
| 3688 | } | 3686 | } |
| 3689 | 3687 | ||
| @@ -3766,7 +3764,7 @@ sctp_disposition_t sctp_sf_do_asconf_ack(struct net *net, | |||
| 3766 | */ | 3764 | */ |
| 3767 | sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP, | 3765 | sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP, |
| 3768 | SCTP_TO(SCTP_EVENT_TIMEOUT_T4_RTO)); | 3766 | SCTP_TO(SCTP_EVENT_TIMEOUT_T4_RTO)); |
| 3769 | sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET,SCTP_NULL()); | 3767 | sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET, SCTP_NULL()); |
| 3770 | sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR, | 3768 | sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR, |
| 3771 | SCTP_ERROR(ECONNABORTED)); | 3769 | SCTP_ERROR(ECONNABORTED)); |
| 3772 | sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, | 3770 | sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, |
| @@ -3800,7 +3798,7 @@ sctp_disposition_t sctp_sf_do_asconf_ack(struct net *net, | |||
| 3800 | /* We are going to ABORT, so we might as well stop | 3798 | /* We are going to ABORT, so we might as well stop |
| 3801 | * processing the rest of the chunks in the packet. | 3799 | * processing the rest of the chunks in the packet. |
| 3802 | */ | 3800 | */ |
| 3803 | sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET,SCTP_NULL()); | 3801 | sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET, SCTP_NULL()); |
| 3804 | sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR, | 3802 | sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR, |
| 3805 | SCTP_ERROR(ECONNABORTED)); | 3803 | SCTP_ERROR(ECONNABORTED)); |
| 3806 | sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, | 3804 | sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, |
| @@ -4452,7 +4450,7 @@ static sctp_disposition_t sctp_sf_violation_chunklen( | |||
| 4452 | void *arg, | 4450 | void *arg, |
| 4453 | sctp_cmd_seq_t *commands) | 4451 | sctp_cmd_seq_t *commands) |
| 4454 | { | 4452 | { |
| 4455 | static const char err_str[]="The following chunk had invalid length:"; | 4453 | static const char err_str[] = "The following chunk had invalid length:"; |
| 4456 | 4454 | ||
| 4457 | return sctp_sf_abort_violation(net, ep, asoc, arg, commands, err_str, | 4455 | return sctp_sf_abort_violation(net, ep, asoc, arg, commands, err_str, |
| 4458 | sizeof(err_str)); | 4456 | sizeof(err_str)); |
| @@ -4515,7 +4513,7 @@ static sctp_disposition_t sctp_sf_violation_ctsn( | |||
| 4515 | void *arg, | 4513 | void *arg, |
| 4516 | sctp_cmd_seq_t *commands) | 4514 | sctp_cmd_seq_t *commands) |
| 4517 | { | 4515 | { |
| 4518 | static const char err_str[]="The cumulative tsn ack beyond the max tsn currently sent:"; | 4516 | static const char err_str[] = "The cumulative tsn ack beyond the max tsn currently sent:"; |
| 4519 | 4517 | ||
| 4520 | return sctp_sf_abort_violation(net, ep, asoc, arg, commands, err_str, | 4518 | return sctp_sf_abort_violation(net, ep, asoc, arg, commands, err_str, |
| 4521 | sizeof(err_str)); | 4519 | sizeof(err_str)); |
| @@ -4535,7 +4533,7 @@ static sctp_disposition_t sctp_sf_violation_chunk( | |||
| 4535 | void *arg, | 4533 | void *arg, |
| 4536 | sctp_cmd_seq_t *commands) | 4534 | sctp_cmd_seq_t *commands) |
| 4537 | { | 4535 | { |
| 4538 | static const char err_str[]="The following chunk violates protocol:"; | 4536 | static const char err_str[] = "The following chunk violates protocol:"; |
| 4539 | 4537 | ||
| 4540 | if (!asoc) | 4538 | if (!asoc) |
| 4541 | return sctp_sf_violation(net, ep, asoc, type, arg, commands); | 4539 | return sctp_sf_violation(net, ep, asoc, type, arg, commands); |
| @@ -4611,7 +4609,7 @@ sctp_disposition_t sctp_sf_do_prm_asoc(struct net *net, | |||
| 4611 | sctp_cmd_seq_t *commands) | 4609 | sctp_cmd_seq_t *commands) |
| 4612 | { | 4610 | { |
| 4613 | struct sctp_chunk *repl; | 4611 | struct sctp_chunk *repl; |
| 4614 | struct sctp_association* my_asoc; | 4612 | struct sctp_association *my_asoc; |
| 4615 | 4613 | ||
| 4616 | /* The comment below says that we enter COOKIE-WAIT AFTER | 4614 | /* The comment below says that we enter COOKIE-WAIT AFTER |
| 4617 | * sending the INIT, but that doesn't actually work in our | 4615 | * sending the INIT, but that doesn't actually work in our |
| @@ -6001,7 +5999,7 @@ static struct sctp_packet *sctp_ootb_pkt_new(struct net *net, | |||
| 6001 | /* Special case the INIT-ACK as there is no peer's vtag | 5999 | /* Special case the INIT-ACK as there is no peer's vtag |
| 6002 | * yet. | 6000 | * yet. |
| 6003 | */ | 6001 | */ |
| 6004 | switch(chunk->chunk_hdr->type) { | 6002 | switch (chunk->chunk_hdr->type) { |
| 6005 | case SCTP_CID_INIT_ACK: | 6003 | case SCTP_CID_INIT_ACK: |
| 6006 | { | 6004 | { |
| 6007 | sctp_initack_chunk_t *initack; | 6005 | sctp_initack_chunk_t *initack; |
| @@ -6018,7 +6016,7 @@ static struct sctp_packet *sctp_ootb_pkt_new(struct net *net, | |||
| 6018 | /* Special case the INIT and stale COOKIE_ECHO as there is no | 6016 | /* Special case the INIT and stale COOKIE_ECHO as there is no |
| 6019 | * vtag yet. | 6017 | * vtag yet. |
| 6020 | */ | 6018 | */ |
| 6021 | switch(chunk->chunk_hdr->type) { | 6019 | switch (chunk->chunk_hdr->type) { |
| 6022 | case SCTP_CID_INIT: | 6020 | case SCTP_CID_INIT: |
| 6023 | { | 6021 | { |
| 6024 | sctp_init_chunk_t *init; | 6022 | sctp_init_chunk_t *init; |
| @@ -6208,7 +6206,7 @@ static int sctp_eat_data(const struct sctp_association *asoc, | |||
| 6208 | */ | 6206 | */ |
| 6209 | if (*sk->sk_prot_creator->memory_pressure) { | 6207 | if (*sk->sk_prot_creator->memory_pressure) { |
| 6210 | if (sctp_tsnmap_has_gap(map) && | 6208 | if (sctp_tsnmap_has_gap(map) && |
| 6211 | (sctp_tsnmap_get_ctsn(map) + 1) == tsn) { | 6209 | (sctp_tsnmap_get_ctsn(map) + 1) == tsn) { |
| 6212 | pr_debug("%s: under pressure, reneging for tsn:%u\n", | 6210 | pr_debug("%s: under pressure, reneging for tsn:%u\n", |
| 6213 | __func__, tsn); | 6211 | __func__, tsn); |
| 6214 | deliver = SCTP_CMD_RENEGE; | 6212 | deliver = SCTP_CMD_RENEGE; |
| @@ -6232,7 +6230,7 @@ static int sctp_eat_data(const struct sctp_association *asoc, | |||
| 6232 | /* We are going to ABORT, so we might as well stop | 6230 | /* We are going to ABORT, so we might as well stop |
| 6233 | * processing the rest of the chunks in the packet. | 6231 | * processing the rest of the chunks in the packet. |
| 6234 | */ | 6232 | */ |
| 6235 | sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET,SCTP_NULL()); | 6233 | sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET, SCTP_NULL()); |
| 6236 | sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR, | 6234 | sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR, |
| 6237 | SCTP_ERROR(ECONNABORTED)); | 6235 | SCTP_ERROR(ECONNABORTED)); |
| 6238 | sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, | 6236 | sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, |
diff --git a/net/sctp/sm_statetable.c b/net/sctp/sm_statetable.c index c5999b2dde7d..a987d54b379c 100644 --- a/net/sctp/sm_statetable.c +++ b/net/sctp/sm_statetable.c | |||
| @@ -22,9 +22,8 @@ | |||
| 22 | * See the GNU General Public License for more details. | 22 | * See the GNU General Public License for more details. |
| 23 | * | 23 | * |
| 24 | * You should have received a copy of the GNU General Public License | 24 | * You should have received a copy of the GNU General Public License |
| 25 | * along with GNU CC; see the file COPYING. If not, write to | 25 | * along with GNU CC; see the file COPYING. If not, see |
| 26 | * the Free Software Foundation, 59 Temple Place - Suite 330, | 26 | * <http://www.gnu.org/licenses/>. |
| 27 | * Boston, MA 02111-1307, USA. | ||
| 28 | * | 27 | * |
| 29 | * Please send any bug reports or fixes you make to the | 28 | * Please send any bug reports or fixes you make to the |
| 30 | * email address(es): | 29 | * email address(es): |
| @@ -70,7 +69,7 @@ static const sctp_sm_table_entry_t bug = { | |||
| 70 | if ((event_subtype._type > (_max))) { \ | 69 | if ((event_subtype._type > (_max))) { \ |
| 71 | pr_warn("table %p possible attack: event %d exceeds max %d\n", \ | 70 | pr_warn("table %p possible attack: event %d exceeds max %d\n", \ |
| 72 | _table, event_subtype._type, _max); \ | 71 | _table, event_subtype._type, _max); \ |
| 73 | rtn = &bug; \ | 72 | rtn = &bug; \ |
| 74 | } else \ | 73 | } else \ |
| 75 | rtn = &_table[event_subtype._type][(int)state]; \ | 74 | rtn = &_table[event_subtype._type][(int)state]; \ |
| 76 | \ | 75 | \ |
diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 42b709c95cf3..9e91d6e5df63 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c | |||
| @@ -28,9 +28,8 @@ | |||
| 28 | * See the GNU General Public License for more details. | 28 | * See the GNU General Public License for more details. |
| 29 | * | 29 | * |
| 30 | * You should have received a copy of the GNU General Public License | 30 | * You should have received a copy of the GNU General Public License |
| 31 | * along with GNU CC; see the file COPYING. If not, write to | 31 | * along with GNU CC; see the file COPYING. If not, see |
| 32 | * the Free Software Foundation, 59 Temple Place - Suite 330, | 32 | * <http://www.gnu.org/licenses/>. |
| 33 | * Boston, MA 02111-1307, USA. | ||
| 34 | * | 33 | * |
| 35 | * Please send any bug reports or fixes you make to the | 34 | * Please send any bug reports or fixes you make to the |
| 36 | * email address(es): | 35 | * email address(es): |
| @@ -83,7 +82,7 @@ static int sctp_writeable(struct sock *sk); | |||
| 83 | static void sctp_wfree(struct sk_buff *skb); | 82 | static void sctp_wfree(struct sk_buff *skb); |
| 84 | static int sctp_wait_for_sndbuf(struct sctp_association *, long *timeo_p, | 83 | static int sctp_wait_for_sndbuf(struct sctp_association *, long *timeo_p, |
| 85 | size_t msg_len); | 84 | size_t msg_len); |
| 86 | static int sctp_wait_for_packet(struct sock * sk, int *err, long *timeo_p); | 85 | static int sctp_wait_for_packet(struct sock *sk, int *err, long *timeo_p); |
| 87 | static int sctp_wait_for_connect(struct sctp_association *, long *timeo_p); | 86 | static int sctp_wait_for_connect(struct sctp_association *, long *timeo_p); |
| 88 | static int sctp_wait_for_accept(struct sock *sk, long timeo); | 87 | static int sctp_wait_for_accept(struct sock *sk, long timeo); |
| 89 | static void sctp_wait_for_close(struct sock *sk, long timeo); | 88 | static void sctp_wait_for_close(struct sock *sk, long timeo); |
| @@ -273,7 +272,7 @@ static int sctp_bind(struct sock *sk, struct sockaddr *addr, int addr_len) | |||
| 273 | { | 272 | { |
| 274 | int retval = 0; | 273 | int retval = 0; |
| 275 | 274 | ||
| 276 | sctp_lock_sock(sk); | 275 | lock_sock(sk); |
| 277 | 276 | ||
| 278 | pr_debug("%s: sk:%p, addr:%p, addr_len:%d\n", __func__, sk, | 277 | pr_debug("%s: sk:%p, addr:%p, addr_len:%d\n", __func__, sk, |
| 279 | addr, addr_len); | 278 | addr, addr_len); |
| @@ -285,7 +284,7 @@ static int sctp_bind(struct sock *sk, struct sockaddr *addr, int addr_len) | |||
| 285 | else | 284 | else |
| 286 | retval = -EINVAL; | 285 | retval = -EINVAL; |
| 287 | 286 | ||
| 288 | sctp_release_sock(sk); | 287 | release_sock(sk); |
| 289 | 288 | ||
| 290 | return retval; | 289 | return retval; |
| 291 | } | 290 | } |
| @@ -953,7 +952,7 @@ int sctp_asconf_mgmt(struct sctp_sock *sp, struct sctp_sockaddr_entry *addrw) | |||
| 953 | * | 952 | * |
| 954 | * Returns 0 if ok, <0 errno code on error. | 953 | * Returns 0 if ok, <0 errno code on error. |
| 955 | */ | 954 | */ |
| 956 | static int sctp_setsockopt_bindx(struct sock* sk, | 955 | static int sctp_setsockopt_bindx(struct sock *sk, |
| 957 | struct sockaddr __user *addrs, | 956 | struct sockaddr __user *addrs, |
| 958 | int addrs_size, int op) | 957 | int addrs_size, int op) |
| 959 | { | 958 | { |
| @@ -1040,7 +1039,7 @@ out: | |||
| 1040 | * Common routine for handling connect() and sctp_connectx(). | 1039 | * Common routine for handling connect() and sctp_connectx(). |
| 1041 | * Connect will come in with just a single address. | 1040 | * Connect will come in with just a single address. |
| 1042 | */ | 1041 | */ |
| 1043 | static int __sctp_connect(struct sock* sk, | 1042 | static int __sctp_connect(struct sock *sk, |
| 1044 | struct sockaddr *kaddrs, | 1043 | struct sockaddr *kaddrs, |
| 1045 | int addrs_size, | 1044 | int addrs_size, |
| 1046 | sctp_assoc_t *assoc_id) | 1045 | sctp_assoc_t *assoc_id) |
| @@ -1300,7 +1299,7 @@ out_free: | |||
| 1300 | * | 1299 | * |
| 1301 | * Returns >=0 if ok, <0 errno code on error. | 1300 | * Returns >=0 if ok, <0 errno code on error. |
| 1302 | */ | 1301 | */ |
| 1303 | static int __sctp_setsockopt_connectx(struct sock* sk, | 1302 | static int __sctp_setsockopt_connectx(struct sock *sk, |
| 1304 | struct sockaddr __user *addrs, | 1303 | struct sockaddr __user *addrs, |
| 1305 | int addrs_size, | 1304 | int addrs_size, |
| 1306 | sctp_assoc_t *assoc_id) | 1305 | sctp_assoc_t *assoc_id) |
| @@ -1338,7 +1337,7 @@ static int __sctp_setsockopt_connectx(struct sock* sk, | |||
| 1338 | * This is an older interface. It's kept for backward compatibility | 1337 | * This is an older interface. It's kept for backward compatibility |
| 1339 | * to the option that doesn't provide association id. | 1338 | * to the option that doesn't provide association id. |
| 1340 | */ | 1339 | */ |
| 1341 | static int sctp_setsockopt_connectx_old(struct sock* sk, | 1340 | static int sctp_setsockopt_connectx_old(struct sock *sk, |
| 1342 | struct sockaddr __user *addrs, | 1341 | struct sockaddr __user *addrs, |
| 1343 | int addrs_size) | 1342 | int addrs_size) |
| 1344 | { | 1343 | { |
| @@ -1351,7 +1350,7 @@ static int sctp_setsockopt_connectx_old(struct sock* sk, | |||
| 1351 | * indication to the call. Error is always negative and association id is | 1350 | * indication to the call. Error is always negative and association id is |
| 1352 | * always positive. | 1351 | * always positive. |
| 1353 | */ | 1352 | */ |
| 1354 | static int sctp_setsockopt_connectx(struct sock* sk, | 1353 | static int sctp_setsockopt_connectx(struct sock *sk, |
| 1355 | struct sockaddr __user *addrs, | 1354 | struct sockaddr __user *addrs, |
| 1356 | int addrs_size) | 1355 | int addrs_size) |
| 1357 | { | 1356 | { |
| @@ -1374,7 +1373,7 @@ static int sctp_setsockopt_connectx(struct sock* sk, | |||
| 1374 | * addrs_num structure member. That way we can re-use the existing | 1373 | * addrs_num structure member. That way we can re-use the existing |
| 1375 | * code. | 1374 | * code. |
| 1376 | */ | 1375 | */ |
| 1377 | static int sctp_getsockopt_connectx3(struct sock* sk, int len, | 1376 | static int sctp_getsockopt_connectx3(struct sock *sk, int len, |
| 1378 | char __user *optval, | 1377 | char __user *optval, |
| 1379 | int __user *optlen) | 1378 | int __user *optlen) |
| 1380 | { | 1379 | { |
| @@ -1462,7 +1461,7 @@ static void sctp_close(struct sock *sk, long timeout) | |||
| 1462 | 1461 | ||
| 1463 | pr_debug("%s: sk:%p, timeout:%ld\n", __func__, sk, timeout); | 1462 | pr_debug("%s: sk:%p, timeout:%ld\n", __func__, sk, timeout); |
| 1464 | 1463 | ||
| 1465 | sctp_lock_sock(sk); | 1464 | lock_sock(sk); |
| 1466 | sk->sk_shutdown = SHUTDOWN_MASK; | 1465 | sk->sk_shutdown = SHUTDOWN_MASK; |
| 1467 | sk->sk_state = SCTP_SS_CLOSING; | 1466 | sk->sk_state = SCTP_SS_CLOSING; |
| 1468 | 1467 | ||
| @@ -1506,13 +1505,13 @@ static void sctp_close(struct sock *sk, long timeout) | |||
| 1506 | sctp_wait_for_close(sk, timeout); | 1505 | sctp_wait_for_close(sk, timeout); |
| 1507 | 1506 | ||
| 1508 | /* This will run the backlog queue. */ | 1507 | /* This will run the backlog queue. */ |
| 1509 | sctp_release_sock(sk); | 1508 | release_sock(sk); |
| 1510 | 1509 | ||
| 1511 | /* Supposedly, no process has access to the socket, but | 1510 | /* Supposedly, no process has access to the socket, but |
| 1512 | * the net layers still may. | 1511 | * the net layers still may. |
| 1513 | */ | 1512 | */ |
| 1514 | sctp_local_bh_disable(); | 1513 | local_bh_disable(); |
| 1515 | sctp_bh_lock_sock(sk); | 1514 | bh_lock_sock(sk); |
| 1516 | 1515 | ||
| 1517 | /* Hold the sock, since sk_common_release() will put sock_put() | 1516 | /* Hold the sock, since sk_common_release() will put sock_put() |
| 1518 | * and we have just a little more cleanup. | 1517 | * and we have just a little more cleanup. |
| @@ -1520,8 +1519,8 @@ static void sctp_close(struct sock *sk, long timeout) | |||
| 1520 | sock_hold(sk); | 1519 | sock_hold(sk); |
| 1521 | sk_common_release(sk); | 1520 | sk_common_release(sk); |
| 1522 | 1521 | ||
| 1523 | sctp_bh_unlock_sock(sk); | 1522 | bh_unlock_sock(sk); |
| 1524 | sctp_local_bh_enable(); | 1523 | local_bh_enable(); |
| 1525 | 1524 | ||
| 1526 | sock_put(sk); | 1525 | sock_put(sk); |
| 1527 | 1526 | ||
| @@ -1569,7 +1568,7 @@ static int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
| 1569 | struct net *net = sock_net(sk); | 1568 | struct net *net = sock_net(sk); |
| 1570 | struct sctp_sock *sp; | 1569 | struct sctp_sock *sp; |
| 1571 | struct sctp_endpoint *ep; | 1570 | struct sctp_endpoint *ep; |
| 1572 | struct sctp_association *new_asoc=NULL, *asoc=NULL; | 1571 | struct sctp_association *new_asoc = NULL, *asoc = NULL; |
| 1573 | struct sctp_transport *transport, *chunk_tp; | 1572 | struct sctp_transport *transport, *chunk_tp; |
| 1574 | struct sctp_chunk *chunk; | 1573 | struct sctp_chunk *chunk; |
| 1575 | union sctp_addr to; | 1574 | union sctp_addr to; |
| @@ -1666,7 +1665,7 @@ static int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
| 1666 | 1665 | ||
| 1667 | pr_debug("%s: about to look up association\n", __func__); | 1666 | pr_debug("%s: about to look up association\n", __func__); |
| 1668 | 1667 | ||
| 1669 | sctp_lock_sock(sk); | 1668 | lock_sock(sk); |
| 1670 | 1669 | ||
| 1671 | /* If a msg_name has been specified, assume this is to be used. */ | 1670 | /* If a msg_name has been specified, assume this is to be used. */ |
| 1672 | if (msg_name) { | 1671 | if (msg_name) { |
| @@ -1744,7 +1743,7 @@ static int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
| 1744 | * either the default or the user specified stream counts. | 1743 | * either the default or the user specified stream counts. |
| 1745 | */ | 1744 | */ |
| 1746 | if (sinfo) { | 1745 | if (sinfo) { |
| 1747 | if (!sinit || (sinit && !sinit->sinit_num_ostreams)) { | 1746 | if (!sinit || !sinit->sinit_num_ostreams) { |
| 1748 | /* Check against the defaults. */ | 1747 | /* Check against the defaults. */ |
| 1749 | if (sinfo->sinfo_stream >= | 1748 | if (sinfo->sinfo_stream >= |
| 1750 | sp->initmsg.sinit_num_ostreams) { | 1749 | sp->initmsg.sinit_num_ostreams) { |
| @@ -1950,7 +1949,7 @@ out_free: | |||
| 1950 | sctp_association_free(asoc); | 1949 | sctp_association_free(asoc); |
| 1951 | } | 1950 | } |
| 1952 | out_unlock: | 1951 | out_unlock: |
| 1953 | sctp_release_sock(sk); | 1952 | release_sock(sk); |
| 1954 | 1953 | ||
| 1955 | out_nounlock: | 1954 | out_nounlock: |
| 1956 | return sctp_error(sk, msg_flags, err); | 1955 | return sctp_error(sk, msg_flags, err); |
| @@ -2036,7 +2035,7 @@ static int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, | |||
| 2036 | "addr_len:%p)\n", __func__, sk, msg, len, noblock, flags, | 2035 | "addr_len:%p)\n", __func__, sk, msg, len, noblock, flags, |
| 2037 | addr_len); | 2036 | addr_len); |
| 2038 | 2037 | ||
| 2039 | sctp_lock_sock(sk); | 2038 | lock_sock(sk); |
| 2040 | 2039 | ||
| 2041 | if (sctp_style(sk, TCP) && !sctp_sstate(sk, ESTABLISHED)) { | 2040 | if (sctp_style(sk, TCP) && !sctp_sstate(sk, ESTABLISHED)) { |
| 2042 | err = -ENOTCONN; | 2041 | err = -ENOTCONN; |
| @@ -2120,7 +2119,7 @@ out_free: | |||
| 2120 | sctp_ulpevent_free(event); | 2119 | sctp_ulpevent_free(event); |
| 2121 | } | 2120 | } |
| 2122 | out: | 2121 | out: |
| 2123 | sctp_release_sock(sk); | 2122 | release_sock(sk); |
| 2124 | return err; | 2123 | return err; |
| 2125 | } | 2124 | } |
| 2126 | 2125 | ||
| @@ -2463,7 +2462,7 @@ static int sctp_setsockopt_peer_addr_params(struct sock *sk, | |||
| 2463 | int hb_change, pmtud_change, sackdelay_change; | 2462 | int hb_change, pmtud_change, sackdelay_change; |
| 2464 | 2463 | ||
| 2465 | if (optlen != sizeof(struct sctp_paddrparams)) | 2464 | if (optlen != sizeof(struct sctp_paddrparams)) |
| 2466 | return - EINVAL; | 2465 | return -EINVAL; |
| 2467 | 2466 | ||
| 2468 | if (copy_from_user(¶ms, optval, optlen)) | 2467 | if (copy_from_user(¶ms, optval, optlen)) |
| 2469 | return -EFAULT; | 2468 | return -EFAULT; |
| @@ -2484,7 +2483,7 @@ static int sctp_setsockopt_peer_addr_params(struct sock *sk, | |||
| 2484 | /* If an address other than INADDR_ANY is specified, and | 2483 | /* If an address other than INADDR_ANY is specified, and |
| 2485 | * no transport is found, then the request is invalid. | 2484 | * no transport is found, then the request is invalid. |
| 2486 | */ | 2485 | */ |
| 2487 | if (!sctp_is_any(sk, ( union sctp_addr *)¶ms.spp_address)) { | 2486 | if (!sctp_is_any(sk, (union sctp_addr *)¶ms.spp_address)) { |
| 2488 | trans = sctp_addr_id2transport(sk, ¶ms.spp_address, | 2487 | trans = sctp_addr_id2transport(sk, ¶ms.spp_address, |
| 2489 | params.spp_assoc_id); | 2488 | params.spp_assoc_id); |
| 2490 | if (!trans) | 2489 | if (!trans) |
| @@ -2528,6 +2527,16 @@ static int sctp_setsockopt_peer_addr_params(struct sock *sk, | |||
| 2528 | return 0; | 2527 | return 0; |
| 2529 | } | 2528 | } |
| 2530 | 2529 | ||
| 2530 | static inline __u32 sctp_spp_sackdelay_enable(__u32 param_flags) | ||
| 2531 | { | ||
| 2532 | return (param_flags & ~SPP_SACKDELAY) | SPP_SACKDELAY_ENABLE; | ||
| 2533 | } | ||
| 2534 | |||
| 2535 | static inline __u32 sctp_spp_sackdelay_disable(__u32 param_flags) | ||
| 2536 | { | ||
| 2537 | return (param_flags & ~SPP_SACKDELAY) | SPP_SACKDELAY_DISABLE; | ||
| 2538 | } | ||
| 2539 | |||
| 2531 | /* | 2540 | /* |
| 2532 | * 7.1.23. Get or set delayed ack timer (SCTP_DELAYED_SACK) | 2541 | * 7.1.23. Get or set delayed ack timer (SCTP_DELAYED_SACK) |
| 2533 | * | 2542 | * |
| @@ -2579,8 +2588,11 @@ static int sctp_setsockopt_delayed_ack(struct sock *sk, | |||
| 2579 | if (params.sack_delay == 0 && params.sack_freq == 0) | 2588 | if (params.sack_delay == 0 && params.sack_freq == 0) |
| 2580 | return 0; | 2589 | return 0; |
| 2581 | } else if (optlen == sizeof(struct sctp_assoc_value)) { | 2590 | } else if (optlen == sizeof(struct sctp_assoc_value)) { |
| 2582 | pr_warn("Use of struct sctp_assoc_value in delayed_ack socket option deprecated\n"); | 2591 | pr_warn_ratelimited(DEPRECATED |
| 2583 | pr_warn("Use struct sctp_sack_info instead\n"); | 2592 | "%s (pid %d) " |
| 2593 | "Use of struct sctp_assoc_value in delayed_ack socket option.\n" | ||
| 2594 | "Use struct sctp_sack_info instead\n", | ||
| 2595 | current->comm, task_pid_nr(current)); | ||
| 2584 | if (copy_from_user(¶ms, optval, optlen)) | 2596 | if (copy_from_user(¶ms, optval, optlen)) |
| 2585 | return -EFAULT; | 2597 | return -EFAULT; |
| 2586 | 2598 | ||
| @@ -2589,7 +2601,7 @@ static int sctp_setsockopt_delayed_ack(struct sock *sk, | |||
| 2589 | else | 2601 | else |
| 2590 | params.sack_freq = 0; | 2602 | params.sack_freq = 0; |
| 2591 | } else | 2603 | } else |
| 2592 | return - EINVAL; | 2604 | return -EINVAL; |
| 2593 | 2605 | ||
| 2594 | /* Validate value parameter. */ | 2606 | /* Validate value parameter. */ |
| 2595 | if (params.sack_delay > 500) | 2607 | if (params.sack_delay > 500) |
| @@ -2608,37 +2620,31 @@ static int sctp_setsockopt_delayed_ack(struct sock *sk, | |||
| 2608 | asoc->sackdelay = | 2620 | asoc->sackdelay = |
| 2609 | msecs_to_jiffies(params.sack_delay); | 2621 | msecs_to_jiffies(params.sack_delay); |
| 2610 | asoc->param_flags = | 2622 | asoc->param_flags = |
| 2611 | (asoc->param_flags & ~SPP_SACKDELAY) | | 2623 | sctp_spp_sackdelay_enable(asoc->param_flags); |
| 2612 | SPP_SACKDELAY_ENABLE; | ||
| 2613 | } else { | 2624 | } else { |
| 2614 | sp->sackdelay = params.sack_delay; | 2625 | sp->sackdelay = params.sack_delay; |
| 2615 | sp->param_flags = | 2626 | sp->param_flags = |
| 2616 | (sp->param_flags & ~SPP_SACKDELAY) | | 2627 | sctp_spp_sackdelay_enable(sp->param_flags); |
| 2617 | SPP_SACKDELAY_ENABLE; | ||
| 2618 | } | 2628 | } |
| 2619 | } | 2629 | } |
| 2620 | 2630 | ||
| 2621 | if (params.sack_freq == 1) { | 2631 | if (params.sack_freq == 1) { |
| 2622 | if (asoc) { | 2632 | if (asoc) { |
| 2623 | asoc->param_flags = | 2633 | asoc->param_flags = |
| 2624 | (asoc->param_flags & ~SPP_SACKDELAY) | | 2634 | sctp_spp_sackdelay_disable(asoc->param_flags); |
| 2625 | SPP_SACKDELAY_DISABLE; | ||
| 2626 | } else { | 2635 | } else { |
| 2627 | sp->param_flags = | 2636 | sp->param_flags = |
| 2628 | (sp->param_flags & ~SPP_SACKDELAY) | | 2637 | sctp_spp_sackdelay_disable(sp->param_flags); |
| 2629 | SPP_SACKDELAY_DISABLE; | ||
| 2630 | } | 2638 | } |
| 2631 | } else if (params.sack_freq > 1) { | 2639 | } else if (params.sack_freq > 1) { |
| 2632 | if (asoc) { | 2640 | if (asoc) { |
| 2633 | asoc->sackfreq = params.sack_freq; | 2641 | asoc->sackfreq = params.sack_freq; |
| 2634 | asoc->param_flags = | 2642 | asoc->param_flags = |
| 2635 | (asoc->param_flags & ~SPP_SACKDELAY) | | 2643 | sctp_spp_sackdelay_enable(asoc->param_flags); |
| 2636 | SPP_SACKDELAY_ENABLE; | ||
| 2637 | } else { | 2644 | } else { |
| 2638 | sp->sackfreq = params.sack_freq; | 2645 | sp->sackfreq = params.sack_freq; |
| 2639 | sp->param_flags = | 2646 | sp->param_flags = |
| 2640 | (sp->param_flags & ~SPP_SACKDELAY) | | 2647 | sctp_spp_sackdelay_enable(sp->param_flags); |
| 2641 | SPP_SACKDELAY_ENABLE; | ||
| 2642 | } | 2648 | } |
| 2643 | } | 2649 | } |
| 2644 | 2650 | ||
| @@ -2650,18 +2656,15 @@ static int sctp_setsockopt_delayed_ack(struct sock *sk, | |||
| 2650 | trans->sackdelay = | 2656 | trans->sackdelay = |
| 2651 | msecs_to_jiffies(params.sack_delay); | 2657 | msecs_to_jiffies(params.sack_delay); |
| 2652 | trans->param_flags = | 2658 | trans->param_flags = |
| 2653 | (trans->param_flags & ~SPP_SACKDELAY) | | 2659 | sctp_spp_sackdelay_enable(trans->param_flags); |
| 2654 | SPP_SACKDELAY_ENABLE; | ||
| 2655 | } | 2660 | } |
| 2656 | if (params.sack_freq == 1) { | 2661 | if (params.sack_freq == 1) { |
| 2657 | trans->param_flags = | 2662 | trans->param_flags = |
| 2658 | (trans->param_flags & ~SPP_SACKDELAY) | | 2663 | sctp_spp_sackdelay_disable(trans->param_flags); |
| 2659 | SPP_SACKDELAY_DISABLE; | ||
| 2660 | } else if (params.sack_freq > 1) { | 2664 | } else if (params.sack_freq > 1) { |
| 2661 | trans->sackfreq = params.sack_freq; | 2665 | trans->sackfreq = params.sack_freq; |
| 2662 | trans->param_flags = | 2666 | trans->param_flags = |
| 2663 | (trans->param_flags & ~SPP_SACKDELAY) | | 2667 | sctp_spp_sackdelay_enable(trans->param_flags); |
| 2664 | SPP_SACKDELAY_ENABLE; | ||
| 2665 | } | 2668 | } |
| 2666 | } | 2669 | } |
| 2667 | } | 2670 | } |
| @@ -2995,8 +2998,11 @@ static int sctp_setsockopt_maxseg(struct sock *sk, char __user *optval, unsigned | |||
| 2995 | int val; | 2998 | int val; |
| 2996 | 2999 | ||
| 2997 | if (optlen == sizeof(int)) { | 3000 | if (optlen == sizeof(int)) { |
| 2998 | pr_warn("Use of int in maxseg socket option deprecated\n"); | 3001 | pr_warn_ratelimited(DEPRECATED |
| 2999 | pr_warn("Use struct sctp_assoc_value instead\n"); | 3002 | "%s (pid %d) " |
| 3003 | "Use of int in maxseg socket option.\n" | ||
| 3004 | "Use struct sctp_assoc_value instead\n", | ||
| 3005 | current->comm, task_pid_nr(current)); | ||
| 3000 | if (copy_from_user(&val, optval, optlen)) | 3006 | if (copy_from_user(&val, optval, optlen)) |
| 3001 | return -EFAULT; | 3007 | return -EFAULT; |
| 3002 | params.assoc_id = 0; | 3008 | params.assoc_id = 0; |
| @@ -3253,8 +3259,11 @@ static int sctp_setsockopt_maxburst(struct sock *sk, | |||
| 3253 | int assoc_id = 0; | 3259 | int assoc_id = 0; |
| 3254 | 3260 | ||
| 3255 | if (optlen == sizeof(int)) { | 3261 | if (optlen == sizeof(int)) { |
| 3256 | pr_warn("Use of int in max_burst socket option deprecated\n"); | 3262 | pr_warn_ratelimited(DEPRECATED |
| 3257 | pr_warn("Use struct sctp_assoc_value instead\n"); | 3263 | "%s (pid %d) " |
| 3264 | "Use of int in max_burst socket option deprecated.\n" | ||
| 3265 | "Use struct sctp_assoc_value instead\n", | ||
| 3266 | current->comm, task_pid_nr(current)); | ||
| 3258 | if (copy_from_user(&val, optval, optlen)) | 3267 | if (copy_from_user(&val, optval, optlen)) |
| 3259 | return -EFAULT; | 3268 | return -EFAULT; |
| 3260 | } else if (optlen == sizeof(struct sctp_assoc_value)) { | 3269 | } else if (optlen == sizeof(struct sctp_assoc_value)) { |
| @@ -3333,7 +3342,7 @@ static int sctp_setsockopt_hmac_ident(struct sock *sk, | |||
| 3333 | if (optlen < sizeof(struct sctp_hmacalgo)) | 3342 | if (optlen < sizeof(struct sctp_hmacalgo)) |
| 3334 | return -EINVAL; | 3343 | return -EINVAL; |
| 3335 | 3344 | ||
| 3336 | hmacs= memdup_user(optval, optlen); | 3345 | hmacs = memdup_user(optval, optlen); |
| 3337 | if (IS_ERR(hmacs)) | 3346 | if (IS_ERR(hmacs)) |
| 3338 | return PTR_ERR(hmacs); | 3347 | return PTR_ERR(hmacs); |
| 3339 | 3348 | ||
| @@ -3371,7 +3380,7 @@ static int sctp_setsockopt_auth_key(struct sock *sk, | |||
| 3371 | if (optlen <= sizeof(struct sctp_authkey)) | 3380 | if (optlen <= sizeof(struct sctp_authkey)) |
| 3372 | return -EINVAL; | 3381 | return -EINVAL; |
| 3373 | 3382 | ||
| 3374 | authkey= memdup_user(optval, optlen); | 3383 | authkey = memdup_user(optval, optlen); |
| 3375 | if (IS_ERR(authkey)) | 3384 | if (IS_ERR(authkey)) |
| 3376 | return PTR_ERR(authkey); | 3385 | return PTR_ERR(authkey); |
| 3377 | 3386 | ||
| @@ -3581,7 +3590,7 @@ static int sctp_setsockopt(struct sock *sk, int level, int optname, | |||
| 3581 | goto out_nounlock; | 3590 | goto out_nounlock; |
| 3582 | } | 3591 | } |
| 3583 | 3592 | ||
| 3584 | sctp_lock_sock(sk); | 3593 | lock_sock(sk); |
| 3585 | 3594 | ||
| 3586 | switch (optname) { | 3595 | switch (optname) { |
| 3587 | case SCTP_SOCKOPT_BINDX_ADD: | 3596 | case SCTP_SOCKOPT_BINDX_ADD: |
| @@ -3699,7 +3708,7 @@ static int sctp_setsockopt(struct sock *sk, int level, int optname, | |||
| 3699 | break; | 3708 | break; |
| 3700 | } | 3709 | } |
| 3701 | 3710 | ||
| 3702 | sctp_release_sock(sk); | 3711 | release_sock(sk); |
| 3703 | 3712 | ||
| 3704 | out_nounlock: | 3713 | out_nounlock: |
| 3705 | return retval; | 3714 | return retval; |
| @@ -3727,7 +3736,7 @@ static int sctp_connect(struct sock *sk, struct sockaddr *addr, | |||
| 3727 | int err = 0; | 3736 | int err = 0; |
| 3728 | struct sctp_af *af; | 3737 | struct sctp_af *af; |
| 3729 | 3738 | ||
| 3730 | sctp_lock_sock(sk); | 3739 | lock_sock(sk); |
| 3731 | 3740 | ||
| 3732 | pr_debug("%s: sk:%p, sockaddr:%p, addr_len:%d\n", __func__, sk, | 3741 | pr_debug("%s: sk:%p, sockaddr:%p, addr_len:%d\n", __func__, sk, |
| 3733 | addr, addr_len); | 3742 | addr, addr_len); |
| @@ -3743,7 +3752,7 @@ static int sctp_connect(struct sock *sk, struct sockaddr *addr, | |||
| 3743 | err = __sctp_connect(sk, addr, af->sockaddr_len, NULL); | 3752 | err = __sctp_connect(sk, addr, af->sockaddr_len, NULL); |
| 3744 | } | 3753 | } |
| 3745 | 3754 | ||
| 3746 | sctp_release_sock(sk); | 3755 | release_sock(sk); |
| 3747 | return err; | 3756 | return err; |
| 3748 | } | 3757 | } |
| 3749 | 3758 | ||
| @@ -3769,7 +3778,7 @@ static struct sock *sctp_accept(struct sock *sk, int flags, int *err) | |||
| 3769 | long timeo; | 3778 | long timeo; |
| 3770 | int error = 0; | 3779 | int error = 0; |
| 3771 | 3780 | ||
| 3772 | sctp_lock_sock(sk); | 3781 | lock_sock(sk); |
| 3773 | 3782 | ||
| 3774 | sp = sctp_sk(sk); | 3783 | sp = sctp_sk(sk); |
| 3775 | ep = sp->ep; | 3784 | ep = sp->ep; |
| @@ -3807,7 +3816,7 @@ static struct sock *sctp_accept(struct sock *sk, int flags, int *err) | |||
| 3807 | sctp_sock_migrate(sk, newsk, asoc, SCTP_SOCKET_TCP); | 3816 | sctp_sock_migrate(sk, newsk, asoc, SCTP_SOCKET_TCP); |
| 3808 | 3817 | ||
| 3809 | out: | 3818 | out: |
| 3810 | sctp_release_sock(sk); | 3819 | release_sock(sk); |
| 3811 | *err = error; | 3820 | *err = error; |
| 3812 | return newsk; | 3821 | return newsk; |
| 3813 | } | 3822 | } |
| @@ -3817,7 +3826,7 @@ static int sctp_ioctl(struct sock *sk, int cmd, unsigned long arg) | |||
| 3817 | { | 3826 | { |
| 3818 | int rc = -ENOTCONN; | 3827 | int rc = -ENOTCONN; |
| 3819 | 3828 | ||
| 3820 | sctp_lock_sock(sk); | 3829 | lock_sock(sk); |
| 3821 | 3830 | ||
| 3822 | /* | 3831 | /* |
| 3823 | * SEQPACKET-style sockets in LISTENING state are valid, for | 3832 | * SEQPACKET-style sockets in LISTENING state are valid, for |
| @@ -3847,7 +3856,7 @@ static int sctp_ioctl(struct sock *sk, int cmd, unsigned long arg) | |||
| 3847 | break; | 3856 | break; |
| 3848 | } | 3857 | } |
| 3849 | out: | 3858 | out: |
| 3850 | sctp_release_sock(sk); | 3859 | release_sock(sk); |
| 3851 | return rc; | 3860 | return rc; |
| 3852 | } | 3861 | } |
| 3853 | 3862 | ||
| @@ -3925,7 +3934,7 @@ static int sctp_init_sock(struct sock *sk) | |||
| 3925 | */ | 3934 | */ |
| 3926 | sp->hbinterval = net->sctp.hb_interval; | 3935 | sp->hbinterval = net->sctp.hb_interval; |
| 3927 | sp->pathmaxrxt = net->sctp.max_retrans_path; | 3936 | sp->pathmaxrxt = net->sctp.max_retrans_path; |
| 3928 | sp->pathmtu = 0; // allow default discovery | 3937 | sp->pathmtu = 0; /* allow default discovery */ |
| 3929 | sp->sackdelay = net->sctp.sack_timeout; | 3938 | sp->sackdelay = net->sctp.sack_timeout; |
| 3930 | sp->sackfreq = 2; | 3939 | sp->sackfreq = 2; |
| 3931 | sp->param_flags = SPP_HB_ENABLE | | 3940 | sp->param_flags = SPP_HB_ENABLE | |
| @@ -4468,7 +4477,7 @@ static int sctp_getsockopt_peer_addr_params(struct sock *sk, int len, | |||
| 4468 | /* If an address other than INADDR_ANY is specified, and | 4477 | /* If an address other than INADDR_ANY is specified, and |
| 4469 | * no transport is found, then the request is invalid. | 4478 | * no transport is found, then the request is invalid. |
| 4470 | */ | 4479 | */ |
| 4471 | if (!sctp_is_any(sk, ( union sctp_addr *)¶ms.spp_address)) { | 4480 | if (!sctp_is_any(sk, (union sctp_addr *)¶ms.spp_address)) { |
| 4472 | trans = sctp_addr_id2transport(sk, ¶ms.spp_address, | 4481 | trans = sctp_addr_id2transport(sk, ¶ms.spp_address, |
| 4473 | params.spp_assoc_id); | 4482 | params.spp_assoc_id); |
| 4474 | if (!trans) { | 4483 | if (!trans) { |
| @@ -4574,12 +4583,15 @@ static int sctp_getsockopt_delayed_ack(struct sock *sk, int len, | |||
| 4574 | if (copy_from_user(¶ms, optval, len)) | 4583 | if (copy_from_user(¶ms, optval, len)) |
| 4575 | return -EFAULT; | 4584 | return -EFAULT; |
| 4576 | } else if (len == sizeof(struct sctp_assoc_value)) { | 4585 | } else if (len == sizeof(struct sctp_assoc_value)) { |
| 4577 | pr_warn("Use of struct sctp_assoc_value in delayed_ack socket option deprecated\n"); | 4586 | pr_warn_ratelimited(DEPRECATED |
| 4578 | pr_warn("Use struct sctp_sack_info instead\n"); | 4587 | "%s (pid %d) " |
| 4588 | "Use of struct sctp_assoc_value in delayed_ack socket option.\n" | ||
| 4589 | "Use struct sctp_sack_info instead\n", | ||
| 4590 | current->comm, task_pid_nr(current)); | ||
| 4579 | if (copy_from_user(¶ms, optval, len)) | 4591 | if (copy_from_user(¶ms, optval, len)) |
| 4580 | return -EFAULT; | 4592 | return -EFAULT; |
| 4581 | } else | 4593 | } else |
| 4582 | return - EINVAL; | 4594 | return -EINVAL; |
| 4583 | 4595 | ||
| 4584 | /* Get association, if sack_assoc_id != 0 and the socket is a one | 4596 | /* Get association, if sack_assoc_id != 0 and the socket is a one |
| 4585 | * to many style socket, and an association was not found, then | 4597 | * to many style socket, and an association was not found, then |
| @@ -4669,8 +4681,8 @@ static int sctp_getsockopt_peer_addrs(struct sock *sk, int len, | |||
| 4669 | if (!asoc) | 4681 | if (!asoc) |
| 4670 | return -EINVAL; | 4682 | return -EINVAL; |
| 4671 | 4683 | ||
| 4672 | to = optval + offsetof(struct sctp_getaddrs,addrs); | 4684 | to = optval + offsetof(struct sctp_getaddrs, addrs); |
| 4673 | space_left = len - offsetof(struct sctp_getaddrs,addrs); | 4685 | space_left = len - offsetof(struct sctp_getaddrs, addrs); |
| 4674 | 4686 | ||
| 4675 | list_for_each_entry(from, &asoc->peer.transport_addr_list, | 4687 | list_for_each_entry(from, &asoc->peer.transport_addr_list, |
| 4676 | transports) { | 4688 | transports) { |
| @@ -4730,7 +4742,7 @@ static int sctp_copy_laddrs(struct sock *sk, __u16 port, void *to, | |||
| 4730 | memcpy(to, &temp, addrlen); | 4742 | memcpy(to, &temp, addrlen); |
| 4731 | 4743 | ||
| 4732 | to += addrlen; | 4744 | to += addrlen; |
| 4733 | cnt ++; | 4745 | cnt++; |
| 4734 | space_left -= addrlen; | 4746 | space_left -= addrlen; |
| 4735 | *bytes_copied += addrlen; | 4747 | *bytes_copied += addrlen; |
| 4736 | } | 4748 | } |
| @@ -4779,8 +4791,8 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len, | |||
| 4779 | bp = &asoc->base.bind_addr; | 4791 | bp = &asoc->base.bind_addr; |
| 4780 | } | 4792 | } |
| 4781 | 4793 | ||
| 4782 | to = optval + offsetof(struct sctp_getaddrs,addrs); | 4794 | to = optval + offsetof(struct sctp_getaddrs, addrs); |
| 4783 | space_left = len - offsetof(struct sctp_getaddrs,addrs); | 4795 | space_left = len - offsetof(struct sctp_getaddrs, addrs); |
| 4784 | 4796 | ||
| 4785 | addrs = kmalloc(space_left, GFP_KERNEL); | 4797 | addrs = kmalloc(space_left, GFP_KERNEL); |
| 4786 | if (!addrs) | 4798 | if (!addrs) |
| @@ -4819,7 +4831,7 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len, | |||
| 4819 | memcpy(buf, &temp, addrlen); | 4831 | memcpy(buf, &temp, addrlen); |
| 4820 | buf += addrlen; | 4832 | buf += addrlen; |
| 4821 | bytes_copied += addrlen; | 4833 | bytes_copied += addrlen; |
| 4822 | cnt ++; | 4834 | cnt++; |
| 4823 | space_left -= addrlen; | 4835 | space_left -= addrlen; |
| 4824 | } | 4836 | } |
| 4825 | 4837 | ||
| @@ -5091,7 +5103,7 @@ static int sctp_getsockopt_associnfo(struct sock *sk, int len, | |||
| 5091 | assocparams.sasoc_cookie_life = ktime_to_ms(asoc->cookie_life); | 5103 | assocparams.sasoc_cookie_life = ktime_to_ms(asoc->cookie_life); |
| 5092 | 5104 | ||
| 5093 | list_for_each(pos, &asoc->peer.transport_addr_list) { | 5105 | list_for_each(pos, &asoc->peer.transport_addr_list) { |
| 5094 | cnt ++; | 5106 | cnt++; |
| 5095 | } | 5107 | } |
| 5096 | 5108 | ||
| 5097 | assocparams.sasoc_number_peer_destinations = cnt; | 5109 | assocparams.sasoc_number_peer_destinations = cnt; |
| @@ -5219,8 +5231,11 @@ static int sctp_getsockopt_maxseg(struct sock *sk, int len, | |||
| 5219 | struct sctp_association *asoc; | 5231 | struct sctp_association *asoc; |
| 5220 | 5232 | ||
| 5221 | if (len == sizeof(int)) { | 5233 | if (len == sizeof(int)) { |
| 5222 | pr_warn("Use of int in maxseg socket option deprecated\n"); | 5234 | pr_warn_ratelimited(DEPRECATED |
| 5223 | pr_warn("Use struct sctp_assoc_value instead\n"); | 5235 | "%s (pid %d) " |
| 5236 | "Use of int in maxseg socket option.\n" | ||
| 5237 | "Use struct sctp_assoc_value instead\n", | ||
| 5238 | current->comm, task_pid_nr(current)); | ||
| 5224 | params.assoc_id = 0; | 5239 | params.assoc_id = 0; |
| 5225 | } else if (len >= sizeof(struct sctp_assoc_value)) { | 5240 | } else if (len >= sizeof(struct sctp_assoc_value)) { |
| 5226 | len = sizeof(struct sctp_assoc_value); | 5241 | len = sizeof(struct sctp_assoc_value); |
| @@ -5311,8 +5326,11 @@ static int sctp_getsockopt_maxburst(struct sock *sk, int len, | |||
| 5311 | struct sctp_association *asoc; | 5326 | struct sctp_association *asoc; |
| 5312 | 5327 | ||
| 5313 | if (len == sizeof(int)) { | 5328 | if (len == sizeof(int)) { |
| 5314 | pr_warn("Use of int in max_burst socket option deprecated\n"); | 5329 | pr_warn_ratelimited(DEPRECATED |
| 5315 | pr_warn("Use struct sctp_assoc_value instead\n"); | 5330 | "%s (pid %d) " |
| 5331 | "Use of int in max_burst socket option.\n" | ||
| 5332 | "Use struct sctp_assoc_value instead\n", | ||
| 5333 | current->comm, task_pid_nr(current)); | ||
| 5316 | params.assoc_id = 0; | 5334 | params.assoc_id = 0; |
| 5317 | } else if (len >= sizeof(struct sctp_assoc_value)) { | 5335 | } else if (len >= sizeof(struct sctp_assoc_value)) { |
| 5318 | len = sizeof(struct sctp_assoc_value); | 5336 | len = sizeof(struct sctp_assoc_value); |
| @@ -5444,7 +5462,8 @@ static int sctp_getsockopt_peer_auth_chunks(struct sock *sk, int len, | |||
| 5444 | return -EFAULT; | 5462 | return -EFAULT; |
| 5445 | num: | 5463 | num: |
| 5446 | len = sizeof(struct sctp_authchunks) + num_chunks; | 5464 | len = sizeof(struct sctp_authchunks) + num_chunks; |
| 5447 | if (put_user(len, optlen)) return -EFAULT; | 5465 | if (put_user(len, optlen)) |
| 5466 | return -EFAULT; | ||
| 5448 | if (put_user(num_chunks, &p->gauth_number_of_chunks)) | 5467 | if (put_user(num_chunks, &p->gauth_number_of_chunks)) |
| 5449 | return -EFAULT; | 5468 | return -EFAULT; |
| 5450 | return 0; | 5469 | return 0; |
| @@ -5476,7 +5495,7 @@ static int sctp_getsockopt_local_auth_chunks(struct sock *sk, int len, | |||
| 5476 | return -EINVAL; | 5495 | return -EINVAL; |
| 5477 | 5496 | ||
| 5478 | if (asoc) | 5497 | if (asoc) |
| 5479 | ch = (struct sctp_chunks_param*)asoc->c.auth_chunks; | 5498 | ch = (struct sctp_chunks_param *)asoc->c.auth_chunks; |
| 5480 | else | 5499 | else |
| 5481 | ch = sctp_sk(sk)->ep->auth_chunk_list; | 5500 | ch = sctp_sk(sk)->ep->auth_chunk_list; |
| 5482 | 5501 | ||
| @@ -5735,7 +5754,7 @@ static int sctp_getsockopt(struct sock *sk, int level, int optname, | |||
| 5735 | if (get_user(len, optlen)) | 5754 | if (get_user(len, optlen)) |
| 5736 | return -EFAULT; | 5755 | return -EFAULT; |
| 5737 | 5756 | ||
| 5738 | sctp_lock_sock(sk); | 5757 | lock_sock(sk); |
| 5739 | 5758 | ||
| 5740 | switch (optname) { | 5759 | switch (optname) { |
| 5741 | case SCTP_STATUS: | 5760 | case SCTP_STATUS: |
| @@ -5859,7 +5878,7 @@ static int sctp_getsockopt(struct sock *sk, int level, int optname, | |||
| 5859 | break; | 5878 | break; |
| 5860 | } | 5879 | } |
| 5861 | 5880 | ||
| 5862 | sctp_release_sock(sk); | 5881 | release_sock(sk); |
| 5863 | return retval; | 5882 | return retval; |
| 5864 | } | 5883 | } |
| 5865 | 5884 | ||
| @@ -5899,7 +5918,7 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr) | |||
| 5899 | 5918 | ||
| 5900 | pr_debug("%s: begins, snum:%d\n", __func__, snum); | 5919 | pr_debug("%s: begins, snum:%d\n", __func__, snum); |
| 5901 | 5920 | ||
| 5902 | sctp_local_bh_disable(); | 5921 | local_bh_disable(); |
| 5903 | 5922 | ||
| 5904 | if (snum == 0) { | 5923 | if (snum == 0) { |
| 5905 | /* Search for an available port. */ | 5924 | /* Search for an available port. */ |
| @@ -5908,7 +5927,7 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr) | |||
| 5908 | 5927 | ||
| 5909 | inet_get_local_port_range(sock_net(sk), &low, &high); | 5928 | inet_get_local_port_range(sock_net(sk), &low, &high); |
| 5910 | remaining = (high - low) + 1; | 5929 | remaining = (high - low) + 1; |
| 5911 | rover = net_random() % remaining + low; | 5930 | rover = prandom_u32() % remaining + low; |
| 5912 | 5931 | ||
| 5913 | do { | 5932 | do { |
| 5914 | rover++; | 5933 | rover++; |
| @@ -5918,14 +5937,14 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr) | |||
| 5918 | continue; | 5937 | continue; |
| 5919 | index = sctp_phashfn(sock_net(sk), rover); | 5938 | index = sctp_phashfn(sock_net(sk), rover); |
| 5920 | head = &sctp_port_hashtable[index]; | 5939 | head = &sctp_port_hashtable[index]; |
| 5921 | sctp_spin_lock(&head->lock); | 5940 | spin_lock(&head->lock); |
| 5922 | sctp_for_each_hentry(pp, &head->chain) | 5941 | sctp_for_each_hentry(pp, &head->chain) |
| 5923 | if ((pp->port == rover) && | 5942 | if ((pp->port == rover) && |
| 5924 | net_eq(sock_net(sk), pp->net)) | 5943 | net_eq(sock_net(sk), pp->net)) |
| 5925 | goto next; | 5944 | goto next; |
| 5926 | break; | 5945 | break; |
| 5927 | next: | 5946 | next: |
| 5928 | sctp_spin_unlock(&head->lock); | 5947 | spin_unlock(&head->lock); |
| 5929 | } while (--remaining > 0); | 5948 | } while (--remaining > 0); |
| 5930 | 5949 | ||
| 5931 | /* Exhausted local port range during search? */ | 5950 | /* Exhausted local port range during search? */ |
| @@ -5946,7 +5965,7 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr) | |||
| 5946 | * port iterator, pp being NULL. | 5965 | * port iterator, pp being NULL. |
| 5947 | */ | 5966 | */ |
| 5948 | head = &sctp_port_hashtable[sctp_phashfn(sock_net(sk), snum)]; | 5967 | head = &sctp_port_hashtable[sctp_phashfn(sock_net(sk), snum)]; |
| 5949 | sctp_spin_lock(&head->lock); | 5968 | spin_lock(&head->lock); |
| 5950 | sctp_for_each_hentry(pp, &head->chain) { | 5969 | sctp_for_each_hentry(pp, &head->chain) { |
| 5951 | if ((pp->port == snum) && net_eq(pp->net, sock_net(sk))) | 5970 | if ((pp->port == snum) && net_eq(pp->net, sock_net(sk))) |
| 5952 | goto pp_found; | 5971 | goto pp_found; |
| @@ -6030,10 +6049,10 @@ success: | |||
| 6030 | ret = 0; | 6049 | ret = 0; |
| 6031 | 6050 | ||
| 6032 | fail_unlock: | 6051 | fail_unlock: |
| 6033 | sctp_spin_unlock(&head->lock); | 6052 | spin_unlock(&head->lock); |
| 6034 | 6053 | ||
| 6035 | fail: | 6054 | fail: |
| 6036 | sctp_local_bh_enable(); | 6055 | local_bh_enable(); |
| 6037 | return ret; | 6056 | return ret; |
| 6038 | } | 6057 | } |
| 6039 | 6058 | ||
| @@ -6125,7 +6144,7 @@ int sctp_inet_listen(struct socket *sock, int backlog) | |||
| 6125 | if (unlikely(backlog < 0)) | 6144 | if (unlikely(backlog < 0)) |
| 6126 | return err; | 6145 | return err; |
| 6127 | 6146 | ||
| 6128 | sctp_lock_sock(sk); | 6147 | lock_sock(sk); |
| 6129 | 6148 | ||
| 6130 | /* Peeled-off sockets are not allowed to listen(). */ | 6149 | /* Peeled-off sockets are not allowed to listen(). */ |
| 6131 | if (sctp_style(sk, UDP_HIGH_BANDWIDTH)) | 6150 | if (sctp_style(sk, UDP_HIGH_BANDWIDTH)) |
| @@ -6158,7 +6177,7 @@ int sctp_inet_listen(struct socket *sock, int backlog) | |||
| 6158 | 6177 | ||
| 6159 | err = 0; | 6178 | err = 0; |
| 6160 | out: | 6179 | out: |
| 6161 | sctp_release_sock(sk); | 6180 | release_sock(sk); |
| 6162 | return err; | 6181 | return err; |
| 6163 | } | 6182 | } |
| 6164 | 6183 | ||
| @@ -6267,20 +6286,20 @@ static inline void __sctp_put_port(struct sock *sk) | |||
| 6267 | inet_sk(sk)->inet_num)]; | 6286 | inet_sk(sk)->inet_num)]; |
| 6268 | struct sctp_bind_bucket *pp; | 6287 | struct sctp_bind_bucket *pp; |
| 6269 | 6288 | ||
| 6270 | sctp_spin_lock(&head->lock); | 6289 | spin_lock(&head->lock); |
| 6271 | pp = sctp_sk(sk)->bind_hash; | 6290 | pp = sctp_sk(sk)->bind_hash; |
| 6272 | __sk_del_bind_node(sk); | 6291 | __sk_del_bind_node(sk); |
| 6273 | sctp_sk(sk)->bind_hash = NULL; | 6292 | sctp_sk(sk)->bind_hash = NULL; |
| 6274 | inet_sk(sk)->inet_num = 0; | 6293 | inet_sk(sk)->inet_num = 0; |
| 6275 | sctp_bucket_destroy(pp); | 6294 | sctp_bucket_destroy(pp); |
| 6276 | sctp_spin_unlock(&head->lock); | 6295 | spin_unlock(&head->lock); |
| 6277 | } | 6296 | } |
| 6278 | 6297 | ||
| 6279 | void sctp_put_port(struct sock *sk) | 6298 | void sctp_put_port(struct sock *sk) |
| 6280 | { | 6299 | { |
| 6281 | sctp_local_bh_disable(); | 6300 | local_bh_disable(); |
| 6282 | __sctp_put_port(sk); | 6301 | __sctp_put_port(sk); |
| 6283 | sctp_local_bh_enable(); | 6302 | local_bh_enable(); |
| 6284 | } | 6303 | } |
| 6285 | 6304 | ||
| 6286 | /* | 6305 | /* |
| @@ -6418,7 +6437,7 @@ static int sctp_msghdr_parse(const struct msghdr *msg, sctp_cmsgs_t *cmsgs) | |||
| 6418 | * Note: This function is the same function as in core/datagram.c | 6437 | * Note: This function is the same function as in core/datagram.c |
| 6419 | * with a few modifications to make lksctp work. | 6438 | * with a few modifications to make lksctp work. |
| 6420 | */ | 6439 | */ |
| 6421 | static int sctp_wait_for_packet(struct sock * sk, int *err, long *timeo_p) | 6440 | static int sctp_wait_for_packet(struct sock *sk, int *err, long *timeo_p) |
| 6422 | { | 6441 | { |
| 6423 | int error; | 6442 | int error; |
| 6424 | DEFINE_WAIT(wait); | 6443 | DEFINE_WAIT(wait); |
| @@ -6455,9 +6474,9 @@ static int sctp_wait_for_packet(struct sock * sk, int *err, long *timeo_p) | |||
| 6455 | * does not fit in the user's buffer, but this seems to be the | 6474 | * does not fit in the user's buffer, but this seems to be the |
| 6456 | * only way to honor MSG_DONTWAIT realistically. | 6475 | * only way to honor MSG_DONTWAIT realistically. |
| 6457 | */ | 6476 | */ |
| 6458 | sctp_release_sock(sk); | 6477 | release_sock(sk); |
| 6459 | *timeo_p = schedule_timeout(*timeo_p); | 6478 | *timeo_p = schedule_timeout(*timeo_p); |
| 6460 | sctp_lock_sock(sk); | 6479 | lock_sock(sk); |
| 6461 | 6480 | ||
| 6462 | ready: | 6481 | ready: |
| 6463 | finish_wait(sk_sleep(sk), &wait); | 6482 | finish_wait(sk_sleep(sk), &wait); |
| @@ -6640,10 +6659,10 @@ static int sctp_wait_for_sndbuf(struct sctp_association *asoc, long *timeo_p, | |||
| 6640 | /* Let another process have a go. Since we are going | 6659 | /* Let another process have a go. Since we are going |
| 6641 | * to sleep anyway. | 6660 | * to sleep anyway. |
| 6642 | */ | 6661 | */ |
| 6643 | sctp_release_sock(sk); | 6662 | release_sock(sk); |
| 6644 | current_timeo = schedule_timeout(current_timeo); | 6663 | current_timeo = schedule_timeout(current_timeo); |
| 6645 | BUG_ON(sk != asoc->base.sk); | 6664 | BUG_ON(sk != asoc->base.sk); |
| 6646 | sctp_lock_sock(sk); | 6665 | lock_sock(sk); |
| 6647 | 6666 | ||
| 6648 | *timeo_p = current_timeo; | 6667 | *timeo_p = current_timeo; |
| 6649 | } | 6668 | } |
| @@ -6748,9 +6767,9 @@ static int sctp_wait_for_connect(struct sctp_association *asoc, long *timeo_p) | |||
| 6748 | /* Let another process have a go. Since we are going | 6767 | /* Let another process have a go. Since we are going |
| 6749 | * to sleep anyway. | 6768 | * to sleep anyway. |
| 6750 | */ | 6769 | */ |
| 6751 | sctp_release_sock(sk); | 6770 | release_sock(sk); |
| 6752 | current_timeo = schedule_timeout(current_timeo); | 6771 | current_timeo = schedule_timeout(current_timeo); |
| 6753 | sctp_lock_sock(sk); | 6772 | lock_sock(sk); |
| 6754 | 6773 | ||
| 6755 | *timeo_p = current_timeo; | 6774 | *timeo_p = current_timeo; |
| 6756 | } | 6775 | } |
| @@ -6793,9 +6812,9 @@ static int sctp_wait_for_accept(struct sock *sk, long timeo) | |||
| 6793 | TASK_INTERRUPTIBLE); | 6812 | TASK_INTERRUPTIBLE); |
| 6794 | 6813 | ||
| 6795 | if (list_empty(&ep->asocs)) { | 6814 | if (list_empty(&ep->asocs)) { |
| 6796 | sctp_release_sock(sk); | 6815 | release_sock(sk); |
| 6797 | timeo = schedule_timeout(timeo); | 6816 | timeo = schedule_timeout(timeo); |
| 6798 | sctp_lock_sock(sk); | 6817 | lock_sock(sk); |
| 6799 | } | 6818 | } |
| 6800 | 6819 | ||
| 6801 | err = -EINVAL; | 6820 | err = -EINVAL; |
| @@ -6828,9 +6847,9 @@ static void sctp_wait_for_close(struct sock *sk, long timeout) | |||
| 6828 | prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); | 6847 | prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); |
| 6829 | if (list_empty(&sctp_sk(sk)->ep->asocs)) | 6848 | if (list_empty(&sctp_sk(sk)->ep->asocs)) |
| 6830 | break; | 6849 | break; |
| 6831 | sctp_release_sock(sk); | 6850 | release_sock(sk); |
| 6832 | timeout = schedule_timeout(timeout); | 6851 | timeout = schedule_timeout(timeout); |
| 6833 | sctp_lock_sock(sk); | 6852 | lock_sock(sk); |
| 6834 | } while (!signal_pending(current) && timeout); | 6853 | } while (!signal_pending(current) && timeout); |
| 6835 | 6854 | ||
| 6836 | finish_wait(sk_sleep(sk), &wait); | 6855 | finish_wait(sk_sleep(sk), &wait); |
| @@ -6931,14 +6950,14 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk, | |||
| 6931 | /* Hook this new socket in to the bind_hash list. */ | 6950 | /* Hook this new socket in to the bind_hash list. */ |
| 6932 | head = &sctp_port_hashtable[sctp_phashfn(sock_net(oldsk), | 6951 | head = &sctp_port_hashtable[sctp_phashfn(sock_net(oldsk), |
| 6933 | inet_sk(oldsk)->inet_num)]; | 6952 | inet_sk(oldsk)->inet_num)]; |
| 6934 | sctp_local_bh_disable(); | 6953 | local_bh_disable(); |
| 6935 | sctp_spin_lock(&head->lock); | 6954 | spin_lock(&head->lock); |
| 6936 | pp = sctp_sk(oldsk)->bind_hash; | 6955 | pp = sctp_sk(oldsk)->bind_hash; |
| 6937 | sk_add_bind_node(newsk, &pp->owner); | 6956 | sk_add_bind_node(newsk, &pp->owner); |
| 6938 | sctp_sk(newsk)->bind_hash = pp; | 6957 | sctp_sk(newsk)->bind_hash = pp; |
| 6939 | inet_sk(newsk)->inet_num = inet_sk(oldsk)->inet_num; | 6958 | inet_sk(newsk)->inet_num = inet_sk(oldsk)->inet_num; |
| 6940 | sctp_spin_unlock(&head->lock); | 6959 | spin_unlock(&head->lock); |
| 6941 | sctp_local_bh_enable(); | 6960 | local_bh_enable(); |
| 6942 | 6961 | ||
| 6943 | /* Copy the bind_addr list from the original endpoint to the new | 6962 | /* Copy the bind_addr list from the original endpoint to the new |
| 6944 | * endpoint so that we can handle restarts properly | 6963 | * endpoint so that we can handle restarts properly |
| @@ -7027,7 +7046,7 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk, | |||
| 7027 | newsk->sk_shutdown |= RCV_SHUTDOWN; | 7046 | newsk->sk_shutdown |= RCV_SHUTDOWN; |
| 7028 | 7047 | ||
| 7029 | newsk->sk_state = SCTP_SS_ESTABLISHED; | 7048 | newsk->sk_state = SCTP_SS_ESTABLISHED; |
| 7030 | sctp_release_sock(newsk); | 7049 | release_sock(newsk); |
| 7031 | } | 7050 | } |
| 7032 | 7051 | ||
| 7033 | 7052 | ||
diff --git a/net/sctp/ssnmap.c b/net/sctp/ssnmap.c index 6007124aefa0..b9c8521c1a98 100644 --- a/net/sctp/ssnmap.c +++ b/net/sctp/ssnmap.c | |||
| @@ -18,9 +18,8 @@ | |||
| 18 | * See the GNU General Public License for more details. | 18 | * See the GNU General Public License for more details. |
| 19 | * | 19 | * |
| 20 | * You should have received a copy of the GNU General Public License | 20 | * You should have received a copy of the GNU General Public License |
| 21 | * along with GNU CC; see the file COPYING. If not, write to | 21 | * along with GNU CC; see the file COPYING. If not, see |
| 22 | * the Free Software Foundation, 59 Temple Place - Suite 330, | 22 | * <http://www.gnu.org/licenses/>. |
| 23 | * Boston, MA 02111-1307, USA. | ||
| 24 | * | 23 | * |
| 25 | * Please send any bug reports or fixes you make to the | 24 | * Please send any bug reports or fixes you make to the |
| 26 | * email address(es): | 25 | * email address(es): |
diff --git a/net/sctp/sysctl.c b/net/sctp/sysctl.c index b0565afb61c7..7135e617ab0f 100644 --- a/net/sctp/sysctl.c +++ b/net/sctp/sysctl.c | |||
| @@ -19,9 +19,8 @@ | |||
| 19 | * See the GNU General Public License for more details. | 19 | * See the GNU General Public License for more details. |
| 20 | * | 20 | * |
| 21 | * You should have received a copy of the GNU General Public License | 21 | * You should have received a copy of the GNU General Public License |
| 22 | * along with GNU CC; see the file COPYING. If not, write to | 22 | * along with GNU CC; see the file COPYING. If not, see |
| 23 | * the Free Software Foundation, 59 Temple Place - Suite 330, | 23 | * <http://www.gnu.org/licenses/>. |
| 24 | * Boston, MA 02111-1307, USA. | ||
| 25 | * | 24 | * |
| 26 | * Please send any bug reports or fixes you make to the | 25 | * Please send any bug reports or fixes you make to the |
| 27 | * email address(es): | 26 | * email address(es): |
| @@ -425,7 +424,7 @@ void sctp_sysctl_net_unregister(struct net *net) | |||
| 425 | kfree(table); | 424 | kfree(table); |
| 426 | } | 425 | } |
| 427 | 426 | ||
| 428 | static struct ctl_table_header * sctp_sysctl_header; | 427 | static struct ctl_table_header *sctp_sysctl_header; |
| 429 | 428 | ||
| 430 | /* Sysctl registration. */ | 429 | /* Sysctl registration. */ |
| 431 | void sctp_sysctl_register(void) | 430 | void sctp_sysctl_register(void) |
diff --git a/net/sctp/transport.c b/net/sctp/transport.c index efc46ffed1fd..d0810dc5f079 100644 --- a/net/sctp/transport.c +++ b/net/sctp/transport.c | |||
| @@ -24,9 +24,8 @@ | |||
| 24 | * See the GNU General Public License for more details. | 24 | * See the GNU General Public License for more details. |
| 25 | * | 25 | * |
| 26 | * You should have received a copy of the GNU General Public License | 26 | * You should have received a copy of the GNU General Public License |
| 27 | * along with GNU CC; see the file COPYING. If not, write to | 27 | * along with GNU CC; see the file COPYING. If not, see |
| 28 | * the Free Software Foundation, 59 Temple Place - Suite 330, | 28 | * <http://www.gnu.org/licenses/>. |
| 29 | * Boston, MA 02111-1307, USA. | ||
| 30 | * | 29 | * |
| 31 | * Please send any bug reports or fixes you make to the | 30 | * Please send any bug reports or fixes you make to the |
| 32 | * email address(es): | 31 | * email address(es): |
diff --git a/net/sctp/tsnmap.c b/net/sctp/tsnmap.c index fbda20028285..7635f9f2311d 100644 --- a/net/sctp/tsnmap.c +++ b/net/sctp/tsnmap.c | |||
| @@ -21,9 +21,8 @@ | |||
| 21 | * See the GNU General Public License for more details. | 21 | * See the GNU General Public License for more details. |
| 22 | * | 22 | * |
| 23 | * You should have received a copy of the GNU General Public License | 23 | * You should have received a copy of the GNU General Public License |
| 24 | * along with GNU CC; see the file COPYING. If not, write to | 24 | * along with GNU CC; see the file COPYING. If not, see |
| 25 | * the Free Software Foundation, 59 Temple Place - Suite 330, | 25 | * <http://www.gnu.org/licenses/>. |
| 26 | * Boston, MA 02111-1307, USA. | ||
| 27 | * | 26 | * |
| 28 | * Please send any bug reports or fixes you make to the | 27 | * Please send any bug reports or fixes you make to the |
| 29 | * email address(es): | 28 | * email address(es): |
diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c index 81089ed65456..85c64658bd0b 100644 --- a/net/sctp/ulpevent.c +++ b/net/sctp/ulpevent.c | |||
| @@ -22,9 +22,8 @@ | |||
| 22 | * See the GNU General Public License for more details. | 22 | * See the GNU General Public License for more details. |
| 23 | * | 23 | * |
| 24 | * You should have received a copy of the GNU General Public License | 24 | * You should have received a copy of the GNU General Public License |
| 25 | * along with GNU CC; see the file COPYING. If not, write to | 25 | * along with GNU CC; see the file COPYING. If not, see |
| 26 | * the Free Software Foundation, 59 Temple Place - Suite 330, | 26 | * <http://www.gnu.org/licenses/>. |
| 27 | * Boston, MA 02111-1307, USA. | ||
| 28 | * | 27 | * |
| 29 | * Please send any bug reports or fixes you make to the | 28 | * Please send any bug reports or fixes you make to the |
| 30 | * email address(es): | 29 | * email address(es): |
diff --git a/net/sctp/ulpqueue.c b/net/sctp/ulpqueue.c index 1c1484ed605d..5dc94117e9d4 100644 --- a/net/sctp/ulpqueue.c +++ b/net/sctp/ulpqueue.c | |||
| @@ -21,9 +21,8 @@ | |||
| 21 | * See the GNU General Public License for more details. | 21 | * See the GNU General Public License for more details. |
| 22 | * | 22 | * |
| 23 | * You should have received a copy of the GNU General Public License | 23 | * You should have received a copy of the GNU General Public License |
| 24 | * along with GNU CC; see the file COPYING. If not, write to | 24 | * along with GNU CC; see the file COPYING. If not, see |
| 25 | * the Free Software Foundation, 59 Temple Place - Suite 330, | 25 | * <http://www.gnu.org/licenses/>. |
| 26 | * Boston, MA 02111-1307, USA. | ||
| 27 | * | 26 | * |
| 28 | * Please send any bug reports or fixes you make to the | 27 | * Please send any bug reports or fixes you make to the |
| 29 | * email address(es): | 28 | * email address(es): |
| @@ -44,9 +43,9 @@ | |||
| 44 | #include <net/sctp/sm.h> | 43 | #include <net/sctp/sm.h> |
| 45 | 44 | ||
| 46 | /* Forward declarations for internal helpers. */ | 45 | /* Forward declarations for internal helpers. */ |
| 47 | static struct sctp_ulpevent * sctp_ulpq_reasm(struct sctp_ulpq *ulpq, | 46 | static struct sctp_ulpevent *sctp_ulpq_reasm(struct sctp_ulpq *ulpq, |
| 48 | struct sctp_ulpevent *); | 47 | struct sctp_ulpevent *); |
| 49 | static struct sctp_ulpevent * sctp_ulpq_order(struct sctp_ulpq *, | 48 | static struct sctp_ulpevent *sctp_ulpq_order(struct sctp_ulpq *, |
| 50 | struct sctp_ulpevent *); | 49 | struct sctp_ulpevent *); |
| 51 | static void sctp_ulpq_reasm_drain(struct sctp_ulpq *ulpq); | 50 | static void sctp_ulpq_reasm_drain(struct sctp_ulpq *ulpq); |
| 52 | 51 | ||
| @@ -108,7 +107,7 @@ int sctp_ulpq_tail_data(struct sctp_ulpq *ulpq, struct sctp_chunk *chunk, | |||
| 108 | event = sctp_ulpq_reasm(ulpq, event); | 107 | event = sctp_ulpq_reasm(ulpq, event); |
| 109 | 108 | ||
| 110 | /* Do ordering if needed. */ | 109 | /* Do ordering if needed. */ |
| 111 | if ((event) && (event->msg_flags & MSG_EOR)){ | 110 | if ((event) && (event->msg_flags & MSG_EOR)) { |
| 112 | /* Create a temporary list to collect chunks on. */ | 111 | /* Create a temporary list to collect chunks on. */ |
| 113 | skb_queue_head_init(&temp); | 112 | skb_queue_head_init(&temp); |
| 114 | __skb_queue_tail(&temp, sctp_event2skb(event)); | 113 | __skb_queue_tail(&temp, sctp_event2skb(event)); |
| @@ -337,7 +336,8 @@ static struct sctp_ulpevent *sctp_make_reassembled_event(struct net *net, | |||
| 337 | pos = f_frag->next; | 336 | pos = f_frag->next; |
| 338 | 337 | ||
| 339 | /* Get the last skb in the f_frag's frag_list if present. */ | 338 | /* Get the last skb in the f_frag's frag_list if present. */ |
| 340 | for (last = list; list; last = list, list = list->next); | 339 | for (last = list; list; last = list, list = list->next) |
| 340 | ; | ||
| 341 | 341 | ||
| 342 | /* Add the list of remaining fragments to the first fragments | 342 | /* Add the list of remaining fragments to the first fragments |
| 343 | * frag_list. | 343 | * frag_list. |
| @@ -727,7 +727,7 @@ static void sctp_ulpq_reasm_drain(struct sctp_ulpq *ulpq) | |||
| 727 | 727 | ||
| 728 | while ((event = sctp_ulpq_retrieve_reassembled(ulpq)) != NULL) { | 728 | while ((event = sctp_ulpq_retrieve_reassembled(ulpq)) != NULL) { |
| 729 | /* Do ordering if needed. */ | 729 | /* Do ordering if needed. */ |
| 730 | if ((event) && (event->msg_flags & MSG_EOR)){ | 730 | if ((event) && (event->msg_flags & MSG_EOR)) { |
| 731 | skb_queue_head_init(&temp); | 731 | skb_queue_head_init(&temp); |
| 732 | __skb_queue_tail(&temp, sctp_event2skb(event)); | 732 | __skb_queue_tail(&temp, sctp_event2skb(event)); |
| 733 | 733 | ||
diff --git a/net/socket.c b/net/socket.c index e83c416708af..879933aaed4c 100644 --- a/net/socket.c +++ b/net/socket.c | |||
| @@ -1445,48 +1445,61 @@ SYSCALL_DEFINE4(socketpair, int, family, int, type, int, protocol, | |||
| 1445 | err = fd1; | 1445 | err = fd1; |
| 1446 | goto out_release_both; | 1446 | goto out_release_both; |
| 1447 | } | 1447 | } |
| 1448 | |||
| 1448 | fd2 = get_unused_fd_flags(flags); | 1449 | fd2 = get_unused_fd_flags(flags); |
| 1449 | if (unlikely(fd2 < 0)) { | 1450 | if (unlikely(fd2 < 0)) { |
| 1450 | err = fd2; | 1451 | err = fd2; |
| 1451 | put_unused_fd(fd1); | 1452 | goto out_put_unused_1; |
| 1452 | goto out_release_both; | ||
| 1453 | } | 1453 | } |
| 1454 | 1454 | ||
| 1455 | newfile1 = sock_alloc_file(sock1, flags, NULL); | 1455 | newfile1 = sock_alloc_file(sock1, flags, NULL); |
| 1456 | if (unlikely(IS_ERR(newfile1))) { | 1456 | if (unlikely(IS_ERR(newfile1))) { |
| 1457 | err = PTR_ERR(newfile1); | 1457 | err = PTR_ERR(newfile1); |
| 1458 | put_unused_fd(fd1); | 1458 | goto out_put_unused_both; |
| 1459 | put_unused_fd(fd2); | ||
| 1460 | goto out_release_both; | ||
| 1461 | } | 1459 | } |
| 1462 | 1460 | ||
| 1463 | newfile2 = sock_alloc_file(sock2, flags, NULL); | 1461 | newfile2 = sock_alloc_file(sock2, flags, NULL); |
| 1464 | if (IS_ERR(newfile2)) { | 1462 | if (IS_ERR(newfile2)) { |
| 1465 | err = PTR_ERR(newfile2); | 1463 | err = PTR_ERR(newfile2); |
| 1466 | fput(newfile1); | 1464 | goto out_fput_1; |
| 1467 | put_unused_fd(fd1); | ||
| 1468 | put_unused_fd(fd2); | ||
| 1469 | sock_release(sock2); | ||
| 1470 | goto out; | ||
| 1471 | } | 1465 | } |
| 1472 | 1466 | ||
| 1467 | err = put_user(fd1, &usockvec[0]); | ||
| 1468 | if (err) | ||
| 1469 | goto out_fput_both; | ||
| 1470 | |||
| 1471 | err = put_user(fd2, &usockvec[1]); | ||
| 1472 | if (err) | ||
| 1473 | goto out_fput_both; | ||
| 1474 | |||
| 1473 | audit_fd_pair(fd1, fd2); | 1475 | audit_fd_pair(fd1, fd2); |
| 1476 | |||
| 1474 | fd_install(fd1, newfile1); | 1477 | fd_install(fd1, newfile1); |
| 1475 | fd_install(fd2, newfile2); | 1478 | fd_install(fd2, newfile2); |
| 1476 | /* fd1 and fd2 may be already another descriptors. | 1479 | /* fd1 and fd2 may be already another descriptors. |
| 1477 | * Not kernel problem. | 1480 | * Not kernel problem. |
| 1478 | */ | 1481 | */ |
| 1479 | 1482 | ||
| 1480 | err = put_user(fd1, &usockvec[0]); | 1483 | return 0; |
| 1481 | if (!err) | ||
| 1482 | err = put_user(fd2, &usockvec[1]); | ||
| 1483 | if (!err) | ||
| 1484 | return 0; | ||
| 1485 | 1484 | ||
| 1486 | sys_close(fd2); | 1485 | out_fput_both: |
| 1487 | sys_close(fd1); | 1486 | fput(newfile2); |
| 1488 | return err; | 1487 | fput(newfile1); |
| 1488 | put_unused_fd(fd2); | ||
| 1489 | put_unused_fd(fd1); | ||
| 1490 | goto out; | ||
| 1491 | |||
| 1492 | out_fput_1: | ||
| 1493 | fput(newfile1); | ||
| 1494 | put_unused_fd(fd2); | ||
| 1495 | put_unused_fd(fd1); | ||
| 1496 | sock_release(sock2); | ||
| 1497 | goto out; | ||
| 1489 | 1498 | ||
| 1499 | out_put_unused_both: | ||
| 1500 | put_unused_fd(fd2); | ||
| 1501 | out_put_unused_1: | ||
| 1502 | put_unused_fd(fd1); | ||
| 1490 | out_release_both: | 1503 | out_release_both: |
| 1491 | sock_release(sock2); | 1504 | sock_release(sock2); |
| 1492 | out_release_1: | 1505 | out_release_1: |
| @@ -2968,11 +2981,8 @@ static int bond_ioctl(struct net *net, unsigned int cmd, | |||
| 2968 | struct compat_ifreq __user *ifr32) | 2981 | struct compat_ifreq __user *ifr32) |
| 2969 | { | 2982 | { |
| 2970 | struct ifreq kifr; | 2983 | struct ifreq kifr; |
| 2971 | struct ifreq __user *uifr; | ||
| 2972 | mm_segment_t old_fs; | 2984 | mm_segment_t old_fs; |
| 2973 | int err; | 2985 | int err; |
| 2974 | u32 data; | ||
| 2975 | void __user *datap; | ||
| 2976 | 2986 | ||
| 2977 | switch (cmd) { | 2987 | switch (cmd) { |
| 2978 | case SIOCBONDENSLAVE: | 2988 | case SIOCBONDENSLAVE: |
| @@ -2989,26 +2999,13 @@ static int bond_ioctl(struct net *net, unsigned int cmd, | |||
| 2989 | set_fs(old_fs); | 2999 | set_fs(old_fs); |
| 2990 | 3000 | ||
| 2991 | return err; | 3001 | return err; |
| 2992 | case SIOCBONDSLAVEINFOQUERY: | ||
| 2993 | case SIOCBONDINFOQUERY: | ||
| 2994 | uifr = compat_alloc_user_space(sizeof(*uifr)); | ||
| 2995 | if (copy_in_user(&uifr->ifr_name, &ifr32->ifr_name, IFNAMSIZ)) | ||
| 2996 | return -EFAULT; | ||
| 2997 | |||
| 2998 | if (get_user(data, &ifr32->ifr_ifru.ifru_data)) | ||
| 2999 | return -EFAULT; | ||
| 3000 | |||
| 3001 | datap = compat_ptr(data); | ||
| 3002 | if (put_user(datap, &uifr->ifr_ifru.ifru_data)) | ||
| 3003 | return -EFAULT; | ||
| 3004 | |||
| 3005 | return dev_ioctl(net, cmd, uifr); | ||
| 3006 | default: | 3002 | default: |
| 3007 | return -ENOIOCTLCMD; | 3003 | return -ENOIOCTLCMD; |
| 3008 | } | 3004 | } |
| 3009 | } | 3005 | } |
| 3010 | 3006 | ||
| 3011 | static int siocdevprivate_ioctl(struct net *net, unsigned int cmd, | 3007 | /* Handle ioctls that use ifreq::ifr_data and just need struct ifreq converted */ |
| 3008 | static int compat_ifr_data_ioctl(struct net *net, unsigned int cmd, | ||
| 3012 | struct compat_ifreq __user *u_ifreq32) | 3009 | struct compat_ifreq __user *u_ifreq32) |
| 3013 | { | 3010 | { |
| 3014 | struct ifreq __user *u_ifreq64; | 3011 | struct ifreq __user *u_ifreq64; |
| @@ -3019,19 +3016,16 @@ static int siocdevprivate_ioctl(struct net *net, unsigned int cmd, | |||
| 3019 | if (copy_from_user(&tmp_buf[0], &(u_ifreq32->ifr_ifrn.ifrn_name[0]), | 3016 | if (copy_from_user(&tmp_buf[0], &(u_ifreq32->ifr_ifrn.ifrn_name[0]), |
| 3020 | IFNAMSIZ)) | 3017 | IFNAMSIZ)) |
| 3021 | return -EFAULT; | 3018 | return -EFAULT; |
| 3022 | if (__get_user(data32, &u_ifreq32->ifr_ifru.ifru_data)) | 3019 | if (get_user(data32, &u_ifreq32->ifr_ifru.ifru_data)) |
| 3023 | return -EFAULT; | 3020 | return -EFAULT; |
| 3024 | data64 = compat_ptr(data32); | 3021 | data64 = compat_ptr(data32); |
| 3025 | 3022 | ||
| 3026 | u_ifreq64 = compat_alloc_user_space(sizeof(*u_ifreq64)); | 3023 | u_ifreq64 = compat_alloc_user_space(sizeof(*u_ifreq64)); |
| 3027 | 3024 | ||
| 3028 | /* Don't check these user accesses, just let that get trapped | ||
| 3029 | * in the ioctl handler instead. | ||
| 3030 | */ | ||
| 3031 | if (copy_to_user(&u_ifreq64->ifr_ifrn.ifrn_name[0], &tmp_buf[0], | 3025 | if (copy_to_user(&u_ifreq64->ifr_ifrn.ifrn_name[0], &tmp_buf[0], |
| 3032 | IFNAMSIZ)) | 3026 | IFNAMSIZ)) |
| 3033 | return -EFAULT; | 3027 | return -EFAULT; |
| 3034 | if (__put_user(data64, &u_ifreq64->ifr_ifru.ifru_data)) | 3028 | if (put_user(data64, &u_ifreq64->ifr_ifru.ifru_data)) |
| 3035 | return -EFAULT; | 3029 | return -EFAULT; |
| 3036 | 3030 | ||
| 3037 | return dev_ioctl(net, cmd, u_ifreq64); | 3031 | return dev_ioctl(net, cmd, u_ifreq64); |
| @@ -3111,27 +3105,6 @@ static int compat_sioc_ifmap(struct net *net, unsigned int cmd, | |||
| 3111 | return err; | 3105 | return err; |
| 3112 | } | 3106 | } |
| 3113 | 3107 | ||
| 3114 | static int compat_siocshwtstamp(struct net *net, struct compat_ifreq __user *uifr32) | ||
| 3115 | { | ||
| 3116 | void __user *uptr; | ||
| 3117 | compat_uptr_t uptr32; | ||
| 3118 | struct ifreq __user *uifr; | ||
| 3119 | |||
| 3120 | uifr = compat_alloc_user_space(sizeof(*uifr)); | ||
| 3121 | if (copy_in_user(uifr, uifr32, sizeof(struct compat_ifreq))) | ||
| 3122 | return -EFAULT; | ||
| 3123 | |||
| 3124 | if (get_user(uptr32, &uifr32->ifr_data)) | ||
| 3125 | return -EFAULT; | ||
| 3126 | |||
| 3127 | uptr = compat_ptr(uptr32); | ||
| 3128 | |||
| 3129 | if (put_user(uptr, &uifr->ifr_data)) | ||
| 3130 | return -EFAULT; | ||
| 3131 | |||
| 3132 | return dev_ioctl(net, SIOCSHWTSTAMP, uifr); | ||
| 3133 | } | ||
| 3134 | |||
| 3135 | struct rtentry32 { | 3108 | struct rtentry32 { |
| 3136 | u32 rt_pad1; | 3109 | u32 rt_pad1; |
| 3137 | struct sockaddr rt_dst; /* target address */ | 3110 | struct sockaddr rt_dst; /* target address */ |
| @@ -3243,7 +3216,7 @@ static int compat_sock_ioctl_trans(struct file *file, struct socket *sock, | |||
| 3243 | struct net *net = sock_net(sk); | 3216 | struct net *net = sock_net(sk); |
| 3244 | 3217 | ||
| 3245 | if (cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15)) | 3218 | if (cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15)) |
| 3246 | return siocdevprivate_ioctl(net, cmd, argp); | 3219 | return compat_ifr_data_ioctl(net, cmd, argp); |
| 3247 | 3220 | ||
| 3248 | switch (cmd) { | 3221 | switch (cmd) { |
| 3249 | case SIOCSIFBR: | 3222 | case SIOCSIFBR: |
| @@ -3263,8 +3236,6 @@ static int compat_sock_ioctl_trans(struct file *file, struct socket *sock, | |||
| 3263 | case SIOCBONDENSLAVE: | 3236 | case SIOCBONDENSLAVE: |
| 3264 | case SIOCBONDRELEASE: | 3237 | case SIOCBONDRELEASE: |
| 3265 | case SIOCBONDSETHWADDR: | 3238 | case SIOCBONDSETHWADDR: |
| 3266 | case SIOCBONDSLAVEINFOQUERY: | ||
| 3267 | case SIOCBONDINFOQUERY: | ||
| 3268 | case SIOCBONDCHANGEACTIVE: | 3239 | case SIOCBONDCHANGEACTIVE: |
| 3269 | return bond_ioctl(net, cmd, argp); | 3240 | return bond_ioctl(net, cmd, argp); |
| 3270 | case SIOCADDRT: | 3241 | case SIOCADDRT: |
| @@ -3274,8 +3245,11 @@ static int compat_sock_ioctl_trans(struct file *file, struct socket *sock, | |||
| 3274 | return do_siocgstamp(net, sock, cmd, argp); | 3245 | return do_siocgstamp(net, sock, cmd, argp); |
| 3275 | case SIOCGSTAMPNS: | 3246 | case SIOCGSTAMPNS: |
| 3276 | return do_siocgstampns(net, sock, cmd, argp); | 3247 | return do_siocgstampns(net, sock, cmd, argp); |
| 3248 | case SIOCBONDSLAVEINFOQUERY: | ||
| 3249 | case SIOCBONDINFOQUERY: | ||
| 3277 | case SIOCSHWTSTAMP: | 3250 | case SIOCSHWTSTAMP: |
| 3278 | return compat_siocshwtstamp(net, argp); | 3251 | case SIOCGHWTSTAMP: |
| 3252 | return compat_ifr_data_ioctl(net, cmd, argp); | ||
| 3279 | 3253 | ||
| 3280 | case FIOSETOWN: | 3254 | case FIOSETOWN: |
| 3281 | case SIOCSPGRP: | 3255 | case SIOCSPGRP: |
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index 42fdfc634e56..0a2aee060f9f 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c | |||
| @@ -536,8 +536,7 @@ static void warn_gssd(void) | |||
| 536 | unsigned long now = jiffies; | 536 | unsigned long now = jiffies; |
| 537 | 537 | ||
| 538 | if (time_after(now, ratelimit)) { | 538 | if (time_after(now, ratelimit)) { |
| 539 | printk(KERN_WARNING "RPC: AUTH_GSS upcall timed out.\n" | 539 | pr_warn("RPC: AUTH_GSS upcall failed. Please check user daemon is running.\n"); |
| 540 | "Please check user daemon is running.\n"); | ||
| 541 | ratelimit = now + 15*HZ; | 540 | ratelimit = now + 15*HZ; |
| 542 | } | 541 | } |
| 543 | } | 542 | } |
| @@ -600,7 +599,6 @@ gss_create_upcall(struct gss_auth *gss_auth, struct gss_cred *gss_cred) | |||
| 600 | struct rpc_pipe *pipe; | 599 | struct rpc_pipe *pipe; |
| 601 | struct rpc_cred *cred = &gss_cred->gc_base; | 600 | struct rpc_cred *cred = &gss_cred->gc_base; |
| 602 | struct gss_upcall_msg *gss_msg; | 601 | struct gss_upcall_msg *gss_msg; |
| 603 | unsigned long timeout; | ||
| 604 | DEFINE_WAIT(wait); | 602 | DEFINE_WAIT(wait); |
| 605 | int err; | 603 | int err; |
| 606 | 604 | ||
| @@ -608,17 +606,16 @@ gss_create_upcall(struct gss_auth *gss_auth, struct gss_cred *gss_cred) | |||
| 608 | __func__, from_kuid(&init_user_ns, cred->cr_uid)); | 606 | __func__, from_kuid(&init_user_ns, cred->cr_uid)); |
| 609 | retry: | 607 | retry: |
| 610 | err = 0; | 608 | err = 0; |
| 611 | /* Default timeout is 15s unless we know that gssd is not running */ | 609 | /* if gssd is down, just skip upcalling altogether */ |
| 612 | timeout = 15 * HZ; | 610 | if (!gssd_running(net)) { |
| 613 | if (!sn->gssd_running) | 611 | warn_gssd(); |
| 614 | timeout = HZ >> 2; | 612 | return -EACCES; |
| 613 | } | ||
| 615 | gss_msg = gss_setup_upcall(gss_auth, cred); | 614 | gss_msg = gss_setup_upcall(gss_auth, cred); |
| 616 | if (PTR_ERR(gss_msg) == -EAGAIN) { | 615 | if (PTR_ERR(gss_msg) == -EAGAIN) { |
| 617 | err = wait_event_interruptible_timeout(pipe_version_waitqueue, | 616 | err = wait_event_interruptible_timeout(pipe_version_waitqueue, |
| 618 | sn->pipe_version >= 0, timeout); | 617 | sn->pipe_version >= 0, 15 * HZ); |
| 619 | if (sn->pipe_version < 0) { | 618 | if (sn->pipe_version < 0) { |
| 620 | if (err == 0) | ||
| 621 | sn->gssd_running = 0; | ||
| 622 | warn_gssd(); | 619 | warn_gssd(); |
| 623 | err = -EACCES; | 620 | err = -EACCES; |
| 624 | } | 621 | } |
diff --git a/net/sunrpc/auth_gss/gss_krb5_keys.c b/net/sunrpc/auth_gss/gss_krb5_keys.c index 76e42e6be755..24589bd2a4b6 100644 --- a/net/sunrpc/auth_gss/gss_krb5_keys.c +++ b/net/sunrpc/auth_gss/gss_krb5_keys.c | |||
| @@ -59,6 +59,7 @@ | |||
| 59 | #include <linux/crypto.h> | 59 | #include <linux/crypto.h> |
| 60 | #include <linux/sunrpc/gss_krb5.h> | 60 | #include <linux/sunrpc/gss_krb5.h> |
| 61 | #include <linux/sunrpc/xdr.h> | 61 | #include <linux/sunrpc/xdr.h> |
| 62 | #include <linux/lcm.h> | ||
| 62 | 63 | ||
| 63 | #ifdef RPC_DEBUG | 64 | #ifdef RPC_DEBUG |
| 64 | # define RPCDBG_FACILITY RPCDBG_AUTH | 65 | # define RPCDBG_FACILITY RPCDBG_AUTH |
| @@ -72,7 +73,7 @@ | |||
| 72 | static void krb5_nfold(u32 inbits, const u8 *in, | 73 | static void krb5_nfold(u32 inbits, const u8 *in, |
| 73 | u32 outbits, u8 *out) | 74 | u32 outbits, u8 *out) |
| 74 | { | 75 | { |
| 75 | int a, b, c, lcm; | 76 | unsigned long ulcm; |
| 76 | int byte, i, msbit; | 77 | int byte, i, msbit; |
| 77 | 78 | ||
| 78 | /* the code below is more readable if I make these bytes | 79 | /* the code below is more readable if I make these bytes |
| @@ -82,17 +83,7 @@ static void krb5_nfold(u32 inbits, const u8 *in, | |||
| 82 | outbits >>= 3; | 83 | outbits >>= 3; |
| 83 | 84 | ||
| 84 | /* first compute lcm(n,k) */ | 85 | /* first compute lcm(n,k) */ |
| 85 | 86 | ulcm = lcm(inbits, outbits); | |
| 86 | a = outbits; | ||
| 87 | b = inbits; | ||
| 88 | |||
| 89 | while (b != 0) { | ||
| 90 | c = b; | ||
| 91 | b = a%b; | ||
| 92 | a = c; | ||
| 93 | } | ||
| 94 | |||
| 95 | lcm = outbits*inbits/a; | ||
| 96 | 87 | ||
| 97 | /* now do the real work */ | 88 | /* now do the real work */ |
| 98 | 89 | ||
| @@ -101,7 +92,7 @@ static void krb5_nfold(u32 inbits, const u8 *in, | |||
| 101 | 92 | ||
| 102 | /* this will end up cycling through k lcm(k,n)/k times, which | 93 | /* this will end up cycling through k lcm(k,n)/k times, which |
| 103 | is correct */ | 94 | is correct */ |
| 104 | for (i = lcm-1; i >= 0; i--) { | 95 | for (i = ulcm-1; i >= 0; i--) { |
| 105 | /* compute the msbit in k which gets added into this byte */ | 96 | /* compute the msbit in k which gets added into this byte */ |
| 106 | msbit = ( | 97 | msbit = ( |
| 107 | /* first, start with the msbit in the first, | 98 | /* first, start with the msbit in the first, |
diff --git a/net/sunrpc/auth_gss/gss_rpc_upcall.c b/net/sunrpc/auth_gss/gss_rpc_upcall.c index 458f85e9b0ba..abbb7dcd1689 100644 --- a/net/sunrpc/auth_gss/gss_rpc_upcall.c +++ b/net/sunrpc/auth_gss/gss_rpc_upcall.c | |||
| @@ -137,7 +137,6 @@ void init_gssp_clnt(struct sunrpc_net *sn) | |||
| 137 | { | 137 | { |
| 138 | mutex_init(&sn->gssp_lock); | 138 | mutex_init(&sn->gssp_lock); |
| 139 | sn->gssp_clnt = NULL; | 139 | sn->gssp_clnt = NULL; |
| 140 | init_waitqueue_head(&sn->gssp_wq); | ||
| 141 | } | 140 | } |
| 142 | 141 | ||
| 143 | int set_gssp_clnt(struct net *net) | 142 | int set_gssp_clnt(struct net *net) |
| @@ -154,7 +153,6 @@ int set_gssp_clnt(struct net *net) | |||
| 154 | sn->gssp_clnt = clnt; | 153 | sn->gssp_clnt = clnt; |
| 155 | } | 154 | } |
| 156 | mutex_unlock(&sn->gssp_lock); | 155 | mutex_unlock(&sn->gssp_lock); |
| 157 | wake_up(&sn->gssp_wq); | ||
| 158 | return ret; | 156 | return ret; |
| 159 | } | 157 | } |
| 160 | 158 | ||
diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c index 008cdade5aae..0f73f4507746 100644 --- a/net/sunrpc/auth_gss/svcauth_gss.c +++ b/net/sunrpc/auth_gss/svcauth_gss.c | |||
| @@ -1263,65 +1263,34 @@ out: | |||
| 1263 | return ret; | 1263 | return ret; |
| 1264 | } | 1264 | } |
| 1265 | 1265 | ||
| 1266 | DEFINE_SPINLOCK(use_gssp_lock); | 1266 | /* |
| 1267 | 1267 | * Try to set the sn->use_gss_proxy variable to a new value. We only allow | |
| 1268 | static bool use_gss_proxy(struct net *net) | 1268 | * it to be changed if it's currently undefined (-1). If it's any other value |
| 1269 | { | 1269 | * then return -EBUSY unless the type wouldn't have changed anyway. |
| 1270 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); | 1270 | */ |
| 1271 | |||
| 1272 | if (sn->use_gss_proxy != -1) | ||
| 1273 | return sn->use_gss_proxy; | ||
| 1274 | spin_lock(&use_gssp_lock); | ||
| 1275 | /* | ||
| 1276 | * If you wanted gss-proxy, you should have said so before | ||
| 1277 | * starting to accept requests: | ||
| 1278 | */ | ||
| 1279 | sn->use_gss_proxy = 0; | ||
| 1280 | spin_unlock(&use_gssp_lock); | ||
| 1281 | return 0; | ||
| 1282 | } | ||
| 1283 | |||
| 1284 | #ifdef CONFIG_PROC_FS | ||
| 1285 | |||
| 1286 | static int set_gss_proxy(struct net *net, int type) | 1271 | static int set_gss_proxy(struct net *net, int type) |
| 1287 | { | 1272 | { |
| 1288 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); | 1273 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); |
| 1289 | int ret = 0; | 1274 | int ret; |
| 1290 | 1275 | ||
| 1291 | WARN_ON_ONCE(type != 0 && type != 1); | 1276 | WARN_ON_ONCE(type != 0 && type != 1); |
| 1292 | spin_lock(&use_gssp_lock); | 1277 | ret = cmpxchg(&sn->use_gss_proxy, -1, type); |
| 1293 | if (sn->use_gss_proxy == -1 || sn->use_gss_proxy == type) | 1278 | if (ret != -1 && ret != type) |
| 1294 | sn->use_gss_proxy = type; | 1279 | return -EBUSY; |
| 1295 | else | 1280 | return 0; |
| 1296 | ret = -EBUSY; | ||
| 1297 | spin_unlock(&use_gssp_lock); | ||
| 1298 | wake_up(&sn->gssp_wq); | ||
| 1299 | return ret; | ||
| 1300 | } | ||
| 1301 | |||
| 1302 | static inline bool gssp_ready(struct sunrpc_net *sn) | ||
| 1303 | { | ||
| 1304 | switch (sn->use_gss_proxy) { | ||
| 1305 | case -1: | ||
| 1306 | return false; | ||
| 1307 | case 0: | ||
| 1308 | return true; | ||
| 1309 | case 1: | ||
| 1310 | return sn->gssp_clnt; | ||
| 1311 | } | ||
| 1312 | WARN_ON_ONCE(1); | ||
| 1313 | return false; | ||
| 1314 | } | 1281 | } |
| 1315 | 1282 | ||
| 1316 | static int wait_for_gss_proxy(struct net *net, struct file *file) | 1283 | static bool use_gss_proxy(struct net *net) |
| 1317 | { | 1284 | { |
| 1318 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); | 1285 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); |
| 1319 | 1286 | ||
| 1320 | if (file->f_flags & O_NONBLOCK && !gssp_ready(sn)) | 1287 | /* If use_gss_proxy is still undefined, then try to disable it */ |
| 1321 | return -EAGAIN; | 1288 | if (sn->use_gss_proxy == -1) |
| 1322 | return wait_event_interruptible(sn->gssp_wq, gssp_ready(sn)); | 1289 | set_gss_proxy(net, 0); |
| 1290 | return sn->use_gss_proxy; | ||
| 1323 | } | 1291 | } |
| 1324 | 1292 | ||
| 1293 | #ifdef CONFIG_PROC_FS | ||
| 1325 | 1294 | ||
| 1326 | static ssize_t write_gssp(struct file *file, const char __user *buf, | 1295 | static ssize_t write_gssp(struct file *file, const char __user *buf, |
| 1327 | size_t count, loff_t *ppos) | 1296 | size_t count, loff_t *ppos) |
| @@ -1342,10 +1311,10 @@ static ssize_t write_gssp(struct file *file, const char __user *buf, | |||
| 1342 | return res; | 1311 | return res; |
| 1343 | if (i != 1) | 1312 | if (i != 1) |
| 1344 | return -EINVAL; | 1313 | return -EINVAL; |
| 1345 | res = set_gss_proxy(net, 1); | 1314 | res = set_gssp_clnt(net); |
| 1346 | if (res) | 1315 | if (res) |
| 1347 | return res; | 1316 | return res; |
| 1348 | res = set_gssp_clnt(net); | 1317 | res = set_gss_proxy(net, 1); |
| 1349 | if (res) | 1318 | if (res) |
| 1350 | return res; | 1319 | return res; |
| 1351 | return count; | 1320 | return count; |
| @@ -1355,16 +1324,12 @@ static ssize_t read_gssp(struct file *file, char __user *buf, | |||
| 1355 | size_t count, loff_t *ppos) | 1324 | size_t count, loff_t *ppos) |
| 1356 | { | 1325 | { |
| 1357 | struct net *net = PDE_DATA(file_inode(file)); | 1326 | struct net *net = PDE_DATA(file_inode(file)); |
| 1327 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); | ||
| 1358 | unsigned long p = *ppos; | 1328 | unsigned long p = *ppos; |
| 1359 | char tbuf[10]; | 1329 | char tbuf[10]; |
| 1360 | size_t len; | 1330 | size_t len; |
| 1361 | int ret; | ||
| 1362 | 1331 | ||
| 1363 | ret = wait_for_gss_proxy(net, file); | 1332 | snprintf(tbuf, sizeof(tbuf), "%d\n", sn->use_gss_proxy); |
| 1364 | if (ret) | ||
| 1365 | return ret; | ||
| 1366 | |||
| 1367 | snprintf(tbuf, sizeof(tbuf), "%d\n", use_gss_proxy(net)); | ||
| 1368 | len = strlen(tbuf); | 1333 | len = strlen(tbuf); |
| 1369 | if (p >= len) | 1334 | if (p >= len) |
| 1370 | return 0; | 1335 | return 0; |
| @@ -1626,8 +1591,7 @@ svcauth_gss_wrap_resp_integ(struct svc_rqst *rqstp) | |||
| 1626 | BUG_ON(integ_len % 4); | 1591 | BUG_ON(integ_len % 4); |
| 1627 | *p++ = htonl(integ_len); | 1592 | *p++ = htonl(integ_len); |
| 1628 | *p++ = htonl(gc->gc_seq); | 1593 | *p++ = htonl(gc->gc_seq); |
| 1629 | if (xdr_buf_subsegment(resbuf, &integ_buf, integ_offset, | 1594 | if (xdr_buf_subsegment(resbuf, &integ_buf, integ_offset, integ_len)) |
| 1630 | integ_len)) | ||
| 1631 | BUG(); | 1595 | BUG(); |
| 1632 | if (resbuf->tail[0].iov_base == NULL) { | 1596 | if (resbuf->tail[0].iov_base == NULL) { |
| 1633 | if (resbuf->head[0].iov_len + RPC_MAX_AUTH_SIZE > PAGE_SIZE) | 1597 | if (resbuf->head[0].iov_len + RPC_MAX_AUTH_SIZE > PAGE_SIZE) |
| @@ -1635,10 +1599,8 @@ svcauth_gss_wrap_resp_integ(struct svc_rqst *rqstp) | |||
| 1635 | resbuf->tail[0].iov_base = resbuf->head[0].iov_base | 1599 | resbuf->tail[0].iov_base = resbuf->head[0].iov_base |
| 1636 | + resbuf->head[0].iov_len; | 1600 | + resbuf->head[0].iov_len; |
| 1637 | resbuf->tail[0].iov_len = 0; | 1601 | resbuf->tail[0].iov_len = 0; |
| 1638 | resv = &resbuf->tail[0]; | ||
| 1639 | } else { | ||
| 1640 | resv = &resbuf->tail[0]; | ||
| 1641 | } | 1602 | } |
| 1603 | resv = &resbuf->tail[0]; | ||
| 1642 | mic.data = (u8 *)resv->iov_base + resv->iov_len + 4; | 1604 | mic.data = (u8 *)resv->iov_base + resv->iov_len + 4; |
| 1643 | if (gss_get_mic(gsd->rsci->mechctx, &integ_buf, &mic)) | 1605 | if (gss_get_mic(gsd->rsci->mechctx, &integ_buf, &mic)) |
| 1644 | goto out_err; | 1606 | goto out_err; |
diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c index a72de074172d..ae333c1845bb 100644 --- a/net/sunrpc/cache.c +++ b/net/sunrpc/cache.c | |||
| @@ -619,7 +619,7 @@ static void cache_limit_defers(void) | |||
| 619 | 619 | ||
| 620 | /* Consider removing either the first or the last */ | 620 | /* Consider removing either the first or the last */ |
| 621 | if (cache_defer_cnt > DFR_MAX) { | 621 | if (cache_defer_cnt > DFR_MAX) { |
| 622 | if (net_random() & 1) | 622 | if (prandom_u32() & 1) |
| 623 | discard = list_entry(cache_defer_list.next, | 623 | discard = list_entry(cache_defer_list.next, |
| 624 | struct cache_deferred_req, recent); | 624 | struct cache_deferred_req, recent); |
| 625 | else | 625 | else |
| @@ -1111,9 +1111,7 @@ void qword_addhex(char **bpp, int *lp, char *buf, int blen) | |||
| 1111 | *bp++ = 'x'; | 1111 | *bp++ = 'x'; |
| 1112 | len -= 2; | 1112 | len -= 2; |
| 1113 | while (blen && len >= 2) { | 1113 | while (blen && len >= 2) { |
| 1114 | unsigned char c = *buf++; | 1114 | bp = hex_byte_pack(bp, *buf++); |
| 1115 | *bp++ = '0' + ((c&0xf0)>>4) + (c>=0xa0)*('a'-'9'-1); | ||
| 1116 | *bp++ = '0' + (c&0x0f) + ((c&0x0f)>=0x0a)*('a'-'9'-1); | ||
| 1117 | len -= 2; | 1115 | len -= 2; |
| 1118 | blen--; | 1116 | blen--; |
| 1119 | } | 1117 | } |
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index f09b7db2c492..0edada973434 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c | |||
| @@ -1529,9 +1529,13 @@ call_refreshresult(struct rpc_task *task) | |||
| 1529 | task->tk_action = call_refresh; | 1529 | task->tk_action = call_refresh; |
| 1530 | switch (status) { | 1530 | switch (status) { |
| 1531 | case 0: | 1531 | case 0: |
| 1532 | if (rpcauth_uptodatecred(task)) | 1532 | if (rpcauth_uptodatecred(task)) { |
| 1533 | task->tk_action = call_allocate; | 1533 | task->tk_action = call_allocate; |
| 1534 | return; | 1534 | return; |
| 1535 | } | ||
| 1536 | /* Use rate-limiting and a max number of retries if refresh | ||
| 1537 | * had status 0 but failed to update the cred. | ||
| 1538 | */ | ||
| 1535 | case -ETIMEDOUT: | 1539 | case -ETIMEDOUT: |
| 1536 | rpc_delay(task, 3*HZ); | 1540 | rpc_delay(task, 3*HZ); |
| 1537 | case -EAGAIN: | 1541 | case -EAGAIN: |
| @@ -1729,6 +1733,7 @@ call_bind_status(struct rpc_task *task) | |||
| 1729 | return; | 1733 | return; |
| 1730 | case -ECONNREFUSED: /* connection problems */ | 1734 | case -ECONNREFUSED: /* connection problems */ |
| 1731 | case -ECONNRESET: | 1735 | case -ECONNRESET: |
| 1736 | case -ECONNABORTED: | ||
| 1732 | case -ENOTCONN: | 1737 | case -ENOTCONN: |
| 1733 | case -EHOSTDOWN: | 1738 | case -EHOSTDOWN: |
| 1734 | case -EHOSTUNREACH: | 1739 | case -EHOSTUNREACH: |
| @@ -1799,7 +1804,9 @@ call_connect_status(struct rpc_task *task) | |||
| 1799 | return; | 1804 | return; |
| 1800 | case -ECONNREFUSED: | 1805 | case -ECONNREFUSED: |
| 1801 | case -ECONNRESET: | 1806 | case -ECONNRESET: |
| 1807 | case -ECONNABORTED: | ||
| 1802 | case -ENETUNREACH: | 1808 | case -ENETUNREACH: |
| 1809 | case -EHOSTUNREACH: | ||
| 1803 | /* retry with existing socket, after a delay */ | 1810 | /* retry with existing socket, after a delay */ |
| 1804 | rpc_delay(task, 3*HZ); | 1811 | rpc_delay(task, 3*HZ); |
| 1805 | if (RPC_IS_SOFTCONN(task)) | 1812 | if (RPC_IS_SOFTCONN(task)) |
| @@ -1902,6 +1909,7 @@ call_transmit_status(struct rpc_task *task) | |||
| 1902 | break; | 1909 | break; |
| 1903 | } | 1910 | } |
| 1904 | case -ECONNRESET: | 1911 | case -ECONNRESET: |
| 1912 | case -ECONNABORTED: | ||
| 1905 | case -ENOTCONN: | 1913 | case -ENOTCONN: |
| 1906 | case -EPIPE: | 1914 | case -EPIPE: |
| 1907 | rpc_task_force_reencode(task); | 1915 | rpc_task_force_reencode(task); |
| @@ -2011,8 +2019,9 @@ call_status(struct rpc_task *task) | |||
| 2011 | xprt_conditional_disconnect(req->rq_xprt, | 2019 | xprt_conditional_disconnect(req->rq_xprt, |
| 2012 | req->rq_connect_cookie); | 2020 | req->rq_connect_cookie); |
| 2013 | break; | 2021 | break; |
| 2014 | case -ECONNRESET: | ||
| 2015 | case -ECONNREFUSED: | 2022 | case -ECONNREFUSED: |
| 2023 | case -ECONNRESET: | ||
| 2024 | case -ECONNABORTED: | ||
| 2016 | rpc_force_rebind(clnt); | 2025 | rpc_force_rebind(clnt); |
| 2017 | rpc_delay(task, 3*HZ); | 2026 | rpc_delay(task, 3*HZ); |
| 2018 | case -EPIPE: | 2027 | case -EPIPE: |
diff --git a/net/sunrpc/netns.h b/net/sunrpc/netns.h index 779742cfc1ff..df5826876535 100644 --- a/net/sunrpc/netns.h +++ b/net/sunrpc/netns.h | |||
| @@ -14,6 +14,7 @@ struct sunrpc_net { | |||
| 14 | struct cache_detail *rsi_cache; | 14 | struct cache_detail *rsi_cache; |
| 15 | 15 | ||
| 16 | struct super_block *pipefs_sb; | 16 | struct super_block *pipefs_sb; |
| 17 | struct rpc_pipe *gssd_dummy; | ||
| 17 | struct mutex pipefs_sb_lock; | 18 | struct mutex pipefs_sb_lock; |
| 18 | 19 | ||
| 19 | struct list_head all_clients; | 20 | struct list_head all_clients; |
| @@ -26,14 +27,11 @@ struct sunrpc_net { | |||
| 26 | unsigned int rpcb_is_af_local : 1; | 27 | unsigned int rpcb_is_af_local : 1; |
| 27 | 28 | ||
| 28 | struct mutex gssp_lock; | 29 | struct mutex gssp_lock; |
| 29 | wait_queue_head_t gssp_wq; | ||
| 30 | struct rpc_clnt *gssp_clnt; | 30 | struct rpc_clnt *gssp_clnt; |
| 31 | int use_gss_proxy; | 31 | int use_gss_proxy; |
| 32 | int pipe_version; | 32 | int pipe_version; |
| 33 | atomic_t pipe_users; | 33 | atomic_t pipe_users; |
| 34 | struct proc_dir_entry *use_gssp_proc; | 34 | struct proc_dir_entry *use_gssp_proc; |
| 35 | |||
| 36 | unsigned int gssd_running; | ||
| 37 | }; | 35 | }; |
| 38 | 36 | ||
| 39 | extern int sunrpc_net_id; | 37 | extern int sunrpc_net_id; |
diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index bf04b30a788a..b18554898562 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c | |||
| @@ -17,6 +17,7 @@ | |||
| 17 | #include <linux/fsnotify.h> | 17 | #include <linux/fsnotify.h> |
| 18 | #include <linux/kernel.h> | 18 | #include <linux/kernel.h> |
| 19 | #include <linux/rcupdate.h> | 19 | #include <linux/rcupdate.h> |
| 20 | #include <linux/utsname.h> | ||
| 20 | 21 | ||
| 21 | #include <asm/ioctls.h> | 22 | #include <asm/ioctls.h> |
| 22 | #include <linux/poll.h> | 23 | #include <linux/poll.h> |
| @@ -38,7 +39,7 @@ | |||
| 38 | #define NET_NAME(net) ((net == &init_net) ? " (init_net)" : "") | 39 | #define NET_NAME(net) ((net == &init_net) ? " (init_net)" : "") |
| 39 | 40 | ||
| 40 | static struct file_system_type rpc_pipe_fs_type; | 41 | static struct file_system_type rpc_pipe_fs_type; |
| 41 | 42 | static const struct rpc_pipe_ops gssd_dummy_pipe_ops; | |
| 42 | 43 | ||
| 43 | static struct kmem_cache *rpc_inode_cachep __read_mostly; | 44 | static struct kmem_cache *rpc_inode_cachep __read_mostly; |
| 44 | 45 | ||
| @@ -216,14 +217,11 @@ rpc_destroy_inode(struct inode *inode) | |||
| 216 | static int | 217 | static int |
| 217 | rpc_pipe_open(struct inode *inode, struct file *filp) | 218 | rpc_pipe_open(struct inode *inode, struct file *filp) |
| 218 | { | 219 | { |
| 219 | struct net *net = inode->i_sb->s_fs_info; | ||
| 220 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); | ||
| 221 | struct rpc_pipe *pipe; | 220 | struct rpc_pipe *pipe; |
| 222 | int first_open; | 221 | int first_open; |
| 223 | int res = -ENXIO; | 222 | int res = -ENXIO; |
| 224 | 223 | ||
| 225 | mutex_lock(&inode->i_mutex); | 224 | mutex_lock(&inode->i_mutex); |
| 226 | sn->gssd_running = 1; | ||
| 227 | pipe = RPC_I(inode)->pipe; | 225 | pipe = RPC_I(inode)->pipe; |
| 228 | if (pipe == NULL) | 226 | if (pipe == NULL) |
| 229 | goto out; | 227 | goto out; |
| @@ -1159,6 +1157,7 @@ enum { | |||
| 1159 | RPCAUTH_nfsd4_cb, | 1157 | RPCAUTH_nfsd4_cb, |
| 1160 | RPCAUTH_cache, | 1158 | RPCAUTH_cache, |
| 1161 | RPCAUTH_nfsd, | 1159 | RPCAUTH_nfsd, |
| 1160 | RPCAUTH_gssd, | ||
| 1162 | RPCAUTH_RootEOF | 1161 | RPCAUTH_RootEOF |
| 1163 | }; | 1162 | }; |
| 1164 | 1163 | ||
| @@ -1195,6 +1194,10 @@ static const struct rpc_filelist files[] = { | |||
| 1195 | .name = "nfsd", | 1194 | .name = "nfsd", |
| 1196 | .mode = S_IFDIR | S_IRUGO | S_IXUGO, | 1195 | .mode = S_IFDIR | S_IRUGO | S_IXUGO, |
| 1197 | }, | 1196 | }, |
| 1197 | [RPCAUTH_gssd] = { | ||
| 1198 | .name = "gssd", | ||
| 1199 | .mode = S_IFDIR | S_IRUGO | S_IXUGO, | ||
| 1200 | }, | ||
| 1198 | }; | 1201 | }; |
| 1199 | 1202 | ||
| 1200 | /* | 1203 | /* |
| @@ -1208,13 +1211,24 @@ struct dentry *rpc_d_lookup_sb(const struct super_block *sb, | |||
| 1208 | } | 1211 | } |
| 1209 | EXPORT_SYMBOL_GPL(rpc_d_lookup_sb); | 1212 | EXPORT_SYMBOL_GPL(rpc_d_lookup_sb); |
| 1210 | 1213 | ||
| 1211 | void rpc_pipefs_init_net(struct net *net) | 1214 | int rpc_pipefs_init_net(struct net *net) |
| 1212 | { | 1215 | { |
| 1213 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); | 1216 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); |
| 1214 | 1217 | ||
| 1218 | sn->gssd_dummy = rpc_mkpipe_data(&gssd_dummy_pipe_ops, 0); | ||
| 1219 | if (IS_ERR(sn->gssd_dummy)) | ||
| 1220 | return PTR_ERR(sn->gssd_dummy); | ||
| 1221 | |||
| 1215 | mutex_init(&sn->pipefs_sb_lock); | 1222 | mutex_init(&sn->pipefs_sb_lock); |
| 1216 | sn->gssd_running = 1; | ||
| 1217 | sn->pipe_version = -1; | 1223 | sn->pipe_version = -1; |
| 1224 | return 0; | ||
| 1225 | } | ||
| 1226 | |||
| 1227 | void rpc_pipefs_exit_net(struct net *net) | ||
| 1228 | { | ||
| 1229 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); | ||
| 1230 | |||
| 1231 | rpc_destroy_pipe_data(sn->gssd_dummy); | ||
| 1218 | } | 1232 | } |
| 1219 | 1233 | ||
| 1220 | /* | 1234 | /* |
| @@ -1244,11 +1258,134 @@ void rpc_put_sb_net(const struct net *net) | |||
| 1244 | } | 1258 | } |
| 1245 | EXPORT_SYMBOL_GPL(rpc_put_sb_net); | 1259 | EXPORT_SYMBOL_GPL(rpc_put_sb_net); |
| 1246 | 1260 | ||
| 1261 | static const struct rpc_filelist gssd_dummy_clnt_dir[] = { | ||
| 1262 | [0] = { | ||
| 1263 | .name = "clntXX", | ||
| 1264 | .mode = S_IFDIR | S_IRUGO | S_IXUGO, | ||
| 1265 | }, | ||
| 1266 | }; | ||
| 1267 | |||
| 1268 | static ssize_t | ||
| 1269 | dummy_downcall(struct file *filp, const char __user *src, size_t len) | ||
| 1270 | { | ||
| 1271 | return -EINVAL; | ||
| 1272 | } | ||
| 1273 | |||
| 1274 | static const struct rpc_pipe_ops gssd_dummy_pipe_ops = { | ||
| 1275 | .upcall = rpc_pipe_generic_upcall, | ||
| 1276 | .downcall = dummy_downcall, | ||
| 1277 | }; | ||
| 1278 | |||
| 1279 | /* | ||
| 1280 | * Here we present a bogus "info" file to keep rpc.gssd happy. We don't expect | ||
| 1281 | * that it will ever use this info to handle an upcall, but rpc.gssd expects | ||
| 1282 | * that this file will be there and have a certain format. | ||
| 1283 | */ | ||
| 1284 | static int | ||
| 1285 | rpc_show_dummy_info(struct seq_file *m, void *v) | ||
| 1286 | { | ||
| 1287 | seq_printf(m, "RPC server: %s\n", utsname()->nodename); | ||
| 1288 | seq_printf(m, "service: foo (1) version 0\n"); | ||
| 1289 | seq_printf(m, "address: 127.0.0.1\n"); | ||
| 1290 | seq_printf(m, "protocol: tcp\n"); | ||
| 1291 | seq_printf(m, "port: 0\n"); | ||
| 1292 | return 0; | ||
| 1293 | } | ||
| 1294 | |||
| 1295 | static int | ||
| 1296 | rpc_dummy_info_open(struct inode *inode, struct file *file) | ||
| 1297 | { | ||
| 1298 | return single_open(file, rpc_show_dummy_info, NULL); | ||
| 1299 | } | ||
| 1300 | |||
| 1301 | static const struct file_operations rpc_dummy_info_operations = { | ||
| 1302 | .owner = THIS_MODULE, | ||
| 1303 | .open = rpc_dummy_info_open, | ||
| 1304 | .read = seq_read, | ||
| 1305 | .llseek = seq_lseek, | ||
| 1306 | .release = single_release, | ||
| 1307 | }; | ||
| 1308 | |||
| 1309 | static const struct rpc_filelist gssd_dummy_info_file[] = { | ||
| 1310 | [0] = { | ||
| 1311 | .name = "info", | ||
| 1312 | .i_fop = &rpc_dummy_info_operations, | ||
| 1313 | .mode = S_IFREG | S_IRUSR, | ||
| 1314 | }, | ||
| 1315 | }; | ||
| 1316 | |||
| 1317 | /** | ||
| 1318 | * rpc_gssd_dummy_populate - create a dummy gssd pipe | ||
| 1319 | * @root: root of the rpc_pipefs filesystem | ||
| 1320 | * @pipe_data: pipe data created when netns is initialized | ||
| 1321 | * | ||
| 1322 | * Create a dummy set of directories and a pipe that gssd can hold open to | ||
| 1323 | * indicate that it is up and running. | ||
| 1324 | */ | ||
| 1325 | static struct dentry * | ||
| 1326 | rpc_gssd_dummy_populate(struct dentry *root, struct rpc_pipe *pipe_data) | ||
| 1327 | { | ||
| 1328 | int ret = 0; | ||
| 1329 | struct dentry *gssd_dentry; | ||
| 1330 | struct dentry *clnt_dentry = NULL; | ||
| 1331 | struct dentry *pipe_dentry = NULL; | ||
| 1332 | struct qstr q = QSTR_INIT(files[RPCAUTH_gssd].name, | ||
| 1333 | strlen(files[RPCAUTH_gssd].name)); | ||
| 1334 | |||
| 1335 | /* We should never get this far if "gssd" doesn't exist */ | ||
| 1336 | gssd_dentry = d_hash_and_lookup(root, &q); | ||
| 1337 | if (!gssd_dentry) | ||
| 1338 | return ERR_PTR(-ENOENT); | ||
| 1339 | |||
| 1340 | ret = rpc_populate(gssd_dentry, gssd_dummy_clnt_dir, 0, 1, NULL); | ||
| 1341 | if (ret) { | ||
| 1342 | pipe_dentry = ERR_PTR(ret); | ||
| 1343 | goto out; | ||
| 1344 | } | ||
| 1345 | |||
| 1346 | q.name = gssd_dummy_clnt_dir[0].name; | ||
| 1347 | q.len = strlen(gssd_dummy_clnt_dir[0].name); | ||
| 1348 | clnt_dentry = d_hash_and_lookup(gssd_dentry, &q); | ||
| 1349 | if (!clnt_dentry) { | ||
| 1350 | pipe_dentry = ERR_PTR(-ENOENT); | ||
| 1351 | goto out; | ||
| 1352 | } | ||
| 1353 | |||
| 1354 | ret = rpc_populate(clnt_dentry, gssd_dummy_info_file, 0, 1, NULL); | ||
| 1355 | if (ret) { | ||
| 1356 | __rpc_depopulate(gssd_dentry, gssd_dummy_clnt_dir, 0, 1); | ||
| 1357 | pipe_dentry = ERR_PTR(ret); | ||
| 1358 | goto out; | ||
| 1359 | } | ||
| 1360 | |||
| 1361 | pipe_dentry = rpc_mkpipe_dentry(clnt_dentry, "gssd", NULL, pipe_data); | ||
| 1362 | if (IS_ERR(pipe_dentry)) { | ||
| 1363 | __rpc_depopulate(clnt_dentry, gssd_dummy_info_file, 0, 1); | ||
| 1364 | __rpc_depopulate(gssd_dentry, gssd_dummy_clnt_dir, 0, 1); | ||
| 1365 | } | ||
| 1366 | out: | ||
| 1367 | dput(clnt_dentry); | ||
| 1368 | dput(gssd_dentry); | ||
| 1369 | return pipe_dentry; | ||
| 1370 | } | ||
| 1371 | |||
| 1372 | static void | ||
| 1373 | rpc_gssd_dummy_depopulate(struct dentry *pipe_dentry) | ||
| 1374 | { | ||
| 1375 | struct dentry *clnt_dir = pipe_dentry->d_parent; | ||
| 1376 | struct dentry *gssd_dir = clnt_dir->d_parent; | ||
| 1377 | |||
| 1378 | __rpc_rmpipe(clnt_dir->d_inode, pipe_dentry); | ||
| 1379 | __rpc_depopulate(clnt_dir, gssd_dummy_info_file, 0, 1); | ||
| 1380 | __rpc_depopulate(gssd_dir, gssd_dummy_clnt_dir, 0, 1); | ||
| 1381 | dput(pipe_dentry); | ||
| 1382 | } | ||
| 1383 | |||
| 1247 | static int | 1384 | static int |
| 1248 | rpc_fill_super(struct super_block *sb, void *data, int silent) | 1385 | rpc_fill_super(struct super_block *sb, void *data, int silent) |
| 1249 | { | 1386 | { |
| 1250 | struct inode *inode; | 1387 | struct inode *inode; |
| 1251 | struct dentry *root; | 1388 | struct dentry *root, *gssd_dentry; |
| 1252 | struct net *net = data; | 1389 | struct net *net = data; |
| 1253 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); | 1390 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); |
| 1254 | int err; | 1391 | int err; |
| @@ -1266,6 +1403,13 @@ rpc_fill_super(struct super_block *sb, void *data, int silent) | |||
| 1266 | return -ENOMEM; | 1403 | return -ENOMEM; |
| 1267 | if (rpc_populate(root, files, RPCAUTH_lockd, RPCAUTH_RootEOF, NULL)) | 1404 | if (rpc_populate(root, files, RPCAUTH_lockd, RPCAUTH_RootEOF, NULL)) |
| 1268 | return -ENOMEM; | 1405 | return -ENOMEM; |
| 1406 | |||
| 1407 | gssd_dentry = rpc_gssd_dummy_populate(root, sn->gssd_dummy); | ||
| 1408 | if (IS_ERR(gssd_dentry)) { | ||
| 1409 | __rpc_depopulate(root, files, RPCAUTH_lockd, RPCAUTH_RootEOF); | ||
| 1410 | return PTR_ERR(gssd_dentry); | ||
| 1411 | } | ||
| 1412 | |||
| 1269 | dprintk("RPC: sending pipefs MOUNT notification for net %p%s\n", | 1413 | dprintk("RPC: sending pipefs MOUNT notification for net %p%s\n", |
| 1270 | net, NET_NAME(net)); | 1414 | net, NET_NAME(net)); |
| 1271 | mutex_lock(&sn->pipefs_sb_lock); | 1415 | mutex_lock(&sn->pipefs_sb_lock); |
| @@ -1280,6 +1424,7 @@ rpc_fill_super(struct super_block *sb, void *data, int silent) | |||
| 1280 | return 0; | 1424 | return 0; |
| 1281 | 1425 | ||
| 1282 | err_depopulate: | 1426 | err_depopulate: |
| 1427 | rpc_gssd_dummy_depopulate(gssd_dentry); | ||
| 1283 | blocking_notifier_call_chain(&rpc_pipefs_notifier_list, | 1428 | blocking_notifier_call_chain(&rpc_pipefs_notifier_list, |
| 1284 | RPC_PIPEFS_UMOUNT, | 1429 | RPC_PIPEFS_UMOUNT, |
| 1285 | sb); | 1430 | sb); |
| @@ -1289,6 +1434,16 @@ err_depopulate: | |||
| 1289 | return err; | 1434 | return err; |
| 1290 | } | 1435 | } |
| 1291 | 1436 | ||
| 1437 | bool | ||
| 1438 | gssd_running(struct net *net) | ||
| 1439 | { | ||
| 1440 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); | ||
| 1441 | struct rpc_pipe *pipe = sn->gssd_dummy; | ||
| 1442 | |||
| 1443 | return pipe->nreaders || pipe->nwriters; | ||
| 1444 | } | ||
| 1445 | EXPORT_SYMBOL_GPL(gssd_running); | ||
| 1446 | |||
| 1292 | static struct dentry * | 1447 | static struct dentry * |
| 1293 | rpc_mount(struct file_system_type *fs_type, | 1448 | rpc_mount(struct file_system_type *fs_type, |
| 1294 | int flags, const char *dev_name, void *data) | 1449 | int flags, const char *dev_name, void *data) |
diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c index 3d6498af9adc..cd30120de9e4 100644 --- a/net/sunrpc/sunrpc_syms.c +++ b/net/sunrpc/sunrpc_syms.c | |||
| @@ -44,12 +44,17 @@ static __net_init int sunrpc_init_net(struct net *net) | |||
| 44 | if (err) | 44 | if (err) |
| 45 | goto err_unixgid; | 45 | goto err_unixgid; |
| 46 | 46 | ||
| 47 | rpc_pipefs_init_net(net); | 47 | err = rpc_pipefs_init_net(net); |
| 48 | if (err) | ||
| 49 | goto err_pipefs; | ||
| 50 | |||
| 48 | INIT_LIST_HEAD(&sn->all_clients); | 51 | INIT_LIST_HEAD(&sn->all_clients); |
| 49 | spin_lock_init(&sn->rpc_client_lock); | 52 | spin_lock_init(&sn->rpc_client_lock); |
| 50 | spin_lock_init(&sn->rpcb_clnt_lock); | 53 | spin_lock_init(&sn->rpcb_clnt_lock); |
| 51 | return 0; | 54 | return 0; |
| 52 | 55 | ||
| 56 | err_pipefs: | ||
| 57 | unix_gid_cache_destroy(net); | ||
| 53 | err_unixgid: | 58 | err_unixgid: |
| 54 | ip_map_cache_destroy(net); | 59 | ip_map_cache_destroy(net); |
| 55 | err_ipmap: | 60 | err_ipmap: |
| @@ -60,6 +65,7 @@ err_proc: | |||
| 60 | 65 | ||
| 61 | static __net_exit void sunrpc_exit_net(struct net *net) | 66 | static __net_exit void sunrpc_exit_net(struct net *net) |
| 62 | { | 67 | { |
| 68 | rpc_pipefs_exit_net(net); | ||
| 63 | unix_gid_cache_destroy(net); | 69 | unix_gid_cache_destroy(net); |
| 64 | ip_map_cache_destroy(net); | 70 | ip_map_cache_destroy(net); |
| 65 | rpc_proc_exit(net); | 71 | rpc_proc_exit(net); |
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index e7fbe368b4a3..5de6801cd924 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c | |||
| @@ -916,9 +916,6 @@ static int __svc_register(struct net *net, const char *progname, | |||
| 916 | #endif | 916 | #endif |
| 917 | } | 917 | } |
| 918 | 918 | ||
| 919 | if (error < 0) | ||
| 920 | printk(KERN_WARNING "svc: failed to register %sv%u RPC " | ||
| 921 | "service (errno %d).\n", progname, version, -error); | ||
| 922 | return error; | 919 | return error; |
| 923 | } | 920 | } |
| 924 | 921 | ||
| @@ -937,6 +934,7 @@ int svc_register(const struct svc_serv *serv, struct net *net, | |||
| 937 | const unsigned short port) | 934 | const unsigned short port) |
| 938 | { | 935 | { |
| 939 | struct svc_program *progp; | 936 | struct svc_program *progp; |
| 937 | struct svc_version *vers; | ||
| 940 | unsigned int i; | 938 | unsigned int i; |
| 941 | int error = 0; | 939 | int error = 0; |
| 942 | 940 | ||
| @@ -946,7 +944,8 @@ int svc_register(const struct svc_serv *serv, struct net *net, | |||
| 946 | 944 | ||
| 947 | for (progp = serv->sv_program; progp; progp = progp->pg_next) { | 945 | for (progp = serv->sv_program; progp; progp = progp->pg_next) { |
| 948 | for (i = 0; i < progp->pg_nvers; i++) { | 946 | for (i = 0; i < progp->pg_nvers; i++) { |
| 949 | if (progp->pg_vers[i] == NULL) | 947 | vers = progp->pg_vers[i]; |
| 948 | if (vers == NULL) | ||
| 950 | continue; | 949 | continue; |
| 951 | 950 | ||
| 952 | dprintk("svc: svc_register(%sv%d, %s, %u, %u)%s\n", | 951 | dprintk("svc: svc_register(%sv%d, %s, %u, %u)%s\n", |
| @@ -955,16 +954,26 @@ int svc_register(const struct svc_serv *serv, struct net *net, | |||
| 955 | proto == IPPROTO_UDP? "udp" : "tcp", | 954 | proto == IPPROTO_UDP? "udp" : "tcp", |
| 956 | port, | 955 | port, |
| 957 | family, | 956 | family, |
| 958 | progp->pg_vers[i]->vs_hidden? | 957 | vers->vs_hidden ? |
| 959 | " (but not telling portmap)" : ""); | 958 | " (but not telling portmap)" : ""); |
| 960 | 959 | ||
| 961 | if (progp->pg_vers[i]->vs_hidden) | 960 | if (vers->vs_hidden) |
| 962 | continue; | 961 | continue; |
| 963 | 962 | ||
| 964 | error = __svc_register(net, progp->pg_name, progp->pg_prog, | 963 | error = __svc_register(net, progp->pg_name, progp->pg_prog, |
| 965 | i, family, proto, port); | 964 | i, family, proto, port); |
| 966 | if (error < 0) | 965 | |
| 966 | if (vers->vs_rpcb_optnl) { | ||
| 967 | error = 0; | ||
| 968 | continue; | ||
| 969 | } | ||
| 970 | |||
| 971 | if (error < 0) { | ||
| 972 | printk(KERN_WARNING "svc: failed to register " | ||
| 973 | "%sv%u RPC service (errno %d).\n", | ||
| 974 | progp->pg_name, i, -error); | ||
| 967 | break; | 975 | break; |
| 976 | } | ||
| 968 | } | 977 | } |
| 969 | } | 978 | } |
| 970 | 979 | ||
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 04199bc8416f..7d4df99f761f 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c | |||
| @@ -749,6 +749,11 @@ static void xprt_connect_status(struct rpc_task *task) | |||
| 749 | } | 749 | } |
| 750 | 750 | ||
| 751 | switch (task->tk_status) { | 751 | switch (task->tk_status) { |
| 752 | case -ECONNREFUSED: | ||
| 753 | case -ECONNRESET: | ||
| 754 | case -ECONNABORTED: | ||
| 755 | case -ENETUNREACH: | ||
| 756 | case -EHOSTUNREACH: | ||
| 752 | case -EAGAIN: | 757 | case -EAGAIN: |
| 753 | dprintk("RPC: %5u xprt_connect_status: retrying\n", task->tk_pid); | 758 | dprintk("RPC: %5u xprt_connect_status: retrying\n", task->tk_pid); |
| 754 | break; | 759 | break; |
| @@ -1188,7 +1193,7 @@ static inline __be32 xprt_alloc_xid(struct rpc_xprt *xprt) | |||
| 1188 | 1193 | ||
| 1189 | static inline void xprt_init_xid(struct rpc_xprt *xprt) | 1194 | static inline void xprt_init_xid(struct rpc_xprt *xprt) |
| 1190 | { | 1195 | { |
| 1191 | xprt->xid = net_random(); | 1196 | xprt->xid = prandom_u32(); |
| 1192 | } | 1197 | } |
| 1193 | 1198 | ||
| 1194 | static void xprt_request_init(struct rpc_task *task, struct rpc_xprt *xprt) | 1199 | static void xprt_request_init(struct rpc_task *task, struct rpc_xprt *xprt) |
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index dd9d295813cf..817a1e523969 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c | |||
| @@ -257,6 +257,7 @@ struct sock_xprt { | |||
| 257 | void (*old_data_ready)(struct sock *, int); | 257 | void (*old_data_ready)(struct sock *, int); |
| 258 | void (*old_state_change)(struct sock *); | 258 | void (*old_state_change)(struct sock *); |
| 259 | void (*old_write_space)(struct sock *); | 259 | void (*old_write_space)(struct sock *); |
| 260 | void (*old_error_report)(struct sock *); | ||
| 260 | }; | 261 | }; |
| 261 | 262 | ||
| 262 | /* | 263 | /* |
| @@ -274,6 +275,11 @@ struct sock_xprt { | |||
| 274 | */ | 275 | */ |
| 275 | #define TCP_RPC_REPLY (1UL << 6) | 276 | #define TCP_RPC_REPLY (1UL << 6) |
| 276 | 277 | ||
| 278 | static inline struct rpc_xprt *xprt_from_sock(struct sock *sk) | ||
| 279 | { | ||
| 280 | return (struct rpc_xprt *) sk->sk_user_data; | ||
| 281 | } | ||
| 282 | |||
| 277 | static inline struct sockaddr *xs_addr(struct rpc_xprt *xprt) | 283 | static inline struct sockaddr *xs_addr(struct rpc_xprt *xprt) |
| 278 | { | 284 | { |
| 279 | return (struct sockaddr *) &xprt->addr; | 285 | return (struct sockaddr *) &xprt->addr; |
| @@ -799,6 +805,7 @@ static void xs_save_old_callbacks(struct sock_xprt *transport, struct sock *sk) | |||
| 799 | transport->old_data_ready = sk->sk_data_ready; | 805 | transport->old_data_ready = sk->sk_data_ready; |
| 800 | transport->old_state_change = sk->sk_state_change; | 806 | transport->old_state_change = sk->sk_state_change; |
| 801 | transport->old_write_space = sk->sk_write_space; | 807 | transport->old_write_space = sk->sk_write_space; |
| 808 | transport->old_error_report = sk->sk_error_report; | ||
| 802 | } | 809 | } |
| 803 | 810 | ||
| 804 | static void xs_restore_old_callbacks(struct sock_xprt *transport, struct sock *sk) | 811 | static void xs_restore_old_callbacks(struct sock_xprt *transport, struct sock *sk) |
| @@ -806,6 +813,34 @@ static void xs_restore_old_callbacks(struct sock_xprt *transport, struct sock *s | |||
| 806 | sk->sk_data_ready = transport->old_data_ready; | 813 | sk->sk_data_ready = transport->old_data_ready; |
| 807 | sk->sk_state_change = transport->old_state_change; | 814 | sk->sk_state_change = transport->old_state_change; |
| 808 | sk->sk_write_space = transport->old_write_space; | 815 | sk->sk_write_space = transport->old_write_space; |
| 816 | sk->sk_error_report = transport->old_error_report; | ||
| 817 | } | ||
| 818 | |||
| 819 | /** | ||
| 820 | * xs_error_report - callback to handle TCP socket state errors | ||
| 821 | * @sk: socket | ||
| 822 | * | ||
| 823 | * Note: we don't call sock_error() since there may be a rpc_task | ||
| 824 | * using the socket, and so we don't want to clear sk->sk_err. | ||
| 825 | */ | ||
| 826 | static void xs_error_report(struct sock *sk) | ||
| 827 | { | ||
| 828 | struct rpc_xprt *xprt; | ||
| 829 | int err; | ||
| 830 | |||
| 831 | read_lock_bh(&sk->sk_callback_lock); | ||
| 832 | if (!(xprt = xprt_from_sock(sk))) | ||
| 833 | goto out; | ||
| 834 | |||
| 835 | err = -sk->sk_err; | ||
| 836 | if (err == 0) | ||
| 837 | goto out; | ||
| 838 | dprintk("RPC: xs_error_report client %p, error=%d...\n", | ||
| 839 | xprt, -err); | ||
| 840 | trace_rpc_socket_error(xprt, sk->sk_socket, err); | ||
| 841 | xprt_wake_pending_tasks(xprt, err); | ||
| 842 | out: | ||
| 843 | read_unlock_bh(&sk->sk_callback_lock); | ||
| 809 | } | 844 | } |
| 810 | 845 | ||
| 811 | static void xs_reset_transport(struct sock_xprt *transport) | 846 | static void xs_reset_transport(struct sock_xprt *transport) |
| @@ -885,11 +920,6 @@ static void xs_destroy(struct rpc_xprt *xprt) | |||
| 885 | module_put(THIS_MODULE); | 920 | module_put(THIS_MODULE); |
| 886 | } | 921 | } |
| 887 | 922 | ||
| 888 | static inline struct rpc_xprt *xprt_from_sock(struct sock *sk) | ||
| 889 | { | ||
| 890 | return (struct rpc_xprt *) sk->sk_user_data; | ||
| 891 | } | ||
| 892 | |||
| 893 | static int xs_local_copy_to_xdr(struct xdr_buf *xdr, struct sk_buff *skb) | 923 | static int xs_local_copy_to_xdr(struct xdr_buf *xdr, struct sk_buff *skb) |
| 894 | { | 924 | { |
| 895 | struct xdr_skb_reader desc = { | 925 | struct xdr_skb_reader desc = { |
| @@ -1674,7 +1704,7 @@ static void xs_udp_timer(struct rpc_xprt *xprt, struct rpc_task *task) | |||
| 1674 | static unsigned short xs_get_random_port(void) | 1704 | static unsigned short xs_get_random_port(void) |
| 1675 | { | 1705 | { |
| 1676 | unsigned short range = xprt_max_resvport - xprt_min_resvport; | 1706 | unsigned short range = xprt_max_resvport - xprt_min_resvport; |
| 1677 | unsigned short rand = (unsigned short) net_random() % range; | 1707 | unsigned short rand = (unsigned short) prandom_u32() % range; |
| 1678 | return rand + xprt_min_resvport; | 1708 | return rand + xprt_min_resvport; |
| 1679 | } | 1709 | } |
| 1680 | 1710 | ||
| @@ -1869,6 +1899,7 @@ static int xs_local_finish_connecting(struct rpc_xprt *xprt, | |||
| 1869 | sk->sk_user_data = xprt; | 1899 | sk->sk_user_data = xprt; |
| 1870 | sk->sk_data_ready = xs_local_data_ready; | 1900 | sk->sk_data_ready = xs_local_data_ready; |
| 1871 | sk->sk_write_space = xs_udp_write_space; | 1901 | sk->sk_write_space = xs_udp_write_space; |
| 1902 | sk->sk_error_report = xs_error_report; | ||
| 1872 | sk->sk_allocation = GFP_ATOMIC; | 1903 | sk->sk_allocation = GFP_ATOMIC; |
| 1873 | 1904 | ||
| 1874 | xprt_clear_connected(xprt); | 1905 | xprt_clear_connected(xprt); |
| @@ -2146,6 +2177,7 @@ static int xs_tcp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock) | |||
| 2146 | sk->sk_data_ready = xs_tcp_data_ready; | 2177 | sk->sk_data_ready = xs_tcp_data_ready; |
| 2147 | sk->sk_state_change = xs_tcp_state_change; | 2178 | sk->sk_state_change = xs_tcp_state_change; |
| 2148 | sk->sk_write_space = xs_tcp_write_space; | 2179 | sk->sk_write_space = xs_tcp_write_space; |
| 2180 | sk->sk_error_report = xs_error_report; | ||
| 2149 | sk->sk_allocation = GFP_ATOMIC; | 2181 | sk->sk_allocation = GFP_ATOMIC; |
| 2150 | 2182 | ||
| 2151 | /* socket options */ | 2183 | /* socket options */ |
| @@ -2932,10 +2964,9 @@ static struct rpc_xprt *xs_setup_bc_tcp(struct xprt_create *args) | |||
| 2932 | 2964 | ||
| 2933 | /* | 2965 | /* |
| 2934 | * Once we've associated a backchannel xprt with a connection, | 2966 | * Once we've associated a backchannel xprt with a connection, |
| 2935 | * we want to keep it around as long as long as the connection | 2967 | * we want to keep it around as long as the connection lasts, |
| 2936 | * lasts, in case we need to start using it for a backchannel | 2968 | * in case we need to start using it for a backchannel again; |
| 2937 | * again; this reference won't be dropped until bc_xprt is | 2969 | * this reference won't be dropped until bc_xprt is destroyed. |
| 2938 | * destroyed. | ||
| 2939 | */ | 2970 | */ |
| 2940 | xprt_get(xprt); | 2971 | xprt_get(xprt); |
| 2941 | args->bc_xprt->xpt_bc_xprt = xprt; | 2972 | args->bc_xprt->xpt_bc_xprt = xprt; |
diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c index 0d4402587fdf..bf860d9e75af 100644 --- a/net/tipc/bcast.c +++ b/net/tipc/bcast.c | |||
| @@ -621,12 +621,6 @@ static int tipc_bcbearer_send(struct sk_buff *buf, struct tipc_bearer *unused1, | |||
| 621 | if (!p) | 621 | if (!p) |
| 622 | break; /* No more bearers to try */ | 622 | break; /* No more bearers to try */ |
| 623 | 623 | ||
| 624 | if (tipc_bearer_blocked(p)) { | ||
| 625 | if (!s || tipc_bearer_blocked(s)) | ||
| 626 | continue; /* Can't use either bearer */ | ||
| 627 | b = s; | ||
| 628 | } | ||
| 629 | |||
| 630 | tipc_nmap_diff(&bcbearer->remains, &b->nodes, | 624 | tipc_nmap_diff(&bcbearer->remains, &b->nodes, |
| 631 | &bcbearer->remains_new); | 625 | &bcbearer->remains_new); |
| 632 | if (bcbearer->remains_new.count == bcbearer->remains.count) | 626 | if (bcbearer->remains_new.count == bcbearer->remains.count) |
| @@ -800,7 +794,7 @@ void tipc_bclink_init(void) | |||
| 800 | void tipc_bclink_stop(void) | 794 | void tipc_bclink_stop(void) |
| 801 | { | 795 | { |
| 802 | spin_lock_bh(&bc_lock); | 796 | spin_lock_bh(&bc_lock); |
| 803 | tipc_link_stop(bcl); | 797 | tipc_link_purge_queues(bcl); |
| 804 | spin_unlock_bh(&bc_lock); | 798 | spin_unlock_bh(&bc_lock); |
| 805 | 799 | ||
| 806 | memset(bclink, 0, sizeof(*bclink)); | 800 | memset(bclink, 0, sizeof(*bclink)); |
diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c index 3f9707a16d06..a38c89969c68 100644 --- a/net/tipc/bearer.c +++ b/net/tipc/bearer.c | |||
| @@ -1,8 +1,8 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * net/tipc/bearer.c: TIPC bearer code | 2 | * net/tipc/bearer.c: TIPC bearer code |
| 3 | * | 3 | * |
| 4 | * Copyright (c) 1996-2006, Ericsson AB | 4 | * Copyright (c) 1996-2006, 2013, Ericsson AB |
| 5 | * Copyright (c) 2004-2006, 2010-2011, Wind River Systems | 5 | * Copyright (c) 2004-2006, 2010-2013, Wind River Systems |
| 6 | * All rights reserved. | 6 | * All rights reserved. |
| 7 | * | 7 | * |
| 8 | * Redistribution and use in source and binary forms, with or without | 8 | * Redistribution and use in source and binary forms, with or without |
| @@ -41,8 +41,13 @@ | |||
| 41 | 41 | ||
| 42 | #define MAX_ADDR_STR 60 | 42 | #define MAX_ADDR_STR 60 |
| 43 | 43 | ||
| 44 | static struct tipc_media *media_list[MAX_MEDIA]; | 44 | static struct tipc_media * const media_info_array[] = { |
| 45 | static u32 media_count; | 45 | ð_media_info, |
| 46 | #ifdef CONFIG_TIPC_MEDIA_IB | ||
| 47 | &ib_media_info, | ||
| 48 | #endif | ||
| 49 | NULL | ||
| 50 | }; | ||
| 46 | 51 | ||
| 47 | struct tipc_bearer tipc_bearers[MAX_BEARERS]; | 52 | struct tipc_bearer tipc_bearers[MAX_BEARERS]; |
| 48 | 53 | ||
| @@ -55,11 +60,11 @@ struct tipc_media *tipc_media_find(const char *name) | |||
| 55 | { | 60 | { |
| 56 | u32 i; | 61 | u32 i; |
| 57 | 62 | ||
| 58 | for (i = 0; i < media_count; i++) { | 63 | for (i = 0; media_info_array[i] != NULL; i++) { |
| 59 | if (!strcmp(media_list[i]->name, name)) | 64 | if (!strcmp(media_info_array[i]->name, name)) |
| 60 | return media_list[i]; | 65 | break; |
| 61 | } | 66 | } |
| 62 | return NULL; | 67 | return media_info_array[i]; |
| 63 | } | 68 | } |
| 64 | 69 | ||
| 65 | /** | 70 | /** |
| @@ -69,44 +74,11 @@ static struct tipc_media *media_find_id(u8 type) | |||
| 69 | { | 74 | { |
| 70 | u32 i; | 75 | u32 i; |
| 71 | 76 | ||
| 72 | for (i = 0; i < media_count; i++) { | 77 | for (i = 0; media_info_array[i] != NULL; i++) { |
| 73 | if (media_list[i]->type_id == type) | 78 | if (media_info_array[i]->type_id == type) |
| 74 | return media_list[i]; | 79 | break; |
| 75 | } | 80 | } |
| 76 | return NULL; | 81 | return media_info_array[i]; |
| 77 | } | ||
| 78 | |||
| 79 | /** | ||
| 80 | * tipc_register_media - register a media type | ||
| 81 | * | ||
| 82 | * Bearers for this media type must be activated separately at a later stage. | ||
| 83 | */ | ||
| 84 | int tipc_register_media(struct tipc_media *m_ptr) | ||
| 85 | { | ||
| 86 | int res = -EINVAL; | ||
| 87 | |||
| 88 | write_lock_bh(&tipc_net_lock); | ||
| 89 | |||
| 90 | if ((strlen(m_ptr->name) + 1) > TIPC_MAX_MEDIA_NAME) | ||
| 91 | goto exit; | ||
| 92 | if (m_ptr->priority > TIPC_MAX_LINK_PRI) | ||
| 93 | goto exit; | ||
| 94 | if ((m_ptr->tolerance < TIPC_MIN_LINK_TOL) || | ||
| 95 | (m_ptr->tolerance > TIPC_MAX_LINK_TOL)) | ||
| 96 | goto exit; | ||
| 97 | if (media_count >= MAX_MEDIA) | ||
| 98 | goto exit; | ||
| 99 | if (tipc_media_find(m_ptr->name) || media_find_id(m_ptr->type_id)) | ||
| 100 | goto exit; | ||
| 101 | |||
| 102 | media_list[media_count] = m_ptr; | ||
| 103 | media_count++; | ||
| 104 | res = 0; | ||
| 105 | exit: | ||
| 106 | write_unlock_bh(&tipc_net_lock); | ||
| 107 | if (res) | ||
| 108 | pr_warn("Media <%s> registration error\n", m_ptr->name); | ||
| 109 | return res; | ||
| 110 | } | 82 | } |
| 111 | 83 | ||
| 112 | /** | 84 | /** |
| @@ -144,13 +116,11 @@ struct sk_buff *tipc_media_get_names(void) | |||
| 144 | if (!buf) | 116 | if (!buf) |
| 145 | return NULL; | 117 | return NULL; |
| 146 | 118 | ||
| 147 | read_lock_bh(&tipc_net_lock); | 119 | for (i = 0; media_info_array[i] != NULL; i++) { |
| 148 | for (i = 0; i < media_count; i++) { | ||
| 149 | tipc_cfg_append_tlv(buf, TIPC_TLV_MEDIA_NAME, | 120 | tipc_cfg_append_tlv(buf, TIPC_TLV_MEDIA_NAME, |
| 150 | media_list[i]->name, | 121 | media_info_array[i]->name, |
| 151 | strlen(media_list[i]->name) + 1); | 122 | strlen(media_info_array[i]->name) + 1); |
| 152 | } | 123 | } |
| 153 | read_unlock_bh(&tipc_net_lock); | ||
| 154 | return buf; | 124 | return buf; |
| 155 | } | 125 | } |
| 156 | 126 | ||
| @@ -215,31 +185,12 @@ struct tipc_bearer *tipc_bearer_find(const char *name) | |||
| 215 | } | 185 | } |
| 216 | 186 | ||
| 217 | /** | 187 | /** |
| 218 | * tipc_bearer_find_interface - locates bearer object with matching interface name | ||
| 219 | */ | ||
| 220 | struct tipc_bearer *tipc_bearer_find_interface(const char *if_name) | ||
| 221 | { | ||
| 222 | struct tipc_bearer *b_ptr; | ||
| 223 | char *b_if_name; | ||
| 224 | u32 i; | ||
| 225 | |||
| 226 | for (i = 0, b_ptr = tipc_bearers; i < MAX_BEARERS; i++, b_ptr++) { | ||
| 227 | if (!b_ptr->active) | ||
| 228 | continue; | ||
| 229 | b_if_name = strchr(b_ptr->name, ':') + 1; | ||
| 230 | if (!strcmp(b_if_name, if_name)) | ||
| 231 | return b_ptr; | ||
| 232 | } | ||
| 233 | return NULL; | ||
| 234 | } | ||
| 235 | |||
| 236 | /** | ||
| 237 | * tipc_bearer_get_names - record names of bearers in buffer | 188 | * tipc_bearer_get_names - record names of bearers in buffer |
| 238 | */ | 189 | */ |
| 239 | struct sk_buff *tipc_bearer_get_names(void) | 190 | struct sk_buff *tipc_bearer_get_names(void) |
| 240 | { | 191 | { |
| 241 | struct sk_buff *buf; | 192 | struct sk_buff *buf; |
| 242 | struct tipc_bearer *b_ptr; | 193 | struct tipc_bearer *b; |
| 243 | int i, j; | 194 | int i, j; |
| 244 | 195 | ||
| 245 | buf = tipc_cfg_reply_alloc(MAX_BEARERS * TLV_SPACE(TIPC_MAX_BEARER_NAME)); | 196 | buf = tipc_cfg_reply_alloc(MAX_BEARERS * TLV_SPACE(TIPC_MAX_BEARER_NAME)); |
| @@ -247,13 +198,13 @@ struct sk_buff *tipc_bearer_get_names(void) | |||
| 247 | return NULL; | 198 | return NULL; |
| 248 | 199 | ||
| 249 | read_lock_bh(&tipc_net_lock); | 200 | read_lock_bh(&tipc_net_lock); |
| 250 | for (i = 0; i < media_count; i++) { | 201 | for (i = 0; media_info_array[i] != NULL; i++) { |
| 251 | for (j = 0; j < MAX_BEARERS; j++) { | 202 | for (j = 0; j < MAX_BEARERS; j++) { |
| 252 | b_ptr = &tipc_bearers[j]; | 203 | b = &tipc_bearers[j]; |
| 253 | if (b_ptr->active && (b_ptr->media == media_list[i])) { | 204 | if (b->active && (b->media == media_info_array[i])) { |
| 254 | tipc_cfg_append_tlv(buf, TIPC_TLV_BEARER_NAME, | 205 | tipc_cfg_append_tlv(buf, TIPC_TLV_BEARER_NAME, |
| 255 | b_ptr->name, | 206 | b->name, |
| 256 | strlen(b_ptr->name) + 1); | 207 | strlen(b->name) + 1); |
| 257 | } | 208 | } |
| 258 | } | 209 | } |
| 259 | } | 210 | } |
| @@ -275,31 +226,6 @@ void tipc_bearer_remove_dest(struct tipc_bearer *b_ptr, u32 dest) | |||
| 275 | tipc_disc_remove_dest(b_ptr->link_req); | 226 | tipc_disc_remove_dest(b_ptr->link_req); |
| 276 | } | 227 | } |
| 277 | 228 | ||
| 278 | /* | ||
| 279 | * Interrupt enabling new requests after bearer blocking: | ||
| 280 | * See bearer_send(). | ||
| 281 | */ | ||
| 282 | void tipc_continue(struct tipc_bearer *b) | ||
| 283 | { | ||
| 284 | spin_lock_bh(&b->lock); | ||
| 285 | b->blocked = 0; | ||
| 286 | spin_unlock_bh(&b->lock); | ||
| 287 | } | ||
| 288 | |||
| 289 | /* | ||
| 290 | * tipc_bearer_blocked - determines if bearer is currently blocked | ||
| 291 | */ | ||
| 292 | int tipc_bearer_blocked(struct tipc_bearer *b) | ||
| 293 | { | ||
| 294 | int res; | ||
| 295 | |||
| 296 | spin_lock_bh(&b->lock); | ||
| 297 | res = b->blocked; | ||
| 298 | spin_unlock_bh(&b->lock); | ||
| 299 | |||
| 300 | return res; | ||
| 301 | } | ||
| 302 | |||
| 303 | /** | 229 | /** |
| 304 | * tipc_enable_bearer - enable bearer with the given name | 230 | * tipc_enable_bearer - enable bearer with the given name |
| 305 | */ | 231 | */ |
| @@ -387,6 +313,7 @@ restart: | |||
| 387 | 313 | ||
| 388 | b_ptr = &tipc_bearers[bearer_id]; | 314 | b_ptr = &tipc_bearers[bearer_id]; |
| 389 | strcpy(b_ptr->name, name); | 315 | strcpy(b_ptr->name, name); |
| 316 | b_ptr->media = m_ptr; | ||
| 390 | res = m_ptr->enable_media(b_ptr); | 317 | res = m_ptr->enable_media(b_ptr); |
| 391 | if (res) { | 318 | if (res) { |
| 392 | pr_warn("Bearer <%s> rejected, enable failure (%d)\n", | 319 | pr_warn("Bearer <%s> rejected, enable failure (%d)\n", |
| @@ -395,7 +322,6 @@ restart: | |||
| 395 | } | 322 | } |
| 396 | 323 | ||
| 397 | b_ptr->identity = bearer_id; | 324 | b_ptr->identity = bearer_id; |
| 398 | b_ptr->media = m_ptr; | ||
| 399 | b_ptr->tolerance = m_ptr->tolerance; | 325 | b_ptr->tolerance = m_ptr->tolerance; |
| 400 | b_ptr->window = m_ptr->window; | 326 | b_ptr->window = m_ptr->window; |
| 401 | b_ptr->net_plane = bearer_id + 'A'; | 327 | b_ptr->net_plane = bearer_id + 'A'; |
| @@ -420,17 +346,16 @@ exit: | |||
| 420 | } | 346 | } |
| 421 | 347 | ||
| 422 | /** | 348 | /** |
| 423 | * tipc_block_bearer - Block the bearer, and reset all its links | 349 | * tipc_reset_bearer - Reset all links established over this bearer |
| 424 | */ | 350 | */ |
| 425 | int tipc_block_bearer(struct tipc_bearer *b_ptr) | 351 | static int tipc_reset_bearer(struct tipc_bearer *b_ptr) |
| 426 | { | 352 | { |
| 427 | struct tipc_link *l_ptr; | 353 | struct tipc_link *l_ptr; |
| 428 | struct tipc_link *temp_l_ptr; | 354 | struct tipc_link *temp_l_ptr; |
| 429 | 355 | ||
| 430 | read_lock_bh(&tipc_net_lock); | 356 | read_lock_bh(&tipc_net_lock); |
| 431 | pr_info("Blocking bearer <%s>\n", b_ptr->name); | 357 | pr_info("Resetting bearer <%s>\n", b_ptr->name); |
| 432 | spin_lock_bh(&b_ptr->lock); | 358 | spin_lock_bh(&b_ptr->lock); |
| 433 | b_ptr->blocked = 1; | ||
| 434 | list_for_each_entry_safe(l_ptr, temp_l_ptr, &b_ptr->links, link_list) { | 359 | list_for_each_entry_safe(l_ptr, temp_l_ptr, &b_ptr->links, link_list) { |
| 435 | struct tipc_node *n_ptr = l_ptr->owner; | 360 | struct tipc_node *n_ptr = l_ptr->owner; |
| 436 | 361 | ||
| @@ -456,7 +381,6 @@ static void bearer_disable(struct tipc_bearer *b_ptr) | |||
| 456 | 381 | ||
| 457 | pr_info("Disabling bearer <%s>\n", b_ptr->name); | 382 | pr_info("Disabling bearer <%s>\n", b_ptr->name); |
| 458 | spin_lock_bh(&b_ptr->lock); | 383 | spin_lock_bh(&b_ptr->lock); |
| 459 | b_ptr->blocked = 1; | ||
| 460 | b_ptr->media->disable_media(b_ptr); | 384 | b_ptr->media->disable_media(b_ptr); |
| 461 | list_for_each_entry_safe(l_ptr, temp_l_ptr, &b_ptr->links, link_list) { | 385 | list_for_each_entry_safe(l_ptr, temp_l_ptr, &b_ptr->links, link_list) { |
| 462 | tipc_link_delete(l_ptr); | 386 | tipc_link_delete(l_ptr); |
| @@ -490,6 +414,211 @@ int tipc_disable_bearer(const char *name) | |||
| 490 | } | 414 | } |
| 491 | 415 | ||
| 492 | 416 | ||
| 417 | /* tipc_l2_media_addr_set - initialize Ethernet media address structure | ||
| 418 | * | ||
| 419 | * Media-dependent "value" field stores MAC address in first 6 bytes | ||
| 420 | * and zeroes out the remaining bytes. | ||
| 421 | */ | ||
| 422 | void tipc_l2_media_addr_set(const struct tipc_bearer *b, | ||
| 423 | struct tipc_media_addr *a, char *mac) | ||
| 424 | { | ||
| 425 | int len = b->media->hwaddr_len; | ||
| 426 | |||
| 427 | if (unlikely(sizeof(a->value) < len)) { | ||
| 428 | WARN_ONCE(1, "Media length invalid\n"); | ||
| 429 | return; | ||
| 430 | } | ||
| 431 | |||
| 432 | memcpy(a->value, mac, len); | ||
| 433 | memset(a->value + len, 0, sizeof(a->value) - len); | ||
| 434 | a->media_id = b->media->type_id; | ||
| 435 | a->broadcast = !memcmp(mac, b->bcast_addr.value, len); | ||
| 436 | } | ||
| 437 | |||
| 438 | int tipc_enable_l2_media(struct tipc_bearer *b) | ||
| 439 | { | ||
| 440 | struct net_device *dev; | ||
| 441 | char *driver_name = strchr((const char *)b->name, ':') + 1; | ||
| 442 | |||
| 443 | /* Find device with specified name */ | ||
| 444 | dev = dev_get_by_name(&init_net, driver_name); | ||
| 445 | if (!dev) | ||
| 446 | return -ENODEV; | ||
| 447 | |||
| 448 | /* Associate TIPC bearer with Ethernet bearer */ | ||
| 449 | b->media_ptr = dev; | ||
| 450 | memset(b->bcast_addr.value, 0, sizeof(b->bcast_addr.value)); | ||
| 451 | memcpy(b->bcast_addr.value, dev->broadcast, b->media->hwaddr_len); | ||
| 452 | b->bcast_addr.media_id = b->media->type_id; | ||
| 453 | b->bcast_addr.broadcast = 1; | ||
| 454 | b->mtu = dev->mtu; | ||
| 455 | tipc_l2_media_addr_set(b, &b->addr, (char *)dev->dev_addr); | ||
| 456 | rcu_assign_pointer(dev->tipc_ptr, b); | ||
| 457 | return 0; | ||
| 458 | } | ||
| 459 | |||
| 460 | /* tipc_disable_l2_media - detach TIPC bearer from an Ethernet interface | ||
| 461 | * | ||
| 462 | * Mark Ethernet bearer as inactive so that incoming buffers are thrown away, | ||
| 463 | * then get worker thread to complete bearer cleanup. (Can't do cleanup | ||
| 464 | * here because cleanup code needs to sleep and caller holds spinlocks.) | ||
| 465 | */ | ||
| 466 | void tipc_disable_l2_media(struct tipc_bearer *b) | ||
| 467 | { | ||
| 468 | struct net_device *dev = (struct net_device *)b->media_ptr; | ||
| 469 | RCU_INIT_POINTER(dev->tipc_ptr, NULL); | ||
| 470 | dev_put(dev); | ||
| 471 | } | ||
| 472 | |||
| 473 | /** | ||
| 474 | * tipc_l2_send_msg - send a TIPC packet out over an Ethernet interface | ||
| 475 | * @buf: the packet to be sent | ||
| 476 | * @b_ptr: the bearer through which the packet is to be sent | ||
| 477 | * @dest: peer destination address | ||
| 478 | */ | ||
| 479 | int tipc_l2_send_msg(struct sk_buff *buf, struct tipc_bearer *b, | ||
| 480 | struct tipc_media_addr *dest) | ||
| 481 | { | ||
| 482 | struct sk_buff *clone; | ||
| 483 | int delta; | ||
| 484 | struct net_device *dev = (struct net_device *)b->media_ptr; | ||
| 485 | |||
| 486 | clone = skb_clone(buf, GFP_ATOMIC); | ||
| 487 | if (!clone) | ||
| 488 | return 0; | ||
| 489 | |||
| 490 | delta = dev->hard_header_len - skb_headroom(buf); | ||
| 491 | if ((delta > 0) && | ||
| 492 | pskb_expand_head(clone, SKB_DATA_ALIGN(delta), 0, GFP_ATOMIC)) { | ||
| 493 | kfree_skb(clone); | ||
| 494 | return 0; | ||
| 495 | } | ||
| 496 | |||
| 497 | skb_reset_network_header(clone); | ||
| 498 | clone->dev = dev; | ||
| 499 | clone->protocol = htons(ETH_P_TIPC); | ||
| 500 | dev_hard_header(clone, dev, ETH_P_TIPC, dest->value, | ||
| 501 | dev->dev_addr, clone->len); | ||
| 502 | dev_queue_xmit(clone); | ||
| 503 | return 0; | ||
| 504 | } | ||
| 505 | |||
| 506 | /* tipc_bearer_send- sends buffer to destination over bearer | ||
| 507 | * | ||
| 508 | * IMPORTANT: | ||
| 509 | * The media send routine must not alter the buffer being passed in | ||
| 510 | * as it may be needed for later retransmission! | ||
| 511 | */ | ||
| 512 | void tipc_bearer_send(struct tipc_bearer *b, struct sk_buff *buf, | ||
| 513 | struct tipc_media_addr *dest) | ||
| 514 | { | ||
| 515 | b->media->send_msg(buf, b, dest); | ||
| 516 | } | ||
| 517 | |||
| 518 | /** | ||
| 519 | * tipc_l2_rcv_msg - handle incoming TIPC message from an interface | ||
| 520 | * @buf: the received packet | ||
| 521 | * @dev: the net device that the packet was received on | ||
| 522 | * @pt: the packet_type structure which was used to register this handler | ||
| 523 | * @orig_dev: the original receive net device in case the device is a bond | ||
| 524 | * | ||
| 525 | * Accept only packets explicitly sent to this node, or broadcast packets; | ||
| 526 | * ignores packets sent using interface multicast, and traffic sent to other | ||
| 527 | * nodes (which can happen if interface is running in promiscuous mode). | ||
| 528 | */ | ||
| 529 | static int tipc_l2_rcv_msg(struct sk_buff *buf, struct net_device *dev, | ||
| 530 | struct packet_type *pt, struct net_device *orig_dev) | ||
| 531 | { | ||
| 532 | struct tipc_bearer *b_ptr; | ||
| 533 | |||
| 534 | if (!net_eq(dev_net(dev), &init_net)) { | ||
| 535 | kfree_skb(buf); | ||
| 536 | return NET_RX_DROP; | ||
| 537 | } | ||
| 538 | |||
| 539 | rcu_read_lock(); | ||
| 540 | b_ptr = rcu_dereference(dev->tipc_ptr); | ||
| 541 | if (likely(b_ptr)) { | ||
| 542 | if (likely(buf->pkt_type <= PACKET_BROADCAST)) { | ||
| 543 | buf->next = NULL; | ||
| 544 | tipc_rcv(buf, b_ptr); | ||
| 545 | rcu_read_unlock(); | ||
| 546 | return NET_RX_SUCCESS; | ||
| 547 | } | ||
| 548 | } | ||
| 549 | rcu_read_unlock(); | ||
| 550 | |||
| 551 | kfree_skb(buf); | ||
| 552 | return NET_RX_DROP; | ||
| 553 | } | ||
| 554 | |||
| 555 | /** | ||
| 556 | * tipc_l2_device_event - handle device events from network device | ||
| 557 | * @nb: the context of the notification | ||
| 558 | * @evt: the type of event | ||
| 559 | * @ptr: the net device that the event was on | ||
| 560 | * | ||
| 561 | * This function is called by the Ethernet driver in case of link | ||
| 562 | * change event. | ||
| 563 | */ | ||
| 564 | static int tipc_l2_device_event(struct notifier_block *nb, unsigned long evt, | ||
| 565 | void *ptr) | ||
| 566 | { | ||
| 567 | struct tipc_bearer *b_ptr; | ||
| 568 | struct net_device *dev = netdev_notifier_info_to_dev(ptr); | ||
| 569 | |||
| 570 | if (!net_eq(dev_net(dev), &init_net)) | ||
| 571 | return NOTIFY_DONE; | ||
| 572 | |||
| 573 | rcu_read_lock(); | ||
| 574 | b_ptr = rcu_dereference(dev->tipc_ptr); | ||
| 575 | if (!b_ptr) { | ||
| 576 | rcu_read_unlock(); | ||
| 577 | return NOTIFY_DONE; | ||
| 578 | } | ||
| 579 | |||
| 580 | b_ptr->mtu = dev->mtu; | ||
| 581 | |||
| 582 | switch (evt) { | ||
| 583 | case NETDEV_CHANGE: | ||
| 584 | if (netif_carrier_ok(dev)) | ||
| 585 | break; | ||
| 586 | case NETDEV_DOWN: | ||
| 587 | case NETDEV_CHANGEMTU: | ||
| 588 | case NETDEV_CHANGEADDR: | ||
| 589 | tipc_reset_bearer(b_ptr); | ||
| 590 | break; | ||
| 591 | case NETDEV_UNREGISTER: | ||
| 592 | case NETDEV_CHANGENAME: | ||
| 593 | tipc_disable_bearer(b_ptr->name); | ||
| 594 | break; | ||
| 595 | } | ||
| 596 | rcu_read_unlock(); | ||
| 597 | |||
| 598 | return NOTIFY_OK; | ||
| 599 | } | ||
| 600 | |||
| 601 | static struct packet_type tipc_packet_type __read_mostly = { | ||
| 602 | .type = __constant_htons(ETH_P_TIPC), | ||
| 603 | .func = tipc_l2_rcv_msg, | ||
| 604 | }; | ||
| 605 | |||
| 606 | static struct notifier_block notifier = { | ||
| 607 | .notifier_call = tipc_l2_device_event, | ||
| 608 | .priority = 0, | ||
| 609 | }; | ||
| 610 | |||
| 611 | int tipc_bearer_setup(void) | ||
| 612 | { | ||
| 613 | dev_add_pack(&tipc_packet_type); | ||
| 614 | return register_netdevice_notifier(¬ifier); | ||
| 615 | } | ||
| 616 | |||
| 617 | void tipc_bearer_cleanup(void) | ||
| 618 | { | ||
| 619 | unregister_netdevice_notifier(¬ifier); | ||
| 620 | dev_remove_pack(&tipc_packet_type); | ||
| 621 | } | ||
| 493 | 622 | ||
| 494 | void tipc_bearer_stop(void) | 623 | void tipc_bearer_stop(void) |
| 495 | { | 624 | { |
| @@ -499,5 +628,4 @@ void tipc_bearer_stop(void) | |||
| 499 | if (tipc_bearers[i].active) | 628 | if (tipc_bearers[i].active) |
| 500 | bearer_disable(&tipc_bearers[i]); | 629 | bearer_disable(&tipc_bearers[i]); |
| 501 | } | 630 | } |
| 502 | media_count = 0; | ||
| 503 | } | 631 | } |
diff --git a/net/tipc/bearer.h b/net/tipc/bearer.h index e5e04be6fffa..4f5db9ad5bf6 100644 --- a/net/tipc/bearer.h +++ b/net/tipc/bearer.h | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * net/tipc/bearer.h: Include file for TIPC bearer code | 2 | * net/tipc/bearer.h: Include file for TIPC bearer code |
| 3 | * | 3 | * |
| 4 | * Copyright (c) 1996-2006, Ericsson AB | 4 | * Copyright (c) 1996-2006, 2013, Ericsson AB |
| 5 | * Copyright (c) 2005, 2010-2011, Wind River Systems | 5 | * Copyright (c) 2005, 2010-2011, Wind River Systems |
| 6 | * All rights reserved. | 6 | * All rights reserved. |
| 7 | * | 7 | * |
| @@ -73,18 +73,18 @@ struct tipc_media_addr { | |||
| 73 | struct tipc_bearer; | 73 | struct tipc_bearer; |
| 74 | 74 | ||
| 75 | /** | 75 | /** |
| 76 | * struct tipc_media - TIPC media information available to internal users | 76 | * struct tipc_media - Media specific info exposed to generic bearer layer |
| 77 | * @send_msg: routine which handles buffer transmission | 77 | * @send_msg: routine which handles buffer transmission |
| 78 | * @enable_media: routine which enables a media | 78 | * @enable_media: routine which enables a media |
| 79 | * @disable_media: routine which disables a media | 79 | * @disable_media: routine which disables a media |
| 80 | * @addr2str: routine which converts media address to string | 80 | * @addr2str: routine which converts media address to string |
| 81 | * @addr2msg: routine which converts media address to protocol message area | 81 | * @addr2msg: routine which converts media address to protocol message area |
| 82 | * @msg2addr: routine which converts media address from protocol message area | 82 | * @msg2addr: routine which converts media address from protocol message area |
| 83 | * @bcast_addr: media address used in broadcasting | ||
| 84 | * @priority: default link (and bearer) priority | 83 | * @priority: default link (and bearer) priority |
| 85 | * @tolerance: default time (in ms) before declaring link failure | 84 | * @tolerance: default time (in ms) before declaring link failure |
| 86 | * @window: default window (in packets) before declaring link congestion | 85 | * @window: default window (in packets) before declaring link congestion |
| 87 | * @type_id: TIPC media identifier | 86 | * @type_id: TIPC media identifier |
| 87 | * @hwaddr_len: TIPC media address len | ||
| 88 | * @name: media name | 88 | * @name: media name |
| 89 | */ | 89 | */ |
| 90 | struct tipc_media { | 90 | struct tipc_media { |
| @@ -101,18 +101,20 @@ struct tipc_media { | |||
| 101 | u32 tolerance; | 101 | u32 tolerance; |
| 102 | u32 window; | 102 | u32 window; |
| 103 | u32 type_id; | 103 | u32 type_id; |
| 104 | u32 hwaddr_len; | ||
| 104 | char name[TIPC_MAX_MEDIA_NAME]; | 105 | char name[TIPC_MAX_MEDIA_NAME]; |
| 105 | }; | 106 | }; |
| 106 | 107 | ||
| 107 | /** | 108 | /** |
| 108 | * struct tipc_bearer - TIPC bearer structure | 109 | * struct tipc_bearer - Generic TIPC bearer structure |
| 110 | * @dev: ptr to associated network device | ||
| 109 | * @usr_handle: pointer to additional media-specific information about bearer | 111 | * @usr_handle: pointer to additional media-specific information about bearer |
| 110 | * @mtu: max packet size bearer can support | 112 | * @mtu: max packet size bearer can support |
| 111 | * @blocked: non-zero if bearer is blocked | ||
| 112 | * @lock: spinlock for controlling access to bearer | 113 | * @lock: spinlock for controlling access to bearer |
| 113 | * @addr: media-specific address associated with bearer | 114 | * @addr: media-specific address associated with bearer |
| 114 | * @name: bearer name (format = media:interface) | 115 | * @name: bearer name (format = media:interface) |
| 115 | * @media: ptr to media structure associated with bearer | 116 | * @media: ptr to media structure associated with bearer |
| 117 | * @bcast_addr: media address used in broadcasting | ||
| 116 | * @priority: default link priority for bearer | 118 | * @priority: default link priority for bearer |
| 117 | * @window: default window size for bearer | 119 | * @window: default window size for bearer |
| 118 | * @tolerance: default link tolerance for bearer | 120 | * @tolerance: default link tolerance for bearer |
| @@ -128,9 +130,8 @@ struct tipc_media { | |||
| 128 | * care of initializing all other fields. | 130 | * care of initializing all other fields. |
| 129 | */ | 131 | */ |
| 130 | struct tipc_bearer { | 132 | struct tipc_bearer { |
| 131 | void *usr_handle; /* initalized by media */ | 133 | void *media_ptr; /* initalized by media */ |
| 132 | u32 mtu; /* initalized by media */ | 134 | u32 mtu; /* initalized by media */ |
| 133 | int blocked; /* initalized by media */ | ||
| 134 | struct tipc_media_addr addr; /* initalized by media */ | 135 | struct tipc_media_addr addr; /* initalized by media */ |
| 135 | char name[TIPC_MAX_BEARER_NAME]; | 136 | char name[TIPC_MAX_BEARER_NAME]; |
| 136 | spinlock_t lock; | 137 | spinlock_t lock; |
| @@ -159,55 +160,40 @@ extern struct tipc_bearer tipc_bearers[]; | |||
| 159 | /* | 160 | /* |
| 160 | * TIPC routines available to supported media types | 161 | * TIPC routines available to supported media types |
| 161 | */ | 162 | */ |
| 162 | int tipc_register_media(struct tipc_media *m_ptr); | ||
| 163 | |||
| 164 | void tipc_recv_msg(struct sk_buff *buf, struct tipc_bearer *tb_ptr); | ||
| 165 | |||
| 166 | int tipc_block_bearer(struct tipc_bearer *b_ptr); | ||
| 167 | void tipc_continue(struct tipc_bearer *tb_ptr); | ||
| 168 | 163 | ||
| 164 | void tipc_rcv(struct sk_buff *buf, struct tipc_bearer *tb_ptr); | ||
| 169 | int tipc_enable_bearer(const char *bearer_name, u32 disc_domain, u32 priority); | 165 | int tipc_enable_bearer(const char *bearer_name, u32 disc_domain, u32 priority); |
| 170 | int tipc_disable_bearer(const char *name); | 166 | int tipc_disable_bearer(const char *name); |
| 171 | 167 | ||
| 172 | /* | 168 | /* |
| 173 | * Routines made available to TIPC by supported media types | 169 | * Routines made available to TIPC by supported media types |
| 174 | */ | 170 | */ |
| 175 | int tipc_eth_media_start(void); | 171 | extern struct tipc_media eth_media_info; |
| 176 | void tipc_eth_media_stop(void); | ||
| 177 | 172 | ||
| 178 | #ifdef CONFIG_TIPC_MEDIA_IB | 173 | #ifdef CONFIG_TIPC_MEDIA_IB |
| 179 | int tipc_ib_media_start(void); | 174 | extern struct tipc_media ib_media_info; |
| 180 | void tipc_ib_media_stop(void); | ||
| 181 | #else | ||
| 182 | static inline int tipc_ib_media_start(void) { return 0; } | ||
| 183 | static inline void tipc_ib_media_stop(void) { return; } | ||
| 184 | #endif | 175 | #endif |
| 185 | 176 | ||
| 186 | int tipc_media_set_priority(const char *name, u32 new_value); | 177 | int tipc_media_set_priority(const char *name, u32 new_value); |
| 187 | int tipc_media_set_window(const char *name, u32 new_value); | 178 | int tipc_media_set_window(const char *name, u32 new_value); |
| 188 | void tipc_media_addr_printf(char *buf, int len, struct tipc_media_addr *a); | 179 | void tipc_media_addr_printf(char *buf, int len, struct tipc_media_addr *a); |
| 189 | struct sk_buff *tipc_media_get_names(void); | 180 | struct sk_buff *tipc_media_get_names(void); |
| 181 | void tipc_l2_media_addr_set(const struct tipc_bearer *b, | ||
| 182 | struct tipc_media_addr *a, char *mac); | ||
| 183 | int tipc_enable_l2_media(struct tipc_bearer *b); | ||
| 184 | void tipc_disable_l2_media(struct tipc_bearer *b); | ||
| 185 | int tipc_l2_send_msg(struct sk_buff *buf, struct tipc_bearer *b, | ||
| 186 | struct tipc_media_addr *dest); | ||
| 190 | 187 | ||
| 191 | struct sk_buff *tipc_bearer_get_names(void); | 188 | struct sk_buff *tipc_bearer_get_names(void); |
| 192 | void tipc_bearer_add_dest(struct tipc_bearer *b_ptr, u32 dest); | 189 | void tipc_bearer_add_dest(struct tipc_bearer *b_ptr, u32 dest); |
| 193 | void tipc_bearer_remove_dest(struct tipc_bearer *b_ptr, u32 dest); | 190 | void tipc_bearer_remove_dest(struct tipc_bearer *b_ptr, u32 dest); |
| 194 | struct tipc_bearer *tipc_bearer_find(const char *name); | 191 | struct tipc_bearer *tipc_bearer_find(const char *name); |
| 195 | struct tipc_bearer *tipc_bearer_find_interface(const char *if_name); | ||
| 196 | struct tipc_media *tipc_media_find(const char *name); | 192 | struct tipc_media *tipc_media_find(const char *name); |
| 197 | int tipc_bearer_blocked(struct tipc_bearer *b_ptr); | 193 | int tipc_bearer_setup(void); |
| 194 | void tipc_bearer_cleanup(void); | ||
| 198 | void tipc_bearer_stop(void); | 195 | void tipc_bearer_stop(void); |
| 199 | 196 | void tipc_bearer_send(struct tipc_bearer *b, struct sk_buff *buf, | |
| 200 | /** | 197 | struct tipc_media_addr *dest); |
| 201 | * tipc_bearer_send- sends buffer to destination over bearer | ||
| 202 | * | ||
| 203 | * IMPORTANT: | ||
| 204 | * The media send routine must not alter the buffer being passed in | ||
| 205 | * as it may be needed for later retransmission! | ||
| 206 | */ | ||
| 207 | static inline void tipc_bearer_send(struct tipc_bearer *b, struct sk_buff *buf, | ||
| 208 | struct tipc_media_addr *dest) | ||
| 209 | { | ||
| 210 | b->media->send_msg(buf, b, dest); | ||
| 211 | } | ||
| 212 | 198 | ||
| 213 | #endif /* _TIPC_BEARER_H */ | 199 | #endif /* _TIPC_BEARER_H */ |
diff --git a/net/tipc/core.c b/net/tipc/core.c index c6d3f75a9e1b..f9e88d8b04ca 100644 --- a/net/tipc/core.c +++ b/net/tipc/core.c | |||
| @@ -82,8 +82,7 @@ struct sk_buff *tipc_buf_acquire(u32 size) | |||
| 82 | static void tipc_core_stop_net(void) | 82 | static void tipc_core_stop_net(void) |
| 83 | { | 83 | { |
| 84 | tipc_net_stop(); | 84 | tipc_net_stop(); |
| 85 | tipc_eth_media_stop(); | 85 | tipc_bearer_cleanup(); |
| 86 | tipc_ib_media_stop(); | ||
| 87 | } | 86 | } |
| 88 | 87 | ||
| 89 | /** | 88 | /** |
| @@ -94,10 +93,7 @@ int tipc_core_start_net(unsigned long addr) | |||
| 94 | int res; | 93 | int res; |
| 95 | 94 | ||
| 96 | tipc_net_start(addr); | 95 | tipc_net_start(addr); |
| 97 | res = tipc_eth_media_start(); | 96 | res = tipc_bearer_setup(); |
| 98 | if (res < 0) | ||
| 99 | goto err; | ||
| 100 | res = tipc_ib_media_start(); | ||
| 101 | if (res < 0) | 97 | if (res < 0) |
| 102 | goto err; | 98 | goto err; |
| 103 | return res; | 99 | return res; |
diff --git a/net/tipc/core.h b/net/tipc/core.h index 94895d4e86ab..1ff477b0450d 100644 --- a/net/tipc/core.h +++ b/net/tipc/core.h | |||
| @@ -47,7 +47,7 @@ | |||
| 47 | #include <linux/mm.h> | 47 | #include <linux/mm.h> |
| 48 | #include <linux/timer.h> | 48 | #include <linux/timer.h> |
| 49 | #include <linux/string.h> | 49 | #include <linux/string.h> |
| 50 | #include <asm/uaccess.h> | 50 | #include <linux/uaccess.h> |
| 51 | #include <linux/interrupt.h> | 51 | #include <linux/interrupt.h> |
| 52 | #include <linux/atomic.h> | 52 | #include <linux/atomic.h> |
| 53 | #include <asm/hardirq.h> | 53 | #include <asm/hardirq.h> |
diff --git a/net/tipc/discover.c b/net/tipc/discover.c index ecc758c6eacf..412ff41b8611 100644 --- a/net/tipc/discover.c +++ b/net/tipc/discover.c | |||
| @@ -50,6 +50,7 @@ | |||
| 50 | * @dest: destination address for request messages | 50 | * @dest: destination address for request messages |
| 51 | * @domain: network domain to which links can be established | 51 | * @domain: network domain to which links can be established |
| 52 | * @num_nodes: number of nodes currently discovered (i.e. with an active link) | 52 | * @num_nodes: number of nodes currently discovered (i.e. with an active link) |
| 53 | * @lock: spinlock for controlling access to requests | ||
| 53 | * @buf: request message to be (repeatedly) sent | 54 | * @buf: request message to be (repeatedly) sent |
| 54 | * @timer: timer governing period between requests | 55 | * @timer: timer governing period between requests |
| 55 | * @timer_intv: current interval between requests (in ms) | 56 | * @timer_intv: current interval between requests (in ms) |
| @@ -59,6 +60,7 @@ struct tipc_link_req { | |||
| 59 | struct tipc_media_addr dest; | 60 | struct tipc_media_addr dest; |
| 60 | u32 domain; | 61 | u32 domain; |
| 61 | int num_nodes; | 62 | int num_nodes; |
| 63 | spinlock_t lock; | ||
| 62 | struct sk_buff *buf; | 64 | struct sk_buff *buf; |
| 63 | struct timer_list timer; | 65 | struct timer_list timer; |
| 64 | unsigned int timer_intv; | 66 | unsigned int timer_intv; |
| @@ -239,7 +241,7 @@ void tipc_disc_recv_msg(struct sk_buff *buf, struct tipc_bearer *b_ptr) | |||
| 239 | /* Accept discovery message & send response, if necessary */ | 241 | /* Accept discovery message & send response, if necessary */ |
| 240 | link_fully_up = link_working_working(link); | 242 | link_fully_up = link_working_working(link); |
| 241 | 243 | ||
| 242 | if ((type == DSC_REQ_MSG) && !link_fully_up && !b_ptr->blocked) { | 244 | if ((type == DSC_REQ_MSG) && !link_fully_up) { |
| 243 | rbuf = tipc_disc_init_msg(DSC_RESP_MSG, orig, b_ptr); | 245 | rbuf = tipc_disc_init_msg(DSC_RESP_MSG, orig, b_ptr); |
| 244 | if (rbuf) { | 246 | if (rbuf) { |
| 245 | tipc_bearer_send(b_ptr, rbuf, &media_addr); | 247 | tipc_bearer_send(b_ptr, rbuf, &media_addr); |
| @@ -274,7 +276,9 @@ static void disc_update(struct tipc_link_req *req) | |||
| 274 | */ | 276 | */ |
| 275 | void tipc_disc_add_dest(struct tipc_link_req *req) | 277 | void tipc_disc_add_dest(struct tipc_link_req *req) |
| 276 | { | 278 | { |
| 279 | spin_lock_bh(&req->lock); | ||
| 277 | req->num_nodes++; | 280 | req->num_nodes++; |
| 281 | spin_unlock_bh(&req->lock); | ||
| 278 | } | 282 | } |
| 279 | 283 | ||
| 280 | /** | 284 | /** |
| @@ -283,18 +287,10 @@ void tipc_disc_add_dest(struct tipc_link_req *req) | |||
| 283 | */ | 287 | */ |
| 284 | void tipc_disc_remove_dest(struct tipc_link_req *req) | 288 | void tipc_disc_remove_dest(struct tipc_link_req *req) |
| 285 | { | 289 | { |
| 290 | spin_lock_bh(&req->lock); | ||
| 286 | req->num_nodes--; | 291 | req->num_nodes--; |
| 287 | disc_update(req); | 292 | disc_update(req); |
| 288 | } | 293 | spin_unlock_bh(&req->lock); |
| 289 | |||
| 290 | /** | ||
| 291 | * disc_send_msg - send link setup request message | ||
| 292 | * @req: ptr to link request structure | ||
| 293 | */ | ||
| 294 | static void disc_send_msg(struct tipc_link_req *req) | ||
| 295 | { | ||
| 296 | if (!req->bearer->blocked) | ||
| 297 | tipc_bearer_send(req->bearer, req->buf, &req->dest); | ||
| 298 | } | 294 | } |
| 299 | 295 | ||
| 300 | /** | 296 | /** |
| @@ -307,7 +303,7 @@ static void disc_timeout(struct tipc_link_req *req) | |||
| 307 | { | 303 | { |
| 308 | int max_delay; | 304 | int max_delay; |
| 309 | 305 | ||
| 310 | spin_lock_bh(&req->bearer->lock); | 306 | spin_lock_bh(&req->lock); |
| 311 | 307 | ||
| 312 | /* Stop searching if only desired node has been found */ | 308 | /* Stop searching if only desired node has been found */ |
| 313 | if (tipc_node(req->domain) && req->num_nodes) { | 309 | if (tipc_node(req->domain) && req->num_nodes) { |
| @@ -322,7 +318,8 @@ static void disc_timeout(struct tipc_link_req *req) | |||
| 322 | * hold at fast polling rate if don't have any associated nodes, | 318 | * hold at fast polling rate if don't have any associated nodes, |
| 323 | * otherwise hold at slow polling rate | 319 | * otherwise hold at slow polling rate |
| 324 | */ | 320 | */ |
| 325 | disc_send_msg(req); | 321 | tipc_bearer_send(req->bearer, req->buf, &req->dest); |
| 322 | |||
| 326 | 323 | ||
| 327 | req->timer_intv *= 2; | 324 | req->timer_intv *= 2; |
| 328 | if (req->num_nodes) | 325 | if (req->num_nodes) |
| @@ -334,7 +331,7 @@ static void disc_timeout(struct tipc_link_req *req) | |||
| 334 | 331 | ||
| 335 | k_start_timer(&req->timer, req->timer_intv); | 332 | k_start_timer(&req->timer, req->timer_intv); |
| 336 | exit: | 333 | exit: |
| 337 | spin_unlock_bh(&req->bearer->lock); | 334 | spin_unlock_bh(&req->lock); |
| 338 | } | 335 | } |
| 339 | 336 | ||
| 340 | /** | 337 | /** |
| @@ -365,10 +362,11 @@ int tipc_disc_create(struct tipc_bearer *b_ptr, struct tipc_media_addr *dest, | |||
| 365 | req->domain = dest_domain; | 362 | req->domain = dest_domain; |
| 366 | req->num_nodes = 0; | 363 | req->num_nodes = 0; |
| 367 | req->timer_intv = TIPC_LINK_REQ_INIT; | 364 | req->timer_intv = TIPC_LINK_REQ_INIT; |
| 365 | spin_lock_init(&req->lock); | ||
| 368 | k_init_timer(&req->timer, (Handler)disc_timeout, (unsigned long)req); | 366 | k_init_timer(&req->timer, (Handler)disc_timeout, (unsigned long)req); |
| 369 | k_start_timer(&req->timer, req->timer_intv); | 367 | k_start_timer(&req->timer, req->timer_intv); |
| 370 | b_ptr->link_req = req; | 368 | b_ptr->link_req = req; |
| 371 | disc_send_msg(req); | 369 | tipc_bearer_send(req->bearer, req->buf, &req->dest); |
| 372 | return 0; | 370 | return 0; |
| 373 | } | 371 | } |
| 374 | 372 | ||
diff --git a/net/tipc/eth_media.c b/net/tipc/eth_media.c index f80d59f5a161..67cf3f935dba 100644 --- a/net/tipc/eth_media.c +++ b/net/tipc/eth_media.c | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * net/tipc/eth_media.c: Ethernet bearer support for TIPC | 2 | * net/tipc/eth_media.c: Ethernet bearer support for TIPC |
| 3 | * | 3 | * |
| 4 | * Copyright (c) 2001-2007, Ericsson AB | 4 | * Copyright (c) 2001-2007, 2013, Ericsson AB |
| 5 | * Copyright (c) 2005-2008, 2011-2013, Wind River Systems | 5 | * Copyright (c) 2005-2008, 2011-2013, Wind River Systems |
| 6 | * All rights reserved. | 6 | * All rights reserved. |
| 7 | * | 7 | * |
| @@ -37,259 +37,11 @@ | |||
| 37 | #include "core.h" | 37 | #include "core.h" |
| 38 | #include "bearer.h" | 38 | #include "bearer.h" |
| 39 | 39 | ||
| 40 | #define MAX_ETH_MEDIA MAX_BEARERS | ||
| 41 | |||
| 42 | #define ETH_ADDR_OFFSET 4 /* message header offset of MAC address */ | 40 | #define ETH_ADDR_OFFSET 4 /* message header offset of MAC address */ |
| 43 | 41 | ||
| 44 | /** | 42 | /* convert Ethernet address to string */ |
| 45 | * struct eth_media - Ethernet bearer data structure | 43 | static int tipc_eth_addr2str(struct tipc_media_addr *a, char *str_buf, |
| 46 | * @bearer: ptr to associated "generic" bearer structure | 44 | int str_size) |
| 47 | * @dev: ptr to associated Ethernet network device | ||
| 48 | * @tipc_packet_type: used in binding TIPC to Ethernet driver | ||
| 49 | * @setup: work item used when enabling bearer | ||
| 50 | * @cleanup: work item used when disabling bearer | ||
| 51 | */ | ||
| 52 | struct eth_media { | ||
| 53 | struct tipc_bearer *bearer; | ||
| 54 | struct net_device *dev; | ||
| 55 | struct packet_type tipc_packet_type; | ||
| 56 | struct work_struct setup; | ||
| 57 | struct work_struct cleanup; | ||
| 58 | }; | ||
| 59 | |||
| 60 | static struct tipc_media eth_media_info; | ||
| 61 | static struct eth_media eth_media_array[MAX_ETH_MEDIA]; | ||
| 62 | static int eth_started; | ||
| 63 | |||
| 64 | static int recv_notification(struct notifier_block *nb, unsigned long evt, | ||
| 65 | void *dv); | ||
| 66 | /* | ||
| 67 | * Network device notifier info | ||
| 68 | */ | ||
| 69 | static struct notifier_block notifier = { | ||
| 70 | .notifier_call = recv_notification, | ||
| 71 | .priority = 0 | ||
| 72 | }; | ||
| 73 | |||
| 74 | /** | ||
| 75 | * eth_media_addr_set - initialize Ethernet media address structure | ||
| 76 | * | ||
| 77 | * Media-dependent "value" field stores MAC address in first 6 bytes | ||
| 78 | * and zeroes out the remaining bytes. | ||
| 79 | */ | ||
| 80 | static void eth_media_addr_set(const struct tipc_bearer *tb_ptr, | ||
| 81 | struct tipc_media_addr *a, char *mac) | ||
| 82 | { | ||
| 83 | memcpy(a->value, mac, ETH_ALEN); | ||
| 84 | memset(a->value + ETH_ALEN, 0, sizeof(a->value) - ETH_ALEN); | ||
| 85 | a->media_id = TIPC_MEDIA_TYPE_ETH; | ||
| 86 | a->broadcast = !memcmp(mac, tb_ptr->bcast_addr.value, ETH_ALEN); | ||
| 87 | } | ||
| 88 | |||
| 89 | /** | ||
| 90 | * send_msg - send a TIPC message out over an Ethernet interface | ||
| 91 | */ | ||
| 92 | static int send_msg(struct sk_buff *buf, struct tipc_bearer *tb_ptr, | ||
| 93 | struct tipc_media_addr *dest) | ||
| 94 | { | ||
| 95 | struct sk_buff *clone; | ||
| 96 | struct net_device *dev; | ||
| 97 | int delta; | ||
| 98 | |||
| 99 | clone = skb_clone(buf, GFP_ATOMIC); | ||
| 100 | if (!clone) | ||
| 101 | return 0; | ||
| 102 | |||
| 103 | dev = ((struct eth_media *)(tb_ptr->usr_handle))->dev; | ||
| 104 | delta = dev->hard_header_len - skb_headroom(buf); | ||
| 105 | |||
| 106 | if ((delta > 0) && | ||
| 107 | pskb_expand_head(clone, SKB_DATA_ALIGN(delta), 0, GFP_ATOMIC)) { | ||
| 108 | kfree_skb(clone); | ||
| 109 | return 0; | ||
| 110 | } | ||
| 111 | |||
| 112 | skb_reset_network_header(clone); | ||
| 113 | clone->dev = dev; | ||
| 114 | clone->protocol = htons(ETH_P_TIPC); | ||
| 115 | dev_hard_header(clone, dev, ETH_P_TIPC, dest->value, | ||
| 116 | dev->dev_addr, clone->len); | ||
| 117 | dev_queue_xmit(clone); | ||
| 118 | return 0; | ||
| 119 | } | ||
| 120 | |||
| 121 | /** | ||
| 122 | * recv_msg - handle incoming TIPC message from an Ethernet interface | ||
| 123 | * | ||
| 124 | * Accept only packets explicitly sent to this node, or broadcast packets; | ||
| 125 | * ignores packets sent using Ethernet multicast, and traffic sent to other | ||
| 126 | * nodes (which can happen if interface is running in promiscuous mode). | ||
| 127 | */ | ||
| 128 | static int recv_msg(struct sk_buff *buf, struct net_device *dev, | ||
| 129 | struct packet_type *pt, struct net_device *orig_dev) | ||
| 130 | { | ||
| 131 | struct eth_media *eb_ptr = (struct eth_media *)pt->af_packet_priv; | ||
| 132 | |||
| 133 | if (!net_eq(dev_net(dev), &init_net)) { | ||
| 134 | kfree_skb(buf); | ||
| 135 | return NET_RX_DROP; | ||
| 136 | } | ||
| 137 | |||
| 138 | if (likely(eb_ptr->bearer)) { | ||
| 139 | if (likely(buf->pkt_type <= PACKET_BROADCAST)) { | ||
| 140 | buf->next = NULL; | ||
| 141 | tipc_recv_msg(buf, eb_ptr->bearer); | ||
| 142 | return NET_RX_SUCCESS; | ||
| 143 | } | ||
| 144 | } | ||
| 145 | kfree_skb(buf); | ||
| 146 | return NET_RX_DROP; | ||
| 147 | } | ||
| 148 | |||
| 149 | /** | ||
| 150 | * setup_media - setup association between Ethernet bearer and interface | ||
| 151 | */ | ||
| 152 | static void setup_media(struct work_struct *work) | ||
| 153 | { | ||
| 154 | struct eth_media *eb_ptr = | ||
| 155 | container_of(work, struct eth_media, setup); | ||
| 156 | |||
| 157 | dev_add_pack(&eb_ptr->tipc_packet_type); | ||
| 158 | } | ||
| 159 | |||
| 160 | /** | ||
| 161 | * enable_media - attach TIPC bearer to an Ethernet interface | ||
| 162 | */ | ||
| 163 | static int enable_media(struct tipc_bearer *tb_ptr) | ||
| 164 | { | ||
| 165 | struct net_device *dev; | ||
| 166 | struct eth_media *eb_ptr = ð_media_array[0]; | ||
| 167 | struct eth_media *stop = ð_media_array[MAX_ETH_MEDIA]; | ||
| 168 | char *driver_name = strchr((const char *)tb_ptr->name, ':') + 1; | ||
| 169 | int pending_dev = 0; | ||
| 170 | |||
| 171 | /* Find unused Ethernet bearer structure */ | ||
| 172 | while (eb_ptr->dev) { | ||
| 173 | if (!eb_ptr->bearer) | ||
| 174 | pending_dev++; | ||
| 175 | if (++eb_ptr == stop) | ||
| 176 | return pending_dev ? -EAGAIN : -EDQUOT; | ||
| 177 | } | ||
| 178 | |||
| 179 | /* Find device with specified name */ | ||
| 180 | dev = dev_get_by_name(&init_net, driver_name); | ||
| 181 | if (!dev) | ||
| 182 | return -ENODEV; | ||
| 183 | |||
| 184 | /* Create Ethernet bearer for device */ | ||
| 185 | eb_ptr->dev = dev; | ||
| 186 | eb_ptr->tipc_packet_type.type = htons(ETH_P_TIPC); | ||
| 187 | eb_ptr->tipc_packet_type.dev = dev; | ||
| 188 | eb_ptr->tipc_packet_type.func = recv_msg; | ||
| 189 | eb_ptr->tipc_packet_type.af_packet_priv = eb_ptr; | ||
| 190 | INIT_LIST_HEAD(&(eb_ptr->tipc_packet_type.list)); | ||
| 191 | INIT_WORK(&eb_ptr->setup, setup_media); | ||
| 192 | schedule_work(&eb_ptr->setup); | ||
| 193 | |||
| 194 | /* Associate TIPC bearer with Ethernet bearer */ | ||
| 195 | eb_ptr->bearer = tb_ptr; | ||
| 196 | tb_ptr->usr_handle = (void *)eb_ptr; | ||
| 197 | memset(tb_ptr->bcast_addr.value, 0, sizeof(tb_ptr->bcast_addr.value)); | ||
| 198 | memcpy(tb_ptr->bcast_addr.value, dev->broadcast, ETH_ALEN); | ||
| 199 | tb_ptr->bcast_addr.media_id = TIPC_MEDIA_TYPE_ETH; | ||
| 200 | tb_ptr->bcast_addr.broadcast = 1; | ||
| 201 | tb_ptr->mtu = dev->mtu; | ||
| 202 | tb_ptr->blocked = 0; | ||
| 203 | eth_media_addr_set(tb_ptr, &tb_ptr->addr, (char *)dev->dev_addr); | ||
| 204 | return 0; | ||
| 205 | } | ||
| 206 | |||
| 207 | /** | ||
| 208 | * cleanup_media - break association between Ethernet bearer and interface | ||
| 209 | * | ||
| 210 | * This routine must be invoked from a work queue because it can sleep. | ||
| 211 | */ | ||
| 212 | static void cleanup_media(struct work_struct *work) | ||
| 213 | { | ||
| 214 | struct eth_media *eb_ptr = | ||
| 215 | container_of(work, struct eth_media, cleanup); | ||
| 216 | |||
| 217 | dev_remove_pack(&eb_ptr->tipc_packet_type); | ||
| 218 | dev_put(eb_ptr->dev); | ||
| 219 | eb_ptr->dev = NULL; | ||
| 220 | } | ||
| 221 | |||
| 222 | /** | ||
| 223 | * disable_media - detach TIPC bearer from an Ethernet interface | ||
| 224 | * | ||
| 225 | * Mark Ethernet bearer as inactive so that incoming buffers are thrown away, | ||
| 226 | * then get worker thread to complete bearer cleanup. (Can't do cleanup | ||
| 227 | * here because cleanup code needs to sleep and caller holds spinlocks.) | ||
| 228 | */ | ||
| 229 | static void disable_media(struct tipc_bearer *tb_ptr) | ||
| 230 | { | ||
| 231 | struct eth_media *eb_ptr = (struct eth_media *)tb_ptr->usr_handle; | ||
| 232 | |||
| 233 | eb_ptr->bearer = NULL; | ||
| 234 | INIT_WORK(&eb_ptr->cleanup, cleanup_media); | ||
| 235 | schedule_work(&eb_ptr->cleanup); | ||
| 236 | } | ||
| 237 | |||
| 238 | /** | ||
| 239 | * recv_notification - handle device updates from OS | ||
| 240 | * | ||
| 241 | * Change the state of the Ethernet bearer (if any) associated with the | ||
| 242 | * specified device. | ||
| 243 | */ | ||
| 244 | static int recv_notification(struct notifier_block *nb, unsigned long evt, | ||
| 245 | void *ptr) | ||
| 246 | { | ||
| 247 | struct net_device *dev = netdev_notifier_info_to_dev(ptr); | ||
| 248 | struct eth_media *eb_ptr = ð_media_array[0]; | ||
| 249 | struct eth_media *stop = ð_media_array[MAX_ETH_MEDIA]; | ||
| 250 | |||
| 251 | if (!net_eq(dev_net(dev), &init_net)) | ||
| 252 | return NOTIFY_DONE; | ||
| 253 | |||
| 254 | while ((eb_ptr->dev != dev)) { | ||
| 255 | if (++eb_ptr == stop) | ||
| 256 | return NOTIFY_DONE; /* couldn't find device */ | ||
| 257 | } | ||
| 258 | if (!eb_ptr->bearer) | ||
| 259 | return NOTIFY_DONE; /* bearer had been disabled */ | ||
| 260 | |||
| 261 | eb_ptr->bearer->mtu = dev->mtu; | ||
| 262 | |||
| 263 | switch (evt) { | ||
| 264 | case NETDEV_CHANGE: | ||
| 265 | if (netif_carrier_ok(dev)) | ||
| 266 | tipc_continue(eb_ptr->bearer); | ||
| 267 | else | ||
| 268 | tipc_block_bearer(eb_ptr->bearer); | ||
| 269 | break; | ||
| 270 | case NETDEV_UP: | ||
| 271 | tipc_continue(eb_ptr->bearer); | ||
| 272 | break; | ||
| 273 | case NETDEV_DOWN: | ||
| 274 | tipc_block_bearer(eb_ptr->bearer); | ||
| 275 | break; | ||
| 276 | case NETDEV_CHANGEMTU: | ||
| 277 | case NETDEV_CHANGEADDR: | ||
| 278 | tipc_block_bearer(eb_ptr->bearer); | ||
| 279 | tipc_continue(eb_ptr->bearer); | ||
| 280 | break; | ||
| 281 | case NETDEV_UNREGISTER: | ||
| 282 | case NETDEV_CHANGENAME: | ||
| 283 | tipc_disable_bearer(eb_ptr->bearer->name); | ||
| 284 | break; | ||
| 285 | } | ||
| 286 | return NOTIFY_OK; | ||
| 287 | } | ||
| 288 | |||
| 289 | /** | ||
| 290 | * eth_addr2str - convert Ethernet address to string | ||
| 291 | */ | ||
| 292 | static int eth_addr2str(struct tipc_media_addr *a, char *str_buf, int str_size) | ||
| 293 | { | 45 | { |
| 294 | if (str_size < 18) /* 18 = strlen("aa:bb:cc:dd:ee:ff\0") */ | 46 | if (str_size < 18) /* 18 = strlen("aa:bb:cc:dd:ee:ff\0") */ |
| 295 | return 1; | 47 | return 1; |
| @@ -298,10 +50,8 @@ static int eth_addr2str(struct tipc_media_addr *a, char *str_buf, int str_size) | |||
| 298 | return 0; | 50 | return 0; |
| 299 | } | 51 | } |
| 300 | 52 | ||
| 301 | /** | 53 | /* convert Ethernet address format to message header format */ |
| 302 | * eth_str2addr - convert Ethernet address format to message header format | 54 | static int tipc_eth_addr2msg(struct tipc_media_addr *a, char *msg_area) |
| 303 | */ | ||
| 304 | static int eth_addr2msg(struct tipc_media_addr *a, char *msg_area) | ||
| 305 | { | 55 | { |
| 306 | memset(msg_area, 0, TIPC_MEDIA_ADDR_SIZE); | 56 | memset(msg_area, 0, TIPC_MEDIA_ADDR_SIZE); |
| 307 | msg_area[TIPC_MEDIA_TYPE_OFFSET] = TIPC_MEDIA_TYPE_ETH; | 57 | msg_area[TIPC_MEDIA_TYPE_OFFSET] = TIPC_MEDIA_TYPE_ETH; |
| @@ -309,68 +59,30 @@ static int eth_addr2msg(struct tipc_media_addr *a, char *msg_area) | |||
| 309 | return 0; | 59 | return 0; |
| 310 | } | 60 | } |
| 311 | 61 | ||
| 312 | /** | 62 | /* convert message header address format to Ethernet format */ |
| 313 | * eth_str2addr - convert message header address format to Ethernet format | 63 | static int tipc_eth_msg2addr(const struct tipc_bearer *tb_ptr, |
| 314 | */ | 64 | struct tipc_media_addr *a, char *msg_area) |
| 315 | static int eth_msg2addr(const struct tipc_bearer *tb_ptr, | ||
| 316 | struct tipc_media_addr *a, char *msg_area) | ||
| 317 | { | 65 | { |
| 318 | if (msg_area[TIPC_MEDIA_TYPE_OFFSET] != TIPC_MEDIA_TYPE_ETH) | 66 | if (msg_area[TIPC_MEDIA_TYPE_OFFSET] != TIPC_MEDIA_TYPE_ETH) |
| 319 | return 1; | 67 | return 1; |
| 320 | 68 | ||
| 321 | eth_media_addr_set(tb_ptr, a, msg_area + ETH_ADDR_OFFSET); | 69 | tipc_l2_media_addr_set(tb_ptr, a, msg_area + ETH_ADDR_OFFSET); |
| 322 | return 0; | 70 | return 0; |
| 323 | } | 71 | } |
| 324 | 72 | ||
| 325 | /* | 73 | /* Ethernet media registration info */ |
| 326 | * Ethernet media registration info | 74 | struct tipc_media eth_media_info = { |
| 327 | */ | 75 | .send_msg = tipc_l2_send_msg, |
| 328 | static struct tipc_media eth_media_info = { | 76 | .enable_media = tipc_enable_l2_media, |
| 329 | .send_msg = send_msg, | 77 | .disable_media = tipc_disable_l2_media, |
| 330 | .enable_media = enable_media, | 78 | .addr2str = tipc_eth_addr2str, |
| 331 | .disable_media = disable_media, | 79 | .addr2msg = tipc_eth_addr2msg, |
| 332 | .addr2str = eth_addr2str, | 80 | .msg2addr = tipc_eth_msg2addr, |
| 333 | .addr2msg = eth_addr2msg, | ||
| 334 | .msg2addr = eth_msg2addr, | ||
| 335 | .priority = TIPC_DEF_LINK_PRI, | 81 | .priority = TIPC_DEF_LINK_PRI, |
| 336 | .tolerance = TIPC_DEF_LINK_TOL, | 82 | .tolerance = TIPC_DEF_LINK_TOL, |
| 337 | .window = TIPC_DEF_LINK_WIN, | 83 | .window = TIPC_DEF_LINK_WIN, |
| 338 | .type_id = TIPC_MEDIA_TYPE_ETH, | 84 | .type_id = TIPC_MEDIA_TYPE_ETH, |
| 85 | .hwaddr_len = ETH_ALEN, | ||
| 339 | .name = "eth" | 86 | .name = "eth" |
| 340 | }; | 87 | }; |
| 341 | 88 | ||
| 342 | /** | ||
| 343 | * tipc_eth_media_start - activate Ethernet bearer support | ||
| 344 | * | ||
| 345 | * Register Ethernet media type with TIPC bearer code. Also register | ||
| 346 | * with OS for notifications about device state changes. | ||
| 347 | */ | ||
| 348 | int tipc_eth_media_start(void) | ||
| 349 | { | ||
| 350 | int res; | ||
| 351 | |||
| 352 | if (eth_started) | ||
| 353 | return -EINVAL; | ||
| 354 | |||
| 355 | res = tipc_register_media(ð_media_info); | ||
| 356 | if (res) | ||
| 357 | return res; | ||
| 358 | |||
| 359 | res = register_netdevice_notifier(¬ifier); | ||
| 360 | if (!res) | ||
| 361 | eth_started = 1; | ||
| 362 | return res; | ||
| 363 | } | ||
| 364 | |||
| 365 | /** | ||
| 366 | * tipc_eth_media_stop - deactivate Ethernet bearer support | ||
| 367 | */ | ||
| 368 | void tipc_eth_media_stop(void) | ||
| 369 | { | ||
| 370 | if (!eth_started) | ||
| 371 | return; | ||
| 372 | |||
| 373 | flush_scheduled_work(); | ||
| 374 | unregister_netdevice_notifier(¬ifier); | ||
| 375 | eth_started = 0; | ||
| 376 | } | ||
diff --git a/net/tipc/ib_media.c b/net/tipc/ib_media.c index c13989297464..844a77e25828 100644 --- a/net/tipc/ib_media.c +++ b/net/tipc/ib_media.c | |||
| @@ -42,252 +42,9 @@ | |||
| 42 | #include "core.h" | 42 | #include "core.h" |
| 43 | #include "bearer.h" | 43 | #include "bearer.h" |
| 44 | 44 | ||
| 45 | #define MAX_IB_MEDIA MAX_BEARERS | 45 | /* convert InfiniBand address to string */ |
| 46 | 46 | static int tipc_ib_addr2str(struct tipc_media_addr *a, char *str_buf, | |
| 47 | /** | 47 | int str_size) |
| 48 | * struct ib_media - Infiniband media data structure | ||
| 49 | * @bearer: ptr to associated "generic" bearer structure | ||
| 50 | * @dev: ptr to associated Infiniband network device | ||
| 51 | * @tipc_packet_type: used in binding TIPC to Infiniband driver | ||
| 52 | * @cleanup: work item used when disabling bearer | ||
| 53 | */ | ||
| 54 | |||
| 55 | struct ib_media { | ||
| 56 | struct tipc_bearer *bearer; | ||
| 57 | struct net_device *dev; | ||
| 58 | struct packet_type tipc_packet_type; | ||
| 59 | struct work_struct setup; | ||
| 60 | struct work_struct cleanup; | ||
| 61 | }; | ||
| 62 | |||
| 63 | static struct tipc_media ib_media_info; | ||
| 64 | static struct ib_media ib_media_array[MAX_IB_MEDIA]; | ||
| 65 | static int ib_started; | ||
| 66 | |||
| 67 | /** | ||
| 68 | * ib_media_addr_set - initialize Infiniband media address structure | ||
| 69 | * | ||
| 70 | * Media-dependent "value" field stores MAC address in first 6 bytes | ||
| 71 | * and zeroes out the remaining bytes. | ||
| 72 | */ | ||
| 73 | static void ib_media_addr_set(const struct tipc_bearer *tb_ptr, | ||
| 74 | struct tipc_media_addr *a, char *mac) | ||
| 75 | { | ||
| 76 | BUILD_BUG_ON(sizeof(a->value) < INFINIBAND_ALEN); | ||
| 77 | memcpy(a->value, mac, INFINIBAND_ALEN); | ||
| 78 | a->media_id = TIPC_MEDIA_TYPE_IB; | ||
| 79 | a->broadcast = !memcmp(mac, tb_ptr->bcast_addr.value, INFINIBAND_ALEN); | ||
| 80 | } | ||
| 81 | |||
| 82 | /** | ||
| 83 | * send_msg - send a TIPC message out over an InfiniBand interface | ||
| 84 | */ | ||
| 85 | static int send_msg(struct sk_buff *buf, struct tipc_bearer *tb_ptr, | ||
| 86 | struct tipc_media_addr *dest) | ||
| 87 | { | ||
| 88 | struct sk_buff *clone; | ||
| 89 | struct net_device *dev; | ||
| 90 | int delta; | ||
| 91 | |||
| 92 | clone = skb_clone(buf, GFP_ATOMIC); | ||
| 93 | if (!clone) | ||
| 94 | return 0; | ||
| 95 | |||
| 96 | dev = ((struct ib_media *)(tb_ptr->usr_handle))->dev; | ||
| 97 | delta = dev->hard_header_len - skb_headroom(buf); | ||
| 98 | |||
| 99 | if ((delta > 0) && | ||
| 100 | pskb_expand_head(clone, SKB_DATA_ALIGN(delta), 0, GFP_ATOMIC)) { | ||
| 101 | kfree_skb(clone); | ||
| 102 | return 0; | ||
| 103 | } | ||
| 104 | |||
| 105 | skb_reset_network_header(clone); | ||
| 106 | clone->dev = dev; | ||
| 107 | clone->protocol = htons(ETH_P_TIPC); | ||
| 108 | dev_hard_header(clone, dev, ETH_P_TIPC, dest->value, | ||
| 109 | dev->dev_addr, clone->len); | ||
| 110 | dev_queue_xmit(clone); | ||
| 111 | return 0; | ||
| 112 | } | ||
| 113 | |||
| 114 | /** | ||
| 115 | * recv_msg - handle incoming TIPC message from an InfiniBand interface | ||
| 116 | * | ||
| 117 | * Accept only packets explicitly sent to this node, or broadcast packets; | ||
| 118 | * ignores packets sent using InfiniBand multicast, and traffic sent to other | ||
| 119 | * nodes (which can happen if interface is running in promiscuous mode). | ||
| 120 | */ | ||
| 121 | static int recv_msg(struct sk_buff *buf, struct net_device *dev, | ||
| 122 | struct packet_type *pt, struct net_device *orig_dev) | ||
| 123 | { | ||
| 124 | struct ib_media *ib_ptr = (struct ib_media *)pt->af_packet_priv; | ||
| 125 | |||
| 126 | if (!net_eq(dev_net(dev), &init_net)) { | ||
| 127 | kfree_skb(buf); | ||
| 128 | return NET_RX_DROP; | ||
| 129 | } | ||
| 130 | |||
| 131 | if (likely(ib_ptr->bearer)) { | ||
| 132 | if (likely(buf->pkt_type <= PACKET_BROADCAST)) { | ||
| 133 | buf->next = NULL; | ||
| 134 | tipc_recv_msg(buf, ib_ptr->bearer); | ||
| 135 | return NET_RX_SUCCESS; | ||
| 136 | } | ||
| 137 | } | ||
| 138 | kfree_skb(buf); | ||
| 139 | return NET_RX_DROP; | ||
| 140 | } | ||
| 141 | |||
| 142 | /** | ||
| 143 | * setup_bearer - setup association between InfiniBand bearer and interface | ||
| 144 | */ | ||
| 145 | static void setup_media(struct work_struct *work) | ||
| 146 | { | ||
| 147 | struct ib_media *ib_ptr = | ||
| 148 | container_of(work, struct ib_media, setup); | ||
| 149 | |||
| 150 | dev_add_pack(&ib_ptr->tipc_packet_type); | ||
| 151 | } | ||
| 152 | |||
| 153 | /** | ||
| 154 | * enable_media - attach TIPC bearer to an InfiniBand interface | ||
| 155 | */ | ||
| 156 | static int enable_media(struct tipc_bearer *tb_ptr) | ||
| 157 | { | ||
| 158 | struct net_device *dev; | ||
| 159 | struct ib_media *ib_ptr = &ib_media_array[0]; | ||
| 160 | struct ib_media *stop = &ib_media_array[MAX_IB_MEDIA]; | ||
| 161 | char *driver_name = strchr((const char *)tb_ptr->name, ':') + 1; | ||
| 162 | int pending_dev = 0; | ||
| 163 | |||
| 164 | /* Find unused InfiniBand bearer structure */ | ||
| 165 | while (ib_ptr->dev) { | ||
| 166 | if (!ib_ptr->bearer) | ||
| 167 | pending_dev++; | ||
| 168 | if (++ib_ptr == stop) | ||
| 169 | return pending_dev ? -EAGAIN : -EDQUOT; | ||
| 170 | } | ||
| 171 | |||
| 172 | /* Find device with specified name */ | ||
| 173 | dev = dev_get_by_name(&init_net, driver_name); | ||
| 174 | if (!dev) | ||
| 175 | return -ENODEV; | ||
| 176 | |||
| 177 | /* Create InfiniBand bearer for device */ | ||
| 178 | ib_ptr->dev = dev; | ||
| 179 | ib_ptr->tipc_packet_type.type = htons(ETH_P_TIPC); | ||
| 180 | ib_ptr->tipc_packet_type.dev = dev; | ||
| 181 | ib_ptr->tipc_packet_type.func = recv_msg; | ||
| 182 | ib_ptr->tipc_packet_type.af_packet_priv = ib_ptr; | ||
| 183 | INIT_LIST_HEAD(&(ib_ptr->tipc_packet_type.list)); | ||
| 184 | INIT_WORK(&ib_ptr->setup, setup_media); | ||
| 185 | schedule_work(&ib_ptr->setup); | ||
| 186 | |||
| 187 | /* Associate TIPC bearer with InfiniBand bearer */ | ||
| 188 | ib_ptr->bearer = tb_ptr; | ||
| 189 | tb_ptr->usr_handle = (void *)ib_ptr; | ||
| 190 | memset(tb_ptr->bcast_addr.value, 0, sizeof(tb_ptr->bcast_addr.value)); | ||
| 191 | memcpy(tb_ptr->bcast_addr.value, dev->broadcast, INFINIBAND_ALEN); | ||
| 192 | tb_ptr->bcast_addr.media_id = TIPC_MEDIA_TYPE_IB; | ||
| 193 | tb_ptr->bcast_addr.broadcast = 1; | ||
| 194 | tb_ptr->mtu = dev->mtu; | ||
| 195 | tb_ptr->blocked = 0; | ||
| 196 | ib_media_addr_set(tb_ptr, &tb_ptr->addr, (char *)dev->dev_addr); | ||
| 197 | return 0; | ||
| 198 | } | ||
| 199 | |||
| 200 | /** | ||
| 201 | * cleanup_bearer - break association between InfiniBand bearer and interface | ||
| 202 | * | ||
| 203 | * This routine must be invoked from a work queue because it can sleep. | ||
| 204 | */ | ||
| 205 | static void cleanup_bearer(struct work_struct *work) | ||
| 206 | { | ||
| 207 | struct ib_media *ib_ptr = | ||
| 208 | container_of(work, struct ib_media, cleanup); | ||
| 209 | |||
| 210 | dev_remove_pack(&ib_ptr->tipc_packet_type); | ||
| 211 | dev_put(ib_ptr->dev); | ||
| 212 | ib_ptr->dev = NULL; | ||
| 213 | } | ||
| 214 | |||
| 215 | /** | ||
| 216 | * disable_media - detach TIPC bearer from an InfiniBand interface | ||
| 217 | * | ||
| 218 | * Mark InfiniBand bearer as inactive so that incoming buffers are thrown away, | ||
| 219 | * then get worker thread to complete bearer cleanup. (Can't do cleanup | ||
| 220 | * here because cleanup code needs to sleep and caller holds spinlocks.) | ||
| 221 | */ | ||
| 222 | static void disable_media(struct tipc_bearer *tb_ptr) | ||
| 223 | { | ||
| 224 | struct ib_media *ib_ptr = (struct ib_media *)tb_ptr->usr_handle; | ||
| 225 | |||
| 226 | ib_ptr->bearer = NULL; | ||
| 227 | INIT_WORK(&ib_ptr->cleanup, cleanup_bearer); | ||
| 228 | schedule_work(&ib_ptr->cleanup); | ||
| 229 | } | ||
| 230 | |||
| 231 | /** | ||
| 232 | * recv_notification - handle device updates from OS | ||
| 233 | * | ||
| 234 | * Change the state of the InfiniBand bearer (if any) associated with the | ||
| 235 | * specified device. | ||
| 236 | */ | ||
| 237 | static int recv_notification(struct notifier_block *nb, unsigned long evt, | ||
| 238 | void *ptr) | ||
| 239 | { | ||
| 240 | struct net_device *dev = netdev_notifier_info_to_dev(ptr); | ||
| 241 | struct ib_media *ib_ptr = &ib_media_array[0]; | ||
| 242 | struct ib_media *stop = &ib_media_array[MAX_IB_MEDIA]; | ||
| 243 | |||
| 244 | if (!net_eq(dev_net(dev), &init_net)) | ||
| 245 | return NOTIFY_DONE; | ||
| 246 | |||
| 247 | while ((ib_ptr->dev != dev)) { | ||
| 248 | if (++ib_ptr == stop) | ||
| 249 | return NOTIFY_DONE; /* couldn't find device */ | ||
| 250 | } | ||
| 251 | if (!ib_ptr->bearer) | ||
| 252 | return NOTIFY_DONE; /* bearer had been disabled */ | ||
| 253 | |||
| 254 | ib_ptr->bearer->mtu = dev->mtu; | ||
| 255 | |||
| 256 | switch (evt) { | ||
| 257 | case NETDEV_CHANGE: | ||
| 258 | if (netif_carrier_ok(dev)) | ||
| 259 | tipc_continue(ib_ptr->bearer); | ||
| 260 | else | ||
| 261 | tipc_block_bearer(ib_ptr->bearer); | ||
| 262 | break; | ||
| 263 | case NETDEV_UP: | ||
| 264 | tipc_continue(ib_ptr->bearer); | ||
| 265 | break; | ||
| 266 | case NETDEV_DOWN: | ||
| 267 | tipc_block_bearer(ib_ptr->bearer); | ||
| 268 | break; | ||
| 269 | case NETDEV_CHANGEMTU: | ||
| 270 | case NETDEV_CHANGEADDR: | ||
| 271 | tipc_block_bearer(ib_ptr->bearer); | ||
| 272 | tipc_continue(ib_ptr->bearer); | ||
| 273 | break; | ||
| 274 | case NETDEV_UNREGISTER: | ||
| 275 | case NETDEV_CHANGENAME: | ||
| 276 | tipc_disable_bearer(ib_ptr->bearer->name); | ||
| 277 | break; | ||
| 278 | } | ||
| 279 | return NOTIFY_OK; | ||
| 280 | } | ||
| 281 | |||
| 282 | static struct notifier_block notifier = { | ||
| 283 | .notifier_call = recv_notification, | ||
| 284 | .priority = 0, | ||
| 285 | }; | ||
| 286 | |||
| 287 | /** | ||
| 288 | * ib_addr2str - convert InfiniBand address to string | ||
| 289 | */ | ||
| 290 | static int ib_addr2str(struct tipc_media_addr *a, char *str_buf, int str_size) | ||
| 291 | { | 48 | { |
| 292 | if (str_size < 60) /* 60 = 19 * strlen("xx:") + strlen("xx\0") */ | 49 | if (str_size < 60) /* 60 = 19 * strlen("xx:") + strlen("xx\0") */ |
| 293 | return 1; | 50 | return 1; |
| @@ -297,10 +54,8 @@ static int ib_addr2str(struct tipc_media_addr *a, char *str_buf, int str_size) | |||
| 297 | return 0; | 54 | return 0; |
| 298 | } | 55 | } |
| 299 | 56 | ||
| 300 | /** | 57 | /* convert InfiniBand address format to message header format */ |
| 301 | * ib_addr2msg - convert InfiniBand address format to message header format | 58 | static int tipc_ib_addr2msg(struct tipc_media_addr *a, char *msg_area) |
| 302 | */ | ||
| 303 | static int ib_addr2msg(struct tipc_media_addr *a, char *msg_area) | ||
| 304 | { | 59 | { |
| 305 | memset(msg_area, 0, TIPC_MEDIA_ADDR_SIZE); | 60 | memset(msg_area, 0, TIPC_MEDIA_ADDR_SIZE); |
| 306 | msg_area[TIPC_MEDIA_TYPE_OFFSET] = TIPC_MEDIA_TYPE_IB; | 61 | msg_area[TIPC_MEDIA_TYPE_OFFSET] = TIPC_MEDIA_TYPE_IB; |
| @@ -308,65 +63,27 @@ static int ib_addr2msg(struct tipc_media_addr *a, char *msg_area) | |||
| 308 | return 0; | 63 | return 0; |
| 309 | } | 64 | } |
| 310 | 65 | ||
| 311 | /** | 66 | /* convert message header address format to InfiniBand format */ |
| 312 | * ib_msg2addr - convert message header address format to InfiniBand format | 67 | static int tipc_ib_msg2addr(const struct tipc_bearer *tb_ptr, |
| 313 | */ | 68 | struct tipc_media_addr *a, char *msg_area) |
| 314 | static int ib_msg2addr(const struct tipc_bearer *tb_ptr, | ||
| 315 | struct tipc_media_addr *a, char *msg_area) | ||
| 316 | { | 69 | { |
| 317 | ib_media_addr_set(tb_ptr, a, msg_area); | 70 | tipc_l2_media_addr_set(tb_ptr, a, msg_area); |
| 318 | return 0; | 71 | return 0; |
| 319 | } | 72 | } |
| 320 | 73 | ||
| 321 | /* | 74 | /* InfiniBand media registration info */ |
| 322 | * InfiniBand media registration info | 75 | struct tipc_media ib_media_info = { |
| 323 | */ | 76 | .send_msg = tipc_l2_send_msg, |
| 324 | static struct tipc_media ib_media_info = { | 77 | .enable_media = tipc_enable_l2_media, |
| 325 | .send_msg = send_msg, | 78 | .disable_media = tipc_disable_l2_media, |
| 326 | .enable_media = enable_media, | 79 | .addr2str = tipc_ib_addr2str, |
| 327 | .disable_media = disable_media, | 80 | .addr2msg = tipc_ib_addr2msg, |
| 328 | .addr2str = ib_addr2str, | 81 | .msg2addr = tipc_ib_msg2addr, |
| 329 | .addr2msg = ib_addr2msg, | ||
| 330 | .msg2addr = ib_msg2addr, | ||
| 331 | .priority = TIPC_DEF_LINK_PRI, | 82 | .priority = TIPC_DEF_LINK_PRI, |
| 332 | .tolerance = TIPC_DEF_LINK_TOL, | 83 | .tolerance = TIPC_DEF_LINK_TOL, |
| 333 | .window = TIPC_DEF_LINK_WIN, | 84 | .window = TIPC_DEF_LINK_WIN, |
| 334 | .type_id = TIPC_MEDIA_TYPE_IB, | 85 | .type_id = TIPC_MEDIA_TYPE_IB, |
| 86 | .hwaddr_len = INFINIBAND_ALEN, | ||
| 335 | .name = "ib" | 87 | .name = "ib" |
| 336 | }; | 88 | }; |
| 337 | 89 | ||
| 338 | /** | ||
| 339 | * tipc_ib_media_start - activate InfiniBand bearer support | ||
| 340 | * | ||
| 341 | * Register InfiniBand media type with TIPC bearer code. Also register | ||
| 342 | * with OS for notifications about device state changes. | ||
| 343 | */ | ||
| 344 | int tipc_ib_media_start(void) | ||
| 345 | { | ||
| 346 | int res; | ||
| 347 | |||
| 348 | if (ib_started) | ||
| 349 | return -EINVAL; | ||
| 350 | |||
| 351 | res = tipc_register_media(&ib_media_info); | ||
| 352 | if (res) | ||
| 353 | return res; | ||
| 354 | |||
| 355 | res = register_netdevice_notifier(¬ifier); | ||
| 356 | if (!res) | ||
| 357 | ib_started = 1; | ||
| 358 | return res; | ||
| 359 | } | ||
| 360 | |||
| 361 | /** | ||
| 362 | * tipc_ib_media_stop - deactivate InfiniBand bearer support | ||
| 363 | */ | ||
| 364 | void tipc_ib_media_stop(void) | ||
| 365 | { | ||
| 366 | if (!ib_started) | ||
| 367 | return; | ||
| 368 | |||
| 369 | flush_scheduled_work(); | ||
| 370 | unregister_netdevice_notifier(¬ifier); | ||
| 371 | ib_started = 0; | ||
| 372 | } | ||
diff --git a/net/tipc/link.c b/net/tipc/link.c index 13b987745820..d4b5de41b682 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * net/tipc/link.c: TIPC link code | 2 | * net/tipc/link.c: TIPC link code |
| 3 | * | 3 | * |
| 4 | * Copyright (c) 1996-2007, 2012, Ericsson AB | 4 | * Copyright (c) 1996-2007, 2012-2014, Ericsson AB |
| 5 | * Copyright (c) 2004-2007, 2010-2013, Wind River Systems | 5 | * Copyright (c) 2004-2007, 2010-2013, Wind River Systems |
| 6 | * All rights reserved. | 6 | * All rights reserved. |
| 7 | * | 7 | * |
| @@ -78,8 +78,8 @@ static const char *link_unk_evt = "Unknown link event "; | |||
| 78 | static void link_handle_out_of_seq_msg(struct tipc_link *l_ptr, | 78 | static void link_handle_out_of_seq_msg(struct tipc_link *l_ptr, |
| 79 | struct sk_buff *buf); | 79 | struct sk_buff *buf); |
| 80 | static void link_recv_proto_msg(struct tipc_link *l_ptr, struct sk_buff *buf); | 80 | static void link_recv_proto_msg(struct tipc_link *l_ptr, struct sk_buff *buf); |
| 81 | static int link_recv_changeover_msg(struct tipc_link **l_ptr, | 81 | static int tipc_link_tunnel_rcv(struct tipc_link **l_ptr, |
| 82 | struct sk_buff **buf); | 82 | struct sk_buff **buf); |
| 83 | static void link_set_supervision_props(struct tipc_link *l_ptr, u32 tolerance); | 83 | static void link_set_supervision_props(struct tipc_link *l_ptr, u32 tolerance); |
| 84 | static int link_send_sections_long(struct tipc_port *sender, | 84 | static int link_send_sections_long(struct tipc_port *sender, |
| 85 | struct iovec const *msg_sect, | 85 | struct iovec const *msg_sect, |
| @@ -87,7 +87,6 @@ static int link_send_sections_long(struct tipc_port *sender, | |||
| 87 | static void link_state_event(struct tipc_link *l_ptr, u32 event); | 87 | static void link_state_event(struct tipc_link *l_ptr, u32 event); |
| 88 | static void link_reset_statistics(struct tipc_link *l_ptr); | 88 | static void link_reset_statistics(struct tipc_link *l_ptr); |
| 89 | static void link_print(struct tipc_link *l_ptr, const char *str); | 89 | static void link_print(struct tipc_link *l_ptr, const char *str); |
| 90 | static void link_start(struct tipc_link *l_ptr); | ||
| 91 | static int link_send_long_buf(struct tipc_link *l_ptr, struct sk_buff *buf); | 90 | static int link_send_long_buf(struct tipc_link *l_ptr, struct sk_buff *buf); |
| 92 | static void tipc_link_send_sync(struct tipc_link *l); | 91 | static void tipc_link_send_sync(struct tipc_link *l); |
| 93 | static void tipc_link_recv_sync(struct tipc_node *n, struct sk_buff *buf); | 92 | static void tipc_link_recv_sync(struct tipc_node *n, struct sk_buff *buf); |
| @@ -278,9 +277,11 @@ struct tipc_link *tipc_link_create(struct tipc_node *n_ptr, | |||
| 278 | 277 | ||
| 279 | tipc_node_attach_link(n_ptr, l_ptr); | 278 | tipc_node_attach_link(n_ptr, l_ptr); |
| 280 | 279 | ||
| 281 | k_init_timer(&l_ptr->timer, (Handler)link_timeout, (unsigned long)l_ptr); | 280 | k_init_timer(&l_ptr->timer, (Handler)link_timeout, |
| 281 | (unsigned long)l_ptr); | ||
| 282 | list_add_tail(&l_ptr->link_list, &b_ptr->links); | 282 | list_add_tail(&l_ptr->link_list, &b_ptr->links); |
| 283 | tipc_k_signal((Handler)link_start, (unsigned long)l_ptr); | 283 | |
| 284 | link_state_event(l_ptr, STARTING_EVT); | ||
| 284 | 285 | ||
| 285 | return l_ptr; | 286 | return l_ptr; |
| 286 | } | 287 | } |
| @@ -305,19 +306,13 @@ void tipc_link_delete(struct tipc_link *l_ptr) | |||
| 305 | tipc_node_lock(l_ptr->owner); | 306 | tipc_node_lock(l_ptr->owner); |
| 306 | tipc_link_reset(l_ptr); | 307 | tipc_link_reset(l_ptr); |
| 307 | tipc_node_detach_link(l_ptr->owner, l_ptr); | 308 | tipc_node_detach_link(l_ptr->owner, l_ptr); |
| 308 | tipc_link_stop(l_ptr); | 309 | tipc_link_purge_queues(l_ptr); |
| 309 | list_del_init(&l_ptr->link_list); | 310 | list_del_init(&l_ptr->link_list); |
| 310 | tipc_node_unlock(l_ptr->owner); | 311 | tipc_node_unlock(l_ptr->owner); |
| 311 | k_term_timer(&l_ptr->timer); | 312 | k_term_timer(&l_ptr->timer); |
| 312 | kfree(l_ptr); | 313 | kfree(l_ptr); |
| 313 | } | 314 | } |
| 314 | 315 | ||
| 315 | static void link_start(struct tipc_link *l_ptr) | ||
| 316 | { | ||
| 317 | tipc_node_lock(l_ptr->owner); | ||
| 318 | link_state_event(l_ptr, STARTING_EVT); | ||
| 319 | tipc_node_unlock(l_ptr->owner); | ||
| 320 | } | ||
| 321 | 316 | ||
| 322 | /** | 317 | /** |
| 323 | * link_schedule_port - schedule port for deferred sending | 318 | * link_schedule_port - schedule port for deferred sending |
| @@ -386,14 +381,7 @@ exit: | |||
| 386 | */ | 381 | */ |
| 387 | static void link_release_outqueue(struct tipc_link *l_ptr) | 382 | static void link_release_outqueue(struct tipc_link *l_ptr) |
| 388 | { | 383 | { |
| 389 | struct sk_buff *buf = l_ptr->first_out; | 384 | kfree_skb_list(l_ptr->first_out); |
| 390 | struct sk_buff *next; | ||
| 391 | |||
| 392 | while (buf) { | ||
| 393 | next = buf->next; | ||
| 394 | kfree_skb(buf); | ||
| 395 | buf = next; | ||
| 396 | } | ||
| 397 | l_ptr->first_out = NULL; | 385 | l_ptr->first_out = NULL; |
| 398 | l_ptr->out_queue_size = 0; | 386 | l_ptr->out_queue_size = 0; |
| 399 | } | 387 | } |
| @@ -410,37 +398,20 @@ void tipc_link_reset_fragments(struct tipc_link *l_ptr) | |||
| 410 | } | 398 | } |
| 411 | 399 | ||
| 412 | /** | 400 | /** |
| 413 | * tipc_link_stop - purge all inbound and outbound messages associated with link | 401 | * tipc_link_purge_queues - purge all pkt queues associated with link |
| 414 | * @l_ptr: pointer to link | 402 | * @l_ptr: pointer to link |
| 415 | */ | 403 | */ |
| 416 | void tipc_link_stop(struct tipc_link *l_ptr) | 404 | void tipc_link_purge_queues(struct tipc_link *l_ptr) |
| 417 | { | 405 | { |
| 418 | struct sk_buff *buf; | 406 | kfree_skb_list(l_ptr->oldest_deferred_in); |
| 419 | struct sk_buff *next; | 407 | kfree_skb_list(l_ptr->first_out); |
| 420 | |||
| 421 | buf = l_ptr->oldest_deferred_in; | ||
| 422 | while (buf) { | ||
| 423 | next = buf->next; | ||
| 424 | kfree_skb(buf); | ||
| 425 | buf = next; | ||
| 426 | } | ||
| 427 | |||
| 428 | buf = l_ptr->first_out; | ||
| 429 | while (buf) { | ||
| 430 | next = buf->next; | ||
| 431 | kfree_skb(buf); | ||
| 432 | buf = next; | ||
| 433 | } | ||
| 434 | |||
| 435 | tipc_link_reset_fragments(l_ptr); | 408 | tipc_link_reset_fragments(l_ptr); |
| 436 | |||
| 437 | kfree_skb(l_ptr->proto_msg_queue); | 409 | kfree_skb(l_ptr->proto_msg_queue); |
| 438 | l_ptr->proto_msg_queue = NULL; | 410 | l_ptr->proto_msg_queue = NULL; |
| 439 | } | 411 | } |
| 440 | 412 | ||
| 441 | void tipc_link_reset(struct tipc_link *l_ptr) | 413 | void tipc_link_reset(struct tipc_link *l_ptr) |
| 442 | { | 414 | { |
| 443 | struct sk_buff *buf; | ||
| 444 | u32 prev_state = l_ptr->state; | 415 | u32 prev_state = l_ptr->state; |
| 445 | u32 checkpoint = l_ptr->next_in_no; | 416 | u32 checkpoint = l_ptr->next_in_no; |
| 446 | int was_active_link = tipc_link_is_active(l_ptr); | 417 | int was_active_link = tipc_link_is_active(l_ptr); |
| @@ -461,8 +432,7 @@ void tipc_link_reset(struct tipc_link *l_ptr) | |||
| 461 | tipc_node_link_down(l_ptr->owner, l_ptr); | 432 | tipc_node_link_down(l_ptr->owner, l_ptr); |
| 462 | tipc_bearer_remove_dest(l_ptr->b_ptr, l_ptr->addr); | 433 | tipc_bearer_remove_dest(l_ptr->b_ptr, l_ptr->addr); |
| 463 | 434 | ||
| 464 | if (was_active_link && tipc_node_active_links(l_ptr->owner) && | 435 | if (was_active_link && tipc_node_active_links(l_ptr->owner)) { |
| 465 | l_ptr->owner->permit_changeover) { | ||
| 466 | l_ptr->reset_checkpoint = checkpoint; | 436 | l_ptr->reset_checkpoint = checkpoint; |
| 467 | l_ptr->exp_msg_count = START_CHANGEOVER; | 437 | l_ptr->exp_msg_count = START_CHANGEOVER; |
| 468 | } | 438 | } |
| @@ -471,12 +441,7 @@ void tipc_link_reset(struct tipc_link *l_ptr) | |||
| 471 | link_release_outqueue(l_ptr); | 441 | link_release_outqueue(l_ptr); |
| 472 | kfree_skb(l_ptr->proto_msg_queue); | 442 | kfree_skb(l_ptr->proto_msg_queue); |
| 473 | l_ptr->proto_msg_queue = NULL; | 443 | l_ptr->proto_msg_queue = NULL; |
| 474 | buf = l_ptr->oldest_deferred_in; | 444 | kfree_skb_list(l_ptr->oldest_deferred_in); |
| 475 | while (buf) { | ||
| 476 | struct sk_buff *next = buf->next; | ||
| 477 | kfree_skb(buf); | ||
| 478 | buf = next; | ||
| 479 | } | ||
| 480 | if (!list_empty(&l_ptr->waiting_ports)) | 445 | if (!list_empty(&l_ptr->waiting_ports)) |
| 481 | tipc_link_wakeup_ports(l_ptr, 1); | 446 | tipc_link_wakeup_ports(l_ptr, 1); |
| 482 | 447 | ||
| @@ -517,10 +482,11 @@ static void link_state_event(struct tipc_link *l_ptr, unsigned int event) | |||
| 517 | if (!l_ptr->started && (event != STARTING_EVT)) | 482 | if (!l_ptr->started && (event != STARTING_EVT)) |
| 518 | return; /* Not yet. */ | 483 | return; /* Not yet. */ |
| 519 | 484 | ||
| 520 | if (link_blocked(l_ptr)) { | 485 | /* Check whether changeover is going on */ |
| 486 | if (l_ptr->exp_msg_count) { | ||
| 521 | if (event == TIMEOUT_EVT) | 487 | if (event == TIMEOUT_EVT) |
| 522 | link_set_timer(l_ptr, cont_intv); | 488 | link_set_timer(l_ptr, cont_intv); |
| 523 | return; /* Changeover going on */ | 489 | return; |
| 524 | } | 490 | } |
| 525 | 491 | ||
| 526 | switch (l_ptr->state) { | 492 | switch (l_ptr->state) { |
| @@ -790,8 +756,7 @@ int tipc_link_send_buf(struct tipc_link *l_ptr, struct sk_buff *buf) | |||
| 790 | return link_send_long_buf(l_ptr, buf); | 756 | return link_send_long_buf(l_ptr, buf); |
| 791 | 757 | ||
| 792 | /* Packet can be queued or sent. */ | 758 | /* Packet can be queued or sent. */ |
| 793 | if (likely(!tipc_bearer_blocked(l_ptr->b_ptr) && | 759 | if (likely(!link_congested(l_ptr))) { |
| 794 | !link_congested(l_ptr))) { | ||
| 795 | link_add_to_outqueue(l_ptr, buf, msg); | 760 | link_add_to_outqueue(l_ptr, buf, msg); |
| 796 | 761 | ||
| 797 | tipc_bearer_send(l_ptr->b_ptr, buf, &l_ptr->media_addr); | 762 | tipc_bearer_send(l_ptr->b_ptr, buf, &l_ptr->media_addr); |
| @@ -957,14 +922,13 @@ static int link_send_buf_fast(struct tipc_link *l_ptr, struct sk_buff *buf, | |||
| 957 | 922 | ||
| 958 | if (likely(!link_congested(l_ptr))) { | 923 | if (likely(!link_congested(l_ptr))) { |
| 959 | if (likely(msg_size(msg) <= l_ptr->max_pkt)) { | 924 | if (likely(msg_size(msg) <= l_ptr->max_pkt)) { |
| 960 | if (likely(!tipc_bearer_blocked(l_ptr->b_ptr))) { | 925 | link_add_to_outqueue(l_ptr, buf, msg); |
| 961 | link_add_to_outqueue(l_ptr, buf, msg); | 926 | tipc_bearer_send(l_ptr->b_ptr, buf, |
| 962 | tipc_bearer_send(l_ptr->b_ptr, buf, | 927 | &l_ptr->media_addr); |
| 963 | &l_ptr->media_addr); | 928 | l_ptr->unacked_window = 0; |
| 964 | l_ptr->unacked_window = 0; | 929 | return res; |
| 965 | return res; | 930 | } |
| 966 | } | 931 | else |
| 967 | } else | ||
| 968 | *used_max_pkt = l_ptr->max_pkt; | 932 | *used_max_pkt = l_ptr->max_pkt; |
| 969 | } | 933 | } |
| 970 | return tipc_link_send_buf(l_ptr, buf); /* All other cases */ | 934 | return tipc_link_send_buf(l_ptr, buf); /* All other cases */ |
| @@ -1013,8 +977,7 @@ exit: | |||
| 1013 | } | 977 | } |
| 1014 | 978 | ||
| 1015 | /* Exit if link (or bearer) is congested */ | 979 | /* Exit if link (or bearer) is congested */ |
| 1016 | if (link_congested(l_ptr) || | 980 | if (link_congested(l_ptr)) { |
| 1017 | tipc_bearer_blocked(l_ptr->b_ptr)) { | ||
| 1018 | res = link_schedule_port(l_ptr, | 981 | res = link_schedule_port(l_ptr, |
| 1019 | sender->ref, res); | 982 | sender->ref, res); |
| 1020 | goto exit; | 983 | goto exit; |
| @@ -1127,10 +1090,7 @@ again: | |||
| 1127 | if (copy_from_user(buf->data + fragm_crs, sect_crs, sz)) { | 1090 | if (copy_from_user(buf->data + fragm_crs, sect_crs, sz)) { |
| 1128 | res = -EFAULT; | 1091 | res = -EFAULT; |
| 1129 | error: | 1092 | error: |
| 1130 | for (; buf_chain; buf_chain = buf) { | 1093 | kfree_skb_list(buf_chain); |
| 1131 | buf = buf_chain->next; | ||
| 1132 | kfree_skb(buf_chain); | ||
| 1133 | } | ||
| 1134 | return res; | 1094 | return res; |
| 1135 | } | 1095 | } |
| 1136 | sect_crs += sz; | 1096 | sect_crs += sz; |
| @@ -1180,18 +1140,12 @@ error: | |||
| 1180 | if (l_ptr->max_pkt < max_pkt) { | 1140 | if (l_ptr->max_pkt < max_pkt) { |
| 1181 | sender->max_pkt = l_ptr->max_pkt; | 1141 | sender->max_pkt = l_ptr->max_pkt; |
| 1182 | tipc_node_unlock(node); | 1142 | tipc_node_unlock(node); |
| 1183 | for (; buf_chain; buf_chain = buf) { | 1143 | kfree_skb_list(buf_chain); |
| 1184 | buf = buf_chain->next; | ||
| 1185 | kfree_skb(buf_chain); | ||
| 1186 | } | ||
| 1187 | goto again; | 1144 | goto again; |
| 1188 | } | 1145 | } |
| 1189 | } else { | 1146 | } else { |
| 1190 | reject: | 1147 | reject: |
| 1191 | for (; buf_chain; buf_chain = buf) { | 1148 | kfree_skb_list(buf_chain); |
| 1192 | buf = buf_chain->next; | ||
| 1193 | kfree_skb(buf_chain); | ||
| 1194 | } | ||
| 1195 | return tipc_port_reject_sections(sender, hdr, msg_sect, | 1149 | return tipc_port_reject_sections(sender, hdr, msg_sect, |
| 1196 | len, TIPC_ERR_NO_NODE); | 1150 | len, TIPC_ERR_NO_NODE); |
| 1197 | } | 1151 | } |
| @@ -1209,7 +1163,7 @@ reject: | |||
| 1209 | /* | 1163 | /* |
| 1210 | * tipc_link_push_packet: Push one unsent packet to the media | 1164 | * tipc_link_push_packet: Push one unsent packet to the media |
| 1211 | */ | 1165 | */ |
| 1212 | u32 tipc_link_push_packet(struct tipc_link *l_ptr) | 1166 | static u32 tipc_link_push_packet(struct tipc_link *l_ptr) |
| 1213 | { | 1167 | { |
| 1214 | struct sk_buff *buf = l_ptr->first_out; | 1168 | struct sk_buff *buf = l_ptr->first_out; |
| 1215 | u32 r_q_size = l_ptr->retransm_queue_size; | 1169 | u32 r_q_size = l_ptr->retransm_queue_size; |
| @@ -1281,9 +1235,6 @@ void tipc_link_push_queue(struct tipc_link *l_ptr) | |||
| 1281 | { | 1235 | { |
| 1282 | u32 res; | 1236 | u32 res; |
| 1283 | 1237 | ||
| 1284 | if (tipc_bearer_blocked(l_ptr->b_ptr)) | ||
| 1285 | return; | ||
| 1286 | |||
| 1287 | do { | 1238 | do { |
| 1288 | res = tipc_link_push_packet(l_ptr); | 1239 | res = tipc_link_push_packet(l_ptr); |
| 1289 | } while (!res); | 1240 | } while (!res); |
| @@ -1370,26 +1321,15 @@ void tipc_link_retransmit(struct tipc_link *l_ptr, struct sk_buff *buf, | |||
| 1370 | 1321 | ||
| 1371 | msg = buf_msg(buf); | 1322 | msg = buf_msg(buf); |
| 1372 | 1323 | ||
| 1373 | if (tipc_bearer_blocked(l_ptr->b_ptr)) { | 1324 | /* Detect repeated retransmit failures */ |
| 1374 | if (l_ptr->retransm_queue_size == 0) { | 1325 | if (l_ptr->last_retransmitted == msg_seqno(msg)) { |
| 1375 | l_ptr->retransm_queue_head = msg_seqno(msg); | 1326 | if (++l_ptr->stale_count > 100) { |
| 1376 | l_ptr->retransm_queue_size = retransmits; | 1327 | link_retransmit_failure(l_ptr, buf); |
| 1377 | } else { | 1328 | return; |
| 1378 | pr_err("Unexpected retransmit on link %s (qsize=%d)\n", | ||
| 1379 | l_ptr->name, l_ptr->retransm_queue_size); | ||
| 1380 | } | 1329 | } |
| 1381 | return; | ||
| 1382 | } else { | 1330 | } else { |
| 1383 | /* Detect repeated retransmit failures on unblocked bearer */ | 1331 | l_ptr->last_retransmitted = msg_seqno(msg); |
| 1384 | if (l_ptr->last_retransmitted == msg_seqno(msg)) { | 1332 | l_ptr->stale_count = 1; |
| 1385 | if (++l_ptr->stale_count > 100) { | ||
| 1386 | link_retransmit_failure(l_ptr, buf); | ||
| 1387 | return; | ||
| 1388 | } | ||
| 1389 | } else { | ||
| 1390 | l_ptr->last_retransmitted = msg_seqno(msg); | ||
| 1391 | l_ptr->stale_count = 1; | ||
| 1392 | } | ||
| 1393 | } | 1333 | } |
| 1394 | 1334 | ||
| 1395 | while (retransmits && (buf != l_ptr->next_out) && buf) { | 1335 | while (retransmits && (buf != l_ptr->next_out) && buf) { |
| @@ -1476,14 +1416,14 @@ static int link_recv_buf_validate(struct sk_buff *buf) | |||
| 1476 | } | 1416 | } |
| 1477 | 1417 | ||
| 1478 | /** | 1418 | /** |
| 1479 | * tipc_recv_msg - process TIPC messages arriving from off-node | 1419 | * tipc_rcv - process TIPC packets/messages arriving from off-node |
| 1480 | * @head: pointer to message buffer chain | 1420 | * @head: pointer to message buffer chain |
| 1481 | * @tb_ptr: pointer to bearer message arrived on | 1421 | * @tb_ptr: pointer to bearer message arrived on |
| 1482 | * | 1422 | * |
| 1483 | * Invoked with no locks held. Bearer pointer must point to a valid bearer | 1423 | * Invoked with no locks held. Bearer pointer must point to a valid bearer |
| 1484 | * structure (i.e. cannot be NULL), but bearer can be inactive. | 1424 | * structure (i.e. cannot be NULL), but bearer can be inactive. |
| 1485 | */ | 1425 | */ |
| 1486 | void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *b_ptr) | 1426 | void tipc_rcv(struct sk_buff *head, struct tipc_bearer *b_ptr) |
| 1487 | { | 1427 | { |
| 1488 | read_lock_bh(&tipc_net_lock); | 1428 | read_lock_bh(&tipc_net_lock); |
| 1489 | while (head) { | 1429 | while (head) { |
| @@ -1658,7 +1598,7 @@ deliver: | |||
| 1658 | continue; | 1598 | continue; |
| 1659 | case CHANGEOVER_PROTOCOL: | 1599 | case CHANGEOVER_PROTOCOL: |
| 1660 | type = msg_type(msg); | 1600 | type = msg_type(msg); |
| 1661 | if (link_recv_changeover_msg(&l_ptr, &buf)) { | 1601 | if (tipc_link_tunnel_rcv(&l_ptr, &buf)) { |
| 1662 | msg = buf_msg(buf); | 1602 | msg = buf_msg(buf); |
| 1663 | seq_no = msg_seqno(msg); | 1603 | seq_no = msg_seqno(msg); |
| 1664 | if (type == ORIGINAL_MSG) | 1604 | if (type == ORIGINAL_MSG) |
| @@ -1787,7 +1727,8 @@ void tipc_link_send_proto_msg(struct tipc_link *l_ptr, u32 msg_typ, | |||
| 1787 | l_ptr->proto_msg_queue = NULL; | 1727 | l_ptr->proto_msg_queue = NULL; |
| 1788 | } | 1728 | } |
| 1789 | 1729 | ||
| 1790 | if (link_blocked(l_ptr)) | 1730 | /* Don't send protocol message during link changeover */ |
| 1731 | if (l_ptr->exp_msg_count) | ||
| 1791 | return; | 1732 | return; |
| 1792 | 1733 | ||
| 1793 | /* Abort non-RESET send if communication with node is prohibited */ | 1734 | /* Abort non-RESET send if communication with node is prohibited */ |
| @@ -1862,12 +1803,6 @@ void tipc_link_send_proto_msg(struct tipc_link *l_ptr, u32 msg_typ, | |||
| 1862 | skb_copy_to_linear_data(buf, msg, sizeof(l_ptr->proto_msg)); | 1803 | skb_copy_to_linear_data(buf, msg, sizeof(l_ptr->proto_msg)); |
| 1863 | buf->priority = TC_PRIO_CONTROL; | 1804 | buf->priority = TC_PRIO_CONTROL; |
| 1864 | 1805 | ||
| 1865 | /* Defer message if bearer is already blocked */ | ||
| 1866 | if (tipc_bearer_blocked(l_ptr->b_ptr)) { | ||
| 1867 | l_ptr->proto_msg_queue = buf; | ||
| 1868 | return; | ||
| 1869 | } | ||
| 1870 | |||
| 1871 | tipc_bearer_send(l_ptr->b_ptr, buf, &l_ptr->media_addr); | 1806 | tipc_bearer_send(l_ptr->b_ptr, buf, &l_ptr->media_addr); |
| 1872 | l_ptr->unacked_window = 0; | 1807 | l_ptr->unacked_window = 0; |
| 1873 | kfree_skb(buf); | 1808 | kfree_skb(buf); |
| @@ -1886,7 +1821,8 @@ static void link_recv_proto_msg(struct tipc_link *l_ptr, struct sk_buff *buf) | |||
| 1886 | u32 msg_tol; | 1821 | u32 msg_tol; |
| 1887 | struct tipc_msg *msg = buf_msg(buf); | 1822 | struct tipc_msg *msg = buf_msg(buf); |
| 1888 | 1823 | ||
| 1889 | if (link_blocked(l_ptr)) | 1824 | /* Discard protocol message during link changeover */ |
| 1825 | if (l_ptr->exp_msg_count) | ||
| 1890 | goto exit; | 1826 | goto exit; |
| 1891 | 1827 | ||
| 1892 | /* record unnumbered packet arrival (force mismatch on next timeout) */ | 1828 | /* record unnumbered packet arrival (force mismatch on next timeout) */ |
| @@ -1896,8 +1832,6 @@ static void link_recv_proto_msg(struct tipc_link *l_ptr, struct sk_buff *buf) | |||
| 1896 | if (tipc_own_addr > msg_prevnode(msg)) | 1832 | if (tipc_own_addr > msg_prevnode(msg)) |
| 1897 | l_ptr->b_ptr->net_plane = msg_net_plane(msg); | 1833 | l_ptr->b_ptr->net_plane = msg_net_plane(msg); |
| 1898 | 1834 | ||
| 1899 | l_ptr->owner->permit_changeover = msg_redundant_link(msg); | ||
| 1900 | |||
| 1901 | switch (msg_type(msg)) { | 1835 | switch (msg_type(msg)) { |
| 1902 | 1836 | ||
| 1903 | case RESET_MSG: | 1837 | case RESET_MSG: |
| @@ -2013,13 +1947,13 @@ exit: | |||
| 2013 | } | 1947 | } |
| 2014 | 1948 | ||
| 2015 | 1949 | ||
| 2016 | /* | 1950 | /* tipc_link_tunnel_xmit(): Tunnel one packet via a link belonging to |
| 2017 | * tipc_link_tunnel(): Send one message via a link belonging to | 1951 | * a different bearer. Owner node is locked. |
| 2018 | * another bearer. Owner node is locked. | ||
| 2019 | */ | 1952 | */ |
| 2020 | static void tipc_link_tunnel(struct tipc_link *l_ptr, | 1953 | static void tipc_link_tunnel_xmit(struct tipc_link *l_ptr, |
| 2021 | struct tipc_msg *tunnel_hdr, struct tipc_msg *msg, | 1954 | struct tipc_msg *tunnel_hdr, |
| 2022 | u32 selector) | 1955 | struct tipc_msg *msg, |
| 1956 | u32 selector) | ||
| 2023 | { | 1957 | { |
| 2024 | struct tipc_link *tunnel; | 1958 | struct tipc_link *tunnel; |
| 2025 | struct sk_buff *buf; | 1959 | struct sk_buff *buf; |
| @@ -2042,12 +1976,13 @@ static void tipc_link_tunnel(struct tipc_link *l_ptr, | |||
| 2042 | } | 1976 | } |
| 2043 | 1977 | ||
| 2044 | 1978 | ||
| 2045 | 1979 | /* tipc_link_failover_send_queue(): A link has gone down, but a second | |
| 2046 | /* | 1980 | * link is still active. We can do failover. Tunnel the failing link's |
| 2047 | * changeover(): Send whole message queue via the remaining link | 1981 | * whole send queue via the remaining link. This way, we don't lose |
| 2048 | * Owner node is locked. | 1982 | * any packets, and sequence order is preserved for subsequent traffic |
| 1983 | * sent over the remaining link. Owner node is locked. | ||
| 2049 | */ | 1984 | */ |
| 2050 | void tipc_link_changeover(struct tipc_link *l_ptr) | 1985 | void tipc_link_failover_send_queue(struct tipc_link *l_ptr) |
| 2051 | { | 1986 | { |
| 2052 | u32 msgcount = l_ptr->out_queue_size; | 1987 | u32 msgcount = l_ptr->out_queue_size; |
| 2053 | struct sk_buff *crs = l_ptr->first_out; | 1988 | struct sk_buff *crs = l_ptr->first_out; |
| @@ -2058,11 +1993,6 @@ void tipc_link_changeover(struct tipc_link *l_ptr) | |||
| 2058 | if (!tunnel) | 1993 | if (!tunnel) |
| 2059 | return; | 1994 | return; |
| 2060 | 1995 | ||
| 2061 | if (!l_ptr->owner->permit_changeover) { | ||
| 2062 | pr_warn("%speer did not permit changeover\n", link_co_err); | ||
| 2063 | return; | ||
| 2064 | } | ||
| 2065 | |||
| 2066 | tipc_msg_init(&tunnel_hdr, CHANGEOVER_PROTOCOL, | 1996 | tipc_msg_init(&tunnel_hdr, CHANGEOVER_PROTOCOL, |
| 2067 | ORIGINAL_MSG, INT_H_SIZE, l_ptr->addr); | 1997 | ORIGINAL_MSG, INT_H_SIZE, l_ptr->addr); |
| 2068 | msg_set_bearer_id(&tunnel_hdr, l_ptr->peer_bearer_id); | 1998 | msg_set_bearer_id(&tunnel_hdr, l_ptr->peer_bearer_id); |
| @@ -2096,20 +2026,30 @@ void tipc_link_changeover(struct tipc_link *l_ptr) | |||
| 2096 | msgcount = msg_msgcnt(msg); | 2026 | msgcount = msg_msgcnt(msg); |
| 2097 | while (msgcount--) { | 2027 | while (msgcount--) { |
| 2098 | msg_set_seqno(m, msg_seqno(msg)); | 2028 | msg_set_seqno(m, msg_seqno(msg)); |
| 2099 | tipc_link_tunnel(l_ptr, &tunnel_hdr, m, | 2029 | tipc_link_tunnel_xmit(l_ptr, &tunnel_hdr, m, |
| 2100 | msg_link_selector(m)); | 2030 | msg_link_selector(m)); |
| 2101 | pos += align(msg_size(m)); | 2031 | pos += align(msg_size(m)); |
| 2102 | m = (struct tipc_msg *)pos; | 2032 | m = (struct tipc_msg *)pos; |
| 2103 | } | 2033 | } |
| 2104 | } else { | 2034 | } else { |
| 2105 | tipc_link_tunnel(l_ptr, &tunnel_hdr, msg, | 2035 | tipc_link_tunnel_xmit(l_ptr, &tunnel_hdr, msg, |
| 2106 | msg_link_selector(msg)); | 2036 | msg_link_selector(msg)); |
| 2107 | } | 2037 | } |
| 2108 | crs = crs->next; | 2038 | crs = crs->next; |
| 2109 | } | 2039 | } |
| 2110 | } | 2040 | } |
| 2111 | 2041 | ||
| 2112 | void tipc_link_send_duplicate(struct tipc_link *l_ptr, struct tipc_link *tunnel) | 2042 | /* tipc_link_dup_send_queue(): A second link has become active. Tunnel a |
| 2043 | * duplicate of the first link's send queue via the new link. This way, we | ||
| 2044 | * are guaranteed that currently queued packets from a socket are delivered | ||
| 2045 | * before future traffic from the same socket, even if this is using the | ||
| 2046 | * new link. The last arriving copy of each duplicate packet is dropped at | ||
| 2047 | * the receiving end by the regular protocol check, so packet cardinality | ||
| 2048 | * and sequence order is preserved per sender/receiver socket pair. | ||
| 2049 | * Owner node is locked. | ||
| 2050 | */ | ||
| 2051 | void tipc_link_dup_send_queue(struct tipc_link *l_ptr, | ||
| 2052 | struct tipc_link *tunnel) | ||
| 2113 | { | 2053 | { |
| 2114 | struct sk_buff *iter; | 2054 | struct sk_buff *iter; |
| 2115 | struct tipc_msg tunnel_hdr; | 2055 | struct tipc_msg tunnel_hdr; |
| @@ -2165,12 +2105,14 @@ static struct sk_buff *buf_extract(struct sk_buff *skb, u32 from_pos) | |||
| 2165 | return eb; | 2105 | return eb; |
| 2166 | } | 2106 | } |
| 2167 | 2107 | ||
| 2168 | /* | 2108 | /* tipc_link_tunnel_rcv(): Receive a tunneled packet, sent |
| 2169 | * link_recv_changeover_msg(): Receive tunneled packet sent | 2109 | * via other link as result of a failover (ORIGINAL_MSG) or |
| 2170 | * via other link. Node is locked. Return extracted buffer. | 2110 | * a new active link (DUPLICATE_MSG). Failover packets are |
| 2111 | * returned to the active link for delivery upwards. | ||
| 2112 | * Owner node is locked. | ||
| 2171 | */ | 2113 | */ |
| 2172 | static int link_recv_changeover_msg(struct tipc_link **l_ptr, | 2114 | static int tipc_link_tunnel_rcv(struct tipc_link **l_ptr, |
| 2173 | struct sk_buff **buf) | 2115 | struct sk_buff **buf) |
| 2174 | { | 2116 | { |
| 2175 | struct sk_buff *tunnel_buf = *buf; | 2117 | struct sk_buff *tunnel_buf = *buf; |
| 2176 | struct tipc_link *dest_link; | 2118 | struct tipc_link *dest_link; |
| @@ -2307,11 +2249,7 @@ static int link_send_long_buf(struct tipc_link *l_ptr, struct sk_buff *buf) | |||
| 2307 | fragm = tipc_buf_acquire(fragm_sz + INT_H_SIZE); | 2249 | fragm = tipc_buf_acquire(fragm_sz + INT_H_SIZE); |
| 2308 | if (fragm == NULL) { | 2250 | if (fragm == NULL) { |
| 2309 | kfree_skb(buf); | 2251 | kfree_skb(buf); |
| 2310 | while (buf_chain) { | 2252 | kfree_skb_list(buf_chain); |
| 2311 | buf = buf_chain; | ||
| 2312 | buf_chain = buf_chain->next; | ||
| 2313 | kfree_skb(buf); | ||
| 2314 | } | ||
| 2315 | return -ENOMEM; | 2253 | return -ENOMEM; |
| 2316 | } | 2254 | } |
| 2317 | msg_set_size(&fragm_hdr, fragm_sz + INT_H_SIZE); | 2255 | msg_set_size(&fragm_hdr, fragm_sz + INT_H_SIZE); |
diff --git a/net/tipc/link.h b/net/tipc/link.h index 8a6c1026644d..3b6aa65b608c 100644 --- a/net/tipc/link.h +++ b/net/tipc/link.h | |||
| @@ -112,7 +112,6 @@ struct tipc_stats { | |||
| 112 | * @continuity_interval: link continuity testing interval [in ms] | 112 | * @continuity_interval: link continuity testing interval [in ms] |
| 113 | * @abort_limit: # of unacknowledged continuity probes needed to reset link | 113 | * @abort_limit: # of unacknowledged continuity probes needed to reset link |
| 114 | * @state: current state of link FSM | 114 | * @state: current state of link FSM |
| 115 | * @blocked: indicates if link has been administratively blocked | ||
| 116 | * @fsm_msg_cnt: # of protocol messages link FSM has sent in current state | 115 | * @fsm_msg_cnt: # of protocol messages link FSM has sent in current state |
| 117 | * @proto_msg: template for control messages generated by link | 116 | * @proto_msg: template for control messages generated by link |
| 118 | * @pmsg: convenience pointer to "proto_msg" field | 117 | * @pmsg: convenience pointer to "proto_msg" field |
| @@ -162,7 +161,6 @@ struct tipc_link { | |||
| 162 | u32 continuity_interval; | 161 | u32 continuity_interval; |
| 163 | u32 abort_limit; | 162 | u32 abort_limit; |
| 164 | int state; | 163 | int state; |
| 165 | int blocked; | ||
| 166 | u32 fsm_msg_cnt; | 164 | u32 fsm_msg_cnt; |
| 167 | struct { | 165 | struct { |
| 168 | unchar hdr[INT_H_SIZE]; | 166 | unchar hdr[INT_H_SIZE]; |
| @@ -218,16 +216,20 @@ struct tipc_link *tipc_link_create(struct tipc_node *n_ptr, | |||
| 218 | struct tipc_bearer *b_ptr, | 216 | struct tipc_bearer *b_ptr, |
| 219 | const struct tipc_media_addr *media_addr); | 217 | const struct tipc_media_addr *media_addr); |
| 220 | void tipc_link_delete(struct tipc_link *l_ptr); | 218 | void tipc_link_delete(struct tipc_link *l_ptr); |
| 221 | void tipc_link_changeover(struct tipc_link *l_ptr); | 219 | void tipc_link_failover_send_queue(struct tipc_link *l_ptr); |
| 222 | void tipc_link_send_duplicate(struct tipc_link *l_ptr, struct tipc_link *dest); | 220 | void tipc_link_dup_send_queue(struct tipc_link *l_ptr, |
| 221 | struct tipc_link *dest); | ||
| 223 | void tipc_link_reset_fragments(struct tipc_link *l_ptr); | 222 | void tipc_link_reset_fragments(struct tipc_link *l_ptr); |
| 224 | int tipc_link_is_up(struct tipc_link *l_ptr); | 223 | int tipc_link_is_up(struct tipc_link *l_ptr); |
| 225 | int tipc_link_is_active(struct tipc_link *l_ptr); | 224 | int tipc_link_is_active(struct tipc_link *l_ptr); |
| 226 | u32 tipc_link_push_packet(struct tipc_link *l_ptr); | 225 | void tipc_link_purge_queues(struct tipc_link *l_ptr); |
| 227 | void tipc_link_stop(struct tipc_link *l_ptr); | 226 | struct sk_buff *tipc_link_cmd_config(const void *req_tlv_area, |
| 228 | struct sk_buff *tipc_link_cmd_config(const void *req_tlv_area, int req_tlv_space, u16 cmd); | 227 | int req_tlv_space, |
| 229 | struct sk_buff *tipc_link_cmd_show_stats(const void *req_tlv_area, int req_tlv_space); | 228 | u16 cmd); |
| 230 | struct sk_buff *tipc_link_cmd_reset_stats(const void *req_tlv_area, int req_tlv_space); | 229 | struct sk_buff *tipc_link_cmd_show_stats(const void *req_tlv_area, |
| 230 | int req_tlv_space); | ||
| 231 | struct sk_buff *tipc_link_cmd_reset_stats(const void *req_tlv_area, | ||
| 232 | int req_tlv_space); | ||
| 231 | void tipc_link_reset(struct tipc_link *l_ptr); | 233 | void tipc_link_reset(struct tipc_link *l_ptr); |
| 232 | int tipc_link_send(struct sk_buff *buf, u32 dest, u32 selector); | 234 | int tipc_link_send(struct sk_buff *buf, u32 dest, u32 selector); |
| 233 | void tipc_link_send_names(struct list_head *message_list, u32 dest); | 235 | void tipc_link_send_names(struct list_head *message_list, u32 dest); |
| @@ -312,11 +314,6 @@ static inline int link_reset_reset(struct tipc_link *l_ptr) | |||
| 312 | return l_ptr->state == RESET_RESET; | 314 | return l_ptr->state == RESET_RESET; |
| 313 | } | 315 | } |
| 314 | 316 | ||
| 315 | static inline int link_blocked(struct tipc_link *l_ptr) | ||
| 316 | { | ||
| 317 | return l_ptr->exp_msg_count || l_ptr->blocked; | ||
| 318 | } | ||
| 319 | |||
| 320 | static inline int link_congested(struct tipc_link *l_ptr) | 317 | static inline int link_congested(struct tipc_link *l_ptr) |
| 321 | { | 318 | { |
| 322 | return l_ptr->out_queue_size >= l_ptr->queue_limit[0]; | 319 | return l_ptr->out_queue_size >= l_ptr->queue_limit[0]; |
diff --git a/net/tipc/name_table.c b/net/tipc/name_table.c index 09dcd54b04e1..92a1533af4e0 100644 --- a/net/tipc/name_table.c +++ b/net/tipc/name_table.c | |||
| @@ -148,8 +148,7 @@ static struct publication *publ_create(u32 type, u32 lower, u32 upper, | |||
| 148 | */ | 148 | */ |
| 149 | static struct sub_seq *tipc_subseq_alloc(u32 cnt) | 149 | static struct sub_seq *tipc_subseq_alloc(u32 cnt) |
| 150 | { | 150 | { |
| 151 | struct sub_seq *sseq = kcalloc(cnt, sizeof(struct sub_seq), GFP_ATOMIC); | 151 | return kcalloc(cnt, sizeof(struct sub_seq), GFP_ATOMIC); |
| 152 | return sseq; | ||
| 153 | } | 152 | } |
| 154 | 153 | ||
| 155 | /** | 154 | /** |
diff --git a/net/tipc/node.c b/net/tipc/node.c index 25100c0a6fe8..efe4d41bf11b 100644 --- a/net/tipc/node.c +++ b/net/tipc/node.c | |||
| @@ -162,7 +162,7 @@ void tipc_node_link_up(struct tipc_node *n_ptr, struct tipc_link *l_ptr) | |||
| 162 | pr_info("New link <%s> becomes standby\n", l_ptr->name); | 162 | pr_info("New link <%s> becomes standby\n", l_ptr->name); |
| 163 | return; | 163 | return; |
| 164 | } | 164 | } |
| 165 | tipc_link_send_duplicate(active[0], l_ptr); | 165 | tipc_link_dup_send_queue(active[0], l_ptr); |
| 166 | if (l_ptr->priority == active[0]->priority) { | 166 | if (l_ptr->priority == active[0]->priority) { |
| 167 | active[0] = l_ptr; | 167 | active[0] = l_ptr; |
| 168 | return; | 168 | return; |
| @@ -225,7 +225,7 @@ void tipc_node_link_down(struct tipc_node *n_ptr, struct tipc_link *l_ptr) | |||
| 225 | if (active[0] == l_ptr) | 225 | if (active[0] == l_ptr) |
| 226 | node_select_active_links(n_ptr); | 226 | node_select_active_links(n_ptr); |
| 227 | if (tipc_node_is_up(n_ptr)) | 227 | if (tipc_node_is_up(n_ptr)) |
| 228 | tipc_link_changeover(l_ptr); | 228 | tipc_link_failover_send_queue(l_ptr); |
| 229 | else | 229 | else |
| 230 | node_lost_contact(n_ptr); | 230 | node_lost_contact(n_ptr); |
| 231 | } | 231 | } |
| @@ -235,11 +235,6 @@ int tipc_node_active_links(struct tipc_node *n_ptr) | |||
| 235 | return n_ptr->active_links[0] != NULL; | 235 | return n_ptr->active_links[0] != NULL; |
| 236 | } | 236 | } |
| 237 | 237 | ||
| 238 | int tipc_node_redundant_links(struct tipc_node *n_ptr) | ||
| 239 | { | ||
| 240 | return n_ptr->working_links > 1; | ||
| 241 | } | ||
| 242 | |||
| 243 | int tipc_node_is_up(struct tipc_node *n_ptr) | 238 | int tipc_node_is_up(struct tipc_node *n_ptr) |
| 244 | { | 239 | { |
| 245 | return tipc_node_active_links(n_ptr); | 240 | return tipc_node_active_links(n_ptr); |
| @@ -291,11 +286,7 @@ static void node_lost_contact(struct tipc_node *n_ptr) | |||
| 291 | 286 | ||
| 292 | /* Flush broadcast link info associated with lost node */ | 287 | /* Flush broadcast link info associated with lost node */ |
| 293 | if (n_ptr->bclink.recv_permitted) { | 288 | if (n_ptr->bclink.recv_permitted) { |
| 294 | while (n_ptr->bclink.deferred_head) { | 289 | kfree_skb_list(n_ptr->bclink.deferred_head); |
| 295 | struct sk_buff *buf = n_ptr->bclink.deferred_head; | ||
| 296 | n_ptr->bclink.deferred_head = buf->next; | ||
| 297 | kfree_skb(buf); | ||
| 298 | } | ||
| 299 | n_ptr->bclink.deferred_size = 0; | 290 | n_ptr->bclink.deferred_size = 0; |
| 300 | 291 | ||
| 301 | if (n_ptr->bclink.reasm_head) { | 292 | if (n_ptr->bclink.reasm_head) { |
diff --git a/net/tipc/node.h b/net/tipc/node.h index e5e96c04e167..63e2e8ead2fe 100644 --- a/net/tipc/node.h +++ b/net/tipc/node.h | |||
| @@ -64,7 +64,6 @@ | |||
| 64 | * @working_links: number of working links to node (both active and standby) | 64 | * @working_links: number of working links to node (both active and standby) |
| 65 | * @block_setup: bit mask of conditions preventing link establishment to node | 65 | * @block_setup: bit mask of conditions preventing link establishment to node |
| 66 | * @link_cnt: number of links to node | 66 | * @link_cnt: number of links to node |
| 67 | * @permit_changeover: non-zero if node has redundant links to this system | ||
| 68 | * @signature: node instance identifier | 67 | * @signature: node instance identifier |
| 69 | * @bclink: broadcast-related info | 68 | * @bclink: broadcast-related info |
| 70 | * @acked: sequence # of last outbound b'cast message acknowledged by node | 69 | * @acked: sequence # of last outbound b'cast message acknowledged by node |
| @@ -89,7 +88,6 @@ struct tipc_node { | |||
| 89 | int link_cnt; | 88 | int link_cnt; |
| 90 | int working_links; | 89 | int working_links; |
| 91 | int block_setup; | 90 | int block_setup; |
| 92 | int permit_changeover; | ||
| 93 | u32 signature; | 91 | u32 signature; |
| 94 | struct { | 92 | struct { |
| 95 | u32 acked; | 93 | u32 acked; |
| @@ -115,7 +113,6 @@ void tipc_node_detach_link(struct tipc_node *n_ptr, struct tipc_link *l_ptr); | |||
| 115 | void tipc_node_link_down(struct tipc_node *n_ptr, struct tipc_link *l_ptr); | 113 | void tipc_node_link_down(struct tipc_node *n_ptr, struct tipc_link *l_ptr); |
| 116 | void tipc_node_link_up(struct tipc_node *n_ptr, struct tipc_link *l_ptr); | 114 | void tipc_node_link_up(struct tipc_node *n_ptr, struct tipc_link *l_ptr); |
| 117 | int tipc_node_active_links(struct tipc_node *n_ptr); | 115 | int tipc_node_active_links(struct tipc_node *n_ptr); |
| 118 | int tipc_node_redundant_links(struct tipc_node *n_ptr); | ||
| 119 | int tipc_node_is_up(struct tipc_node *n_ptr); | 116 | int tipc_node_is_up(struct tipc_node *n_ptr); |
| 120 | struct sk_buff *tipc_node_get_links(const void *req_tlv_area, int req_tlv_space); | 117 | struct sk_buff *tipc_node_get_links(const void *req_tlv_area, int req_tlv_space); |
| 121 | struct sk_buff *tipc_node_get_nodes(const void *req_tlv_area, int req_tlv_space); | 118 | struct sk_buff *tipc_node_get_nodes(const void *req_tlv_area, int req_tlv_space); |
diff --git a/net/tipc/port.c b/net/tipc/port.c index d43f3182b1d4..b742b2654525 100644 --- a/net/tipc/port.c +++ b/net/tipc/port.c | |||
| @@ -817,17 +817,14 @@ exit: | |||
| 817 | */ | 817 | */ |
| 818 | int __tipc_disconnect(struct tipc_port *tp_ptr) | 818 | int __tipc_disconnect(struct tipc_port *tp_ptr) |
| 819 | { | 819 | { |
| 820 | int res; | ||
| 821 | |||
| 822 | if (tp_ptr->connected) { | 820 | if (tp_ptr->connected) { |
| 823 | tp_ptr->connected = 0; | 821 | tp_ptr->connected = 0; |
| 824 | /* let timer expire on it's own to avoid deadlock! */ | 822 | /* let timer expire on it's own to avoid deadlock! */ |
| 825 | tipc_nodesub_unsubscribe(&tp_ptr->subscription); | 823 | tipc_nodesub_unsubscribe(&tp_ptr->subscription); |
| 826 | res = 0; | 824 | return 0; |
| 827 | } else { | ||
| 828 | res = -ENOTCONN; | ||
| 829 | } | 825 | } |
| 830 | return res; | 826 | |
| 827 | return -ENOTCONN; | ||
| 831 | } | 828 | } |
| 832 | 829 | ||
| 833 | /* | 830 | /* |
diff --git a/net/tipc/server.c b/net/tipc/server.c index fd3fa57a410e..b635ca347a87 100644 --- a/net/tipc/server.c +++ b/net/tipc/server.c | |||
| @@ -55,7 +55,7 @@ | |||
| 55 | * @usr_data: user-specified field | 55 | * @usr_data: user-specified field |
| 56 | * @rx_action: what to do when connection socket is active | 56 | * @rx_action: what to do when connection socket is active |
| 57 | * @outqueue: pointer to first outbound message in queue | 57 | * @outqueue: pointer to first outbound message in queue |
| 58 | * @outqueue_lock: controll access to the outqueue | 58 | * @outqueue_lock: control access to the outqueue |
| 59 | * @outqueue: list of connection objects for its server | 59 | * @outqueue: list of connection objects for its server |
| 60 | * @swork: send work item | 60 | * @swork: send work item |
| 61 | */ | 61 | */ |
diff --git a/net/tipc/socket.c b/net/tipc/socket.c index e741416d1d24..aab4948f0aff 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c | |||
| @@ -55,9 +55,6 @@ struct tipc_sock { | |||
| 55 | #define tipc_sk(sk) ((struct tipc_sock *)(sk)) | 55 | #define tipc_sk(sk) ((struct tipc_sock *)(sk)) |
| 56 | #define tipc_sk_port(sk) (tipc_sk(sk)->p) | 56 | #define tipc_sk_port(sk) (tipc_sk(sk)->p) |
| 57 | 57 | ||
| 58 | #define tipc_rx_ready(sock) (!skb_queue_empty(&sock->sk->sk_receive_queue) || \ | ||
| 59 | (sock->state == SS_DISCONNECTING)) | ||
| 60 | |||
| 61 | static int backlog_rcv(struct sock *sk, struct sk_buff *skb); | 58 | static int backlog_rcv(struct sock *sk, struct sk_buff *skb); |
| 62 | static u32 dispatch(struct tipc_port *tport, struct sk_buff *buf); | 59 | static u32 dispatch(struct tipc_port *tport, struct sk_buff *buf); |
| 63 | static void wakeupdispatch(struct tipc_port *tport); | 60 | static void wakeupdispatch(struct tipc_port *tport); |
| @@ -239,7 +236,6 @@ static int tipc_sk_create(struct net *net, struct socket *sock, int protocol, | |||
| 239 | int tipc_sock_create_local(int type, struct socket **res) | 236 | int tipc_sock_create_local(int type, struct socket **res) |
| 240 | { | 237 | { |
| 241 | int rc; | 238 | int rc; |
| 242 | struct sock *sk; | ||
| 243 | 239 | ||
| 244 | rc = sock_create_lite(AF_TIPC, type, 0, res); | 240 | rc = sock_create_lite(AF_TIPC, type, 0, res); |
| 245 | if (rc < 0) { | 241 | if (rc < 0) { |
| @@ -248,8 +244,6 @@ int tipc_sock_create_local(int type, struct socket **res) | |||
| 248 | } | 244 | } |
| 249 | tipc_sk_create(&init_net, *res, 0, 1); | 245 | tipc_sk_create(&init_net, *res, 0, 1); |
| 250 | 246 | ||
| 251 | sk = (*res)->sk; | ||
| 252 | |||
| 253 | return 0; | 247 | return 0; |
| 254 | } | 248 | } |
| 255 | 249 | ||
| @@ -570,6 +564,31 @@ static int dest_name_check(struct sockaddr_tipc *dest, struct msghdr *m) | |||
| 570 | return 0; | 564 | return 0; |
| 571 | } | 565 | } |
| 572 | 566 | ||
| 567 | static int tipc_wait_for_sndmsg(struct socket *sock, long *timeo_p) | ||
| 568 | { | ||
| 569 | struct sock *sk = sock->sk; | ||
| 570 | struct tipc_port *tport = tipc_sk_port(sk); | ||
| 571 | DEFINE_WAIT(wait); | ||
| 572 | int done; | ||
| 573 | |||
| 574 | do { | ||
| 575 | int err = sock_error(sk); | ||
| 576 | if (err) | ||
| 577 | return err; | ||
| 578 | if (sock->state == SS_DISCONNECTING) | ||
| 579 | return -EPIPE; | ||
| 580 | if (!*timeo_p) | ||
| 581 | return -EAGAIN; | ||
| 582 | if (signal_pending(current)) | ||
| 583 | return sock_intr_errno(*timeo_p); | ||
| 584 | |||
| 585 | prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); | ||
| 586 | done = sk_wait_event(sk, timeo_p, !tport->congested); | ||
| 587 | finish_wait(sk_sleep(sk), &wait); | ||
| 588 | } while (!done); | ||
| 589 | return 0; | ||
| 590 | } | ||
| 591 | |||
| 573 | /** | 592 | /** |
| 574 | * send_msg - send message in connectionless manner | 593 | * send_msg - send message in connectionless manner |
| 575 | * @iocb: if NULL, indicates that socket lock is already held | 594 | * @iocb: if NULL, indicates that socket lock is already held |
| @@ -589,9 +608,9 @@ static int send_msg(struct kiocb *iocb, struct socket *sock, | |||
| 589 | { | 608 | { |
| 590 | struct sock *sk = sock->sk; | 609 | struct sock *sk = sock->sk; |
| 591 | struct tipc_port *tport = tipc_sk_port(sk); | 610 | struct tipc_port *tport = tipc_sk_port(sk); |
| 592 | struct sockaddr_tipc *dest = (struct sockaddr_tipc *)m->msg_name; | 611 | DECLARE_SOCKADDR(struct sockaddr_tipc *, dest, m->msg_name); |
| 593 | int needs_conn; | 612 | int needs_conn; |
| 594 | long timeout_val; | 613 | long timeo; |
| 595 | int res = -EINVAL; | 614 | int res = -EINVAL; |
| 596 | 615 | ||
| 597 | if (unlikely(!dest)) | 616 | if (unlikely(!dest)) |
| @@ -628,8 +647,7 @@ static int send_msg(struct kiocb *iocb, struct socket *sock, | |||
| 628 | reject_rx_queue(sk); | 647 | reject_rx_queue(sk); |
| 629 | } | 648 | } |
| 630 | 649 | ||
| 631 | timeout_val = sock_sndtimeo(sk, m->msg_flags & MSG_DONTWAIT); | 650 | timeo = sock_sndtimeo(sk, m->msg_flags & MSG_DONTWAIT); |
| 632 | |||
| 633 | do { | 651 | do { |
| 634 | if (dest->addrtype == TIPC_ADDR_NAME) { | 652 | if (dest->addrtype == TIPC_ADDR_NAME) { |
| 635 | res = dest_name_check(dest, m); | 653 | res = dest_name_check(dest, m); |
| @@ -663,14 +681,9 @@ static int send_msg(struct kiocb *iocb, struct socket *sock, | |||
| 663 | sock->state = SS_CONNECTING; | 681 | sock->state = SS_CONNECTING; |
| 664 | break; | 682 | break; |
| 665 | } | 683 | } |
| 666 | if (timeout_val <= 0L) { | 684 | res = tipc_wait_for_sndmsg(sock, &timeo); |
| 667 | res = timeout_val ? timeout_val : -EWOULDBLOCK; | 685 | if (res) |
| 668 | break; | 686 | break; |
| 669 | } | ||
| 670 | release_sock(sk); | ||
| 671 | timeout_val = wait_event_interruptible_timeout(*sk_sleep(sk), | ||
| 672 | !tport->congested, timeout_val); | ||
| 673 | lock_sock(sk); | ||
| 674 | } while (1); | 687 | } while (1); |
| 675 | 688 | ||
| 676 | exit: | 689 | exit: |
| @@ -679,6 +692,34 @@ exit: | |||
| 679 | return res; | 692 | return res; |
| 680 | } | 693 | } |
| 681 | 694 | ||
| 695 | static int tipc_wait_for_sndpkt(struct socket *sock, long *timeo_p) | ||
| 696 | { | ||
| 697 | struct sock *sk = sock->sk; | ||
| 698 | struct tipc_port *tport = tipc_sk_port(sk); | ||
| 699 | DEFINE_WAIT(wait); | ||
| 700 | int done; | ||
| 701 | |||
| 702 | do { | ||
| 703 | int err = sock_error(sk); | ||
| 704 | if (err) | ||
| 705 | return err; | ||
| 706 | if (sock->state == SS_DISCONNECTING) | ||
| 707 | return -EPIPE; | ||
| 708 | else if (sock->state != SS_CONNECTED) | ||
| 709 | return -ENOTCONN; | ||
| 710 | if (!*timeo_p) | ||
| 711 | return -EAGAIN; | ||
| 712 | if (signal_pending(current)) | ||
| 713 | return sock_intr_errno(*timeo_p); | ||
| 714 | |||
| 715 | prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); | ||
| 716 | done = sk_wait_event(sk, timeo_p, | ||
| 717 | (!tport->congested || !tport->connected)); | ||
| 718 | finish_wait(sk_sleep(sk), &wait); | ||
| 719 | } while (!done); | ||
| 720 | return 0; | ||
| 721 | } | ||
| 722 | |||
| 682 | /** | 723 | /** |
| 683 | * send_packet - send a connection-oriented message | 724 | * send_packet - send a connection-oriented message |
| 684 | * @iocb: if NULL, indicates that socket lock is already held | 725 | * @iocb: if NULL, indicates that socket lock is already held |
| @@ -695,9 +736,9 @@ static int send_packet(struct kiocb *iocb, struct socket *sock, | |||
| 695 | { | 736 | { |
| 696 | struct sock *sk = sock->sk; | 737 | struct sock *sk = sock->sk; |
| 697 | struct tipc_port *tport = tipc_sk_port(sk); | 738 | struct tipc_port *tport = tipc_sk_port(sk); |
| 698 | struct sockaddr_tipc *dest = (struct sockaddr_tipc *)m->msg_name; | 739 | DECLARE_SOCKADDR(struct sockaddr_tipc *, dest, m->msg_name); |
| 699 | long timeout_val; | 740 | int res = -EINVAL; |
| 700 | int res; | 741 | long timeo; |
| 701 | 742 | ||
| 702 | /* Handle implied connection establishment */ | 743 | /* Handle implied connection establishment */ |
| 703 | if (unlikely(dest)) | 744 | if (unlikely(dest)) |
| @@ -709,30 +750,24 @@ static int send_packet(struct kiocb *iocb, struct socket *sock, | |||
| 709 | if (iocb) | 750 | if (iocb) |
| 710 | lock_sock(sk); | 751 | lock_sock(sk); |
| 711 | 752 | ||
| 712 | timeout_val = sock_sndtimeo(sk, m->msg_flags & MSG_DONTWAIT); | 753 | if (unlikely(sock->state != SS_CONNECTED)) { |
| 754 | if (sock->state == SS_DISCONNECTING) | ||
| 755 | res = -EPIPE; | ||
| 756 | else | ||
| 757 | res = -ENOTCONN; | ||
| 758 | goto exit; | ||
| 759 | } | ||
| 713 | 760 | ||
| 761 | timeo = sock_sndtimeo(sk, m->msg_flags & MSG_DONTWAIT); | ||
| 714 | do { | 762 | do { |
| 715 | if (unlikely(sock->state != SS_CONNECTED)) { | ||
| 716 | if (sock->state == SS_DISCONNECTING) | ||
| 717 | res = -EPIPE; | ||
| 718 | else | ||
| 719 | res = -ENOTCONN; | ||
| 720 | break; | ||
| 721 | } | ||
| 722 | |||
| 723 | res = tipc_send(tport->ref, m->msg_iov, total_len); | 763 | res = tipc_send(tport->ref, m->msg_iov, total_len); |
| 724 | if (likely(res != -ELINKCONG)) | 764 | if (likely(res != -ELINKCONG)) |
| 725 | break; | 765 | break; |
| 726 | if (timeout_val <= 0L) { | 766 | res = tipc_wait_for_sndpkt(sock, &timeo); |
| 727 | res = timeout_val ? timeout_val : -EWOULDBLOCK; | 767 | if (res) |
| 728 | break; | 768 | break; |
| 729 | } | ||
| 730 | release_sock(sk); | ||
| 731 | timeout_val = wait_event_interruptible_timeout(*sk_sleep(sk), | ||
| 732 | (!tport->congested || !tport->connected), timeout_val); | ||
| 733 | lock_sock(sk); | ||
| 734 | } while (1); | 769 | } while (1); |
| 735 | 770 | exit: | |
| 736 | if (iocb) | 771 | if (iocb) |
| 737 | release_sock(sk); | 772 | release_sock(sk); |
| 738 | return res; | 773 | return res; |
| @@ -770,16 +805,11 @@ static int send_stream(struct kiocb *iocb, struct socket *sock, | |||
| 770 | 805 | ||
| 771 | /* Handle special cases where there is no connection */ | 806 | /* Handle special cases where there is no connection */ |
| 772 | if (unlikely(sock->state != SS_CONNECTED)) { | 807 | if (unlikely(sock->state != SS_CONNECTED)) { |
| 773 | if (sock->state == SS_UNCONNECTED) { | 808 | if (sock->state == SS_UNCONNECTED) |
| 774 | res = send_packet(NULL, sock, m, total_len); | 809 | res = send_packet(NULL, sock, m, total_len); |
| 775 | goto exit; | 810 | else |
| 776 | } else if (sock->state == SS_DISCONNECTING) { | 811 | res = sock->state == SS_DISCONNECTING ? -EPIPE : -ENOTCONN; |
| 777 | res = -EPIPE; | 812 | goto exit; |
| 778 | goto exit; | ||
| 779 | } else { | ||
| 780 | res = -ENOTCONN; | ||
| 781 | goto exit; | ||
| 782 | } | ||
| 783 | } | 813 | } |
| 784 | 814 | ||
| 785 | if (unlikely(m->msg_name)) { | 815 | if (unlikely(m->msg_name)) { |
| @@ -876,7 +906,7 @@ static int auto_connect(struct socket *sock, struct tipc_msg *msg) | |||
| 876 | */ | 906 | */ |
| 877 | static void set_orig_addr(struct msghdr *m, struct tipc_msg *msg) | 907 | static void set_orig_addr(struct msghdr *m, struct tipc_msg *msg) |
| 878 | { | 908 | { |
| 879 | struct sockaddr_tipc *addr = (struct sockaddr_tipc *)m->msg_name; | 909 | DECLARE_SOCKADDR(struct sockaddr_tipc *, addr, m->msg_name); |
| 880 | 910 | ||
| 881 | if (addr) { | 911 | if (addr) { |
| 882 | addr->family = AF_TIPC; | 912 | addr->family = AF_TIPC; |
| @@ -961,6 +991,37 @@ static int anc_data_recv(struct msghdr *m, struct tipc_msg *msg, | |||
| 961 | return 0; | 991 | return 0; |
| 962 | } | 992 | } |
| 963 | 993 | ||
| 994 | static int tipc_wait_for_rcvmsg(struct socket *sock, long timeo) | ||
| 995 | { | ||
| 996 | struct sock *sk = sock->sk; | ||
| 997 | DEFINE_WAIT(wait); | ||
| 998 | int err; | ||
| 999 | |||
| 1000 | for (;;) { | ||
| 1001 | prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); | ||
| 1002 | if (skb_queue_empty(&sk->sk_receive_queue)) { | ||
| 1003 | if (sock->state == SS_DISCONNECTING) { | ||
| 1004 | err = -ENOTCONN; | ||
| 1005 | break; | ||
| 1006 | } | ||
| 1007 | release_sock(sk); | ||
| 1008 | timeo = schedule_timeout(timeo); | ||
| 1009 | lock_sock(sk); | ||
| 1010 | } | ||
| 1011 | err = 0; | ||
| 1012 | if (!skb_queue_empty(&sk->sk_receive_queue)) | ||
| 1013 | break; | ||
| 1014 | err = sock_intr_errno(timeo); | ||
| 1015 | if (signal_pending(current)) | ||
| 1016 | break; | ||
| 1017 | err = -EAGAIN; | ||
| 1018 | if (!timeo) | ||
| 1019 | break; | ||
| 1020 | } | ||
| 1021 | finish_wait(sk_sleep(sk), &wait); | ||
| 1022 | return err; | ||
| 1023 | } | ||
| 1024 | |||
| 964 | /** | 1025 | /** |
| 965 | * recv_msg - receive packet-oriented message | 1026 | * recv_msg - receive packet-oriented message |
| 966 | * @iocb: (unused) | 1027 | * @iocb: (unused) |
| @@ -980,7 +1041,7 @@ static int recv_msg(struct kiocb *iocb, struct socket *sock, | |||
| 980 | struct tipc_port *tport = tipc_sk_port(sk); | 1041 | struct tipc_port *tport = tipc_sk_port(sk); |
| 981 | struct sk_buff *buf; | 1042 | struct sk_buff *buf; |
| 982 | struct tipc_msg *msg; | 1043 | struct tipc_msg *msg; |
| 983 | long timeout; | 1044 | long timeo; |
| 984 | unsigned int sz; | 1045 | unsigned int sz; |
| 985 | u32 err; | 1046 | u32 err; |
| 986 | int res; | 1047 | int res; |
| @@ -996,25 +1057,13 @@ static int recv_msg(struct kiocb *iocb, struct socket *sock, | |||
| 996 | goto exit; | 1057 | goto exit; |
| 997 | } | 1058 | } |
| 998 | 1059 | ||
| 999 | timeout = sock_rcvtimeo(sk, flags & MSG_DONTWAIT); | 1060 | timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT); |
| 1000 | restart: | 1061 | restart: |
| 1001 | 1062 | ||
| 1002 | /* Look for a message in receive queue; wait if necessary */ | 1063 | /* Look for a message in receive queue; wait if necessary */ |
| 1003 | while (skb_queue_empty(&sk->sk_receive_queue)) { | 1064 | res = tipc_wait_for_rcvmsg(sock, timeo); |
| 1004 | if (sock->state == SS_DISCONNECTING) { | 1065 | if (res) |
| 1005 | res = -ENOTCONN; | 1066 | goto exit; |
| 1006 | goto exit; | ||
| 1007 | } | ||
| 1008 | if (timeout <= 0L) { | ||
| 1009 | res = timeout ? timeout : -EWOULDBLOCK; | ||
| 1010 | goto exit; | ||
| 1011 | } | ||
| 1012 | release_sock(sk); | ||
| 1013 | timeout = wait_event_interruptible_timeout(*sk_sleep(sk), | ||
| 1014 | tipc_rx_ready(sock), | ||
| 1015 | timeout); | ||
| 1016 | lock_sock(sk); | ||
| 1017 | } | ||
| 1018 | 1067 | ||
| 1019 | /* Look at first message in receive queue */ | 1068 | /* Look at first message in receive queue */ |
| 1020 | buf = skb_peek(&sk->sk_receive_queue); | 1069 | buf = skb_peek(&sk->sk_receive_queue); |
| @@ -1086,7 +1135,7 @@ static int recv_stream(struct kiocb *iocb, struct socket *sock, | |||
| 1086 | struct tipc_port *tport = tipc_sk_port(sk); | 1135 | struct tipc_port *tport = tipc_sk_port(sk); |
| 1087 | struct sk_buff *buf; | 1136 | struct sk_buff *buf; |
| 1088 | struct tipc_msg *msg; | 1137 | struct tipc_msg *msg; |
| 1089 | long timeout; | 1138 | long timeo; |
| 1090 | unsigned int sz; | 1139 | unsigned int sz; |
| 1091 | int sz_to_copy, target, needed; | 1140 | int sz_to_copy, target, needed; |
| 1092 | int sz_copied = 0; | 1141 | int sz_copied = 0; |
| @@ -1099,31 +1148,19 @@ static int recv_stream(struct kiocb *iocb, struct socket *sock, | |||
| 1099 | 1148 | ||
| 1100 | lock_sock(sk); | 1149 | lock_sock(sk); |
| 1101 | 1150 | ||
| 1102 | if (unlikely((sock->state == SS_UNCONNECTED))) { | 1151 | if (unlikely(sock->state == SS_UNCONNECTED)) { |
| 1103 | res = -ENOTCONN; | 1152 | res = -ENOTCONN; |
| 1104 | goto exit; | 1153 | goto exit; |
| 1105 | } | 1154 | } |
| 1106 | 1155 | ||
| 1107 | target = sock_rcvlowat(sk, flags & MSG_WAITALL, buf_len); | 1156 | target = sock_rcvlowat(sk, flags & MSG_WAITALL, buf_len); |
| 1108 | timeout = sock_rcvtimeo(sk, flags & MSG_DONTWAIT); | 1157 | timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT); |
| 1109 | 1158 | ||
| 1110 | restart: | 1159 | restart: |
| 1111 | /* Look for a message in receive queue; wait if necessary */ | 1160 | /* Look for a message in receive queue; wait if necessary */ |
| 1112 | while (skb_queue_empty(&sk->sk_receive_queue)) { | 1161 | res = tipc_wait_for_rcvmsg(sock, timeo); |
| 1113 | if (sock->state == SS_DISCONNECTING) { | 1162 | if (res) |
| 1114 | res = -ENOTCONN; | 1163 | goto exit; |
| 1115 | goto exit; | ||
| 1116 | } | ||
| 1117 | if (timeout <= 0L) { | ||
| 1118 | res = timeout ? timeout : -EWOULDBLOCK; | ||
| 1119 | goto exit; | ||
| 1120 | } | ||
| 1121 | release_sock(sk); | ||
| 1122 | timeout = wait_event_interruptible_timeout(*sk_sleep(sk), | ||
| 1123 | tipc_rx_ready(sock), | ||
| 1124 | timeout); | ||
| 1125 | lock_sock(sk); | ||
| 1126 | } | ||
| 1127 | 1164 | ||
| 1128 | /* Look at first message in receive queue */ | 1165 | /* Look at first message in receive queue */ |
| 1129 | buf = skb_peek(&sk->sk_receive_queue); | 1166 | buf = skb_peek(&sk->sk_receive_queue); |
| @@ -1327,14 +1364,12 @@ static u32 filter_connect(struct tipc_sock *tsock, struct sk_buff **buf) | |||
| 1327 | static unsigned int rcvbuf_limit(struct sock *sk, struct sk_buff *buf) | 1364 | static unsigned int rcvbuf_limit(struct sock *sk, struct sk_buff *buf) |
| 1328 | { | 1365 | { |
| 1329 | struct tipc_msg *msg = buf_msg(buf); | 1366 | struct tipc_msg *msg = buf_msg(buf); |
| 1330 | unsigned int limit; | ||
| 1331 | 1367 | ||
| 1332 | if (msg_connected(msg)) | 1368 | if (msg_connected(msg)) |
| 1333 | limit = sysctl_tipc_rmem[2]; | 1369 | return sysctl_tipc_rmem[2]; |
| 1334 | else | 1370 | |
| 1335 | limit = sk->sk_rcvbuf >> TIPC_CRITICAL_IMPORTANCE << | 1371 | return sk->sk_rcvbuf >> TIPC_CRITICAL_IMPORTANCE << |
| 1336 | msg_importance(msg); | 1372 | msg_importance(msg); |
| 1337 | return limit; | ||
| 1338 | } | 1373 | } |
| 1339 | 1374 | ||
| 1340 | /** | 1375 | /** |
| @@ -1448,6 +1483,28 @@ static void wakeupdispatch(struct tipc_port *tport) | |||
| 1448 | sk->sk_write_space(sk); | 1483 | sk->sk_write_space(sk); |
| 1449 | } | 1484 | } |
| 1450 | 1485 | ||
| 1486 | static int tipc_wait_for_connect(struct socket *sock, long *timeo_p) | ||
| 1487 | { | ||
| 1488 | struct sock *sk = sock->sk; | ||
| 1489 | DEFINE_WAIT(wait); | ||
| 1490 | int done; | ||
| 1491 | |||
| 1492 | do { | ||
| 1493 | int err = sock_error(sk); | ||
| 1494 | if (err) | ||
| 1495 | return err; | ||
| 1496 | if (!*timeo_p) | ||
| 1497 | return -ETIMEDOUT; | ||
| 1498 | if (signal_pending(current)) | ||
| 1499 | return sock_intr_errno(*timeo_p); | ||
| 1500 | |||
| 1501 | prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); | ||
| 1502 | done = sk_wait_event(sk, timeo_p, sock->state != SS_CONNECTING); | ||
| 1503 | finish_wait(sk_sleep(sk), &wait); | ||
| 1504 | } while (!done); | ||
| 1505 | return 0; | ||
| 1506 | } | ||
| 1507 | |||
| 1451 | /** | 1508 | /** |
| 1452 | * connect - establish a connection to another TIPC port | 1509 | * connect - establish a connection to another TIPC port |
| 1453 | * @sock: socket structure | 1510 | * @sock: socket structure |
| @@ -1463,7 +1520,8 @@ static int connect(struct socket *sock, struct sockaddr *dest, int destlen, | |||
| 1463 | struct sock *sk = sock->sk; | 1520 | struct sock *sk = sock->sk; |
| 1464 | struct sockaddr_tipc *dst = (struct sockaddr_tipc *)dest; | 1521 | struct sockaddr_tipc *dst = (struct sockaddr_tipc *)dest; |
| 1465 | struct msghdr m = {NULL,}; | 1522 | struct msghdr m = {NULL,}; |
| 1466 | unsigned int timeout; | 1523 | long timeout = (flags & O_NONBLOCK) ? 0 : tipc_sk(sk)->conn_timeout; |
| 1524 | socket_state previous; | ||
| 1467 | int res; | 1525 | int res; |
| 1468 | 1526 | ||
| 1469 | lock_sock(sk); | 1527 | lock_sock(sk); |
| @@ -1485,8 +1543,7 @@ static int connect(struct socket *sock, struct sockaddr *dest, int destlen, | |||
| 1485 | goto exit; | 1543 | goto exit; |
| 1486 | } | 1544 | } |
| 1487 | 1545 | ||
| 1488 | timeout = (flags & O_NONBLOCK) ? 0 : tipc_sk(sk)->conn_timeout; | 1546 | previous = sock->state; |
| 1489 | |||
| 1490 | switch (sock->state) { | 1547 | switch (sock->state) { |
| 1491 | case SS_UNCONNECTED: | 1548 | case SS_UNCONNECTED: |
| 1492 | /* Send a 'SYN-' to destination */ | 1549 | /* Send a 'SYN-' to destination */ |
| @@ -1508,43 +1565,22 @@ static int connect(struct socket *sock, struct sockaddr *dest, int destlen, | |||
| 1508 | * case is EINPROGRESS, rather than EALREADY. | 1565 | * case is EINPROGRESS, rather than EALREADY. |
| 1509 | */ | 1566 | */ |
| 1510 | res = -EINPROGRESS; | 1567 | res = -EINPROGRESS; |
| 1511 | break; | ||
| 1512 | case SS_CONNECTING: | 1568 | case SS_CONNECTING: |
| 1513 | res = -EALREADY; | 1569 | if (previous == SS_CONNECTING) |
| 1570 | res = -EALREADY; | ||
| 1571 | if (!timeout) | ||
| 1572 | goto exit; | ||
| 1573 | timeout = msecs_to_jiffies(timeout); | ||
| 1574 | /* Wait until an 'ACK' or 'RST' arrives, or a timeout occurs */ | ||
| 1575 | res = tipc_wait_for_connect(sock, &timeout); | ||
| 1514 | break; | 1576 | break; |
| 1515 | case SS_CONNECTED: | 1577 | case SS_CONNECTED: |
| 1516 | res = -EISCONN; | 1578 | res = -EISCONN; |
| 1517 | break; | 1579 | break; |
| 1518 | default: | 1580 | default: |
| 1519 | res = -EINVAL; | 1581 | res = -EINVAL; |
| 1520 | goto exit; | 1582 | break; |
| 1521 | } | ||
| 1522 | |||
| 1523 | if (sock->state == SS_CONNECTING) { | ||
| 1524 | if (!timeout) | ||
| 1525 | goto exit; | ||
| 1526 | |||
| 1527 | /* Wait until an 'ACK' or 'RST' arrives, or a timeout occurs */ | ||
| 1528 | release_sock(sk); | ||
| 1529 | res = wait_event_interruptible_timeout(*sk_sleep(sk), | ||
| 1530 | sock->state != SS_CONNECTING, | ||
| 1531 | timeout ? (long)msecs_to_jiffies(timeout) | ||
| 1532 | : MAX_SCHEDULE_TIMEOUT); | ||
| 1533 | lock_sock(sk); | ||
| 1534 | if (res <= 0) { | ||
| 1535 | if (res == 0) | ||
| 1536 | res = -ETIMEDOUT; | ||
| 1537 | else | ||
| 1538 | ; /* leave "res" unchanged */ | ||
| 1539 | goto exit; | ||
| 1540 | } | ||
| 1541 | } | 1583 | } |
| 1542 | |||
| 1543 | if (unlikely(sock->state == SS_DISCONNECTING)) | ||
| 1544 | res = sock_error(sk); | ||
| 1545 | else | ||
| 1546 | res = 0; | ||
| 1547 | |||
| 1548 | exit: | 1584 | exit: |
| 1549 | release_sock(sk); | 1585 | release_sock(sk); |
| 1550 | return res; | 1586 | return res; |
| @@ -1575,6 +1611,42 @@ static int listen(struct socket *sock, int len) | |||
| 1575 | return res; | 1611 | return res; |
| 1576 | } | 1612 | } |
| 1577 | 1613 | ||
| 1614 | static int tipc_wait_for_accept(struct socket *sock, long timeo) | ||
| 1615 | { | ||
| 1616 | struct sock *sk = sock->sk; | ||
| 1617 | DEFINE_WAIT(wait); | ||
| 1618 | int err; | ||
| 1619 | |||
| 1620 | /* True wake-one mechanism for incoming connections: only | ||
| 1621 | * one process gets woken up, not the 'whole herd'. | ||
| 1622 | * Since we do not 'race & poll' for established sockets | ||
| 1623 | * anymore, the common case will execute the loop only once. | ||
| 1624 | */ | ||
| 1625 | for (;;) { | ||
| 1626 | prepare_to_wait_exclusive(sk_sleep(sk), &wait, | ||
| 1627 | TASK_INTERRUPTIBLE); | ||
| 1628 | if (skb_queue_empty(&sk->sk_receive_queue)) { | ||
| 1629 | release_sock(sk); | ||
| 1630 | timeo = schedule_timeout(timeo); | ||
| 1631 | lock_sock(sk); | ||
| 1632 | } | ||
| 1633 | err = 0; | ||
| 1634 | if (!skb_queue_empty(&sk->sk_receive_queue)) | ||
| 1635 | break; | ||
| 1636 | err = -EINVAL; | ||
| 1637 | if (sock->state != SS_LISTENING) | ||
| 1638 | break; | ||
| 1639 | err = sock_intr_errno(timeo); | ||
| 1640 | if (signal_pending(current)) | ||
| 1641 | break; | ||
| 1642 | err = -EAGAIN; | ||
| 1643 | if (!timeo) | ||
| 1644 | break; | ||
| 1645 | } | ||
| 1646 | finish_wait(sk_sleep(sk), &wait); | ||
| 1647 | return err; | ||
| 1648 | } | ||
| 1649 | |||
| 1578 | /** | 1650 | /** |
| 1579 | * accept - wait for connection request | 1651 | * accept - wait for connection request |
| 1580 | * @sock: listening socket | 1652 | * @sock: listening socket |
| @@ -1591,7 +1663,7 @@ static int accept(struct socket *sock, struct socket *new_sock, int flags) | |||
| 1591 | struct tipc_port *new_tport; | 1663 | struct tipc_port *new_tport; |
| 1592 | struct tipc_msg *msg; | 1664 | struct tipc_msg *msg; |
| 1593 | u32 new_ref; | 1665 | u32 new_ref; |
| 1594 | 1666 | long timeo; | |
| 1595 | int res; | 1667 | int res; |
| 1596 | 1668 | ||
| 1597 | lock_sock(sk); | 1669 | lock_sock(sk); |
| @@ -1601,18 +1673,10 @@ static int accept(struct socket *sock, struct socket *new_sock, int flags) | |||
| 1601 | goto exit; | 1673 | goto exit; |
| 1602 | } | 1674 | } |
| 1603 | 1675 | ||
| 1604 | while (skb_queue_empty(&sk->sk_receive_queue)) { | 1676 | timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK); |
| 1605 | if (flags & O_NONBLOCK) { | 1677 | res = tipc_wait_for_accept(sock, timeo); |
| 1606 | res = -EWOULDBLOCK; | 1678 | if (res) |
| 1607 | goto exit; | 1679 | goto exit; |
| 1608 | } | ||
| 1609 | release_sock(sk); | ||
| 1610 | res = wait_event_interruptible(*sk_sleep(sk), | ||
| 1611 | (!skb_queue_empty(&sk->sk_receive_queue))); | ||
| 1612 | lock_sock(sk); | ||
| 1613 | if (res) | ||
| 1614 | goto exit; | ||
| 1615 | } | ||
| 1616 | 1680 | ||
| 1617 | buf = skb_peek(&sk->sk_receive_queue); | 1681 | buf = skb_peek(&sk->sk_receive_queue); |
| 1618 | 1682 | ||
diff --git a/net/tipc/subscr.c b/net/tipc/subscr.c index d38bb45d82e9..7cb0bd5b1176 100644 --- a/net/tipc/subscr.c +++ b/net/tipc/subscr.c | |||
| @@ -42,7 +42,7 @@ | |||
| 42 | /** | 42 | /** |
| 43 | * struct tipc_subscriber - TIPC network topology subscriber | 43 | * struct tipc_subscriber - TIPC network topology subscriber |
| 44 | * @conid: connection identifier to server connecting to subscriber | 44 | * @conid: connection identifier to server connecting to subscriber |
| 45 | * @lock: controll access to subscriber | 45 | * @lock: control access to subscriber |
| 46 | * @subscription_list: list of subscription objects for this subscriber | 46 | * @subscription_list: list of subscription objects for this subscriber |
| 47 | */ | 47 | */ |
| 48 | struct tipc_subscriber { | 48 | struct tipc_subscriber { |
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index a427623ee574..29fc8bee9702 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c | |||
| @@ -80,6 +80,8 @@ | |||
| 80 | * with BSD names. | 80 | * with BSD names. |
| 81 | */ | 81 | */ |
| 82 | 82 | ||
| 83 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
| 84 | |||
| 83 | #include <linux/module.h> | 85 | #include <linux/module.h> |
| 84 | #include <linux/kernel.h> | 86 | #include <linux/kernel.h> |
| 85 | #include <linux/signal.h> | 87 | #include <linux/signal.h> |
| @@ -366,7 +368,7 @@ static void unix_sock_destructor(struct sock *sk) | |||
| 366 | WARN_ON(!sk_unhashed(sk)); | 368 | WARN_ON(!sk_unhashed(sk)); |
| 367 | WARN_ON(sk->sk_socket); | 369 | WARN_ON(sk->sk_socket); |
| 368 | if (!sock_flag(sk, SOCK_DEAD)) { | 370 | if (!sock_flag(sk, SOCK_DEAD)) { |
| 369 | printk(KERN_INFO "Attempt to release alive unix socket: %p\n", sk); | 371 | pr_info("Attempt to release alive unix socket: %p\n", sk); |
| 370 | return; | 372 | return; |
| 371 | } | 373 | } |
| 372 | 374 | ||
| @@ -378,7 +380,7 @@ static void unix_sock_destructor(struct sock *sk) | |||
| 378 | sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); | 380 | sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); |
| 379 | local_bh_enable(); | 381 | local_bh_enable(); |
| 380 | #ifdef UNIX_REFCNT_DEBUG | 382 | #ifdef UNIX_REFCNT_DEBUG |
| 381 | printk(KERN_DEBUG "UNIX %p is destroyed, %ld are still alive.\n", sk, | 383 | pr_debug("UNIX %p is destroyed, %ld are still alive.\n", sk, |
| 382 | atomic_long_read(&unix_nr_socks)); | 384 | atomic_long_read(&unix_nr_socks)); |
| 383 | #endif | 385 | #endif |
| 384 | } | 386 | } |
| @@ -1448,7 +1450,7 @@ static int unix_dgram_sendmsg(struct kiocb *kiocb, struct socket *sock, | |||
| 1448 | struct sock *sk = sock->sk; | 1450 | struct sock *sk = sock->sk; |
| 1449 | struct net *net = sock_net(sk); | 1451 | struct net *net = sock_net(sk); |
| 1450 | struct unix_sock *u = unix_sk(sk); | 1452 | struct unix_sock *u = unix_sk(sk); |
| 1451 | struct sockaddr_un *sunaddr = msg->msg_name; | 1453 | DECLARE_SOCKADDR(struct sockaddr_un *, sunaddr, msg->msg_name); |
| 1452 | struct sock *other = NULL; | 1454 | struct sock *other = NULL; |
| 1453 | int namelen = 0; /* fake GCC */ | 1455 | int namelen = 0; /* fake GCC */ |
| 1454 | int err; | 1456 | int err; |
| @@ -1910,7 +1912,7 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock, | |||
| 1910 | struct scm_cookie tmp_scm; | 1912 | struct scm_cookie tmp_scm; |
| 1911 | struct sock *sk = sock->sk; | 1913 | struct sock *sk = sock->sk; |
| 1912 | struct unix_sock *u = unix_sk(sk); | 1914 | struct unix_sock *u = unix_sk(sk); |
| 1913 | struct sockaddr_un *sunaddr = msg->msg_name; | 1915 | DECLARE_SOCKADDR(struct sockaddr_un *, sunaddr, msg->msg_name); |
| 1914 | int copied = 0; | 1916 | int copied = 0; |
| 1915 | int check_creds = 0; | 1917 | int check_creds = 0; |
| 1916 | int target; | 1918 | int target; |
| @@ -2441,8 +2443,7 @@ static int __init af_unix_init(void) | |||
| 2441 | 2443 | ||
| 2442 | rc = proto_register(&unix_proto, 1); | 2444 | rc = proto_register(&unix_proto, 1); |
| 2443 | if (rc != 0) { | 2445 | if (rc != 0) { |
| 2444 | printk(KERN_CRIT "%s: Cannot create unix_sock SLAB cache!\n", | 2446 | pr_crit("%s: Cannot create unix_sock SLAB cache!\n", __func__); |
| 2445 | __func__); | ||
| 2446 | goto out; | 2447 | goto out; |
| 2447 | } | 2448 | } |
| 2448 | 2449 | ||
diff --git a/net/vmw_vsock/vmci_transport.c b/net/vmw_vsock/vmci_transport.c index 687360da62d9..9bb63ffec4f2 100644 --- a/net/vmw_vsock/vmci_transport.c +++ b/net/vmw_vsock/vmci_transport.c | |||
| @@ -1779,10 +1779,8 @@ static int vmci_transport_dgram_dequeue(struct kiocb *kiocb, | |||
| 1779 | goto out; | 1779 | goto out; |
| 1780 | 1780 | ||
| 1781 | if (msg->msg_name) { | 1781 | if (msg->msg_name) { |
| 1782 | struct sockaddr_vm *vm_addr; | ||
| 1783 | |||
| 1784 | /* Provide the address of the sender. */ | 1782 | /* Provide the address of the sender. */ |
| 1785 | vm_addr = (struct sockaddr_vm *)msg->msg_name; | 1783 | DECLARE_SOCKADDR(struct sockaddr_vm *, vm_addr, msg->msg_name); |
| 1786 | vsock_addr_init(vm_addr, dg->src.context, dg->src.resource); | 1784 | vsock_addr_init(vm_addr, dg->src.context, dg->src.resource); |
| 1787 | msg->msg_namelen = sizeof(*vm_addr); | 1785 | msg->msg_namelen = sizeof(*vm_addr); |
| 1788 | } | 1786 | } |
diff --git a/net/wireless/ap.c b/net/wireless/ap.c index 324e8d851dc4..11ee4ed04f73 100644 --- a/net/wireless/ap.c +++ b/net/wireless/ap.c | |||
| @@ -29,6 +29,7 @@ static int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev, | |||
| 29 | wdev->beacon_interval = 0; | 29 | wdev->beacon_interval = 0; |
| 30 | wdev->channel = NULL; | 30 | wdev->channel = NULL; |
| 31 | wdev->ssid_len = 0; | 31 | wdev->ssid_len = 0; |
| 32 | rdev_set_qos_map(rdev, dev, NULL); | ||
| 32 | } | 33 | } |
| 33 | 34 | ||
| 34 | return err; | 35 | return err; |
diff --git a/net/wireless/chan.c b/net/wireless/chan.c index 9b8cc877eb19..78559b5bbd1f 100644 --- a/net/wireless/chan.c +++ b/net/wireless/chan.c | |||
| @@ -277,6 +277,32 @@ void cfg80211_set_dfs_state(struct wiphy *wiphy, | |||
| 277 | width, dfs_state); | 277 | width, dfs_state); |
| 278 | } | 278 | } |
| 279 | 279 | ||
| 280 | static u32 cfg80211_get_start_freq(u32 center_freq, | ||
| 281 | u32 bandwidth) | ||
| 282 | { | ||
| 283 | u32 start_freq; | ||
| 284 | |||
| 285 | if (bandwidth <= 20) | ||
| 286 | start_freq = center_freq; | ||
| 287 | else | ||
| 288 | start_freq = center_freq - bandwidth/2 + 10; | ||
| 289 | |||
| 290 | return start_freq; | ||
| 291 | } | ||
| 292 | |||
| 293 | static u32 cfg80211_get_end_freq(u32 center_freq, | ||
| 294 | u32 bandwidth) | ||
| 295 | { | ||
| 296 | u32 end_freq; | ||
| 297 | |||
| 298 | if (bandwidth <= 20) | ||
| 299 | end_freq = center_freq; | ||
| 300 | else | ||
| 301 | end_freq = center_freq + bandwidth/2 - 10; | ||
| 302 | |||
| 303 | return end_freq; | ||
| 304 | } | ||
| 305 | |||
| 280 | static int cfg80211_get_chans_dfs_required(struct wiphy *wiphy, | 306 | static int cfg80211_get_chans_dfs_required(struct wiphy *wiphy, |
| 281 | u32 center_freq, | 307 | u32 center_freq, |
| 282 | u32 bandwidth) | 308 | u32 bandwidth) |
| @@ -284,13 +310,8 @@ static int cfg80211_get_chans_dfs_required(struct wiphy *wiphy, | |||
| 284 | struct ieee80211_channel *c; | 310 | struct ieee80211_channel *c; |
| 285 | u32 freq, start_freq, end_freq; | 311 | u32 freq, start_freq, end_freq; |
| 286 | 312 | ||
| 287 | if (bandwidth <= 20) { | 313 | start_freq = cfg80211_get_start_freq(center_freq, bandwidth); |
| 288 | start_freq = center_freq; | 314 | end_freq = cfg80211_get_end_freq(center_freq, bandwidth); |
| 289 | end_freq = center_freq; | ||
| 290 | } else { | ||
| 291 | start_freq = center_freq - bandwidth/2 + 10; | ||
| 292 | end_freq = center_freq + bandwidth/2 - 10; | ||
| 293 | } | ||
| 294 | 315 | ||
| 295 | for (freq = start_freq; freq <= end_freq; freq += 20) { | 316 | for (freq = start_freq; freq <= end_freq; freq += 20) { |
| 296 | c = ieee80211_get_channel(wiphy, freq); | 317 | c = ieee80211_get_channel(wiphy, freq); |
| @@ -330,33 +351,159 @@ int cfg80211_chandef_dfs_required(struct wiphy *wiphy, | |||
| 330 | } | 351 | } |
| 331 | EXPORT_SYMBOL(cfg80211_chandef_dfs_required); | 352 | EXPORT_SYMBOL(cfg80211_chandef_dfs_required); |
| 332 | 353 | ||
| 333 | static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy, | 354 | static int cfg80211_get_chans_dfs_usable(struct wiphy *wiphy, |
| 334 | u32 center_freq, u32 bandwidth, | 355 | u32 center_freq, |
| 335 | u32 prohibited_flags) | 356 | u32 bandwidth) |
| 336 | { | 357 | { |
| 337 | struct ieee80211_channel *c; | 358 | struct ieee80211_channel *c; |
| 338 | u32 freq, start_freq, end_freq; | 359 | u32 freq, start_freq, end_freq; |
| 360 | int count = 0; | ||
| 339 | 361 | ||
| 340 | if (bandwidth <= 20) { | 362 | start_freq = cfg80211_get_start_freq(center_freq, bandwidth); |
| 341 | start_freq = center_freq; | 363 | end_freq = cfg80211_get_end_freq(center_freq, bandwidth); |
| 342 | end_freq = center_freq; | 364 | |
| 343 | } else { | 365 | /* |
| 344 | start_freq = center_freq - bandwidth/2 + 10; | 366 | * Check entire range of channels for the bandwidth. |
| 345 | end_freq = center_freq + bandwidth/2 - 10; | 367 | * Check all channels are DFS channels (DFS_USABLE or |
| 368 | * DFS_AVAILABLE). Return number of usable channels | ||
| 369 | * (require CAC). Allow DFS and non-DFS channel mix. | ||
| 370 | */ | ||
| 371 | for (freq = start_freq; freq <= end_freq; freq += 20) { | ||
| 372 | c = ieee80211_get_channel(wiphy, freq); | ||
| 373 | if (!c) | ||
| 374 | return -EINVAL; | ||
| 375 | |||
| 376 | if (c->flags & IEEE80211_CHAN_DISABLED) | ||
| 377 | return -EINVAL; | ||
| 378 | |||
| 379 | if (c->flags & IEEE80211_CHAN_RADAR) { | ||
| 380 | if (c->dfs_state == NL80211_DFS_UNAVAILABLE) | ||
| 381 | return -EINVAL; | ||
| 382 | |||
| 383 | if (c->dfs_state == NL80211_DFS_USABLE) | ||
| 384 | count++; | ||
| 385 | } | ||
| 346 | } | 386 | } |
| 347 | 387 | ||
| 388 | return count; | ||
| 389 | } | ||
| 390 | |||
| 391 | bool cfg80211_chandef_dfs_usable(struct wiphy *wiphy, | ||
| 392 | const struct cfg80211_chan_def *chandef) | ||
| 393 | { | ||
| 394 | int width; | ||
| 395 | int r1, r2 = 0; | ||
| 396 | |||
| 397 | if (WARN_ON(!cfg80211_chandef_valid(chandef))) | ||
| 398 | return false; | ||
| 399 | |||
| 400 | width = cfg80211_chandef_get_width(chandef); | ||
| 401 | if (width < 0) | ||
| 402 | return false; | ||
| 403 | |||
| 404 | r1 = cfg80211_get_chans_dfs_usable(wiphy, chandef->center_freq1, | ||
| 405 | width); | ||
| 406 | |||
| 407 | if (r1 < 0) | ||
| 408 | return false; | ||
| 409 | |||
| 410 | switch (chandef->width) { | ||
| 411 | case NL80211_CHAN_WIDTH_80P80: | ||
| 412 | WARN_ON(!chandef->center_freq2); | ||
| 413 | r2 = cfg80211_get_chans_dfs_usable(wiphy, | ||
| 414 | chandef->center_freq2, | ||
| 415 | width); | ||
| 416 | if (r2 < 0) | ||
| 417 | return false; | ||
| 418 | break; | ||
| 419 | default: | ||
| 420 | WARN_ON(chandef->center_freq2); | ||
| 421 | break; | ||
| 422 | } | ||
| 423 | |||
| 424 | return (r1 + r2 > 0); | ||
| 425 | } | ||
| 426 | |||
| 427 | |||
| 428 | static bool cfg80211_get_chans_dfs_available(struct wiphy *wiphy, | ||
| 429 | u32 center_freq, | ||
| 430 | u32 bandwidth) | ||
| 431 | { | ||
| 432 | struct ieee80211_channel *c; | ||
| 433 | u32 freq, start_freq, end_freq; | ||
| 434 | |||
| 435 | start_freq = cfg80211_get_start_freq(center_freq, bandwidth); | ||
| 436 | end_freq = cfg80211_get_end_freq(center_freq, bandwidth); | ||
| 437 | |||
| 438 | /* | ||
| 439 | * Check entire range of channels for the bandwidth. | ||
| 440 | * If any channel in between is disabled or has not | ||
| 441 | * had gone through CAC return false | ||
| 442 | */ | ||
| 348 | for (freq = start_freq; freq <= end_freq; freq += 20) { | 443 | for (freq = start_freq; freq <= end_freq; freq += 20) { |
| 349 | c = ieee80211_get_channel(wiphy, freq); | 444 | c = ieee80211_get_channel(wiphy, freq); |
| 350 | if (!c) | 445 | if (!c) |
| 351 | return false; | 446 | return false; |
| 352 | 447 | ||
| 353 | /* check for radar flags */ | 448 | if (c->flags & IEEE80211_CHAN_DISABLED) |
| 354 | if ((prohibited_flags & c->flags & IEEE80211_CHAN_RADAR) && | 449 | return false; |
| 450 | |||
| 451 | if ((c->flags & IEEE80211_CHAN_RADAR) && | ||
| 355 | (c->dfs_state != NL80211_DFS_AVAILABLE)) | 452 | (c->dfs_state != NL80211_DFS_AVAILABLE)) |
| 356 | return false; | 453 | return false; |
| 454 | } | ||
| 455 | |||
| 456 | return true; | ||
| 457 | } | ||
| 458 | |||
| 459 | static bool cfg80211_chandef_dfs_available(struct wiphy *wiphy, | ||
| 460 | const struct cfg80211_chan_def *chandef) | ||
| 461 | { | ||
| 462 | int width; | ||
| 463 | int r; | ||
| 464 | |||
| 465 | if (WARN_ON(!cfg80211_chandef_valid(chandef))) | ||
| 466 | return false; | ||
| 467 | |||
| 468 | width = cfg80211_chandef_get_width(chandef); | ||
| 469 | if (width < 0) | ||
| 470 | return false; | ||
| 471 | |||
| 472 | r = cfg80211_get_chans_dfs_available(wiphy, chandef->center_freq1, | ||
| 473 | width); | ||
| 474 | |||
| 475 | /* If any of channels unavailable for cf1 just return */ | ||
| 476 | if (!r) | ||
| 477 | return r; | ||
| 478 | |||
| 479 | switch (chandef->width) { | ||
| 480 | case NL80211_CHAN_WIDTH_80P80: | ||
| 481 | WARN_ON(!chandef->center_freq2); | ||
| 482 | r = cfg80211_get_chans_dfs_available(wiphy, | ||
| 483 | chandef->center_freq2, | ||
| 484 | width); | ||
| 485 | default: | ||
| 486 | WARN_ON(chandef->center_freq2); | ||
| 487 | break; | ||
| 488 | } | ||
| 489 | |||
| 490 | return r; | ||
| 491 | } | ||
| 357 | 492 | ||
| 358 | /* check for the other flags */ | 493 | |
| 359 | if (c->flags & prohibited_flags & ~IEEE80211_CHAN_RADAR) | 494 | static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy, |
| 495 | u32 center_freq, u32 bandwidth, | ||
| 496 | u32 prohibited_flags) | ||
| 497 | { | ||
| 498 | struct ieee80211_channel *c; | ||
| 499 | u32 freq, start_freq, end_freq; | ||
| 500 | |||
| 501 | start_freq = cfg80211_get_start_freq(center_freq, bandwidth); | ||
| 502 | end_freq = cfg80211_get_end_freq(center_freq, bandwidth); | ||
| 503 | |||
| 504 | for (freq = start_freq; freq <= end_freq; freq += 20) { | ||
| 505 | c = ieee80211_get_channel(wiphy, freq); | ||
| 506 | if (!c || c->flags & prohibited_flags) | ||
| 360 | return false; | 507 | return false; |
| 361 | } | 508 | } |
| 362 | 509 | ||
| @@ -462,14 +609,19 @@ bool cfg80211_reg_can_beacon(struct wiphy *wiphy, | |||
| 462 | struct cfg80211_chan_def *chandef) | 609 | struct cfg80211_chan_def *chandef) |
| 463 | { | 610 | { |
| 464 | bool res; | 611 | bool res; |
| 612 | u32 prohibited_flags = IEEE80211_CHAN_DISABLED | | ||
| 613 | IEEE80211_CHAN_NO_IR | | ||
| 614 | IEEE80211_CHAN_RADAR; | ||
| 465 | 615 | ||
| 466 | trace_cfg80211_reg_can_beacon(wiphy, chandef); | 616 | trace_cfg80211_reg_can_beacon(wiphy, chandef); |
| 467 | 617 | ||
| 468 | res = cfg80211_chandef_usable(wiphy, chandef, | 618 | if (cfg80211_chandef_dfs_required(wiphy, chandef) > 0 && |
| 469 | IEEE80211_CHAN_DISABLED | | 619 | cfg80211_chandef_dfs_available(wiphy, chandef)) { |
| 470 | IEEE80211_CHAN_PASSIVE_SCAN | | 620 | /* We can skip IEEE80211_CHAN_NO_IR if chandef dfs available */ |
| 471 | IEEE80211_CHAN_NO_IBSS | | 621 | prohibited_flags = IEEE80211_CHAN_DISABLED; |
| 472 | IEEE80211_CHAN_RADAR); | 622 | } |
| 623 | |||
| 624 | res = cfg80211_chandef_usable(wiphy, chandef, prohibited_flags); | ||
| 473 | 625 | ||
| 474 | trace_cfg80211_return_bool(res); | 626 | trace_cfg80211_return_bool(res); |
| 475 | return res; | 627 | return res; |
| @@ -510,6 +662,7 @@ cfg80211_get_chan_state(struct wireless_dev *wdev, | |||
| 510 | : CHAN_MODE_EXCLUSIVE; | 662 | : CHAN_MODE_EXCLUSIVE; |
| 511 | return; | 663 | return; |
| 512 | } | 664 | } |
| 665 | break; | ||
| 513 | case NL80211_IFTYPE_STATION: | 666 | case NL80211_IFTYPE_STATION: |
| 514 | case NL80211_IFTYPE_P2P_CLIENT: | 667 | case NL80211_IFTYPE_P2P_CLIENT: |
| 515 | if (wdev->current_bss) { | 668 | if (wdev->current_bss) { |
diff --git a/net/wireless/core.c b/net/wireless/core.c index 52b865fb7351..d89dee2259b5 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
| @@ -203,17 +203,8 @@ void cfg80211_stop_p2p_device(struct cfg80211_registered_device *rdev, | |||
| 203 | 203 | ||
| 204 | rdev->opencount--; | 204 | rdev->opencount--; |
| 205 | 205 | ||
| 206 | if (rdev->scan_req && rdev->scan_req->wdev == wdev) { | 206 | WARN_ON(rdev->scan_req && rdev->scan_req->wdev == wdev && |
| 207 | /* | 207 | !rdev->scan_req->notified); |
| 208 | * If the scan request wasn't notified as done, set it | ||
| 209 | * to aborted and leak it after a warning. The driver | ||
| 210 | * should have notified us that it ended at the latest | ||
| 211 | * during rdev_stop_p2p_device(). | ||
| 212 | */ | ||
| 213 | if (WARN_ON(!rdev->scan_req->notified)) | ||
| 214 | rdev->scan_req->aborted = true; | ||
| 215 | ___cfg80211_scan_done(rdev, !rdev->scan_req->notified); | ||
| 216 | } | ||
| 217 | } | 208 | } |
| 218 | 209 | ||
| 219 | static int cfg80211_rfkill_set_block(void *data, bool blocked) | 210 | static int cfg80211_rfkill_set_block(void *data, bool blocked) |
| @@ -357,8 +348,6 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) | |||
| 357 | rdev->wiphy.rts_threshold = (u32) -1; | 348 | rdev->wiphy.rts_threshold = (u32) -1; |
| 358 | rdev->wiphy.coverage_class = 0; | 349 | rdev->wiphy.coverage_class = 0; |
| 359 | 350 | ||
| 360 | rdev->wiphy.features = NL80211_FEATURE_SCAN_FLUSH; | ||
| 361 | |||
| 362 | return &rdev->wiphy; | 351 | return &rdev->wiphy; |
| 363 | } | 352 | } |
| 364 | EXPORT_SYMBOL(wiphy_new); | 353 | EXPORT_SYMBOL(wiphy_new); |
| @@ -575,6 +564,8 @@ int wiphy_register(struct wiphy *wiphy) | |||
| 575 | /* check and set up bitrates */ | 564 | /* check and set up bitrates */ |
| 576 | ieee80211_set_bitrate_flags(wiphy); | 565 | ieee80211_set_bitrate_flags(wiphy); |
| 577 | 566 | ||
| 567 | rdev->wiphy.features |= NL80211_FEATURE_SCAN_FLUSH; | ||
| 568 | |||
| 578 | rtnl_lock(); | 569 | rtnl_lock(); |
| 579 | res = device_add(&rdev->wiphy.dev); | 570 | res = device_add(&rdev->wiphy.dev); |
| 580 | if (res) { | 571 | if (res) { |
| @@ -595,7 +586,7 @@ int wiphy_register(struct wiphy *wiphy) | |||
| 595 | if (IS_ERR(rdev->wiphy.debugfsdir)) | 586 | if (IS_ERR(rdev->wiphy.debugfsdir)) |
| 596 | rdev->wiphy.debugfsdir = NULL; | 587 | rdev->wiphy.debugfsdir = NULL; |
| 597 | 588 | ||
| 598 | if (wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY) { | 589 | if (wiphy->regulatory_flags & REGULATORY_CUSTOM_REG) { |
| 599 | struct regulatory_request request; | 590 | struct regulatory_request request; |
| 600 | 591 | ||
| 601 | request.wiphy_idx = get_wiphy_idx(wiphy); | 592 | request.wiphy_idx = get_wiphy_idx(wiphy); |
| @@ -765,13 +756,16 @@ void cfg80211_leave(struct cfg80211_registered_device *rdev, | |||
| 765 | { | 756 | { |
| 766 | struct net_device *dev = wdev->netdev; | 757 | struct net_device *dev = wdev->netdev; |
| 767 | 758 | ||
| 759 | ASSERT_RTNL(); | ||
| 760 | |||
| 768 | switch (wdev->iftype) { | 761 | switch (wdev->iftype) { |
| 769 | case NL80211_IFTYPE_ADHOC: | 762 | case NL80211_IFTYPE_ADHOC: |
| 770 | cfg80211_leave_ibss(rdev, dev, true); | 763 | cfg80211_leave_ibss(rdev, dev, true); |
| 771 | break; | 764 | break; |
| 772 | case NL80211_IFTYPE_P2P_CLIENT: | 765 | case NL80211_IFTYPE_P2P_CLIENT: |
| 773 | case NL80211_IFTYPE_STATION: | 766 | case NL80211_IFTYPE_STATION: |
| 774 | __cfg80211_stop_sched_scan(rdev, false); | 767 | if (rdev->sched_scan_req && dev == rdev->sched_scan_req->dev) |
| 768 | __cfg80211_stop_sched_scan(rdev, false); | ||
| 775 | 769 | ||
| 776 | wdev_lock(wdev); | 770 | wdev_lock(wdev); |
| 777 | #ifdef CONFIG_CFG80211_WEXT | 771 | #ifdef CONFIG_CFG80211_WEXT |
| @@ -865,11 +859,8 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, | |||
| 865 | break; | 859 | break; |
| 866 | case NETDEV_DOWN: | 860 | case NETDEV_DOWN: |
| 867 | cfg80211_update_iface_num(rdev, wdev->iftype, -1); | 861 | cfg80211_update_iface_num(rdev, wdev->iftype, -1); |
| 868 | if (rdev->scan_req && rdev->scan_req->wdev == wdev) { | 862 | WARN_ON(rdev->scan_req && rdev->scan_req->wdev == wdev && |
| 869 | if (WARN_ON(!rdev->scan_req->notified)) | 863 | !rdev->scan_req->notified); |
| 870 | rdev->scan_req->aborted = true; | ||
| 871 | ___cfg80211_scan_done(rdev, true); | ||
| 872 | } | ||
| 873 | 864 | ||
| 874 | if (WARN_ON(rdev->sched_scan_req && | 865 | if (WARN_ON(rdev->sched_scan_req && |
| 875 | rdev->sched_scan_req->dev == wdev->netdev)) { | 866 | rdev->sched_scan_req->dev == wdev->netdev)) { |
diff --git a/net/wireless/core.h b/net/wireless/core.h index af10e59af2d8..37ec16d7bb1a 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
| @@ -67,9 +67,7 @@ struct cfg80211_registered_device { | |||
| 67 | struct work_struct scan_done_wk; | 67 | struct work_struct scan_done_wk; |
| 68 | struct work_struct sched_scan_results_wk; | 68 | struct work_struct sched_scan_results_wk; |
| 69 | 69 | ||
| 70 | #ifdef CONFIG_NL80211_TESTMODE | 70 | struct genl_info *cur_cmd_info; |
| 71 | struct genl_info *testmode_info; | ||
| 72 | #endif | ||
| 73 | 71 | ||
| 74 | struct work_struct conn_work; | 72 | struct work_struct conn_work; |
| 75 | struct work_struct event_work; | 73 | struct work_struct event_work; |
| @@ -317,9 +315,8 @@ void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlpid); | |||
| 317 | void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev); | 315 | void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev); |
| 318 | int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, | 316 | int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, |
| 319 | struct wireless_dev *wdev, | 317 | struct wireless_dev *wdev, |
| 320 | struct ieee80211_channel *chan, bool offchan, | 318 | struct cfg80211_mgmt_tx_params *params, |
| 321 | unsigned int wait, const u8 *buf, size_t len, | 319 | u64 *cookie); |
| 322 | bool no_cck, bool dont_wait_for_ack, u64 *cookie); | ||
| 323 | void cfg80211_oper_and_ht_capa(struct ieee80211_ht_cap *ht_capa, | 320 | void cfg80211_oper_and_ht_capa(struct ieee80211_ht_cap *ht_capa, |
| 324 | const struct ieee80211_ht_cap *ht_capa_mask); | 321 | const struct ieee80211_ht_cap *ht_capa_mask); |
| 325 | void cfg80211_oper_and_vht_capa(struct ieee80211_vht_cap *vht_capa, | 322 | void cfg80211_oper_and_vht_capa(struct ieee80211_vht_cap *vht_capa, |
| @@ -364,7 +361,7 @@ int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev, | |||
| 364 | struct key_params *params, int key_idx, | 361 | struct key_params *params, int key_idx, |
| 365 | bool pairwise, const u8 *mac_addr); | 362 | bool pairwise, const u8 *mac_addr); |
| 366 | void __cfg80211_scan_done(struct work_struct *wk); | 363 | void __cfg80211_scan_done(struct work_struct *wk); |
| 367 | void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak); | 364 | void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev); |
| 368 | void __cfg80211_sched_scan_results(struct work_struct *wk); | 365 | void __cfg80211_sched_scan_results(struct work_struct *wk); |
| 369 | int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev, | 366 | int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev, |
| 370 | bool driver_initiated); | 367 | bool driver_initiated); |
| @@ -382,6 +379,19 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev, | |||
| 382 | enum cfg80211_chan_mode chanmode, | 379 | enum cfg80211_chan_mode chanmode, |
| 383 | u8 radar_detect); | 380 | u8 radar_detect); |
| 384 | 381 | ||
| 382 | /** | ||
| 383 | * cfg80211_chandef_dfs_usable - checks if chandef is DFS usable | ||
| 384 | * @wiphy: the wiphy to validate against | ||
| 385 | * @chandef: the channel definition to check | ||
| 386 | * | ||
| 387 | * Checks if chandef is usable and we can/need start CAC on such channel. | ||
| 388 | * | ||
| 389 | * Return: Return true if all channels available and at least | ||
| 390 | * one channel require CAC (NL80211_DFS_USABLE) | ||
| 391 | */ | ||
| 392 | bool cfg80211_chandef_dfs_usable(struct wiphy *wiphy, | ||
| 393 | const struct cfg80211_chan_def *chandef); | ||
| 394 | |||
| 385 | void cfg80211_set_dfs_state(struct wiphy *wiphy, | 395 | void cfg80211_set_dfs_state(struct wiphy *wiphy, |
| 386 | const struct cfg80211_chan_def *chandef, | 396 | const struct cfg80211_chan_def *chandef, |
| 387 | enum nl80211_dfs_state dfs_state); | 397 | enum nl80211_dfs_state dfs_state); |
diff --git a/net/wireless/genregdb.awk b/net/wireless/genregdb.awk index 42ed274e81f4..9a8217d2a908 100644 --- a/net/wireless/genregdb.awk +++ b/net/wireless/genregdb.awk | |||
| @@ -33,15 +33,7 @@ BEGIN { | |||
| 33 | regdb = "const struct ieee80211_regdomain *reg_regdb[] = {\n" | 33 | regdb = "const struct ieee80211_regdomain *reg_regdb[] = {\n" |
| 34 | } | 34 | } |
| 35 | 35 | ||
| 36 | /^[ \t]*#/ { | 36 | function parse_country_head() { |
| 37 | # Ignore | ||
| 38 | } | ||
| 39 | |||
| 40 | !active && /^[ \t]*$/ { | ||
| 41 | # Ignore | ||
| 42 | } | ||
| 43 | |||
| 44 | !active && /country/ { | ||
| 45 | country=$2 | 37 | country=$2 |
| 46 | sub(/:/, "", country) | 38 | sub(/:/, "", country) |
| 47 | printf "static const struct ieee80211_regdomain regdom_%s = {\n", country | 39 | printf "static const struct ieee80211_regdomain regdom_%s = {\n", country |
| @@ -57,7 +49,8 @@ BEGIN { | |||
| 57 | regdb = regdb "\t®dom_" country ",\n" | 49 | regdb = regdb "\t®dom_" country ",\n" |
| 58 | } | 50 | } |
| 59 | 51 | ||
| 60 | active && /^[ \t]*\(/ { | 52 | function parse_reg_rule() |
| 53 | { | ||
| 61 | start = $1 | 54 | start = $1 |
| 62 | sub(/\(/, "", start) | 55 | sub(/\(/, "", start) |
| 63 | end = $3 | 56 | end = $3 |
| @@ -107,17 +100,21 @@ active && /^[ \t]*\(/ { | |||
| 107 | } else if (flagarray[arg] == "PTMP-ONLY") { | 100 | } else if (flagarray[arg] == "PTMP-ONLY") { |
| 108 | flags = flags "\n\t\t\tNL80211_RRF_PTMP_ONLY | " | 101 | flags = flags "\n\t\t\tNL80211_RRF_PTMP_ONLY | " |
| 109 | } else if (flagarray[arg] == "PASSIVE-SCAN") { | 102 | } else if (flagarray[arg] == "PASSIVE-SCAN") { |
| 110 | flags = flags "\n\t\t\tNL80211_RRF_PASSIVE_SCAN | " | 103 | flags = flags "\n\t\t\tNL80211_RRF_NO_IR | " |
| 111 | } else if (flagarray[arg] == "NO-IBSS") { | 104 | } else if (flagarray[arg] == "NO-IBSS") { |
| 112 | flags = flags "\n\t\t\tNL80211_RRF_NO_IBSS | " | 105 | flags = flags "\n\t\t\tNL80211_RRF_NO_IR | " |
| 106 | } else if (flagarray[arg] == "NO-IR") { | ||
| 107 | flags = flags "\n\t\t\tNL80211_RRF_NO_IR | " | ||
| 113 | } | 108 | } |
| 109 | |||
| 114 | } | 110 | } |
| 115 | flags = flags "0" | 111 | flags = flags "0" |
| 116 | printf "\t\tREG_RULE(%d, %d, %d, %d, %d, %s),\n", start, end, bw, gain, power, flags | 112 | printf "\t\tREG_RULE(%d, %d, %d, %d, %d, %s),\n", start, end, bw, gain, power, flags |
| 117 | rules++ | 113 | rules++ |
| 118 | } | 114 | } |
| 119 | 115 | ||
| 120 | active && /^[ \t]*$/ { | 116 | function print_tail_country() |
| 117 | { | ||
| 121 | active = 0 | 118 | active = 0 |
| 122 | printf "\t},\n" | 119 | printf "\t},\n" |
| 123 | printf "\t.n_reg_rules = %d\n", rules | 120 | printf "\t.n_reg_rules = %d\n", rules |
| @@ -125,7 +122,29 @@ active && /^[ \t]*$/ { | |||
| 125 | rules = 0; | 122 | rules = 0; |
| 126 | } | 123 | } |
| 127 | 124 | ||
| 125 | /^[ \t]*#/ { | ||
| 126 | # Ignore | ||
| 127 | } | ||
| 128 | |||
| 129 | !active && /^[ \t]*$/ { | ||
| 130 | # Ignore | ||
| 131 | } | ||
| 132 | |||
| 133 | !active && /country/ { | ||
| 134 | parse_country_head() | ||
| 135 | } | ||
| 136 | |||
| 137 | active && /^[ \t]*\(/ { | ||
| 138 | parse_reg_rule() | ||
| 139 | } | ||
| 140 | |||
| 141 | active && /^[ \t]*$/ { | ||
| 142 | print_tail_country() | ||
| 143 | } | ||
| 144 | |||
| 128 | END { | 145 | END { |
| 146 | if (active) | ||
| 147 | print_tail_country() | ||
| 129 | print regdb "};" | 148 | print regdb "};" |
| 130 | print "" | 149 | print "" |
| 131 | print "int reg_regdb_size = ARRAY_SIZE(reg_regdb);" | 150 | print "int reg_regdb_size = ARRAY_SIZE(reg_regdb);" |
diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c index 89737ee2669a..f911c5f9f903 100644 --- a/net/wireless/ibss.c +++ b/net/wireless/ibss.c | |||
| @@ -183,6 +183,8 @@ static void __cfg80211_clear_ibss(struct net_device *dev, bool nowext) | |||
| 183 | kfree(wdev->connect_keys); | 183 | kfree(wdev->connect_keys); |
| 184 | wdev->connect_keys = NULL; | 184 | wdev->connect_keys = NULL; |
| 185 | 185 | ||
| 186 | rdev_set_qos_map(rdev, dev, NULL); | ||
| 187 | |||
| 186 | /* | 188 | /* |
| 187 | * Delete all the keys ... pairwise keys can't really | 189 | * Delete all the keys ... pairwise keys can't really |
| 188 | * exist any more anyway, but default keys might. | 190 | * exist any more anyway, but default keys might. |
| @@ -274,7 +276,7 @@ int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev, | |||
| 274 | 276 | ||
| 275 | for (i = 0; i < sband->n_channels; i++) { | 277 | for (i = 0; i < sband->n_channels; i++) { |
| 276 | chan = &sband->channels[i]; | 278 | chan = &sband->channels[i]; |
| 277 | if (chan->flags & IEEE80211_CHAN_NO_IBSS) | 279 | if (chan->flags & IEEE80211_CHAN_NO_IR) |
| 278 | continue; | 280 | continue; |
| 279 | if (chan->flags & IEEE80211_CHAN_DISABLED) | 281 | if (chan->flags & IEEE80211_CHAN_DISABLED) |
| 280 | continue; | 282 | continue; |
| @@ -346,7 +348,7 @@ int cfg80211_ibss_wext_siwfreq(struct net_device *dev, | |||
| 346 | chan = ieee80211_get_channel(wdev->wiphy, freq); | 348 | chan = ieee80211_get_channel(wdev->wiphy, freq); |
| 347 | if (!chan) | 349 | if (!chan) |
| 348 | return -EINVAL; | 350 | return -EINVAL; |
| 349 | if (chan->flags & IEEE80211_CHAN_NO_IBSS || | 351 | if (chan->flags & IEEE80211_CHAN_NO_IR || |
| 350 | chan->flags & IEEE80211_CHAN_DISABLED) | 352 | chan->flags & IEEE80211_CHAN_DISABLED) |
| 351 | return -EINVAL; | 353 | return -EINVAL; |
| 352 | } | 354 | } |
diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c index 0553fd4d85ae..885862447b63 100644 --- a/net/wireless/mesh.c +++ b/net/wireless/mesh.c | |||
| @@ -99,6 +99,7 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev, | |||
| 99 | const struct mesh_config *conf) | 99 | const struct mesh_config *conf) |
| 100 | { | 100 | { |
| 101 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 101 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
| 102 | u8 radar_detect_width = 0; | ||
| 102 | int err; | 103 | int err; |
| 103 | 104 | ||
| 104 | BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN != IEEE80211_MAX_MESH_ID_LEN); | 105 | BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN != IEEE80211_MAX_MESH_ID_LEN); |
| @@ -141,8 +142,7 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev, | |||
| 141 | 142 | ||
| 142 | for (i = 0; i < sband->n_channels; i++) { | 143 | for (i = 0; i < sband->n_channels; i++) { |
| 143 | chan = &sband->channels[i]; | 144 | chan = &sband->channels[i]; |
| 144 | if (chan->flags & (IEEE80211_CHAN_NO_IBSS | | 145 | if (chan->flags & (IEEE80211_CHAN_NO_IR | |
| 145 | IEEE80211_CHAN_PASSIVE_SCAN | | ||
| 146 | IEEE80211_CHAN_DISABLED | | 146 | IEEE80211_CHAN_DISABLED | |
| 147 | IEEE80211_CHAN_RADAR)) | 147 | IEEE80211_CHAN_RADAR)) |
| 148 | continue; | 148 | continue; |
| @@ -178,8 +178,16 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev, | |||
| 178 | if (!cfg80211_reg_can_beacon(&rdev->wiphy, &setup->chandef)) | 178 | if (!cfg80211_reg_can_beacon(&rdev->wiphy, &setup->chandef)) |
| 179 | return -EINVAL; | 179 | return -EINVAL; |
| 180 | 180 | ||
| 181 | err = cfg80211_can_use_chan(rdev, wdev, setup->chandef.chan, | 181 | err = cfg80211_chandef_dfs_required(wdev->wiphy, &setup->chandef); |
| 182 | CHAN_MODE_SHARED); | 182 | if (err < 0) |
| 183 | return err; | ||
| 184 | if (err) | ||
| 185 | radar_detect_width = BIT(setup->chandef.width); | ||
| 186 | |||
| 187 | err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype, | ||
| 188 | setup->chandef.chan, | ||
| 189 | CHAN_MODE_SHARED, | ||
| 190 | radar_detect_width); | ||
| 183 | if (err) | 191 | if (err) |
| 184 | return err; | 192 | return err; |
| 185 | 193 | ||
| @@ -269,6 +277,7 @@ static int __cfg80211_leave_mesh(struct cfg80211_registered_device *rdev, | |||
| 269 | if (!err) { | 277 | if (!err) { |
| 270 | wdev->mesh_id_len = 0; | 278 | wdev->mesh_id_len = 0; |
| 271 | wdev->channel = NULL; | 279 | wdev->channel = NULL; |
| 280 | rdev_set_qos_map(rdev, dev, NULL); | ||
| 272 | } | 281 | } |
| 273 | 282 | ||
| 274 | return err; | 283 | return err; |
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 6a6b1c8e907d..52cca05044a8 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c | |||
| @@ -520,9 +520,7 @@ void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev) | |||
| 520 | 520 | ||
| 521 | int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, | 521 | int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, |
| 522 | struct wireless_dev *wdev, | 522 | struct wireless_dev *wdev, |
| 523 | struct ieee80211_channel *chan, bool offchan, | 523 | struct cfg80211_mgmt_tx_params *params, u64 *cookie) |
| 524 | unsigned int wait, const u8 *buf, size_t len, | ||
| 525 | bool no_cck, bool dont_wait_for_ack, u64 *cookie) | ||
| 526 | { | 524 | { |
| 527 | const struct ieee80211_mgmt *mgmt; | 525 | const struct ieee80211_mgmt *mgmt; |
| 528 | u16 stype; | 526 | u16 stype; |
| @@ -533,10 +531,10 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, | |||
| 533 | if (!rdev->ops->mgmt_tx) | 531 | if (!rdev->ops->mgmt_tx) |
| 534 | return -EOPNOTSUPP; | 532 | return -EOPNOTSUPP; |
| 535 | 533 | ||
| 536 | if (len < 24 + 1) | 534 | if (params->len < 24 + 1) |
| 537 | return -EINVAL; | 535 | return -EINVAL; |
| 538 | 536 | ||
| 539 | mgmt = (const struct ieee80211_mgmt *) buf; | 537 | mgmt = (const struct ieee80211_mgmt *)params->buf; |
| 540 | 538 | ||
| 541 | if (!ieee80211_is_mgmt(mgmt->frame_control)) | 539 | if (!ieee80211_is_mgmt(mgmt->frame_control)) |
| 542 | return -EINVAL; | 540 | return -EINVAL; |
| @@ -615,9 +613,7 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, | |||
| 615 | return -EINVAL; | 613 | return -EINVAL; |
| 616 | 614 | ||
| 617 | /* Transmit the Action frame as requested by user space */ | 615 | /* Transmit the Action frame as requested by user space */ |
| 618 | return rdev_mgmt_tx(rdev, wdev, chan, offchan, | 616 | return rdev_mgmt_tx(rdev, wdev, params, cookie); |
| 619 | wait, buf, len, no_cck, dont_wait_for_ack, | ||
| 620 | cookie); | ||
| 621 | } | 617 | } |
| 622 | 618 | ||
| 623 | bool cfg80211_rx_mgmt(struct wireless_dev *wdev, int freq, int sig_mbm, | 619 | bool cfg80211_rx_mgmt(struct wireless_dev *wdev, int freq, int sig_mbm, |
| @@ -763,12 +759,12 @@ void cfg80211_radar_event(struct wiphy *wiphy, | |||
| 763 | EXPORT_SYMBOL(cfg80211_radar_event); | 759 | EXPORT_SYMBOL(cfg80211_radar_event); |
| 764 | 760 | ||
| 765 | void cfg80211_cac_event(struct net_device *netdev, | 761 | void cfg80211_cac_event(struct net_device *netdev, |
| 762 | const struct cfg80211_chan_def *chandef, | ||
| 766 | enum nl80211_radar_event event, gfp_t gfp) | 763 | enum nl80211_radar_event event, gfp_t gfp) |
| 767 | { | 764 | { |
| 768 | struct wireless_dev *wdev = netdev->ieee80211_ptr; | 765 | struct wireless_dev *wdev = netdev->ieee80211_ptr; |
| 769 | struct wiphy *wiphy = wdev->wiphy; | 766 | struct wiphy *wiphy = wdev->wiphy; |
| 770 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | 767 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); |
| 771 | struct cfg80211_chan_def chandef; | ||
| 772 | unsigned long timeout; | 768 | unsigned long timeout; |
| 773 | 769 | ||
| 774 | trace_cfg80211_cac_event(netdev, event); | 770 | trace_cfg80211_cac_event(netdev, event); |
| @@ -779,14 +775,12 @@ void cfg80211_cac_event(struct net_device *netdev, | |||
| 779 | if (WARN_ON(!wdev->channel)) | 775 | if (WARN_ON(!wdev->channel)) |
| 780 | return; | 776 | return; |
| 781 | 777 | ||
| 782 | cfg80211_chandef_create(&chandef, wdev->channel, NL80211_CHAN_NO_HT); | ||
| 783 | |||
| 784 | switch (event) { | 778 | switch (event) { |
| 785 | case NL80211_RADAR_CAC_FINISHED: | 779 | case NL80211_RADAR_CAC_FINISHED: |
| 786 | timeout = wdev->cac_start_time + | 780 | timeout = wdev->cac_start_time + |
| 787 | msecs_to_jiffies(IEEE80211_DFS_MIN_CAC_TIME_MS); | 781 | msecs_to_jiffies(IEEE80211_DFS_MIN_CAC_TIME_MS); |
| 788 | WARN_ON(!time_after_eq(jiffies, timeout)); | 782 | WARN_ON(!time_after_eq(jiffies, timeout)); |
| 789 | cfg80211_set_dfs_state(wiphy, &chandef, NL80211_DFS_AVAILABLE); | 783 | cfg80211_set_dfs_state(wiphy, chandef, NL80211_DFS_AVAILABLE); |
| 790 | break; | 784 | break; |
| 791 | case NL80211_RADAR_CAC_ABORTED: | 785 | case NL80211_RADAR_CAC_ABORTED: |
| 792 | break; | 786 | break; |
| @@ -796,6 +790,6 @@ void cfg80211_cac_event(struct net_device *netdev, | |||
| 796 | } | 790 | } |
| 797 | wdev->cac_started = false; | 791 | wdev->cac_started = false; |
| 798 | 792 | ||
| 799 | nl80211_radar_notify(rdev, &chandef, event, netdev, gfp); | 793 | nl80211_radar_notify(rdev, chandef, event, netdev, gfp); |
| 800 | } | 794 | } |
| 801 | EXPORT_SYMBOL(cfg80211_cac_event); | 795 | EXPORT_SYMBOL(cfg80211_cac_event); |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 138dc3bb8b67..7a742594916e 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
| @@ -53,6 +53,7 @@ enum nl80211_multicast_groups { | |||
| 53 | NL80211_MCGRP_SCAN, | 53 | NL80211_MCGRP_SCAN, |
| 54 | NL80211_MCGRP_REGULATORY, | 54 | NL80211_MCGRP_REGULATORY, |
| 55 | NL80211_MCGRP_MLME, | 55 | NL80211_MCGRP_MLME, |
| 56 | NL80211_MCGRP_VENDOR, | ||
| 56 | NL80211_MCGRP_TESTMODE /* keep last - ifdef! */ | 57 | NL80211_MCGRP_TESTMODE /* keep last - ifdef! */ |
| 57 | }; | 58 | }; |
| 58 | 59 | ||
| @@ -61,6 +62,7 @@ static const struct genl_multicast_group nl80211_mcgrps[] = { | |||
| 61 | [NL80211_MCGRP_SCAN] = { .name = "scan", }, | 62 | [NL80211_MCGRP_SCAN] = { .name = "scan", }, |
| 62 | [NL80211_MCGRP_REGULATORY] = { .name = "regulatory", }, | 63 | [NL80211_MCGRP_REGULATORY] = { .name = "regulatory", }, |
| 63 | [NL80211_MCGRP_MLME] = { .name = "mlme", }, | 64 | [NL80211_MCGRP_MLME] = { .name = "mlme", }, |
| 65 | [NL80211_MCGRP_VENDOR] = { .name = "vendor", }, | ||
| 64 | #ifdef CONFIG_NL80211_TESTMODE | 66 | #ifdef CONFIG_NL80211_TESTMODE |
| 65 | [NL80211_MCGRP_TESTMODE] = { .name = "testmode", } | 67 | [NL80211_MCGRP_TESTMODE] = { .name = "testmode", } |
| 66 | #endif | 68 | #endif |
| @@ -163,7 +165,7 @@ __cfg80211_rdev_from_attrs(struct net *netns, struct nlattr **attrs) | |||
| 163 | 165 | ||
| 164 | if (attrs[NL80211_ATTR_IFINDEX]) { | 166 | if (attrs[NL80211_ATTR_IFINDEX]) { |
| 165 | int ifindex = nla_get_u32(attrs[NL80211_ATTR_IFINDEX]); | 167 | int ifindex = nla_get_u32(attrs[NL80211_ATTR_IFINDEX]); |
| 166 | netdev = dev_get_by_index(netns, ifindex); | 168 | netdev = __dev_get_by_index(netns, ifindex); |
| 167 | if (netdev) { | 169 | if (netdev) { |
| 168 | if (netdev->ieee80211_ptr) | 170 | if (netdev->ieee80211_ptr) |
| 169 | tmp = wiphy_to_dev( | 171 | tmp = wiphy_to_dev( |
| @@ -171,8 +173,6 @@ __cfg80211_rdev_from_attrs(struct net *netns, struct nlattr **attrs) | |||
| 171 | else | 173 | else |
| 172 | tmp = NULL; | 174 | tmp = NULL; |
| 173 | 175 | ||
| 174 | dev_put(netdev); | ||
| 175 | |||
| 176 | /* not wireless device -- return error */ | 176 | /* not wireless device -- return error */ |
| 177 | if (!tmp) | 177 | if (!tmp) |
| 178 | return ERR_PTR(-EINVAL); | 178 | return ERR_PTR(-EINVAL); |
| @@ -376,6 +376,12 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { | |||
| 376 | [NL80211_ATTR_STA_SUPPORTED_CHANNELS] = { .type = NLA_BINARY }, | 376 | [NL80211_ATTR_STA_SUPPORTED_CHANNELS] = { .type = NLA_BINARY }, |
| 377 | [NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES] = { .type = NLA_BINARY }, | 377 | [NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES] = { .type = NLA_BINARY }, |
| 378 | [NL80211_ATTR_HANDLE_DFS] = { .type = NLA_FLAG }, | 378 | [NL80211_ATTR_HANDLE_DFS] = { .type = NLA_FLAG }, |
| 379 | [NL80211_ATTR_OPMODE_NOTIF] = { .type = NLA_U8 }, | ||
| 380 | [NL80211_ATTR_VENDOR_ID] = { .type = NLA_U32 }, | ||
| 381 | [NL80211_ATTR_VENDOR_SUBCMD] = { .type = NLA_U32 }, | ||
| 382 | [NL80211_ATTR_VENDOR_DATA] = { .type = NLA_BINARY }, | ||
| 383 | [NL80211_ATTR_QOS_MAP] = { .type = NLA_BINARY, | ||
| 384 | .len = IEEE80211_QOS_MAP_LEN_MAX }, | ||
| 379 | }; | 385 | }; |
| 380 | 386 | ||
| 381 | /* policy for the key attributes */ | 387 | /* policy for the key attributes */ |
| @@ -564,12 +570,12 @@ static int nl80211_msg_put_channel(struct sk_buff *msg, | |||
| 564 | if ((chan->flags & IEEE80211_CHAN_DISABLED) && | 570 | if ((chan->flags & IEEE80211_CHAN_DISABLED) && |
| 565 | nla_put_flag(msg, NL80211_FREQUENCY_ATTR_DISABLED)) | 571 | nla_put_flag(msg, NL80211_FREQUENCY_ATTR_DISABLED)) |
| 566 | goto nla_put_failure; | 572 | goto nla_put_failure; |
| 567 | if ((chan->flags & IEEE80211_CHAN_PASSIVE_SCAN) && | 573 | if (chan->flags & IEEE80211_CHAN_NO_IR) { |
| 568 | nla_put_flag(msg, NL80211_FREQUENCY_ATTR_PASSIVE_SCAN)) | 574 | if (nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_IR)) |
| 569 | goto nla_put_failure; | 575 | goto nla_put_failure; |
| 570 | if ((chan->flags & IEEE80211_CHAN_NO_IBSS) && | 576 | if (nla_put_flag(msg, __NL80211_FREQUENCY_ATTR_NO_IBSS)) |
| 571 | nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_IBSS)) | 577 | goto nla_put_failure; |
| 572 | goto nla_put_failure; | 578 | } |
| 573 | if (chan->flags & IEEE80211_CHAN_RADAR) { | 579 | if (chan->flags & IEEE80211_CHAN_RADAR) { |
| 574 | if (nla_put_flag(msg, NL80211_FREQUENCY_ATTR_RADAR)) | 580 | if (nla_put_flag(msg, NL80211_FREQUENCY_ATTR_RADAR)) |
| 575 | goto nla_put_failure; | 581 | goto nla_put_failure; |
| @@ -1247,10 +1253,6 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, | |||
| 1247 | if ((dev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP) && | 1253 | if ((dev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP) && |
| 1248 | nla_put_flag(msg, NL80211_ATTR_TDLS_EXTERNAL_SETUP)) | 1254 | nla_put_flag(msg, NL80211_ATTR_TDLS_EXTERNAL_SETUP)) |
| 1249 | goto nla_put_failure; | 1255 | goto nla_put_failure; |
| 1250 | if ((dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_5_10_MHZ) && | ||
| 1251 | nla_put_flag(msg, WIPHY_FLAG_SUPPORTS_5_10_MHZ)) | ||
| 1252 | goto nla_put_failure; | ||
| 1253 | |||
| 1254 | state->split_start++; | 1256 | state->split_start++; |
| 1255 | if (state->split) | 1257 | if (state->split) |
| 1256 | break; | 1258 | break; |
| @@ -1454,6 +1456,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, | |||
| 1454 | if (dev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH) | 1456 | if (dev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH) |
| 1455 | CMD(channel_switch, CHANNEL_SWITCH); | 1457 | CMD(channel_switch, CHANNEL_SWITCH); |
| 1456 | } | 1458 | } |
| 1459 | CMD(set_qos_map, SET_QOS_MAP); | ||
| 1457 | 1460 | ||
| 1458 | #ifdef CONFIG_NL80211_TESTMODE | 1461 | #ifdef CONFIG_NL80211_TESTMODE |
| 1459 | CMD(testmode_cmd, TESTMODE); | 1462 | CMD(testmode_cmd, TESTMODE); |
| @@ -1579,6 +1582,46 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, | |||
| 1579 | if (nl80211_send_coalesce(msg, dev)) | 1582 | if (nl80211_send_coalesce(msg, dev)) |
| 1580 | goto nla_put_failure; | 1583 | goto nla_put_failure; |
| 1581 | 1584 | ||
| 1585 | if ((dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_5_10_MHZ) && | ||
| 1586 | (nla_put_flag(msg, NL80211_ATTR_SUPPORT_5_MHZ) || | ||
| 1587 | nla_put_flag(msg, NL80211_ATTR_SUPPORT_10_MHZ))) | ||
| 1588 | goto nla_put_failure; | ||
| 1589 | state->split_start++; | ||
| 1590 | break; | ||
| 1591 | case 11: | ||
| 1592 | if (dev->wiphy.n_vendor_commands) { | ||
| 1593 | const struct nl80211_vendor_cmd_info *info; | ||
| 1594 | struct nlattr *nested; | ||
| 1595 | |||
| 1596 | nested = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA); | ||
| 1597 | if (!nested) | ||
| 1598 | goto nla_put_failure; | ||
| 1599 | |||
| 1600 | for (i = 0; i < dev->wiphy.n_vendor_commands; i++) { | ||
| 1601 | info = &dev->wiphy.vendor_commands[i].info; | ||
| 1602 | if (nla_put(msg, i + 1, sizeof(*info), info)) | ||
| 1603 | goto nla_put_failure; | ||
| 1604 | } | ||
| 1605 | nla_nest_end(msg, nested); | ||
| 1606 | } | ||
| 1607 | |||
| 1608 | if (dev->wiphy.n_vendor_events) { | ||
| 1609 | const struct nl80211_vendor_cmd_info *info; | ||
| 1610 | struct nlattr *nested; | ||
| 1611 | |||
| 1612 | nested = nla_nest_start(msg, | ||
| 1613 | NL80211_ATTR_VENDOR_EVENTS); | ||
| 1614 | if (!nested) | ||
| 1615 | goto nla_put_failure; | ||
| 1616 | |||
| 1617 | for (i = 0; i < dev->wiphy.n_vendor_events; i++) { | ||
| 1618 | info = &dev->wiphy.vendor_events[i]; | ||
| 1619 | if (nla_put(msg, i + 1, sizeof(*info), info)) | ||
| 1620 | goto nla_put_failure; | ||
| 1621 | } | ||
| 1622 | nla_nest_end(msg, nested); | ||
| 1623 | } | ||
| 1624 | |||
| 1582 | /* done */ | 1625 | /* done */ |
| 1583 | state->split_start = 0; | 1626 | state->split_start = 0; |
| 1584 | break; | 1627 | break; |
| @@ -1611,7 +1654,7 @@ static int nl80211_dump_wiphy_parse(struct sk_buff *skb, | |||
| 1611 | struct cfg80211_registered_device *rdev; | 1654 | struct cfg80211_registered_device *rdev; |
| 1612 | int ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]); | 1655 | int ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]); |
| 1613 | 1656 | ||
| 1614 | netdev = dev_get_by_index(sock_net(skb->sk), ifidx); | 1657 | netdev = __dev_get_by_index(sock_net(skb->sk), ifidx); |
| 1615 | if (!netdev) | 1658 | if (!netdev) |
| 1616 | return -ENODEV; | 1659 | return -ENODEV; |
| 1617 | if (netdev->ieee80211_ptr) { | 1660 | if (netdev->ieee80211_ptr) { |
| @@ -1619,7 +1662,6 @@ static int nl80211_dump_wiphy_parse(struct sk_buff *skb, | |||
| 1619 | netdev->ieee80211_ptr->wiphy); | 1662 | netdev->ieee80211_ptr->wiphy); |
| 1620 | state->filter_wiphy = rdev->wiphy_idx; | 1663 | state->filter_wiphy = rdev->wiphy_idx; |
| 1621 | } | 1664 | } |
| 1622 | dev_put(netdev); | ||
| 1623 | } | 1665 | } |
| 1624 | 1666 | ||
| 1625 | return 0; | 1667 | return 0; |
| @@ -1942,7 +1984,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
| 1942 | if (info->attrs[NL80211_ATTR_IFINDEX]) { | 1984 | if (info->attrs[NL80211_ATTR_IFINDEX]) { |
| 1943 | int ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]); | 1985 | int ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]); |
| 1944 | 1986 | ||
| 1945 | netdev = dev_get_by_index(genl_info_net(info), ifindex); | 1987 | netdev = __dev_get_by_index(genl_info_net(info), ifindex); |
| 1946 | if (netdev && netdev->ieee80211_ptr) | 1988 | if (netdev && netdev->ieee80211_ptr) |
| 1947 | rdev = wiphy_to_dev(netdev->ieee80211_ptr->wiphy); | 1989 | rdev = wiphy_to_dev(netdev->ieee80211_ptr->wiphy); |
| 1948 | else | 1990 | else |
| @@ -1970,32 +2012,24 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
| 1970 | rdev, nla_data(info->attrs[NL80211_ATTR_WIPHY_NAME])); | 2012 | rdev, nla_data(info->attrs[NL80211_ATTR_WIPHY_NAME])); |
| 1971 | 2013 | ||
| 1972 | if (result) | 2014 | if (result) |
| 1973 | goto bad_res; | 2015 | return result; |
| 1974 | 2016 | ||
| 1975 | if (info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS]) { | 2017 | if (info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS]) { |
| 1976 | struct ieee80211_txq_params txq_params; | 2018 | struct ieee80211_txq_params txq_params; |
| 1977 | struct nlattr *tb[NL80211_TXQ_ATTR_MAX + 1]; | 2019 | struct nlattr *tb[NL80211_TXQ_ATTR_MAX + 1]; |
| 1978 | 2020 | ||
| 1979 | if (!rdev->ops->set_txq_params) { | 2021 | if (!rdev->ops->set_txq_params) |
| 1980 | result = -EOPNOTSUPP; | 2022 | return -EOPNOTSUPP; |
| 1981 | goto bad_res; | ||
| 1982 | } | ||
| 1983 | 2023 | ||
| 1984 | if (!netdev) { | 2024 | if (!netdev) |
| 1985 | result = -EINVAL; | 2025 | return -EINVAL; |
| 1986 | goto bad_res; | ||
| 1987 | } | ||
| 1988 | 2026 | ||
| 1989 | if (netdev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && | 2027 | if (netdev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && |
| 1990 | netdev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) { | 2028 | netdev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) |
| 1991 | result = -EINVAL; | 2029 | return -EINVAL; |
| 1992 | goto bad_res; | ||
| 1993 | } | ||
| 1994 | 2030 | ||
| 1995 | if (!netif_running(netdev)) { | 2031 | if (!netif_running(netdev)) |
| 1996 | result = -ENETDOWN; | 2032 | return -ENETDOWN; |
| 1997 | goto bad_res; | ||
| 1998 | } | ||
| 1999 | 2033 | ||
| 2000 | nla_for_each_nested(nl_txq_params, | 2034 | nla_for_each_nested(nl_txq_params, |
| 2001 | info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS], | 2035 | info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS], |
| @@ -2006,12 +2040,12 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
| 2006 | txq_params_policy); | 2040 | txq_params_policy); |
| 2007 | result = parse_txq_params(tb, &txq_params); | 2041 | result = parse_txq_params(tb, &txq_params); |
| 2008 | if (result) | 2042 | if (result) |
| 2009 | goto bad_res; | 2043 | return result; |
| 2010 | 2044 | ||
| 2011 | result = rdev_set_txq_params(rdev, netdev, | 2045 | result = rdev_set_txq_params(rdev, netdev, |
| 2012 | &txq_params); | 2046 | &txq_params); |
| 2013 | if (result) | 2047 | if (result) |
| 2014 | goto bad_res; | 2048 | return result; |
| 2015 | } | 2049 | } |
| 2016 | } | 2050 | } |
| 2017 | 2051 | ||
| @@ -2020,7 +2054,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
| 2020 | nl80211_can_set_dev_channel(wdev) ? wdev : NULL, | 2054 | nl80211_can_set_dev_channel(wdev) ? wdev : NULL, |
| 2021 | info); | 2055 | info); |
| 2022 | if (result) | 2056 | if (result) |
| 2023 | goto bad_res; | 2057 | return result; |
| 2024 | } | 2058 | } |
| 2025 | 2059 | ||
| 2026 | if (info->attrs[NL80211_ATTR_WIPHY_TX_POWER_SETTING]) { | 2060 | if (info->attrs[NL80211_ATTR_WIPHY_TX_POWER_SETTING]) { |
| @@ -2031,19 +2065,15 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
| 2031 | if (!(rdev->wiphy.features & NL80211_FEATURE_VIF_TXPOWER)) | 2065 | if (!(rdev->wiphy.features & NL80211_FEATURE_VIF_TXPOWER)) |
| 2032 | txp_wdev = NULL; | 2066 | txp_wdev = NULL; |
| 2033 | 2067 | ||
| 2034 | if (!rdev->ops->set_tx_power) { | 2068 | if (!rdev->ops->set_tx_power) |
| 2035 | result = -EOPNOTSUPP; | 2069 | return -EOPNOTSUPP; |
| 2036 | goto bad_res; | ||
| 2037 | } | ||
| 2038 | 2070 | ||
| 2039 | idx = NL80211_ATTR_WIPHY_TX_POWER_SETTING; | 2071 | idx = NL80211_ATTR_WIPHY_TX_POWER_SETTING; |
| 2040 | type = nla_get_u32(info->attrs[idx]); | 2072 | type = nla_get_u32(info->attrs[idx]); |
| 2041 | 2073 | ||
| 2042 | if (!info->attrs[NL80211_ATTR_WIPHY_TX_POWER_LEVEL] && | 2074 | if (!info->attrs[NL80211_ATTR_WIPHY_TX_POWER_LEVEL] && |
| 2043 | (type != NL80211_TX_POWER_AUTOMATIC)) { | 2075 | (type != NL80211_TX_POWER_AUTOMATIC)) |
| 2044 | result = -EINVAL; | 2076 | return -EINVAL; |
| 2045 | goto bad_res; | ||
| 2046 | } | ||
| 2047 | 2077 | ||
| 2048 | if (type != NL80211_TX_POWER_AUTOMATIC) { | 2078 | if (type != NL80211_TX_POWER_AUTOMATIC) { |
| 2049 | idx = NL80211_ATTR_WIPHY_TX_POWER_LEVEL; | 2079 | idx = NL80211_ATTR_WIPHY_TX_POWER_LEVEL; |
| @@ -2052,7 +2082,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
| 2052 | 2082 | ||
| 2053 | result = rdev_set_tx_power(rdev, txp_wdev, type, mbm); | 2083 | result = rdev_set_tx_power(rdev, txp_wdev, type, mbm); |
| 2054 | if (result) | 2084 | if (result) |
| 2055 | goto bad_res; | 2085 | return result; |
| 2056 | } | 2086 | } |
| 2057 | 2087 | ||
| 2058 | if (info->attrs[NL80211_ATTR_WIPHY_ANTENNA_TX] && | 2088 | if (info->attrs[NL80211_ATTR_WIPHY_ANTENNA_TX] && |
| @@ -2060,10 +2090,8 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
| 2060 | u32 tx_ant, rx_ant; | 2090 | u32 tx_ant, rx_ant; |
| 2061 | if ((!rdev->wiphy.available_antennas_tx && | 2091 | if ((!rdev->wiphy.available_antennas_tx && |
| 2062 | !rdev->wiphy.available_antennas_rx) || | 2092 | !rdev->wiphy.available_antennas_rx) || |
| 2063 | !rdev->ops->set_antenna) { | 2093 | !rdev->ops->set_antenna) |
| 2064 | result = -EOPNOTSUPP; | 2094 | return -EOPNOTSUPP; |
| 2065 | goto bad_res; | ||
| 2066 | } | ||
| 2067 | 2095 | ||
| 2068 | tx_ant = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_ANTENNA_TX]); | 2096 | tx_ant = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_ANTENNA_TX]); |
| 2069 | rx_ant = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_ANTENNA_RX]); | 2097 | rx_ant = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_ANTENNA_RX]); |
| @@ -2071,17 +2099,15 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
| 2071 | /* reject antenna configurations which don't match the | 2099 | /* reject antenna configurations which don't match the |
| 2072 | * available antenna masks, except for the "all" mask */ | 2100 | * available antenna masks, except for the "all" mask */ |
| 2073 | if ((~tx_ant && (tx_ant & ~rdev->wiphy.available_antennas_tx)) || | 2101 | if ((~tx_ant && (tx_ant & ~rdev->wiphy.available_antennas_tx)) || |
| 2074 | (~rx_ant && (rx_ant & ~rdev->wiphy.available_antennas_rx))) { | 2102 | (~rx_ant && (rx_ant & ~rdev->wiphy.available_antennas_rx))) |
| 2075 | result = -EINVAL; | 2103 | return -EINVAL; |
| 2076 | goto bad_res; | ||
| 2077 | } | ||
| 2078 | 2104 | ||
| 2079 | tx_ant = tx_ant & rdev->wiphy.available_antennas_tx; | 2105 | tx_ant = tx_ant & rdev->wiphy.available_antennas_tx; |
| 2080 | rx_ant = rx_ant & rdev->wiphy.available_antennas_rx; | 2106 | rx_ant = rx_ant & rdev->wiphy.available_antennas_rx; |
| 2081 | 2107 | ||
| 2082 | result = rdev_set_antenna(rdev, tx_ant, rx_ant); | 2108 | result = rdev_set_antenna(rdev, tx_ant, rx_ant); |
| 2083 | if (result) | 2109 | if (result) |
| 2084 | goto bad_res; | 2110 | return result; |
| 2085 | } | 2111 | } |
| 2086 | 2112 | ||
| 2087 | changed = 0; | 2113 | changed = 0; |
| @@ -2089,30 +2115,27 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
| 2089 | if (info->attrs[NL80211_ATTR_WIPHY_RETRY_SHORT]) { | 2115 | if (info->attrs[NL80211_ATTR_WIPHY_RETRY_SHORT]) { |
| 2090 | retry_short = nla_get_u8( | 2116 | retry_short = nla_get_u8( |
| 2091 | info->attrs[NL80211_ATTR_WIPHY_RETRY_SHORT]); | 2117 | info->attrs[NL80211_ATTR_WIPHY_RETRY_SHORT]); |
| 2092 | if (retry_short == 0) { | 2118 | if (retry_short == 0) |
| 2093 | result = -EINVAL; | 2119 | return -EINVAL; |
| 2094 | goto bad_res; | 2120 | |
| 2095 | } | ||
| 2096 | changed |= WIPHY_PARAM_RETRY_SHORT; | 2121 | changed |= WIPHY_PARAM_RETRY_SHORT; |
| 2097 | } | 2122 | } |
| 2098 | 2123 | ||
| 2099 | if (info->attrs[NL80211_ATTR_WIPHY_RETRY_LONG]) { | 2124 | if (info->attrs[NL80211_ATTR_WIPHY_RETRY_LONG]) { |
| 2100 | retry_long = nla_get_u8( | 2125 | retry_long = nla_get_u8( |
| 2101 | info->attrs[NL80211_ATTR_WIPHY_RETRY_LONG]); | 2126 | info->attrs[NL80211_ATTR_WIPHY_RETRY_LONG]); |
| 2102 | if (retry_long == 0) { | 2127 | if (retry_long == 0) |
| 2103 | result = -EINVAL; | 2128 | return -EINVAL; |
| 2104 | goto bad_res; | 2129 | |
| 2105 | } | ||
| 2106 | changed |= WIPHY_PARAM_RETRY_LONG; | 2130 | changed |= WIPHY_PARAM_RETRY_LONG; |
| 2107 | } | 2131 | } |
| 2108 | 2132 | ||
| 2109 | if (info->attrs[NL80211_ATTR_WIPHY_FRAG_THRESHOLD]) { | 2133 | if (info->attrs[NL80211_ATTR_WIPHY_FRAG_THRESHOLD]) { |
| 2110 | frag_threshold = nla_get_u32( | 2134 | frag_threshold = nla_get_u32( |
| 2111 | info->attrs[NL80211_ATTR_WIPHY_FRAG_THRESHOLD]); | 2135 | info->attrs[NL80211_ATTR_WIPHY_FRAG_THRESHOLD]); |
| 2112 | if (frag_threshold < 256) { | 2136 | if (frag_threshold < 256) |
| 2113 | result = -EINVAL; | 2137 | return -EINVAL; |
| 2114 | goto bad_res; | 2138 | |
| 2115 | } | ||
| 2116 | if (frag_threshold != (u32) -1) { | 2139 | if (frag_threshold != (u32) -1) { |
| 2117 | /* | 2140 | /* |
| 2118 | * Fragments (apart from the last one) are required to | 2141 | * Fragments (apart from the last one) are required to |
| @@ -2142,10 +2165,8 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
| 2142 | u32 old_frag_threshold, old_rts_threshold; | 2165 | u32 old_frag_threshold, old_rts_threshold; |
| 2143 | u8 old_coverage_class; | 2166 | u8 old_coverage_class; |
| 2144 | 2167 | ||
| 2145 | if (!rdev->ops->set_wiphy_params) { | 2168 | if (!rdev->ops->set_wiphy_params) |
| 2146 | result = -EOPNOTSUPP; | 2169 | return -EOPNOTSUPP; |
| 2147 | goto bad_res; | ||
| 2148 | } | ||
| 2149 | 2170 | ||
| 2150 | old_retry_short = rdev->wiphy.retry_short; | 2171 | old_retry_short = rdev->wiphy.retry_short; |
| 2151 | old_retry_long = rdev->wiphy.retry_long; | 2172 | old_retry_long = rdev->wiphy.retry_long; |
| @@ -2173,11 +2194,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
| 2173 | rdev->wiphy.coverage_class = old_coverage_class; | 2194 | rdev->wiphy.coverage_class = old_coverage_class; |
| 2174 | } | 2195 | } |
| 2175 | } | 2196 | } |
| 2176 | 2197 | return 0; | |
| 2177 | bad_res: | ||
| 2178 | if (netdev) | ||
| 2179 | dev_put(netdev); | ||
| 2180 | return result; | ||
| 2181 | } | 2198 | } |
| 2182 | 2199 | ||
| 2183 | static inline u64 wdev_id(struct wireless_dev *wdev) | 2200 | static inline u64 wdev_id(struct wireless_dev *wdev) |
| @@ -2187,7 +2204,7 @@ static inline u64 wdev_id(struct wireless_dev *wdev) | |||
| 2187 | } | 2204 | } |
| 2188 | 2205 | ||
| 2189 | static int nl80211_send_chandef(struct sk_buff *msg, | 2206 | static int nl80211_send_chandef(struct sk_buff *msg, |
| 2190 | struct cfg80211_chan_def *chandef) | 2207 | const struct cfg80211_chan_def *chandef) |
| 2191 | { | 2208 | { |
| 2192 | WARN_ON(!cfg80211_chandef_valid(chandef)); | 2209 | WARN_ON(!cfg80211_chandef_valid(chandef)); |
| 2193 | 2210 | ||
| @@ -3236,6 +3253,7 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) | |||
| 3236 | return PTR_ERR(params.acl); | 3253 | return PTR_ERR(params.acl); |
| 3237 | } | 3254 | } |
| 3238 | 3255 | ||
| 3256 | wdev_lock(wdev); | ||
| 3239 | err = rdev_start_ap(rdev, dev, ¶ms); | 3257 | err = rdev_start_ap(rdev, dev, ¶ms); |
| 3240 | if (!err) { | 3258 | if (!err) { |
| 3241 | wdev->preset_chandef = params.chandef; | 3259 | wdev->preset_chandef = params.chandef; |
| @@ -3244,6 +3262,7 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) | |||
| 3244 | wdev->ssid_len = params.ssid_len; | 3262 | wdev->ssid_len = params.ssid_len; |
| 3245 | memcpy(wdev->ssid, params.ssid, wdev->ssid_len); | 3263 | memcpy(wdev->ssid, params.ssid, wdev->ssid_len); |
| 3246 | } | 3264 | } |
| 3265 | wdev_unlock(wdev); | ||
| 3247 | 3266 | ||
| 3248 | kfree(params.acl); | 3267 | kfree(params.acl); |
| 3249 | 3268 | ||
| @@ -3272,7 +3291,11 @@ static int nl80211_set_beacon(struct sk_buff *skb, struct genl_info *info) | |||
| 3272 | if (err) | 3291 | if (err) |
| 3273 | return err; | 3292 | return err; |
| 3274 | 3293 | ||
| 3275 | return rdev_change_beacon(rdev, dev, ¶ms); | 3294 | wdev_lock(wdev); |
| 3295 | err = rdev_change_beacon(rdev, dev, ¶ms); | ||
| 3296 | wdev_unlock(wdev); | ||
| 3297 | |||
| 3298 | return err; | ||
| 3276 | } | 3299 | } |
| 3277 | 3300 | ||
| 3278 | static int nl80211_stop_ap(struct sk_buff *skb, struct genl_info *info) | 3301 | static int nl80211_stop_ap(struct sk_buff *skb, struct genl_info *info) |
| @@ -4144,6 +4167,12 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) | |||
| 4144 | params.vht_capa = | 4167 | params.vht_capa = |
| 4145 | nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]); | 4168 | nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]); |
| 4146 | 4169 | ||
| 4170 | if (info->attrs[NL80211_ATTR_OPMODE_NOTIF]) { | ||
| 4171 | params.opmode_notif_used = true; | ||
| 4172 | params.opmode_notif = | ||
| 4173 | nla_get_u8(info->attrs[NL80211_ATTR_OPMODE_NOTIF]); | ||
| 4174 | } | ||
| 4175 | |||
| 4147 | if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION]) { | 4176 | if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION]) { |
| 4148 | params.plink_action = | 4177 | params.plink_action = |
| 4149 | nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]); | 4178 | nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]); |
| @@ -4478,7 +4507,9 @@ static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info) | |||
| 4478 | { | 4507 | { |
| 4479 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 4508 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
| 4480 | struct net_device *dev = info->user_ptr[1]; | 4509 | struct net_device *dev = info->user_ptr[1]; |
| 4510 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
| 4481 | struct bss_parameters params; | 4511 | struct bss_parameters params; |
| 4512 | int err; | ||
| 4482 | 4513 | ||
| 4483 | memset(¶ms, 0, sizeof(params)); | 4514 | memset(¶ms, 0, sizeof(params)); |
| 4484 | /* default to not changing parameters */ | 4515 | /* default to not changing parameters */ |
| @@ -4544,7 +4575,11 @@ static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info) | |||
| 4544 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) | 4575 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) |
| 4545 | return -EOPNOTSUPP; | 4576 | return -EOPNOTSUPP; |
| 4546 | 4577 | ||
| 4547 | return rdev_change_bss(rdev, dev, ¶ms); | 4578 | wdev_lock(wdev); |
| 4579 | err = rdev_change_bss(rdev, dev, ¶ms); | ||
| 4580 | wdev_unlock(wdev); | ||
| 4581 | |||
| 4582 | return err; | ||
| 4548 | } | 4583 | } |
| 4549 | 4584 | ||
| 4550 | static const struct nla_policy reg_rule_policy[NL80211_REG_RULE_ATTR_MAX + 1] = { | 4585 | static const struct nla_policy reg_rule_policy[NL80211_REG_RULE_ATTR_MAX + 1] = { |
| @@ -5098,7 +5133,7 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info) | |||
| 5098 | char *alpha2 = NULL; | 5133 | char *alpha2 = NULL; |
| 5099 | int rem_reg_rules = 0, r = 0; | 5134 | int rem_reg_rules = 0, r = 0; |
| 5100 | u32 num_rules = 0, rule_idx = 0, size_of_regd; | 5135 | u32 num_rules = 0, rule_idx = 0, size_of_regd; |
| 5101 | u8 dfs_region = 0; | 5136 | enum nl80211_dfs_regions dfs_region = NL80211_DFS_UNSET; |
| 5102 | struct ieee80211_regdomain *rd = NULL; | 5137 | struct ieee80211_regdomain *rd = NULL; |
| 5103 | 5138 | ||
| 5104 | if (!info->attrs[NL80211_ATTR_REG_ALPHA2]) | 5139 | if (!info->attrs[NL80211_ATTR_REG_ALPHA2]) |
| @@ -5119,6 +5154,9 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info) | |||
| 5119 | return -EINVAL; | 5154 | return -EINVAL; |
| 5120 | } | 5155 | } |
| 5121 | 5156 | ||
| 5157 | if (!reg_is_valid_request(alpha2)) | ||
| 5158 | return -EINVAL; | ||
| 5159 | |||
| 5122 | size_of_regd = sizeof(struct ieee80211_regdomain) + | 5160 | size_of_regd = sizeof(struct ieee80211_regdomain) + |
| 5123 | num_rules * sizeof(struct ieee80211_reg_rule); | 5161 | num_rules * sizeof(struct ieee80211_reg_rule); |
| 5124 | 5162 | ||
| @@ -5219,12 +5257,7 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
| 5219 | goto unlock; | 5257 | goto unlock; |
| 5220 | } | 5258 | } |
| 5221 | } else { | 5259 | } else { |
| 5222 | enum ieee80211_band band; | 5260 | n_channels = ieee80211_get_num_supported_channels(wiphy); |
| 5223 | n_channels = 0; | ||
| 5224 | |||
| 5225 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) | ||
| 5226 | if (wiphy->bands[band]) | ||
| 5227 | n_channels += wiphy->bands[band]->n_channels; | ||
| 5228 | } | 5261 | } |
| 5229 | 5262 | ||
| 5230 | if (info->attrs[NL80211_ATTR_SCAN_SSIDS]) | 5263 | if (info->attrs[NL80211_ATTR_SCAN_SSIDS]) |
| @@ -5365,10 +5398,8 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
| 5365 | if (info->attrs[NL80211_ATTR_SCAN_FLAGS]) { | 5398 | if (info->attrs[NL80211_ATTR_SCAN_FLAGS]) { |
| 5366 | request->flags = nla_get_u32( | 5399 | request->flags = nla_get_u32( |
| 5367 | info->attrs[NL80211_ATTR_SCAN_FLAGS]); | 5400 | info->attrs[NL80211_ATTR_SCAN_FLAGS]); |
| 5368 | if (((request->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) && | 5401 | if ((request->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) && |
| 5369 | !(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN)) || | 5402 | !(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN)) { |
| 5370 | ((request->flags & NL80211_SCAN_FLAG_FLUSH) && | ||
| 5371 | !(wiphy->features & NL80211_FEATURE_SCAN_FLUSH))) { | ||
| 5372 | err = -EOPNOTSUPP; | 5403 | err = -EOPNOTSUPP; |
| 5373 | goto out_free; | 5404 | goto out_free; |
| 5374 | } | 5405 | } |
| @@ -5434,11 +5465,7 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, | |||
| 5434 | if (!n_channels) | 5465 | if (!n_channels) |
| 5435 | return -EINVAL; | 5466 | return -EINVAL; |
| 5436 | } else { | 5467 | } else { |
| 5437 | n_channels = 0; | 5468 | n_channels = ieee80211_get_num_supported_channels(wiphy); |
| 5438 | |||
| 5439 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) | ||
| 5440 | if (wiphy->bands[band]) | ||
| 5441 | n_channels += wiphy->bands[band]->n_channels; | ||
| 5442 | } | 5469 | } |
| 5443 | 5470 | ||
| 5444 | if (info->attrs[NL80211_ATTR_SCAN_SSIDS]) | 5471 | if (info->attrs[NL80211_ATTR_SCAN_SSIDS]) |
| @@ -5608,10 +5635,8 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, | |||
| 5608 | if (info->attrs[NL80211_ATTR_SCAN_FLAGS]) { | 5635 | if (info->attrs[NL80211_ATTR_SCAN_FLAGS]) { |
| 5609 | request->flags = nla_get_u32( | 5636 | request->flags = nla_get_u32( |
| 5610 | info->attrs[NL80211_ATTR_SCAN_FLAGS]); | 5637 | info->attrs[NL80211_ATTR_SCAN_FLAGS]); |
| 5611 | if (((request->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) && | 5638 | if ((request->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) && |
| 5612 | !(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN)) || | 5639 | !(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN)) { |
| 5613 | ((request->flags & NL80211_SCAN_FLAG_FLUSH) && | ||
| 5614 | !(wiphy->features & NL80211_FEATURE_SCAN_FLUSH))) { | ||
| 5615 | err = -EOPNOTSUPP; | 5640 | err = -EOPNOTSUPP; |
| 5616 | goto out_free; | 5641 | goto out_free; |
| 5617 | } | 5642 | } |
| @@ -5655,8 +5680,13 @@ static int nl80211_start_radar_detection(struct sk_buff *skb, | |||
| 5655 | struct net_device *dev = info->user_ptr[1]; | 5680 | struct net_device *dev = info->user_ptr[1]; |
| 5656 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 5681 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
| 5657 | struct cfg80211_chan_def chandef; | 5682 | struct cfg80211_chan_def chandef; |
| 5683 | enum nl80211_dfs_regions dfs_region; | ||
| 5658 | int err; | 5684 | int err; |
| 5659 | 5685 | ||
| 5686 | dfs_region = reg_get_dfs_region(wdev->wiphy); | ||
| 5687 | if (dfs_region == NL80211_DFS_UNSET) | ||
| 5688 | return -EINVAL; | ||
| 5689 | |||
| 5660 | err = nl80211_parse_chandef(rdev, info, &chandef); | 5690 | err = nl80211_parse_chandef(rdev, info, &chandef); |
| 5661 | if (err) | 5691 | if (err) |
| 5662 | return err; | 5692 | return err; |
| @@ -5674,7 +5704,7 @@ static int nl80211_start_radar_detection(struct sk_buff *skb, | |||
| 5674 | if (err == 0) | 5704 | if (err == 0) |
| 5675 | return -EINVAL; | 5705 | return -EINVAL; |
| 5676 | 5706 | ||
| 5677 | if (chandef.chan->dfs_state != NL80211_DFS_USABLE) | 5707 | if (!cfg80211_chandef_dfs_usable(wdev->wiphy, &chandef)) |
| 5678 | return -EINVAL; | 5708 | return -EINVAL; |
| 5679 | 5709 | ||
| 5680 | if (!rdev->ops->start_radar_detection) | 5710 | if (!rdev->ops->start_radar_detection) |
| @@ -5814,7 +5844,11 @@ skip_beacons: | |||
| 5814 | if (info->attrs[NL80211_ATTR_CH_SWITCH_BLOCK_TX]) | 5844 | if (info->attrs[NL80211_ATTR_CH_SWITCH_BLOCK_TX]) |
| 5815 | params.block_tx = true; | 5845 | params.block_tx = true; |
| 5816 | 5846 | ||
| 5817 | return rdev_channel_switch(rdev, dev, ¶ms); | 5847 | wdev_lock(wdev); |
| 5848 | err = rdev_channel_switch(rdev, dev, ¶ms); | ||
| 5849 | wdev_unlock(wdev); | ||
| 5850 | |||
| 5851 | return err; | ||
| 5818 | } | 5852 | } |
| 5819 | 5853 | ||
| 5820 | static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb, | 5854 | static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb, |
| @@ -6677,6 +6711,101 @@ static int nl80211_set_mcast_rate(struct sk_buff *skb, struct genl_info *info) | |||
| 6677 | return err; | 6711 | return err; |
| 6678 | } | 6712 | } |
| 6679 | 6713 | ||
| 6714 | static struct sk_buff * | ||
| 6715 | __cfg80211_alloc_vendor_skb(struct cfg80211_registered_device *rdev, | ||
| 6716 | int approxlen, u32 portid, u32 seq, | ||
| 6717 | enum nl80211_commands cmd, | ||
| 6718 | enum nl80211_attrs attr, | ||
| 6719 | const struct nl80211_vendor_cmd_info *info, | ||
| 6720 | gfp_t gfp) | ||
| 6721 | { | ||
| 6722 | struct sk_buff *skb; | ||
| 6723 | void *hdr; | ||
| 6724 | struct nlattr *data; | ||
| 6725 | |||
| 6726 | skb = nlmsg_new(approxlen + 100, gfp); | ||
| 6727 | if (!skb) | ||
| 6728 | return NULL; | ||
| 6729 | |||
| 6730 | hdr = nl80211hdr_put(skb, portid, seq, 0, cmd); | ||
| 6731 | if (!hdr) { | ||
| 6732 | kfree_skb(skb); | ||
| 6733 | return NULL; | ||
| 6734 | } | ||
| 6735 | |||
| 6736 | if (nla_put_u32(skb, NL80211_ATTR_WIPHY, rdev->wiphy_idx)) | ||
| 6737 | goto nla_put_failure; | ||
| 6738 | |||
| 6739 | if (info) { | ||
| 6740 | if (nla_put_u32(skb, NL80211_ATTR_VENDOR_ID, | ||
| 6741 | info->vendor_id)) | ||
| 6742 | goto nla_put_failure; | ||
| 6743 | if (nla_put_u32(skb, NL80211_ATTR_VENDOR_SUBCMD, | ||
| 6744 | info->subcmd)) | ||
| 6745 | goto nla_put_failure; | ||
| 6746 | } | ||
| 6747 | |||
| 6748 | data = nla_nest_start(skb, attr); | ||
| 6749 | |||
| 6750 | ((void **)skb->cb)[0] = rdev; | ||
| 6751 | ((void **)skb->cb)[1] = hdr; | ||
| 6752 | ((void **)skb->cb)[2] = data; | ||
| 6753 | |||
| 6754 | return skb; | ||
| 6755 | |||
| 6756 | nla_put_failure: | ||
| 6757 | kfree_skb(skb); | ||
| 6758 | return NULL; | ||
| 6759 | } | ||
| 6760 | |||
| 6761 | struct sk_buff *__cfg80211_alloc_event_skb(struct wiphy *wiphy, | ||
| 6762 | enum nl80211_commands cmd, | ||
| 6763 | enum nl80211_attrs attr, | ||
| 6764 | int vendor_event_idx, | ||
| 6765 | int approxlen, gfp_t gfp) | ||
| 6766 | { | ||
| 6767 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
| 6768 | const struct nl80211_vendor_cmd_info *info; | ||
| 6769 | |||
| 6770 | switch (cmd) { | ||
| 6771 | case NL80211_CMD_TESTMODE: | ||
| 6772 | if (WARN_ON(vendor_event_idx != -1)) | ||
| 6773 | return NULL; | ||
| 6774 | info = NULL; | ||
| 6775 | break; | ||
| 6776 | case NL80211_CMD_VENDOR: | ||
| 6777 | if (WARN_ON(vendor_event_idx < 0 || | ||
| 6778 | vendor_event_idx >= wiphy->n_vendor_events)) | ||
| 6779 | return NULL; | ||
| 6780 | info = &wiphy->vendor_events[vendor_event_idx]; | ||
| 6781 | break; | ||
| 6782 | default: | ||
| 6783 | WARN_ON(1); | ||
| 6784 | return NULL; | ||
| 6785 | } | ||
| 6786 | |||
| 6787 | return __cfg80211_alloc_vendor_skb(rdev, approxlen, 0, 0, | ||
| 6788 | cmd, attr, info, gfp); | ||
| 6789 | } | ||
| 6790 | EXPORT_SYMBOL(__cfg80211_alloc_event_skb); | ||
| 6791 | |||
| 6792 | void __cfg80211_send_event_skb(struct sk_buff *skb, gfp_t gfp) | ||
| 6793 | { | ||
| 6794 | struct cfg80211_registered_device *rdev = ((void **)skb->cb)[0]; | ||
| 6795 | void *hdr = ((void **)skb->cb)[1]; | ||
| 6796 | struct nlattr *data = ((void **)skb->cb)[2]; | ||
| 6797 | enum nl80211_multicast_groups mcgrp = NL80211_MCGRP_TESTMODE; | ||
| 6798 | |||
| 6799 | nla_nest_end(skb, data); | ||
| 6800 | genlmsg_end(skb, hdr); | ||
| 6801 | |||
| 6802 | if (data->nla_type == NL80211_ATTR_VENDOR_DATA) | ||
| 6803 | mcgrp = NL80211_MCGRP_VENDOR; | ||
| 6804 | |||
| 6805 | genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), skb, 0, | ||
| 6806 | mcgrp, gfp); | ||
| 6807 | } | ||
| 6808 | EXPORT_SYMBOL(__cfg80211_send_event_skb); | ||
| 6680 | 6809 | ||
| 6681 | #ifdef CONFIG_NL80211_TESTMODE | 6810 | #ifdef CONFIG_NL80211_TESTMODE |
| 6682 | static int nl80211_testmode_do(struct sk_buff *skb, struct genl_info *info) | 6811 | static int nl80211_testmode_do(struct sk_buff *skb, struct genl_info *info) |
| @@ -6701,11 +6830,11 @@ static int nl80211_testmode_do(struct sk_buff *skb, struct genl_info *info) | |||
| 6701 | if (!info->attrs[NL80211_ATTR_TESTDATA]) | 6830 | if (!info->attrs[NL80211_ATTR_TESTDATA]) |
| 6702 | return -EINVAL; | 6831 | return -EINVAL; |
| 6703 | 6832 | ||
| 6704 | rdev->testmode_info = info; | 6833 | rdev->cur_cmd_info = info; |
| 6705 | err = rdev_testmode_cmd(rdev, wdev, | 6834 | err = rdev_testmode_cmd(rdev, wdev, |
| 6706 | nla_data(info->attrs[NL80211_ATTR_TESTDATA]), | 6835 | nla_data(info->attrs[NL80211_ATTR_TESTDATA]), |
| 6707 | nla_len(info->attrs[NL80211_ATTR_TESTDATA])); | 6836 | nla_len(info->attrs[NL80211_ATTR_TESTDATA])); |
| 6708 | rdev->testmode_info = NULL; | 6837 | rdev->cur_cmd_info = NULL; |
| 6709 | 6838 | ||
| 6710 | return err; | 6839 | return err; |
| 6711 | } | 6840 | } |
| @@ -6804,93 +6933,6 @@ static int nl80211_testmode_dump(struct sk_buff *skb, | |||
| 6804 | rtnl_unlock(); | 6933 | rtnl_unlock(); |
| 6805 | return err; | 6934 | return err; |
| 6806 | } | 6935 | } |
| 6807 | |||
| 6808 | static struct sk_buff * | ||
| 6809 | __cfg80211_testmode_alloc_skb(struct cfg80211_registered_device *rdev, | ||
| 6810 | int approxlen, u32 portid, u32 seq, gfp_t gfp) | ||
| 6811 | { | ||
| 6812 | struct sk_buff *skb; | ||
| 6813 | void *hdr; | ||
| 6814 | struct nlattr *data; | ||
| 6815 | |||
| 6816 | skb = nlmsg_new(approxlen + 100, gfp); | ||
| 6817 | if (!skb) | ||
| 6818 | return NULL; | ||
| 6819 | |||
| 6820 | hdr = nl80211hdr_put(skb, portid, seq, 0, NL80211_CMD_TESTMODE); | ||
| 6821 | if (!hdr) { | ||
| 6822 | kfree_skb(skb); | ||
| 6823 | return NULL; | ||
| 6824 | } | ||
| 6825 | |||
| 6826 | if (nla_put_u32(skb, NL80211_ATTR_WIPHY, rdev->wiphy_idx)) | ||
| 6827 | goto nla_put_failure; | ||
| 6828 | data = nla_nest_start(skb, NL80211_ATTR_TESTDATA); | ||
| 6829 | |||
| 6830 | ((void **)skb->cb)[0] = rdev; | ||
| 6831 | ((void **)skb->cb)[1] = hdr; | ||
| 6832 | ((void **)skb->cb)[2] = data; | ||
| 6833 | |||
| 6834 | return skb; | ||
| 6835 | |||
| 6836 | nla_put_failure: | ||
| 6837 | kfree_skb(skb); | ||
| 6838 | return NULL; | ||
| 6839 | } | ||
| 6840 | |||
| 6841 | struct sk_buff *cfg80211_testmode_alloc_reply_skb(struct wiphy *wiphy, | ||
| 6842 | int approxlen) | ||
| 6843 | { | ||
| 6844 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
| 6845 | |||
| 6846 | if (WARN_ON(!rdev->testmode_info)) | ||
| 6847 | return NULL; | ||
| 6848 | |||
| 6849 | return __cfg80211_testmode_alloc_skb(rdev, approxlen, | ||
| 6850 | rdev->testmode_info->snd_portid, | ||
| 6851 | rdev->testmode_info->snd_seq, | ||
| 6852 | GFP_KERNEL); | ||
| 6853 | } | ||
| 6854 | EXPORT_SYMBOL(cfg80211_testmode_alloc_reply_skb); | ||
| 6855 | |||
| 6856 | int cfg80211_testmode_reply(struct sk_buff *skb) | ||
| 6857 | { | ||
| 6858 | struct cfg80211_registered_device *rdev = ((void **)skb->cb)[0]; | ||
| 6859 | void *hdr = ((void **)skb->cb)[1]; | ||
| 6860 | struct nlattr *data = ((void **)skb->cb)[2]; | ||
| 6861 | |||
| 6862 | if (WARN_ON(!rdev->testmode_info)) { | ||
| 6863 | kfree_skb(skb); | ||
| 6864 | return -EINVAL; | ||
| 6865 | } | ||
| 6866 | |||
| 6867 | nla_nest_end(skb, data); | ||
| 6868 | genlmsg_end(skb, hdr); | ||
| 6869 | return genlmsg_reply(skb, rdev->testmode_info); | ||
| 6870 | } | ||
| 6871 | EXPORT_SYMBOL(cfg80211_testmode_reply); | ||
| 6872 | |||
| 6873 | struct sk_buff *cfg80211_testmode_alloc_event_skb(struct wiphy *wiphy, | ||
| 6874 | int approxlen, gfp_t gfp) | ||
| 6875 | { | ||
| 6876 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
| 6877 | |||
| 6878 | return __cfg80211_testmode_alloc_skb(rdev, approxlen, 0, 0, gfp); | ||
| 6879 | } | ||
| 6880 | EXPORT_SYMBOL(cfg80211_testmode_alloc_event_skb); | ||
| 6881 | |||
| 6882 | void cfg80211_testmode_event(struct sk_buff *skb, gfp_t gfp) | ||
| 6883 | { | ||
| 6884 | struct cfg80211_registered_device *rdev = ((void **)skb->cb)[0]; | ||
| 6885 | void *hdr = ((void **)skb->cb)[1]; | ||
| 6886 | struct nlattr *data = ((void **)skb->cb)[2]; | ||
| 6887 | |||
| 6888 | nla_nest_end(skb, data); | ||
| 6889 | genlmsg_end(skb, hdr); | ||
| 6890 | genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), skb, 0, | ||
| 6891 | NL80211_MCGRP_TESTMODE, gfp); | ||
| 6892 | } | ||
| 6893 | EXPORT_SYMBOL(cfg80211_testmode_event); | ||
| 6894 | #endif | 6936 | #endif |
| 6895 | 6937 | ||
| 6896 | static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) | 6938 | static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) |
| @@ -7312,11 +7354,72 @@ static bool ht_rateset_to_mask(struct ieee80211_supported_band *sband, | |||
| 7312 | return true; | 7354 | return true; |
| 7313 | } | 7355 | } |
| 7314 | 7356 | ||
| 7357 | static u16 vht_mcs_map_to_mcs_mask(u8 vht_mcs_map) | ||
| 7358 | { | ||
| 7359 | u16 mcs_mask = 0; | ||
| 7360 | |||
| 7361 | switch (vht_mcs_map) { | ||
| 7362 | case IEEE80211_VHT_MCS_NOT_SUPPORTED: | ||
| 7363 | break; | ||
| 7364 | case IEEE80211_VHT_MCS_SUPPORT_0_7: | ||
| 7365 | mcs_mask = 0x00FF; | ||
| 7366 | break; | ||
| 7367 | case IEEE80211_VHT_MCS_SUPPORT_0_8: | ||
| 7368 | mcs_mask = 0x01FF; | ||
| 7369 | break; | ||
| 7370 | case IEEE80211_VHT_MCS_SUPPORT_0_9: | ||
| 7371 | mcs_mask = 0x03FF; | ||
| 7372 | break; | ||
| 7373 | default: | ||
| 7374 | break; | ||
| 7375 | } | ||
| 7376 | |||
| 7377 | return mcs_mask; | ||
| 7378 | } | ||
| 7379 | |||
| 7380 | static void vht_build_mcs_mask(u16 vht_mcs_map, | ||
| 7381 | u16 vht_mcs_mask[NL80211_VHT_NSS_MAX]) | ||
| 7382 | { | ||
| 7383 | u8 nss; | ||
| 7384 | |||
| 7385 | for (nss = 0; nss < NL80211_VHT_NSS_MAX; nss++) { | ||
| 7386 | vht_mcs_mask[nss] = vht_mcs_map_to_mcs_mask(vht_mcs_map & 0x03); | ||
| 7387 | vht_mcs_map >>= 2; | ||
| 7388 | } | ||
| 7389 | } | ||
| 7390 | |||
| 7391 | static bool vht_set_mcs_mask(struct ieee80211_supported_band *sband, | ||
| 7392 | struct nl80211_txrate_vht *txrate, | ||
| 7393 | u16 mcs[NL80211_VHT_NSS_MAX]) | ||
| 7394 | { | ||
| 7395 | u16 tx_mcs_map = le16_to_cpu(sband->vht_cap.vht_mcs.tx_mcs_map); | ||
| 7396 | u16 tx_mcs_mask[NL80211_VHT_NSS_MAX] = {}; | ||
| 7397 | u8 i; | ||
| 7398 | |||
| 7399 | if (!sband->vht_cap.vht_supported) | ||
| 7400 | return false; | ||
| 7401 | |||
| 7402 | memset(mcs, 0, sizeof(u16) * NL80211_VHT_NSS_MAX); | ||
| 7403 | |||
| 7404 | /* Build vht_mcs_mask from VHT capabilities */ | ||
| 7405 | vht_build_mcs_mask(tx_mcs_map, tx_mcs_mask); | ||
| 7406 | |||
| 7407 | for (i = 0; i < NL80211_VHT_NSS_MAX; i++) { | ||
| 7408 | if ((tx_mcs_mask[i] & txrate->mcs[i]) == txrate->mcs[i]) | ||
| 7409 | mcs[i] = txrate->mcs[i]; | ||
| 7410 | else | ||
| 7411 | return false; | ||
| 7412 | } | ||
| 7413 | |||
| 7414 | return true; | ||
| 7415 | } | ||
| 7416 | |||
| 7315 | static const struct nla_policy nl80211_txattr_policy[NL80211_TXRATE_MAX + 1] = { | 7417 | static const struct nla_policy nl80211_txattr_policy[NL80211_TXRATE_MAX + 1] = { |
| 7316 | [NL80211_TXRATE_LEGACY] = { .type = NLA_BINARY, | 7418 | [NL80211_TXRATE_LEGACY] = { .type = NLA_BINARY, |
| 7317 | .len = NL80211_MAX_SUPP_RATES }, | 7419 | .len = NL80211_MAX_SUPP_RATES }, |
| 7318 | [NL80211_TXRATE_MCS] = { .type = NLA_BINARY, | 7420 | [NL80211_TXRATE_HT] = { .type = NLA_BINARY, |
| 7319 | .len = NL80211_MAX_SUPP_HT_RATES }, | 7421 | .len = NL80211_MAX_SUPP_HT_RATES }, |
| 7422 | [NL80211_TXRATE_VHT] = { .len = sizeof(struct nl80211_txrate_vht)}, | ||
| 7320 | }; | 7423 | }; |
| 7321 | 7424 | ||
| 7322 | static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb, | 7425 | static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb, |
| @@ -7329,9 +7432,7 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb, | |||
| 7329 | struct net_device *dev = info->user_ptr[1]; | 7432 | struct net_device *dev = info->user_ptr[1]; |
| 7330 | struct nlattr *tx_rates; | 7433 | struct nlattr *tx_rates; |
| 7331 | struct ieee80211_supported_band *sband; | 7434 | struct ieee80211_supported_band *sband; |
| 7332 | 7435 | u16 vht_tx_mcs_map; | |
| 7333 | if (info->attrs[NL80211_ATTR_TX_RATES] == NULL) | ||
| 7334 | return -EINVAL; | ||
| 7335 | 7436 | ||
| 7336 | if (!rdev->ops->set_bitrate_mask) | 7437 | if (!rdev->ops->set_bitrate_mask) |
| 7337 | return -EOPNOTSUPP; | 7438 | return -EOPNOTSUPP; |
| @@ -7340,17 +7441,26 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb, | |||
| 7340 | /* Default to all rates enabled */ | 7441 | /* Default to all rates enabled */ |
| 7341 | for (i = 0; i < IEEE80211_NUM_BANDS; i++) { | 7442 | for (i = 0; i < IEEE80211_NUM_BANDS; i++) { |
| 7342 | sband = rdev->wiphy.bands[i]; | 7443 | sband = rdev->wiphy.bands[i]; |
| 7343 | mask.control[i].legacy = | 7444 | |
| 7344 | sband ? (1 << sband->n_bitrates) - 1 : 0; | 7445 | if (!sband) |
| 7345 | if (sband) | 7446 | continue; |
| 7346 | memcpy(mask.control[i].mcs, | 7447 | |
| 7347 | sband->ht_cap.mcs.rx_mask, | 7448 | mask.control[i].legacy = (1 << sband->n_bitrates) - 1; |
| 7348 | sizeof(mask.control[i].mcs)); | 7449 | memcpy(mask.control[i].ht_mcs, |
| 7349 | else | 7450 | sband->ht_cap.mcs.rx_mask, |
| 7350 | memset(mask.control[i].mcs, 0, | 7451 | sizeof(mask.control[i].ht_mcs)); |
| 7351 | sizeof(mask.control[i].mcs)); | 7452 | |
| 7453 | if (!sband->vht_cap.vht_supported) | ||
| 7454 | continue; | ||
| 7455 | |||
| 7456 | vht_tx_mcs_map = le16_to_cpu(sband->vht_cap.vht_mcs.tx_mcs_map); | ||
| 7457 | vht_build_mcs_mask(vht_tx_mcs_map, mask.control[i].vht_mcs); | ||
| 7352 | } | 7458 | } |
| 7353 | 7459 | ||
| 7460 | /* if no rates are given set it back to the defaults */ | ||
| 7461 | if (!info->attrs[NL80211_ATTR_TX_RATES]) | ||
| 7462 | goto out; | ||
| 7463 | |||
| 7354 | /* | 7464 | /* |
| 7355 | * The nested attribute uses enum nl80211_band as the index. This maps | 7465 | * The nested attribute uses enum nl80211_band as the index. This maps |
| 7356 | * directly to the enum ieee80211_band values used in cfg80211. | 7466 | * directly to the enum ieee80211_band values used in cfg80211. |
| @@ -7375,31 +7485,44 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb, | |||
| 7375 | nla_len(tb[NL80211_TXRATE_LEGACY])) | 7485 | nla_len(tb[NL80211_TXRATE_LEGACY])) |
| 7376 | return -EINVAL; | 7486 | return -EINVAL; |
| 7377 | } | 7487 | } |
| 7378 | if (tb[NL80211_TXRATE_MCS]) { | 7488 | if (tb[NL80211_TXRATE_HT]) { |
| 7379 | if (!ht_rateset_to_mask( | 7489 | if (!ht_rateset_to_mask( |
| 7380 | sband, | 7490 | sband, |
| 7381 | nla_data(tb[NL80211_TXRATE_MCS]), | 7491 | nla_data(tb[NL80211_TXRATE_HT]), |
| 7382 | nla_len(tb[NL80211_TXRATE_MCS]), | 7492 | nla_len(tb[NL80211_TXRATE_HT]), |
| 7383 | mask.control[band].mcs)) | 7493 | mask.control[band].ht_mcs)) |
| 7494 | return -EINVAL; | ||
| 7495 | } | ||
| 7496 | if (tb[NL80211_TXRATE_VHT]) { | ||
| 7497 | if (!vht_set_mcs_mask( | ||
| 7498 | sband, | ||
| 7499 | nla_data(tb[NL80211_TXRATE_VHT]), | ||
| 7500 | mask.control[band].vht_mcs)) | ||
| 7384 | return -EINVAL; | 7501 | return -EINVAL; |
| 7385 | } | 7502 | } |
| 7386 | 7503 | ||
| 7387 | if (mask.control[band].legacy == 0) { | 7504 | if (mask.control[band].legacy == 0) { |
| 7388 | /* don't allow empty legacy rates if HT | 7505 | /* don't allow empty legacy rates if HT or VHT |
| 7389 | * is not even supported. */ | 7506 | * are not even supported. |
| 7390 | if (!rdev->wiphy.bands[band]->ht_cap.ht_supported) | 7507 | */ |
| 7508 | if (!(rdev->wiphy.bands[band]->ht_cap.ht_supported || | ||
| 7509 | rdev->wiphy.bands[band]->vht_cap.vht_supported)) | ||
| 7391 | return -EINVAL; | 7510 | return -EINVAL; |
| 7392 | 7511 | ||
| 7393 | for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) | 7512 | for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) |
| 7394 | if (mask.control[band].mcs[i]) | 7513 | if (mask.control[band].ht_mcs[i]) |
| 7395 | break; | 7514 | goto out; |
| 7515 | |||
| 7516 | for (i = 0; i < NL80211_VHT_NSS_MAX; i++) | ||
| 7517 | if (mask.control[band].vht_mcs[i]) | ||
| 7518 | goto out; | ||
| 7396 | 7519 | ||
| 7397 | /* legacy and mcs rates may not be both empty */ | 7520 | /* legacy and mcs rates may not be both empty */ |
| 7398 | if (i == IEEE80211_HT_MCS_MASK_LEN) | 7521 | return -EINVAL; |
| 7399 | return -EINVAL; | ||
| 7400 | } | 7522 | } |
| 7401 | } | 7523 | } |
| 7402 | 7524 | ||
| 7525 | out: | ||
| 7403 | return rdev_set_bitrate_mask(rdev, dev, NULL, &mask); | 7526 | return rdev_set_bitrate_mask(rdev, dev, NULL, &mask); |
| 7404 | } | 7527 | } |
| 7405 | 7528 | ||
| @@ -7447,10 +7570,10 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) | |||
| 7447 | void *hdr = NULL; | 7570 | void *hdr = NULL; |
| 7448 | u64 cookie; | 7571 | u64 cookie; |
| 7449 | struct sk_buff *msg = NULL; | 7572 | struct sk_buff *msg = NULL; |
| 7450 | unsigned int wait = 0; | 7573 | struct cfg80211_mgmt_tx_params params = { |
| 7451 | bool offchan, no_cck, dont_wait_for_ack; | 7574 | .dont_wait_for_ack = |
| 7452 | 7575 | info->attrs[NL80211_ATTR_DONT_WAIT_FOR_ACK], | |
| 7453 | dont_wait_for_ack = info->attrs[NL80211_ATTR_DONT_WAIT_FOR_ACK]; | 7576 | }; |
| 7454 | 7577 | ||
| 7455 | if (!info->attrs[NL80211_ATTR_FRAME]) | 7578 | if (!info->attrs[NL80211_ATTR_FRAME]) |
| 7456 | return -EINVAL; | 7579 | return -EINVAL; |
| @@ -7477,24 +7600,24 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) | |||
| 7477 | if (info->attrs[NL80211_ATTR_DURATION]) { | 7600 | if (info->attrs[NL80211_ATTR_DURATION]) { |
| 7478 | if (!(rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX)) | 7601 | if (!(rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX)) |
| 7479 | return -EINVAL; | 7602 | return -EINVAL; |
| 7480 | wait = nla_get_u32(info->attrs[NL80211_ATTR_DURATION]); | 7603 | params.wait = nla_get_u32(info->attrs[NL80211_ATTR_DURATION]); |
| 7481 | 7604 | ||
| 7482 | /* | 7605 | /* |
| 7483 | * We should wait on the channel for at least a minimum amount | 7606 | * We should wait on the channel for at least a minimum amount |
| 7484 | * of time (10ms) but no longer than the driver supports. | 7607 | * of time (10ms) but no longer than the driver supports. |
| 7485 | */ | 7608 | */ |
| 7486 | if (wait < NL80211_MIN_REMAIN_ON_CHANNEL_TIME || | 7609 | if (params.wait < NL80211_MIN_REMAIN_ON_CHANNEL_TIME || |
| 7487 | wait > rdev->wiphy.max_remain_on_channel_duration) | 7610 | params.wait > rdev->wiphy.max_remain_on_channel_duration) |
| 7488 | return -EINVAL; | 7611 | return -EINVAL; |
| 7489 | 7612 | ||
| 7490 | } | 7613 | } |
| 7491 | 7614 | ||
| 7492 | offchan = info->attrs[NL80211_ATTR_OFFCHANNEL_TX_OK]; | 7615 | params.offchan = info->attrs[NL80211_ATTR_OFFCHANNEL_TX_OK]; |
| 7493 | 7616 | ||
| 7494 | if (offchan && !(rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX)) | 7617 | if (params.offchan && !(rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX)) |
| 7495 | return -EINVAL; | 7618 | return -EINVAL; |
| 7496 | 7619 | ||
| 7497 | no_cck = nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]); | 7620 | params.no_cck = nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]); |
| 7498 | 7621 | ||
| 7499 | /* get the channel if any has been specified, otherwise pass NULL to | 7622 | /* get the channel if any has been specified, otherwise pass NULL to |
| 7500 | * the driver. The latter will use the current one | 7623 | * the driver. The latter will use the current one |
| @@ -7506,10 +7629,10 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) | |||
| 7506 | return err; | 7629 | return err; |
| 7507 | } | 7630 | } |
| 7508 | 7631 | ||
| 7509 | if (!chandef.chan && offchan) | 7632 | if (!chandef.chan && params.offchan) |
| 7510 | return -EINVAL; | 7633 | return -EINVAL; |
| 7511 | 7634 | ||
| 7512 | if (!dont_wait_for_ack) { | 7635 | if (!params.dont_wait_for_ack) { |
| 7513 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 7636 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
| 7514 | if (!msg) | 7637 | if (!msg) |
| 7515 | return -ENOMEM; | 7638 | return -ENOMEM; |
| @@ -7522,10 +7645,10 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) | |||
| 7522 | } | 7645 | } |
| 7523 | } | 7646 | } |
| 7524 | 7647 | ||
| 7525 | err = cfg80211_mlme_mgmt_tx(rdev, wdev, chandef.chan, offchan, wait, | 7648 | params.buf = nla_data(info->attrs[NL80211_ATTR_FRAME]); |
| 7526 | nla_data(info->attrs[NL80211_ATTR_FRAME]), | 7649 | params.len = nla_len(info->attrs[NL80211_ATTR_FRAME]); |
| 7527 | nla_len(info->attrs[NL80211_ATTR_FRAME]), | 7650 | params.chan = chandef.chan; |
| 7528 | no_cck, dont_wait_for_ack, &cookie); | 7651 | err = cfg80211_mlme_mgmt_tx(rdev, wdev, ¶ms, &cookie); |
| 7529 | if (err) | 7652 | if (err) |
| 7530 | goto free_msg; | 7653 | goto free_msg; |
| 7531 | 7654 | ||
| @@ -8859,6 +8982,162 @@ static int nl80211_crit_protocol_stop(struct sk_buff *skb, | |||
| 8859 | return 0; | 8982 | return 0; |
| 8860 | } | 8983 | } |
| 8861 | 8984 | ||
| 8985 | static int nl80211_vendor_cmd(struct sk_buff *skb, struct genl_info *info) | ||
| 8986 | { | ||
| 8987 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
| 8988 | struct wireless_dev *wdev = | ||
| 8989 | __cfg80211_wdev_from_attrs(genl_info_net(info), info->attrs); | ||
| 8990 | int i, err; | ||
| 8991 | u32 vid, subcmd; | ||
| 8992 | |||
| 8993 | if (!rdev->wiphy.vendor_commands) | ||
| 8994 | return -EOPNOTSUPP; | ||
| 8995 | |||
| 8996 | if (IS_ERR(wdev)) { | ||
| 8997 | err = PTR_ERR(wdev); | ||
| 8998 | if (err != -EINVAL) | ||
| 8999 | return err; | ||
| 9000 | wdev = NULL; | ||
| 9001 | } else if (wdev->wiphy != &rdev->wiphy) { | ||
| 9002 | return -EINVAL; | ||
| 9003 | } | ||
| 9004 | |||
| 9005 | if (!info->attrs[NL80211_ATTR_VENDOR_ID] || | ||
| 9006 | !info->attrs[NL80211_ATTR_VENDOR_SUBCMD]) | ||
| 9007 | return -EINVAL; | ||
| 9008 | |||
| 9009 | vid = nla_get_u32(info->attrs[NL80211_ATTR_VENDOR_ID]); | ||
| 9010 | subcmd = nla_get_u32(info->attrs[NL80211_ATTR_VENDOR_SUBCMD]); | ||
| 9011 | for (i = 0; i < rdev->wiphy.n_vendor_commands; i++) { | ||
| 9012 | const struct wiphy_vendor_command *vcmd; | ||
| 9013 | void *data = NULL; | ||
| 9014 | int len = 0; | ||
| 9015 | |||
| 9016 | vcmd = &rdev->wiphy.vendor_commands[i]; | ||
| 9017 | |||
| 9018 | if (vcmd->info.vendor_id != vid || vcmd->info.subcmd != subcmd) | ||
| 9019 | continue; | ||
| 9020 | |||
| 9021 | if (vcmd->flags & (WIPHY_VENDOR_CMD_NEED_WDEV | | ||
| 9022 | WIPHY_VENDOR_CMD_NEED_NETDEV)) { | ||
| 9023 | if (!wdev) | ||
| 9024 | return -EINVAL; | ||
| 9025 | if (vcmd->flags & WIPHY_VENDOR_CMD_NEED_NETDEV && | ||
| 9026 | !wdev->netdev) | ||
| 9027 | return -EINVAL; | ||
| 9028 | |||
| 9029 | if (vcmd->flags & WIPHY_VENDOR_CMD_NEED_RUNNING) { | ||
| 9030 | if (wdev->netdev && | ||
| 9031 | !netif_running(wdev->netdev)) | ||
| 9032 | return -ENETDOWN; | ||
| 9033 | if (!wdev->netdev && !wdev->p2p_started) | ||
| 9034 | return -ENETDOWN; | ||
| 9035 | } | ||
| 9036 | } else { | ||
| 9037 | wdev = NULL; | ||
| 9038 | } | ||
| 9039 | |||
| 9040 | if (info->attrs[NL80211_ATTR_VENDOR_DATA]) { | ||
| 9041 | data = nla_data(info->attrs[NL80211_ATTR_VENDOR_DATA]); | ||
| 9042 | len = nla_len(info->attrs[NL80211_ATTR_VENDOR_DATA]); | ||
| 9043 | } | ||
| 9044 | |||
| 9045 | rdev->cur_cmd_info = info; | ||
| 9046 | err = rdev->wiphy.vendor_commands[i].doit(&rdev->wiphy, wdev, | ||
| 9047 | data, len); | ||
| 9048 | rdev->cur_cmd_info = NULL; | ||
| 9049 | return err; | ||
| 9050 | } | ||
| 9051 | |||
| 9052 | return -EOPNOTSUPP; | ||
| 9053 | } | ||
| 9054 | |||
| 9055 | struct sk_buff *__cfg80211_alloc_reply_skb(struct wiphy *wiphy, | ||
| 9056 | enum nl80211_commands cmd, | ||
| 9057 | enum nl80211_attrs attr, | ||
| 9058 | int approxlen) | ||
| 9059 | { | ||
| 9060 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
| 9061 | |||
| 9062 | if (WARN_ON(!rdev->cur_cmd_info)) | ||
| 9063 | return NULL; | ||
| 9064 | |||
| 9065 | return __cfg80211_alloc_vendor_skb(rdev, approxlen, | ||
| 9066 | rdev->cur_cmd_info->snd_portid, | ||
| 9067 | rdev->cur_cmd_info->snd_seq, | ||
| 9068 | cmd, attr, NULL, GFP_KERNEL); | ||
| 9069 | } | ||
| 9070 | EXPORT_SYMBOL(__cfg80211_alloc_reply_skb); | ||
| 9071 | |||
| 9072 | int cfg80211_vendor_cmd_reply(struct sk_buff *skb) | ||
| 9073 | { | ||
| 9074 | struct cfg80211_registered_device *rdev = ((void **)skb->cb)[0]; | ||
| 9075 | void *hdr = ((void **)skb->cb)[1]; | ||
| 9076 | struct nlattr *data = ((void **)skb->cb)[2]; | ||
| 9077 | |||
| 9078 | if (WARN_ON(!rdev->cur_cmd_info)) { | ||
| 9079 | kfree_skb(skb); | ||
| 9080 | return -EINVAL; | ||
| 9081 | } | ||
| 9082 | |||
| 9083 | nla_nest_end(skb, data); | ||
| 9084 | genlmsg_end(skb, hdr); | ||
| 9085 | return genlmsg_reply(skb, rdev->cur_cmd_info); | ||
| 9086 | } | ||
| 9087 | EXPORT_SYMBOL_GPL(cfg80211_vendor_cmd_reply); | ||
| 9088 | |||
| 9089 | |||
| 9090 | static int nl80211_set_qos_map(struct sk_buff *skb, | ||
| 9091 | struct genl_info *info) | ||
| 9092 | { | ||
| 9093 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
| 9094 | struct cfg80211_qos_map *qos_map = NULL; | ||
| 9095 | struct net_device *dev = info->user_ptr[1]; | ||
| 9096 | u8 *pos, len, num_des, des_len, des; | ||
| 9097 | int ret; | ||
| 9098 | |||
| 9099 | if (!rdev->ops->set_qos_map) | ||
| 9100 | return -EOPNOTSUPP; | ||
| 9101 | |||
| 9102 | if (info->attrs[NL80211_ATTR_QOS_MAP]) { | ||
| 9103 | pos = nla_data(info->attrs[NL80211_ATTR_QOS_MAP]); | ||
| 9104 | len = nla_len(info->attrs[NL80211_ATTR_QOS_MAP]); | ||
| 9105 | |||
| 9106 | if (len % 2 || len < IEEE80211_QOS_MAP_LEN_MIN || | ||
| 9107 | len > IEEE80211_QOS_MAP_LEN_MAX) | ||
| 9108 | return -EINVAL; | ||
| 9109 | |||
| 9110 | qos_map = kzalloc(sizeof(struct cfg80211_qos_map), GFP_KERNEL); | ||
| 9111 | if (!qos_map) | ||
| 9112 | return -ENOMEM; | ||
| 9113 | |||
| 9114 | num_des = (len - IEEE80211_QOS_MAP_LEN_MIN) >> 1; | ||
| 9115 | if (num_des) { | ||
| 9116 | des_len = num_des * | ||
| 9117 | sizeof(struct cfg80211_dscp_exception); | ||
| 9118 | memcpy(qos_map->dscp_exception, pos, des_len); | ||
| 9119 | qos_map->num_des = num_des; | ||
| 9120 | for (des = 0; des < num_des; des++) { | ||
| 9121 | if (qos_map->dscp_exception[des].up > 7) { | ||
| 9122 | kfree(qos_map); | ||
| 9123 | return -EINVAL; | ||
| 9124 | } | ||
| 9125 | } | ||
| 9126 | pos += des_len; | ||
| 9127 | } | ||
| 9128 | memcpy(qos_map->up, pos, IEEE80211_QOS_MAP_LEN_MIN); | ||
| 9129 | } | ||
| 9130 | |||
| 9131 | wdev_lock(dev->ieee80211_ptr); | ||
| 9132 | ret = nl80211_key_allowed(dev->ieee80211_ptr); | ||
| 9133 | if (!ret) | ||
| 9134 | ret = rdev_set_qos_map(rdev, dev, qos_map); | ||
| 9135 | wdev_unlock(dev->ieee80211_ptr); | ||
| 9136 | |||
| 9137 | kfree(qos_map); | ||
| 9138 | return ret; | ||
| 9139 | } | ||
| 9140 | |||
| 8862 | #define NL80211_FLAG_NEED_WIPHY 0x01 | 9141 | #define NL80211_FLAG_NEED_WIPHY 0x01 |
| 8863 | #define NL80211_FLAG_NEED_NETDEV 0x02 | 9142 | #define NL80211_FLAG_NEED_NETDEV 0x02 |
| 8864 | #define NL80211_FLAG_NEED_RTNL 0x04 | 9143 | #define NL80211_FLAG_NEED_RTNL 0x04 |
| @@ -9583,6 +9862,22 @@ static const struct genl_ops nl80211_ops[] = { | |||
| 9583 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | 9862 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | |
| 9584 | NL80211_FLAG_NEED_RTNL, | 9863 | NL80211_FLAG_NEED_RTNL, |
| 9585 | }, | 9864 | }, |
| 9865 | { | ||
| 9866 | .cmd = NL80211_CMD_VENDOR, | ||
| 9867 | .doit = nl80211_vendor_cmd, | ||
| 9868 | .policy = nl80211_policy, | ||
| 9869 | .flags = GENL_ADMIN_PERM, | ||
| 9870 | .internal_flags = NL80211_FLAG_NEED_WIPHY | | ||
| 9871 | NL80211_FLAG_NEED_RTNL, | ||
| 9872 | }, | ||
| 9873 | { | ||
| 9874 | .cmd = NL80211_CMD_SET_QOS_MAP, | ||
| 9875 | .doit = nl80211_set_qos_map, | ||
| 9876 | .policy = nl80211_policy, | ||
| 9877 | .flags = GENL_ADMIN_PERM, | ||
| 9878 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
| 9879 | NL80211_FLAG_NEED_RTNL, | ||
| 9880 | }, | ||
| 9586 | }; | 9881 | }; |
| 9587 | 9882 | ||
| 9588 | /* notification functions */ | 9883 | /* notification functions */ |
| @@ -10810,21 +11105,18 @@ void cfg80211_ch_switch_notify(struct net_device *dev, | |||
| 10810 | struct wiphy *wiphy = wdev->wiphy; | 11105 | struct wiphy *wiphy = wdev->wiphy; |
| 10811 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | 11106 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); |
| 10812 | 11107 | ||
| 10813 | trace_cfg80211_ch_switch_notify(dev, chandef); | 11108 | ASSERT_WDEV_LOCK(wdev); |
| 10814 | 11109 | ||
| 10815 | wdev_lock(wdev); | 11110 | trace_cfg80211_ch_switch_notify(dev, chandef); |
| 10816 | 11111 | ||
| 10817 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP && | 11112 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP && |
| 10818 | wdev->iftype != NL80211_IFTYPE_P2P_GO && | 11113 | wdev->iftype != NL80211_IFTYPE_P2P_GO && |
| 10819 | wdev->iftype != NL80211_IFTYPE_ADHOC && | 11114 | wdev->iftype != NL80211_IFTYPE_ADHOC && |
| 10820 | wdev->iftype != NL80211_IFTYPE_MESH_POINT)) | 11115 | wdev->iftype != NL80211_IFTYPE_MESH_POINT)) |
| 10821 | goto out; | 11116 | return; |
| 10822 | 11117 | ||
| 10823 | wdev->channel = chandef->chan; | 11118 | wdev->channel = chandef->chan; |
| 10824 | nl80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL); | 11119 | nl80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL); |
| 10825 | out: | ||
| 10826 | wdev_unlock(wdev); | ||
| 10827 | return; | ||
| 10828 | } | 11120 | } |
| 10829 | EXPORT_SYMBOL(cfg80211_ch_switch_notify); | 11121 | EXPORT_SYMBOL(cfg80211_ch_switch_notify); |
| 10830 | 11122 | ||
| @@ -10883,7 +11175,7 @@ EXPORT_SYMBOL(cfg80211_cqm_txe_notify); | |||
| 10883 | 11175 | ||
| 10884 | void | 11176 | void |
| 10885 | nl80211_radar_notify(struct cfg80211_registered_device *rdev, | 11177 | nl80211_radar_notify(struct cfg80211_registered_device *rdev, |
| 10886 | struct cfg80211_chan_def *chandef, | 11178 | const struct cfg80211_chan_def *chandef, |
| 10887 | enum nl80211_radar_event event, | 11179 | enum nl80211_radar_event event, |
| 10888 | struct net_device *netdev, gfp_t gfp) | 11180 | struct net_device *netdev, gfp_t gfp) |
| 10889 | { | 11181 | { |
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h index 2c0f2b3c07cb..b1b231324e10 100644 --- a/net/wireless/nl80211.h +++ b/net/wireless/nl80211.h | |||
| @@ -70,7 +70,7 @@ int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, | |||
| 70 | 70 | ||
| 71 | void | 71 | void |
| 72 | nl80211_radar_notify(struct cfg80211_registered_device *rdev, | 72 | nl80211_radar_notify(struct cfg80211_registered_device *rdev, |
| 73 | struct cfg80211_chan_def *chandef, | 73 | const struct cfg80211_chan_def *chandef, |
| 74 | enum nl80211_radar_event event, | 74 | enum nl80211_radar_event event, |
| 75 | struct net_device *netdev, gfp_t gfp); | 75 | struct net_device *netdev, gfp_t gfp); |
| 76 | 76 | ||
diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h index 37ce9fdfe934..c8e225947adb 100644 --- a/net/wireless/rdev-ops.h +++ b/net/wireless/rdev-ops.h | |||
| @@ -624,16 +624,12 @@ rdev_cancel_remain_on_channel(struct cfg80211_registered_device *rdev, | |||
| 624 | 624 | ||
| 625 | static inline int rdev_mgmt_tx(struct cfg80211_registered_device *rdev, | 625 | static inline int rdev_mgmt_tx(struct cfg80211_registered_device *rdev, |
| 626 | struct wireless_dev *wdev, | 626 | struct wireless_dev *wdev, |
| 627 | struct ieee80211_channel *chan, bool offchan, | 627 | struct cfg80211_mgmt_tx_params *params, |
| 628 | unsigned int wait, const u8 *buf, size_t len, | 628 | u64 *cookie) |
| 629 | bool no_cck, bool dont_wait_for_ack, u64 *cookie) | ||
| 630 | { | 629 | { |
| 631 | int ret; | 630 | int ret; |
| 632 | trace_rdev_mgmt_tx(&rdev->wiphy, wdev, chan, offchan, | 631 | trace_rdev_mgmt_tx(&rdev->wiphy, wdev, params); |
| 633 | wait, no_cck, dont_wait_for_ack); | 632 | ret = rdev->ops->mgmt_tx(&rdev->wiphy, wdev, params, cookie); |
| 634 | ret = rdev->ops->mgmt_tx(&rdev->wiphy, wdev, chan, offchan, | ||
| 635 | wait, buf, len, no_cck, | ||
| 636 | dont_wait_for_ack, cookie); | ||
| 637 | trace_rdev_return_int_cookie(&rdev->wiphy, ret, *cookie); | 633 | trace_rdev_return_int_cookie(&rdev->wiphy, ret, *cookie); |
| 638 | return ret; | 634 | return ret; |
| 639 | } | 635 | } |
| @@ -936,4 +932,19 @@ static inline int rdev_channel_switch(struct cfg80211_registered_device *rdev, | |||
| 936 | return ret; | 932 | return ret; |
| 937 | } | 933 | } |
| 938 | 934 | ||
| 935 | static inline int rdev_set_qos_map(struct cfg80211_registered_device *rdev, | ||
| 936 | struct net_device *dev, | ||
| 937 | struct cfg80211_qos_map *qos_map) | ||
| 938 | { | ||
| 939 | int ret = -EOPNOTSUPP; | ||
| 940 | |||
| 941 | if (rdev->ops->set_qos_map) { | ||
| 942 | trace_rdev_set_qos_map(&rdev->wiphy, dev, qos_map); | ||
| 943 | ret = rdev->ops->set_qos_map(&rdev->wiphy, dev, qos_map); | ||
| 944 | trace_rdev_return_int(&rdev->wiphy, ret); | ||
| 945 | } | ||
| 946 | |||
| 947 | return ret; | ||
| 948 | } | ||
| 949 | |||
| 939 | #endif /* __CFG80211_RDEV_OPS */ | 950 | #endif /* __CFG80211_RDEV_OPS */ |
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 7da67fd0b418..9b897fca7487 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c | |||
| @@ -120,6 +120,48 @@ static const struct ieee80211_regdomain *get_wiphy_regdom(struct wiphy *wiphy) | |||
| 120 | return rtnl_dereference(wiphy->regd); | 120 | return rtnl_dereference(wiphy->regd); |
| 121 | } | 121 | } |
| 122 | 122 | ||
| 123 | static const char *reg_dfs_region_str(enum nl80211_dfs_regions dfs_region) | ||
| 124 | { | ||
| 125 | switch (dfs_region) { | ||
| 126 | case NL80211_DFS_UNSET: | ||
| 127 | return "unset"; | ||
| 128 | case NL80211_DFS_FCC: | ||
| 129 | return "FCC"; | ||
| 130 | case NL80211_DFS_ETSI: | ||
| 131 | return "ETSI"; | ||
| 132 | case NL80211_DFS_JP: | ||
| 133 | return "JP"; | ||
| 134 | } | ||
| 135 | return "Unknown"; | ||
| 136 | } | ||
| 137 | |||
| 138 | enum nl80211_dfs_regions reg_get_dfs_region(struct wiphy *wiphy) | ||
| 139 | { | ||
| 140 | const struct ieee80211_regdomain *regd = NULL; | ||
| 141 | const struct ieee80211_regdomain *wiphy_regd = NULL; | ||
| 142 | |||
| 143 | regd = get_cfg80211_regdom(); | ||
| 144 | if (!wiphy) | ||
| 145 | goto out; | ||
| 146 | |||
| 147 | wiphy_regd = get_wiphy_regdom(wiphy); | ||
| 148 | if (!wiphy_regd) | ||
| 149 | goto out; | ||
| 150 | |||
| 151 | if (wiphy_regd->dfs_region == regd->dfs_region) | ||
| 152 | goto out; | ||
| 153 | |||
| 154 | REG_DBG_PRINT("%s: device specific dfs_region " | ||
| 155 | "(%s) disagrees with cfg80211's " | ||
| 156 | "central dfs_region (%s)\n", | ||
| 157 | dev_name(&wiphy->dev), | ||
| 158 | reg_dfs_region_str(wiphy_regd->dfs_region), | ||
| 159 | reg_dfs_region_str(regd->dfs_region)); | ||
| 160 | |||
| 161 | out: | ||
| 162 | return regd->dfs_region; | ||
| 163 | } | ||
| 164 | |||
| 123 | static void rcu_free_regdom(const struct ieee80211_regdomain *r) | 165 | static void rcu_free_regdom(const struct ieee80211_regdomain *r) |
| 124 | { | 166 | { |
| 125 | if (!r) | 167 | if (!r) |
| @@ -163,35 +205,29 @@ static const struct ieee80211_regdomain world_regdom = { | |||
| 163 | REG_RULE(2412-10, 2462+10, 40, 6, 20, 0), | 205 | REG_RULE(2412-10, 2462+10, 40, 6, 20, 0), |
| 164 | /* IEEE 802.11b/g, channels 12..13. */ | 206 | /* IEEE 802.11b/g, channels 12..13. */ |
| 165 | REG_RULE(2467-10, 2472+10, 40, 6, 20, | 207 | REG_RULE(2467-10, 2472+10, 40, 6, 20, |
| 166 | NL80211_RRF_PASSIVE_SCAN | | 208 | NL80211_RRF_NO_IR), |
| 167 | NL80211_RRF_NO_IBSS), | ||
| 168 | /* IEEE 802.11 channel 14 - Only JP enables | 209 | /* IEEE 802.11 channel 14 - Only JP enables |
| 169 | * this and for 802.11b only */ | 210 | * this and for 802.11b only */ |
| 170 | REG_RULE(2484-10, 2484+10, 20, 6, 20, | 211 | REG_RULE(2484-10, 2484+10, 20, 6, 20, |
| 171 | NL80211_RRF_PASSIVE_SCAN | | 212 | NL80211_RRF_NO_IR | |
| 172 | NL80211_RRF_NO_IBSS | | ||
| 173 | NL80211_RRF_NO_OFDM), | 213 | NL80211_RRF_NO_OFDM), |
| 174 | /* IEEE 802.11a, channel 36..48 */ | 214 | /* IEEE 802.11a, channel 36..48 */ |
| 175 | REG_RULE(5180-10, 5240+10, 160, 6, 20, | 215 | REG_RULE(5180-10, 5240+10, 160, 6, 20, |
| 176 | NL80211_RRF_PASSIVE_SCAN | | 216 | NL80211_RRF_NO_IR), |
| 177 | NL80211_RRF_NO_IBSS), | ||
| 178 | 217 | ||
| 179 | /* IEEE 802.11a, channel 52..64 - DFS required */ | 218 | /* IEEE 802.11a, channel 52..64 - DFS required */ |
| 180 | REG_RULE(5260-10, 5320+10, 160, 6, 20, | 219 | REG_RULE(5260-10, 5320+10, 160, 6, 20, |
| 181 | NL80211_RRF_PASSIVE_SCAN | | 220 | NL80211_RRF_NO_IR | |
| 182 | NL80211_RRF_NO_IBSS | | ||
| 183 | NL80211_RRF_DFS), | 221 | NL80211_RRF_DFS), |
| 184 | 222 | ||
| 185 | /* IEEE 802.11a, channel 100..144 - DFS required */ | 223 | /* IEEE 802.11a, channel 100..144 - DFS required */ |
| 186 | REG_RULE(5500-10, 5720+10, 160, 6, 20, | 224 | REG_RULE(5500-10, 5720+10, 160, 6, 20, |
| 187 | NL80211_RRF_PASSIVE_SCAN | | 225 | NL80211_RRF_NO_IR | |
| 188 | NL80211_RRF_NO_IBSS | | ||
| 189 | NL80211_RRF_DFS), | 226 | NL80211_RRF_DFS), |
| 190 | 227 | ||
| 191 | /* IEEE 802.11a, channel 149..165 */ | 228 | /* IEEE 802.11a, channel 149..165 */ |
| 192 | REG_RULE(5745-10, 5825+10, 80, 6, 20, | 229 | REG_RULE(5745-10, 5825+10, 80, 6, 20, |
| 193 | NL80211_RRF_PASSIVE_SCAN | | 230 | NL80211_RRF_NO_IR), |
| 194 | NL80211_RRF_NO_IBSS), | ||
| 195 | 231 | ||
| 196 | /* IEEE 802.11ad (60gHz), channels 1..3 */ | 232 | /* IEEE 802.11ad (60gHz), channels 1..3 */ |
| 197 | REG_RULE(56160+2160*1-1080, 56160+2160*3+1080, 2160, 0, 0, 0), | 233 | REG_RULE(56160+2160*1-1080, 56160+2160*3+1080, 2160, 0, 0, 0), |
| @@ -208,11 +244,26 @@ static char user_alpha2[2]; | |||
| 208 | module_param(ieee80211_regdom, charp, 0444); | 244 | module_param(ieee80211_regdom, charp, 0444); |
| 209 | MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code"); | 245 | MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code"); |
| 210 | 246 | ||
| 247 | static void reg_kfree_last_request(void) | ||
| 248 | { | ||
| 249 | struct regulatory_request *lr; | ||
| 250 | |||
| 251 | lr = get_last_request(); | ||
| 252 | |||
| 253 | if (lr != &core_request_world && lr) | ||
| 254 | kfree_rcu(lr, rcu_head); | ||
| 255 | } | ||
| 256 | |||
| 257 | static void reg_update_last_request(struct regulatory_request *request) | ||
| 258 | { | ||
| 259 | reg_kfree_last_request(); | ||
| 260 | rcu_assign_pointer(last_request, request); | ||
| 261 | } | ||
| 262 | |||
| 211 | static void reset_regdomains(bool full_reset, | 263 | static void reset_regdomains(bool full_reset, |
| 212 | const struct ieee80211_regdomain *new_regdom) | 264 | const struct ieee80211_regdomain *new_regdom) |
| 213 | { | 265 | { |
| 214 | const struct ieee80211_regdomain *r; | 266 | const struct ieee80211_regdomain *r; |
| 215 | struct regulatory_request *lr; | ||
| 216 | 267 | ||
| 217 | ASSERT_RTNL(); | 268 | ASSERT_RTNL(); |
| 218 | 269 | ||
| @@ -235,10 +286,7 @@ static void reset_regdomains(bool full_reset, | |||
| 235 | if (!full_reset) | 286 | if (!full_reset) |
| 236 | return; | 287 | return; |
| 237 | 288 | ||
| 238 | lr = get_last_request(); | 289 | reg_update_last_request(&core_request_world); |
| 239 | if (lr != &core_request_world && lr) | ||
| 240 | kfree_rcu(lr, rcu_head); | ||
| 241 | rcu_assign_pointer(last_request, &core_request_world); | ||
| 242 | } | 290 | } |
| 243 | 291 | ||
| 244 | /* | 292 | /* |
| @@ -456,7 +504,15 @@ static int call_crda(const char *alpha2) | |||
| 456 | return kobject_uevent(®_pdev->dev.kobj, KOBJ_CHANGE); | 504 | return kobject_uevent(®_pdev->dev.kobj, KOBJ_CHANGE); |
| 457 | } | 505 | } |
| 458 | 506 | ||
| 459 | static bool reg_is_valid_request(const char *alpha2) | 507 | static enum reg_request_treatment |
| 508 | reg_call_crda(struct regulatory_request *request) | ||
| 509 | { | ||
| 510 | if (call_crda(request->alpha2)) | ||
| 511 | return REG_REQ_IGNORE; | ||
| 512 | return REG_REQ_OK; | ||
| 513 | } | ||
| 514 | |||
| 515 | bool reg_is_valid_request(const char *alpha2) | ||
| 460 | { | 516 | { |
| 461 | struct regulatory_request *lr = get_last_request(); | 517 | struct regulatory_request *lr = get_last_request(); |
| 462 | 518 | ||
| @@ -557,6 +613,20 @@ static bool freq_in_rule_band(const struct ieee80211_freq_range *freq_range, | |||
| 557 | } | 613 | } |
| 558 | 614 | ||
| 559 | /* | 615 | /* |
| 616 | * Later on we can perhaps use the more restrictive DFS | ||
| 617 | * region but we don't have information for that yet so | ||
| 618 | * for now simply disallow conflicts. | ||
| 619 | */ | ||
| 620 | static enum nl80211_dfs_regions | ||
| 621 | reg_intersect_dfs_region(const enum nl80211_dfs_regions dfs_region1, | ||
| 622 | const enum nl80211_dfs_regions dfs_region2) | ||
| 623 | { | ||
| 624 | if (dfs_region1 != dfs_region2) | ||
| 625 | return NL80211_DFS_UNSET; | ||
| 626 | return dfs_region1; | ||
| 627 | } | ||
| 628 | |||
| 629 | /* | ||
| 560 | * Helper for regdom_intersect(), this does the real | 630 | * Helper for regdom_intersect(), this does the real |
| 561 | * mathematical intersection fun | 631 | * mathematical intersection fun |
| 562 | */ | 632 | */ |
| @@ -687,6 +757,8 @@ regdom_intersect(const struct ieee80211_regdomain *rd1, | |||
| 687 | rd->n_reg_rules = num_rules; | 757 | rd->n_reg_rules = num_rules; |
| 688 | rd->alpha2[0] = '9'; | 758 | rd->alpha2[0] = '9'; |
| 689 | rd->alpha2[1] = '8'; | 759 | rd->alpha2[1] = '8'; |
| 760 | rd->dfs_region = reg_intersect_dfs_region(rd1->dfs_region, | ||
| 761 | rd2->dfs_region); | ||
| 690 | 762 | ||
| 691 | return rd; | 763 | return rd; |
| 692 | } | 764 | } |
| @@ -698,10 +770,8 @@ regdom_intersect(const struct ieee80211_regdomain *rd1, | |||
| 698 | static u32 map_regdom_flags(u32 rd_flags) | 770 | static u32 map_regdom_flags(u32 rd_flags) |
| 699 | { | 771 | { |
| 700 | u32 channel_flags = 0; | 772 | u32 channel_flags = 0; |
| 701 | if (rd_flags & NL80211_RRF_PASSIVE_SCAN) | 773 | if (rd_flags & NL80211_RRF_NO_IR_ALL) |
| 702 | channel_flags |= IEEE80211_CHAN_PASSIVE_SCAN; | 774 | channel_flags |= IEEE80211_CHAN_NO_IR; |
| 703 | if (rd_flags & NL80211_RRF_NO_IBSS) | ||
| 704 | channel_flags |= IEEE80211_CHAN_NO_IBSS; | ||
| 705 | if (rd_flags & NL80211_RRF_DFS) | 775 | if (rd_flags & NL80211_RRF_DFS) |
| 706 | channel_flags |= IEEE80211_CHAN_RADAR; | 776 | channel_flags |= IEEE80211_CHAN_RADAR; |
| 707 | if (rd_flags & NL80211_RRF_NO_OFDM) | 777 | if (rd_flags & NL80211_RRF_NO_OFDM) |
| @@ -854,8 +924,18 @@ static void handle_channel(struct wiphy *wiphy, | |||
| 854 | PTR_ERR(reg_rule) == -ERANGE) | 924 | PTR_ERR(reg_rule) == -ERANGE) |
| 855 | return; | 925 | return; |
| 856 | 926 | ||
| 857 | REG_DBG_PRINT("Disabling freq %d MHz\n", chan->center_freq); | 927 | if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER && |
| 858 | chan->flags |= IEEE80211_CHAN_DISABLED; | 928 | request_wiphy && request_wiphy == wiphy && |
| 929 | request_wiphy->regulatory_flags & REGULATORY_STRICT_REG) { | ||
| 930 | REG_DBG_PRINT("Disabling freq %d MHz for good\n", | ||
| 931 | chan->center_freq); | ||
| 932 | chan->orig_flags |= IEEE80211_CHAN_DISABLED; | ||
| 933 | chan->flags = chan->orig_flags; | ||
| 934 | } else { | ||
| 935 | REG_DBG_PRINT("Disabling freq %d MHz\n", | ||
| 936 | chan->center_freq); | ||
| 937 | chan->flags |= IEEE80211_CHAN_DISABLED; | ||
| 938 | } | ||
| 859 | return; | 939 | return; |
| 860 | } | 940 | } |
| 861 | 941 | ||
| @@ -873,7 +953,7 @@ static void handle_channel(struct wiphy *wiphy, | |||
| 873 | 953 | ||
| 874 | if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER && | 954 | if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER && |
| 875 | request_wiphy && request_wiphy == wiphy && | 955 | request_wiphy && request_wiphy == wiphy && |
| 876 | request_wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY) { | 956 | request_wiphy->regulatory_flags & REGULATORY_STRICT_REG) { |
| 877 | /* | 957 | /* |
| 878 | * This guarantees the driver's requested regulatory domain | 958 | * This guarantees the driver's requested regulatory domain |
| 879 | * will always be used as a base for further regulatory | 959 | * will always be used as a base for further regulatory |
| @@ -899,13 +979,11 @@ static void handle_channel(struct wiphy *wiphy, | |||
| 899 | chan->max_reg_power = (int) MBM_TO_DBM(power_rule->max_eirp); | 979 | chan->max_reg_power = (int) MBM_TO_DBM(power_rule->max_eirp); |
| 900 | if (chan->orig_mpwr) { | 980 | if (chan->orig_mpwr) { |
| 901 | /* | 981 | /* |
| 902 | * Devices that have their own custom regulatory domain | 982 | * Devices that use REGULATORY_COUNTRY_IE_FOLLOW_POWER |
| 903 | * but also use WIPHY_FLAG_STRICT_REGULATORY will follow the | 983 | * will always follow the passed country IE power settings. |
| 904 | * passed country IE power settings. | ||
| 905 | */ | 984 | */ |
| 906 | if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE && | 985 | if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE && |
| 907 | wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY && | 986 | wiphy->regulatory_flags & REGULATORY_COUNTRY_IE_FOLLOW_POWER) |
| 908 | wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY) | ||
| 909 | chan->max_power = chan->max_reg_power; | 987 | chan->max_power = chan->max_reg_power; |
| 910 | else | 988 | else |
| 911 | chan->max_power = min(chan->orig_mpwr, | 989 | chan->max_power = min(chan->orig_mpwr, |
| @@ -975,8 +1053,8 @@ static bool reg_dev_ignore_cell_hint(struct wiphy *wiphy) | |||
| 975 | 1053 | ||
| 976 | static bool wiphy_strict_alpha2_regd(struct wiphy *wiphy) | 1054 | static bool wiphy_strict_alpha2_regd(struct wiphy *wiphy) |
| 977 | { | 1055 | { |
| 978 | if (wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY && | 1056 | if (wiphy->regulatory_flags & REGULATORY_STRICT_REG && |
| 979 | !(wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY)) | 1057 | !(wiphy->regulatory_flags & REGULATORY_CUSTOM_REG)) |
| 980 | return true; | 1058 | return true; |
| 981 | return false; | 1059 | return false; |
| 982 | } | 1060 | } |
| @@ -994,7 +1072,7 @@ static bool ignore_reg_update(struct wiphy *wiphy, | |||
| 994 | } | 1072 | } |
| 995 | 1073 | ||
| 996 | if (initiator == NL80211_REGDOM_SET_BY_CORE && | 1074 | if (initiator == NL80211_REGDOM_SET_BY_CORE && |
| 997 | wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY) { | 1075 | wiphy->regulatory_flags & REGULATORY_CUSTOM_REG) { |
| 998 | REG_DBG_PRINT("Ignoring regulatory request set by %s " | 1076 | REG_DBG_PRINT("Ignoring regulatory request set by %s " |
| 999 | "since the driver uses its own custom " | 1077 | "since the driver uses its own custom " |
| 1000 | "regulatory domain\n", | 1078 | "regulatory domain\n", |
| @@ -1032,7 +1110,7 @@ static bool reg_is_world_roaming(struct wiphy *wiphy) | |||
| 1032 | return true; | 1110 | return true; |
| 1033 | 1111 | ||
| 1034 | if (lr && lr->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE && | 1112 | if (lr && lr->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE && |
| 1035 | wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY) | 1113 | wiphy->regulatory_flags & REGULATORY_CUSTOM_REG) |
| 1036 | return true; | 1114 | return true; |
| 1037 | 1115 | ||
| 1038 | return false; | 1116 | return false; |
| @@ -1060,19 +1138,14 @@ static void handle_reg_beacon(struct wiphy *wiphy, unsigned int chan_idx, | |||
| 1060 | if (!reg_is_world_roaming(wiphy)) | 1138 | if (!reg_is_world_roaming(wiphy)) |
| 1061 | return; | 1139 | return; |
| 1062 | 1140 | ||
| 1063 | if (wiphy->flags & WIPHY_FLAG_DISABLE_BEACON_HINTS) | 1141 | if (wiphy->regulatory_flags & REGULATORY_DISABLE_BEACON_HINTS) |
| 1064 | return; | 1142 | return; |
| 1065 | 1143 | ||
| 1066 | chan_before.center_freq = chan->center_freq; | 1144 | chan_before.center_freq = chan->center_freq; |
| 1067 | chan_before.flags = chan->flags; | 1145 | chan_before.flags = chan->flags; |
| 1068 | 1146 | ||
| 1069 | if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN) { | 1147 | if (chan->flags & IEEE80211_CHAN_NO_IR) { |
| 1070 | chan->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN; | 1148 | chan->flags &= ~IEEE80211_CHAN_NO_IR; |
| 1071 | channel_changed = true; | ||
| 1072 | } | ||
| 1073 | |||
| 1074 | if (chan->flags & IEEE80211_CHAN_NO_IBSS) { | ||
| 1075 | chan->flags &= ~IEEE80211_CHAN_NO_IBSS; | ||
| 1076 | channel_changed = true; | 1149 | channel_changed = true; |
| 1077 | } | 1150 | } |
| 1078 | 1151 | ||
| @@ -1205,14 +1278,30 @@ static void reg_process_ht_flags(struct wiphy *wiphy) | |||
| 1205 | reg_process_ht_flags_band(wiphy, wiphy->bands[band]); | 1278 | reg_process_ht_flags_band(wiphy, wiphy->bands[band]); |
| 1206 | } | 1279 | } |
| 1207 | 1280 | ||
| 1281 | static void reg_call_notifier(struct wiphy *wiphy, | ||
| 1282 | struct regulatory_request *request) | ||
| 1283 | { | ||
| 1284 | if (wiphy->reg_notifier) | ||
| 1285 | wiphy->reg_notifier(wiphy, request); | ||
| 1286 | } | ||
| 1287 | |||
| 1208 | static void wiphy_update_regulatory(struct wiphy *wiphy, | 1288 | static void wiphy_update_regulatory(struct wiphy *wiphy, |
| 1209 | enum nl80211_reg_initiator initiator) | 1289 | enum nl80211_reg_initiator initiator) |
| 1210 | { | 1290 | { |
| 1211 | enum ieee80211_band band; | 1291 | enum ieee80211_band band; |
| 1212 | struct regulatory_request *lr = get_last_request(); | 1292 | struct regulatory_request *lr = get_last_request(); |
| 1213 | 1293 | ||
| 1214 | if (ignore_reg_update(wiphy, initiator)) | 1294 | if (ignore_reg_update(wiphy, initiator)) { |
| 1295 | /* | ||
| 1296 | * Regulatory updates set by CORE are ignored for custom | ||
| 1297 | * regulatory cards. Let us notify the changes to the driver, | ||
| 1298 | * as some drivers used this to restore its orig_* reg domain. | ||
| 1299 | */ | ||
| 1300 | if (initiator == NL80211_REGDOM_SET_BY_CORE && | ||
| 1301 | wiphy->regulatory_flags & REGULATORY_CUSTOM_REG) | ||
| 1302 | reg_call_notifier(wiphy, lr); | ||
| 1215 | return; | 1303 | return; |
| 1304 | } | ||
| 1216 | 1305 | ||
| 1217 | lr->dfs_region = get_cfg80211_regdom()->dfs_region; | 1306 | lr->dfs_region = get_cfg80211_regdom()->dfs_region; |
| 1218 | 1307 | ||
| @@ -1221,9 +1310,7 @@ static void wiphy_update_regulatory(struct wiphy *wiphy, | |||
| 1221 | 1310 | ||
| 1222 | reg_process_beacons(wiphy); | 1311 | reg_process_beacons(wiphy); |
| 1223 | reg_process_ht_flags(wiphy); | 1312 | reg_process_ht_flags(wiphy); |
| 1224 | 1313 | reg_call_notifier(wiphy, lr); | |
| 1225 | if (wiphy->reg_notifier) | ||
| 1226 | wiphy->reg_notifier(wiphy, lr); | ||
| 1227 | } | 1314 | } |
| 1228 | 1315 | ||
| 1229 | static void update_all_wiphy_regulatory(enum nl80211_reg_initiator initiator) | 1316 | static void update_all_wiphy_regulatory(enum nl80211_reg_initiator initiator) |
| @@ -1236,15 +1323,6 @@ static void update_all_wiphy_regulatory(enum nl80211_reg_initiator initiator) | |||
| 1236 | list_for_each_entry(rdev, &cfg80211_rdev_list, list) { | 1323 | list_for_each_entry(rdev, &cfg80211_rdev_list, list) { |
| 1237 | wiphy = &rdev->wiphy; | 1324 | wiphy = &rdev->wiphy; |
| 1238 | wiphy_update_regulatory(wiphy, initiator); | 1325 | wiphy_update_regulatory(wiphy, initiator); |
| 1239 | /* | ||
| 1240 | * Regulatory updates set by CORE are ignored for custom | ||
| 1241 | * regulatory cards. Let us notify the changes to the driver, | ||
| 1242 | * as some drivers used this to restore its orig_* reg domain. | ||
| 1243 | */ | ||
| 1244 | if (initiator == NL80211_REGDOM_SET_BY_CORE && | ||
| 1245 | wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY && | ||
| 1246 | wiphy->reg_notifier) | ||
| 1247 | wiphy->reg_notifier(wiphy, get_last_request()); | ||
| 1248 | } | 1326 | } |
| 1249 | } | 1327 | } |
| 1250 | 1328 | ||
| @@ -1263,7 +1341,8 @@ static void handle_channel_custom(struct wiphy *wiphy, | |||
| 1263 | if (IS_ERR(reg_rule)) { | 1341 | if (IS_ERR(reg_rule)) { |
| 1264 | REG_DBG_PRINT("Disabling freq %d MHz as custom regd has no rule that fits it\n", | 1342 | REG_DBG_PRINT("Disabling freq %d MHz as custom regd has no rule that fits it\n", |
| 1265 | chan->center_freq); | 1343 | chan->center_freq); |
| 1266 | chan->flags = IEEE80211_CHAN_DISABLED; | 1344 | chan->orig_flags |= IEEE80211_CHAN_DISABLED; |
| 1345 | chan->flags = chan->orig_flags; | ||
| 1267 | return; | 1346 | return; |
| 1268 | } | 1347 | } |
| 1269 | 1348 | ||
| @@ -1305,6 +1384,10 @@ void wiphy_apply_custom_regulatory(struct wiphy *wiphy, | |||
| 1305 | enum ieee80211_band band; | 1384 | enum ieee80211_band band; |
| 1306 | unsigned int bands_set = 0; | 1385 | unsigned int bands_set = 0; |
| 1307 | 1386 | ||
| 1387 | WARN(!(wiphy->regulatory_flags & REGULATORY_CUSTOM_REG), | ||
| 1388 | "wiphy should have REGULATORY_CUSTOM_REG\n"); | ||
| 1389 | wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG; | ||
| 1390 | |||
| 1308 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { | 1391 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { |
| 1309 | if (!wiphy->bands[band]) | 1392 | if (!wiphy->bands[band]) |
| 1310 | continue; | 1393 | continue; |
| @@ -1320,225 +1403,285 @@ void wiphy_apply_custom_regulatory(struct wiphy *wiphy, | |||
| 1320 | } | 1403 | } |
| 1321 | EXPORT_SYMBOL(wiphy_apply_custom_regulatory); | 1404 | EXPORT_SYMBOL(wiphy_apply_custom_regulatory); |
| 1322 | 1405 | ||
| 1323 | /* This has the logic which determines when a new request | 1406 | static void reg_set_request_processed(void) |
| 1324 | * should be ignored. */ | ||
| 1325 | static enum reg_request_treatment | ||
| 1326 | get_reg_request_treatment(struct wiphy *wiphy, | ||
| 1327 | struct regulatory_request *pending_request) | ||
| 1328 | { | 1407 | { |
| 1329 | struct wiphy *last_wiphy = NULL; | 1408 | bool need_more_processing = false; |
| 1330 | struct regulatory_request *lr = get_last_request(); | 1409 | struct regulatory_request *lr = get_last_request(); |
| 1331 | 1410 | ||
| 1332 | /* All initial requests are respected */ | 1411 | lr->processed = true; |
| 1333 | if (!lr) | ||
| 1334 | return REG_REQ_OK; | ||
| 1335 | 1412 | ||
| 1336 | switch (pending_request->initiator) { | 1413 | spin_lock(®_requests_lock); |
| 1337 | case NL80211_REGDOM_SET_BY_CORE: | 1414 | if (!list_empty(®_requests_list)) |
| 1338 | return REG_REQ_OK; | 1415 | need_more_processing = true; |
| 1339 | case NL80211_REGDOM_SET_BY_COUNTRY_IE: | 1416 | spin_unlock(®_requests_lock); |
| 1340 | if (reg_request_cell_base(lr)) { | ||
| 1341 | /* Trust a Cell base station over the AP's country IE */ | ||
| 1342 | if (regdom_changes(pending_request->alpha2)) | ||
| 1343 | return REG_REQ_IGNORE; | ||
| 1344 | return REG_REQ_ALREADY_SET; | ||
| 1345 | } | ||
| 1346 | 1417 | ||
| 1347 | last_wiphy = wiphy_idx_to_wiphy(lr->wiphy_idx); | 1418 | if (lr->initiator == NL80211_REGDOM_SET_BY_USER) |
| 1419 | cancel_delayed_work(®_timeout); | ||
| 1348 | 1420 | ||
| 1349 | if (unlikely(!is_an_alpha2(pending_request->alpha2))) | 1421 | if (need_more_processing) |
| 1350 | return -EINVAL; | 1422 | schedule_work(®_work); |
| 1351 | if (lr->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) { | 1423 | } |
| 1352 | if (last_wiphy != wiphy) { | ||
| 1353 | /* | ||
| 1354 | * Two cards with two APs claiming different | ||
| 1355 | * Country IE alpha2s. We could | ||
| 1356 | * intersect them, but that seems unlikely | ||
| 1357 | * to be correct. Reject second one for now. | ||
| 1358 | */ | ||
| 1359 | if (regdom_changes(pending_request->alpha2)) | ||
| 1360 | return REG_REQ_IGNORE; | ||
| 1361 | return REG_REQ_ALREADY_SET; | ||
| 1362 | } | ||
| 1363 | /* | ||
| 1364 | * Two consecutive Country IE hints on the same wiphy. | ||
| 1365 | * This should be picked up early by the driver/stack | ||
| 1366 | */ | ||
| 1367 | if (WARN_ON(regdom_changes(pending_request->alpha2))) | ||
| 1368 | return REG_REQ_OK; | ||
| 1369 | return REG_REQ_ALREADY_SET; | ||
| 1370 | } | ||
| 1371 | return REG_REQ_OK; | ||
| 1372 | case NL80211_REGDOM_SET_BY_DRIVER: | ||
| 1373 | if (lr->initiator == NL80211_REGDOM_SET_BY_CORE) { | ||
| 1374 | if (regdom_changes(pending_request->alpha2)) | ||
| 1375 | return REG_REQ_OK; | ||
| 1376 | return REG_REQ_ALREADY_SET; | ||
| 1377 | } | ||
| 1378 | 1424 | ||
| 1379 | /* | 1425 | /** |
| 1380 | * This would happen if you unplug and plug your card | 1426 | * reg_process_hint_core - process core regulatory requests |
| 1381 | * back in or if you add a new device for which the previously | 1427 | * @pending_request: a pending core regulatory request |
| 1382 | * loaded card also agrees on the regulatory domain. | 1428 | * |
| 1383 | */ | 1429 | * The wireless subsystem can use this function to process |
| 1384 | if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER && | 1430 | * a regulatory request issued by the regulatory core. |
| 1385 | !regdom_changes(pending_request->alpha2)) | 1431 | * |
| 1386 | return REG_REQ_ALREADY_SET; | 1432 | * Returns one of the different reg request treatment values. |
| 1433 | */ | ||
| 1434 | static enum reg_request_treatment | ||
| 1435 | reg_process_hint_core(struct regulatory_request *core_request) | ||
| 1436 | { | ||
| 1437 | |||
| 1438 | core_request->intersect = false; | ||
| 1439 | core_request->processed = false; | ||
| 1440 | |||
| 1441 | reg_update_last_request(core_request); | ||
| 1442 | |||
| 1443 | return reg_call_crda(core_request); | ||
| 1444 | } | ||
| 1387 | 1445 | ||
| 1446 | static enum reg_request_treatment | ||
| 1447 | __reg_process_hint_user(struct regulatory_request *user_request) | ||
| 1448 | { | ||
| 1449 | struct regulatory_request *lr = get_last_request(); | ||
| 1450 | |||
| 1451 | if (reg_request_cell_base(user_request)) | ||
| 1452 | return reg_ignore_cell_hint(user_request); | ||
| 1453 | |||
| 1454 | if (reg_request_cell_base(lr)) | ||
| 1455 | return REG_REQ_IGNORE; | ||
| 1456 | |||
| 1457 | if (lr->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) | ||
| 1388 | return REG_REQ_INTERSECT; | 1458 | return REG_REQ_INTERSECT; |
| 1389 | case NL80211_REGDOM_SET_BY_USER: | 1459 | /* |
| 1390 | if (reg_request_cell_base(pending_request)) | 1460 | * If the user knows better the user should set the regdom |
| 1391 | return reg_ignore_cell_hint(pending_request); | 1461 | * to their country before the IE is picked up |
| 1462 | */ | ||
| 1463 | if (lr->initiator == NL80211_REGDOM_SET_BY_USER && | ||
| 1464 | lr->intersect) | ||
| 1465 | return REG_REQ_IGNORE; | ||
| 1466 | /* | ||
| 1467 | * Process user requests only after previous user/driver/core | ||
| 1468 | * requests have been processed | ||
| 1469 | */ | ||
| 1470 | if ((lr->initiator == NL80211_REGDOM_SET_BY_CORE || | ||
| 1471 | lr->initiator == NL80211_REGDOM_SET_BY_DRIVER || | ||
| 1472 | lr->initiator == NL80211_REGDOM_SET_BY_USER) && | ||
| 1473 | regdom_changes(lr->alpha2)) | ||
| 1474 | return REG_REQ_IGNORE; | ||
| 1392 | 1475 | ||
| 1393 | if (reg_request_cell_base(lr)) | 1476 | if (!regdom_changes(user_request->alpha2)) |
| 1394 | return REG_REQ_IGNORE; | 1477 | return REG_REQ_ALREADY_SET; |
| 1395 | 1478 | ||
| 1396 | if (lr->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) | 1479 | return REG_REQ_OK; |
| 1397 | return REG_REQ_INTERSECT; | 1480 | } |
| 1398 | /* | ||
| 1399 | * If the user knows better the user should set the regdom | ||
| 1400 | * to their country before the IE is picked up | ||
| 1401 | */ | ||
| 1402 | if (lr->initiator == NL80211_REGDOM_SET_BY_USER && | ||
| 1403 | lr->intersect) | ||
| 1404 | return REG_REQ_IGNORE; | ||
| 1405 | /* | ||
| 1406 | * Process user requests only after previous user/driver/core | ||
| 1407 | * requests have been processed | ||
| 1408 | */ | ||
| 1409 | if ((lr->initiator == NL80211_REGDOM_SET_BY_CORE || | ||
| 1410 | lr->initiator == NL80211_REGDOM_SET_BY_DRIVER || | ||
| 1411 | lr->initiator == NL80211_REGDOM_SET_BY_USER) && | ||
| 1412 | regdom_changes(lr->alpha2)) | ||
| 1413 | return REG_REQ_IGNORE; | ||
| 1414 | 1481 | ||
| 1415 | if (!regdom_changes(pending_request->alpha2)) | 1482 | /** |
| 1416 | return REG_REQ_ALREADY_SET; | 1483 | * reg_process_hint_user - process user regulatory requests |
| 1484 | * @user_request: a pending user regulatory request | ||
| 1485 | * | ||
| 1486 | * The wireless subsystem can use this function to process | ||
| 1487 | * a regulatory request initiated by userspace. | ||
| 1488 | * | ||
| 1489 | * Returns one of the different reg request treatment values. | ||
| 1490 | */ | ||
| 1491 | static enum reg_request_treatment | ||
| 1492 | reg_process_hint_user(struct regulatory_request *user_request) | ||
| 1493 | { | ||
| 1494 | enum reg_request_treatment treatment; | ||
| 1417 | 1495 | ||
| 1418 | return REG_REQ_OK; | 1496 | treatment = __reg_process_hint_user(user_request); |
| 1497 | if (treatment == REG_REQ_IGNORE || | ||
| 1498 | treatment == REG_REQ_ALREADY_SET) { | ||
| 1499 | kfree(user_request); | ||
| 1500 | return treatment; | ||
| 1419 | } | 1501 | } |
| 1420 | 1502 | ||
| 1421 | return REG_REQ_IGNORE; | 1503 | user_request->intersect = treatment == REG_REQ_INTERSECT; |
| 1504 | user_request->processed = false; | ||
| 1505 | |||
| 1506 | reg_update_last_request(user_request); | ||
| 1507 | |||
| 1508 | user_alpha2[0] = user_request->alpha2[0]; | ||
| 1509 | user_alpha2[1] = user_request->alpha2[1]; | ||
| 1510 | |||
| 1511 | return reg_call_crda(user_request); | ||
| 1422 | } | 1512 | } |
| 1423 | 1513 | ||
| 1424 | static void reg_set_request_processed(void) | 1514 | static enum reg_request_treatment |
| 1515 | __reg_process_hint_driver(struct regulatory_request *driver_request) | ||
| 1425 | { | 1516 | { |
| 1426 | bool need_more_processing = false; | ||
| 1427 | struct regulatory_request *lr = get_last_request(); | 1517 | struct regulatory_request *lr = get_last_request(); |
| 1428 | 1518 | ||
| 1429 | lr->processed = true; | 1519 | if (lr->initiator == NL80211_REGDOM_SET_BY_CORE) { |
| 1430 | 1520 | if (regdom_changes(driver_request->alpha2)) | |
| 1431 | spin_lock(®_requests_lock); | 1521 | return REG_REQ_OK; |
| 1432 | if (!list_empty(®_requests_list)) | 1522 | return REG_REQ_ALREADY_SET; |
| 1433 | need_more_processing = true; | 1523 | } |
| 1434 | spin_unlock(®_requests_lock); | ||
| 1435 | 1524 | ||
| 1436 | if (lr->initiator == NL80211_REGDOM_SET_BY_USER) | 1525 | /* |
| 1437 | cancel_delayed_work(®_timeout); | 1526 | * This would happen if you unplug and plug your card |
| 1527 | * back in or if you add a new device for which the previously | ||
| 1528 | * loaded card also agrees on the regulatory domain. | ||
| 1529 | */ | ||
| 1530 | if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER && | ||
| 1531 | !regdom_changes(driver_request->alpha2)) | ||
| 1532 | return REG_REQ_ALREADY_SET; | ||
| 1438 | 1533 | ||
| 1439 | if (need_more_processing) | 1534 | return REG_REQ_INTERSECT; |
| 1440 | schedule_work(®_work); | ||
| 1441 | } | 1535 | } |
| 1442 | 1536 | ||
| 1443 | /** | 1537 | /** |
| 1444 | * __regulatory_hint - hint to the wireless core a regulatory domain | 1538 | * reg_process_hint_driver - process driver regulatory requests |
| 1445 | * @wiphy: if the hint comes from country information from an AP, this | 1539 | * @driver_request: a pending driver regulatory request |
| 1446 | * is required to be set to the wiphy that received the information | ||
| 1447 | * @pending_request: the regulatory request currently being processed | ||
| 1448 | * | 1540 | * |
| 1449 | * The Wireless subsystem can use this function to hint to the wireless core | 1541 | * The wireless subsystem can use this function to process |
| 1450 | * what it believes should be the current regulatory domain. | 1542 | * a regulatory request issued by an 802.11 driver. |
| 1451 | * | 1543 | * |
| 1452 | * Returns one of the different reg request treatment values. | 1544 | * Returns one of the different reg request treatment values. |
| 1453 | */ | 1545 | */ |
| 1454 | static enum reg_request_treatment | 1546 | static enum reg_request_treatment |
| 1455 | __regulatory_hint(struct wiphy *wiphy, | 1547 | reg_process_hint_driver(struct wiphy *wiphy, |
| 1456 | struct regulatory_request *pending_request) | 1548 | struct regulatory_request *driver_request) |
| 1457 | { | 1549 | { |
| 1458 | const struct ieee80211_regdomain *regd; | 1550 | const struct ieee80211_regdomain *regd; |
| 1459 | bool intersect = false; | ||
| 1460 | enum reg_request_treatment treatment; | 1551 | enum reg_request_treatment treatment; |
| 1461 | struct regulatory_request *lr; | ||
| 1462 | 1552 | ||
| 1463 | treatment = get_reg_request_treatment(wiphy, pending_request); | 1553 | treatment = __reg_process_hint_driver(driver_request); |
| 1464 | 1554 | ||
| 1465 | switch (treatment) { | 1555 | switch (treatment) { |
| 1466 | case REG_REQ_INTERSECT: | ||
| 1467 | if (pending_request->initiator == | ||
| 1468 | NL80211_REGDOM_SET_BY_DRIVER) { | ||
| 1469 | regd = reg_copy_regd(get_cfg80211_regdom()); | ||
| 1470 | if (IS_ERR(regd)) { | ||
| 1471 | kfree(pending_request); | ||
| 1472 | return PTR_ERR(regd); | ||
| 1473 | } | ||
| 1474 | rcu_assign_pointer(wiphy->regd, regd); | ||
| 1475 | } | ||
| 1476 | intersect = true; | ||
| 1477 | break; | ||
| 1478 | case REG_REQ_OK: | 1556 | case REG_REQ_OK: |
| 1479 | break; | 1557 | break; |
| 1480 | default: | 1558 | case REG_REQ_IGNORE: |
| 1481 | /* | 1559 | kfree(driver_request); |
| 1482 | * If the regulatory domain being requested by the | ||
| 1483 | * driver has already been set just copy it to the | ||
| 1484 | * wiphy | ||
| 1485 | */ | ||
| 1486 | if (treatment == REG_REQ_ALREADY_SET && | ||
| 1487 | pending_request->initiator == NL80211_REGDOM_SET_BY_DRIVER) { | ||
| 1488 | regd = reg_copy_regd(get_cfg80211_regdom()); | ||
| 1489 | if (IS_ERR(regd)) { | ||
| 1490 | kfree(pending_request); | ||
| 1491 | return REG_REQ_IGNORE; | ||
| 1492 | } | ||
| 1493 | treatment = REG_REQ_ALREADY_SET; | ||
| 1494 | rcu_assign_pointer(wiphy->regd, regd); | ||
| 1495 | goto new_request; | ||
| 1496 | } | ||
| 1497 | kfree(pending_request); | ||
| 1498 | return treatment; | 1560 | return treatment; |
| 1561 | case REG_REQ_INTERSECT: | ||
| 1562 | /* fall through */ | ||
| 1563 | case REG_REQ_ALREADY_SET: | ||
| 1564 | regd = reg_copy_regd(get_cfg80211_regdom()); | ||
| 1565 | if (IS_ERR(regd)) { | ||
| 1566 | kfree(driver_request); | ||
| 1567 | return REG_REQ_IGNORE; | ||
| 1568 | } | ||
| 1569 | rcu_assign_pointer(wiphy->regd, regd); | ||
| 1499 | } | 1570 | } |
| 1500 | 1571 | ||
| 1501 | new_request: | ||
| 1502 | lr = get_last_request(); | ||
| 1503 | if (lr != &core_request_world && lr) | ||
| 1504 | kfree_rcu(lr, rcu_head); | ||
| 1505 | 1572 | ||
| 1506 | pending_request->intersect = intersect; | 1573 | driver_request->intersect = treatment == REG_REQ_INTERSECT; |
| 1507 | pending_request->processed = false; | 1574 | driver_request->processed = false; |
| 1508 | rcu_assign_pointer(last_request, pending_request); | 1575 | |
| 1509 | lr = pending_request; | 1576 | reg_update_last_request(driver_request); |
| 1577 | |||
| 1578 | /* | ||
| 1579 | * Since CRDA will not be called in this case as we already | ||
| 1580 | * have applied the requested regulatory domain before we just | ||
| 1581 | * inform userspace we have processed the request | ||
| 1582 | */ | ||
| 1583 | if (treatment == REG_REQ_ALREADY_SET) { | ||
| 1584 | nl80211_send_reg_change_event(driver_request); | ||
| 1585 | reg_set_request_processed(); | ||
| 1586 | return treatment; | ||
| 1587 | } | ||
| 1588 | |||
| 1589 | return reg_call_crda(driver_request); | ||
| 1590 | } | ||
| 1510 | 1591 | ||
| 1511 | pending_request = NULL; | 1592 | static enum reg_request_treatment |
| 1593 | __reg_process_hint_country_ie(struct wiphy *wiphy, | ||
| 1594 | struct regulatory_request *country_ie_request) | ||
| 1595 | { | ||
| 1596 | struct wiphy *last_wiphy = NULL; | ||
| 1597 | struct regulatory_request *lr = get_last_request(); | ||
| 1512 | 1598 | ||
| 1513 | if (lr->initiator == NL80211_REGDOM_SET_BY_USER) { | 1599 | if (reg_request_cell_base(lr)) { |
| 1514 | user_alpha2[0] = lr->alpha2[0]; | 1600 | /* Trust a Cell base station over the AP's country IE */ |
| 1515 | user_alpha2[1] = lr->alpha2[1]; | 1601 | if (regdom_changes(country_ie_request->alpha2)) |
| 1602 | return REG_REQ_IGNORE; | ||
| 1603 | return REG_REQ_ALREADY_SET; | ||
| 1604 | } else { | ||
| 1605 | if (wiphy->regulatory_flags & REGULATORY_COUNTRY_IE_IGNORE) | ||
| 1606 | return REG_REQ_IGNORE; | ||
| 1516 | } | 1607 | } |
| 1517 | 1608 | ||
| 1518 | /* When r == REG_REQ_INTERSECT we do need to call CRDA */ | 1609 | if (unlikely(!is_an_alpha2(country_ie_request->alpha2))) |
| 1519 | if (treatment != REG_REQ_OK && treatment != REG_REQ_INTERSECT) { | 1610 | return -EINVAL; |
| 1611 | |||
| 1612 | if (lr->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE) | ||
| 1613 | return REG_REQ_OK; | ||
| 1614 | |||
| 1615 | last_wiphy = wiphy_idx_to_wiphy(lr->wiphy_idx); | ||
| 1616 | |||
| 1617 | if (last_wiphy != wiphy) { | ||
| 1520 | /* | 1618 | /* |
| 1521 | * Since CRDA will not be called in this case as we already | 1619 | * Two cards with two APs claiming different |
| 1522 | * have applied the requested regulatory domain before we just | 1620 | * Country IE alpha2s. We could |
| 1523 | * inform userspace we have processed the request | 1621 | * intersect them, but that seems unlikely |
| 1622 | * to be correct. Reject second one for now. | ||
| 1524 | */ | 1623 | */ |
| 1525 | if (treatment == REG_REQ_ALREADY_SET) { | 1624 | if (regdom_changes(country_ie_request->alpha2)) |
| 1526 | nl80211_send_reg_change_event(lr); | 1625 | return REG_REQ_IGNORE; |
| 1527 | reg_set_request_processed(); | 1626 | return REG_REQ_ALREADY_SET; |
| 1528 | } | ||
| 1529 | return treatment; | ||
| 1530 | } | 1627 | } |
| 1628 | /* | ||
| 1629 | * Two consecutive Country IE hints on the same wiphy. | ||
| 1630 | * This should be picked up early by the driver/stack | ||
| 1631 | */ | ||
| 1632 | if (WARN_ON(regdom_changes(country_ie_request->alpha2))) | ||
| 1633 | return REG_REQ_OK; | ||
| 1634 | return REG_REQ_ALREADY_SET; | ||
| 1635 | } | ||
| 1531 | 1636 | ||
| 1532 | if (call_crda(lr->alpha2)) | 1637 | /** |
| 1638 | * reg_process_hint_country_ie - process regulatory requests from country IEs | ||
| 1639 | * @country_ie_request: a regulatory request from a country IE | ||
| 1640 | * | ||
| 1641 | * The wireless subsystem can use this function to process | ||
| 1642 | * a regulatory request issued by a country Information Element. | ||
| 1643 | * | ||
| 1644 | * Returns one of the different reg request treatment values. | ||
| 1645 | */ | ||
| 1646 | static enum reg_request_treatment | ||
| 1647 | reg_process_hint_country_ie(struct wiphy *wiphy, | ||
| 1648 | struct regulatory_request *country_ie_request) | ||
| 1649 | { | ||
| 1650 | enum reg_request_treatment treatment; | ||
| 1651 | |||
| 1652 | treatment = __reg_process_hint_country_ie(wiphy, country_ie_request); | ||
| 1653 | |||
| 1654 | switch (treatment) { | ||
| 1655 | case REG_REQ_OK: | ||
| 1656 | break; | ||
| 1657 | case REG_REQ_IGNORE: | ||
| 1658 | /* fall through */ | ||
| 1659 | case REG_REQ_ALREADY_SET: | ||
| 1660 | kfree(country_ie_request); | ||
| 1661 | return treatment; | ||
| 1662 | case REG_REQ_INTERSECT: | ||
| 1663 | kfree(country_ie_request); | ||
| 1664 | /* | ||
| 1665 | * This doesn't happen yet, not sure we | ||
| 1666 | * ever want to support it for this case. | ||
| 1667 | */ | ||
| 1668 | WARN_ONCE(1, "Unexpected intersection for country IEs"); | ||
| 1533 | return REG_REQ_IGNORE; | 1669 | return REG_REQ_IGNORE; |
| 1534 | return REG_REQ_OK; | 1670 | } |
| 1671 | |||
| 1672 | country_ie_request->intersect = false; | ||
| 1673 | country_ie_request->processed = false; | ||
| 1674 | |||
| 1675 | reg_update_last_request(country_ie_request); | ||
| 1676 | |||
| 1677 | return reg_call_crda(country_ie_request); | ||
| 1535 | } | 1678 | } |
| 1536 | 1679 | ||
| 1537 | /* This processes *all* regulatory hints */ | 1680 | /* This processes *all* regulatory hints */ |
| 1538 | static void reg_process_hint(struct regulatory_request *reg_request, | 1681 | static void reg_process_hint(struct regulatory_request *reg_request) |
| 1539 | enum nl80211_reg_initiator reg_initiator) | ||
| 1540 | { | 1682 | { |
| 1541 | struct wiphy *wiphy = NULL; | 1683 | struct wiphy *wiphy = NULL; |
| 1684 | enum reg_request_treatment treatment; | ||
| 1542 | 1685 | ||
| 1543 | if (WARN_ON(!reg_request->alpha2)) | 1686 | if (WARN_ON(!reg_request->alpha2)) |
| 1544 | return; | 1687 | return; |
| @@ -1546,23 +1689,37 @@ static void reg_process_hint(struct regulatory_request *reg_request, | |||
| 1546 | if (reg_request->wiphy_idx != WIPHY_IDX_INVALID) | 1689 | if (reg_request->wiphy_idx != WIPHY_IDX_INVALID) |
| 1547 | wiphy = wiphy_idx_to_wiphy(reg_request->wiphy_idx); | 1690 | wiphy = wiphy_idx_to_wiphy(reg_request->wiphy_idx); |
| 1548 | 1691 | ||
| 1549 | if (reg_initiator == NL80211_REGDOM_SET_BY_DRIVER && !wiphy) { | 1692 | if (reg_request->initiator == NL80211_REGDOM_SET_BY_DRIVER && !wiphy) { |
| 1550 | kfree(reg_request); | 1693 | kfree(reg_request); |
| 1551 | return; | 1694 | return; |
| 1552 | } | 1695 | } |
| 1553 | 1696 | ||
| 1554 | switch (__regulatory_hint(wiphy, reg_request)) { | 1697 | switch (reg_request->initiator) { |
| 1555 | case REG_REQ_ALREADY_SET: | 1698 | case NL80211_REGDOM_SET_BY_CORE: |
| 1556 | /* This is required so that the orig_* parameters are saved */ | 1699 | reg_process_hint_core(reg_request); |
| 1557 | if (wiphy && wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY) | 1700 | return; |
| 1558 | wiphy_update_regulatory(wiphy, reg_initiator); | 1701 | case NL80211_REGDOM_SET_BY_USER: |
| 1702 | treatment = reg_process_hint_user(reg_request); | ||
| 1703 | if (treatment == REG_REQ_OK || | ||
| 1704 | treatment == REG_REQ_ALREADY_SET) | ||
| 1705 | return; | ||
| 1706 | schedule_delayed_work(®_timeout, msecs_to_jiffies(3142)); | ||
| 1707 | return; | ||
| 1708 | case NL80211_REGDOM_SET_BY_DRIVER: | ||
| 1709 | treatment = reg_process_hint_driver(wiphy, reg_request); | ||
| 1559 | break; | 1710 | break; |
| 1560 | default: | 1711 | case NL80211_REGDOM_SET_BY_COUNTRY_IE: |
| 1561 | if (reg_initiator == NL80211_REGDOM_SET_BY_USER) | 1712 | treatment = reg_process_hint_country_ie(wiphy, reg_request); |
| 1562 | schedule_delayed_work(®_timeout, | ||
| 1563 | msecs_to_jiffies(3142)); | ||
| 1564 | break; | 1713 | break; |
| 1714 | default: | ||
| 1715 | WARN(1, "invalid initiator %d\n", reg_request->initiator); | ||
| 1716 | return; | ||
| 1565 | } | 1717 | } |
| 1718 | |||
| 1719 | /* This is required so that the orig_* parameters are saved */ | ||
| 1720 | if (treatment == REG_REQ_ALREADY_SET && wiphy && | ||
| 1721 | wiphy->regulatory_flags & REGULATORY_STRICT_REG) | ||
| 1722 | wiphy_update_regulatory(wiphy, reg_request->initiator); | ||
| 1566 | } | 1723 | } |
| 1567 | 1724 | ||
| 1568 | /* | 1725 | /* |
| @@ -1596,7 +1753,7 @@ static void reg_process_pending_hints(void) | |||
| 1596 | 1753 | ||
| 1597 | spin_unlock(®_requests_lock); | 1754 | spin_unlock(®_requests_lock); |
| 1598 | 1755 | ||
| 1599 | reg_process_hint(reg_request, reg_request->initiator); | 1756 | reg_process_hint(reg_request); |
| 1600 | } | 1757 | } |
| 1601 | 1758 | ||
| 1602 | /* Processes beacon hints -- this has nothing to do with country IEs */ | 1759 | /* Processes beacon hints -- this has nothing to do with country IEs */ |
| @@ -1696,6 +1853,8 @@ int regulatory_hint(struct wiphy *wiphy, const char *alpha2) | |||
| 1696 | if (WARN_ON(!alpha2 || !wiphy)) | 1853 | if (WARN_ON(!alpha2 || !wiphy)) |
| 1697 | return -EINVAL; | 1854 | return -EINVAL; |
| 1698 | 1855 | ||
| 1856 | wiphy->regulatory_flags &= ~REGULATORY_CUSTOM_REG; | ||
| 1857 | |||
| 1699 | request = kzalloc(sizeof(struct regulatory_request), GFP_KERNEL); | 1858 | request = kzalloc(sizeof(struct regulatory_request), GFP_KERNEL); |
| 1700 | if (!request) | 1859 | if (!request) |
| 1701 | return -ENOMEM; | 1860 | return -ENOMEM; |
| @@ -1888,7 +2047,7 @@ static void restore_regulatory_settings(bool reset_user) | |||
| 1888 | world_alpha2[1] = cfg80211_world_regdom->alpha2[1]; | 2047 | world_alpha2[1] = cfg80211_world_regdom->alpha2[1]; |
| 1889 | 2048 | ||
| 1890 | list_for_each_entry(rdev, &cfg80211_rdev_list, list) { | 2049 | list_for_each_entry(rdev, &cfg80211_rdev_list, list) { |
| 1891 | if (rdev->wiphy.flags & WIPHY_FLAG_CUSTOM_REGULATORY) | 2050 | if (rdev->wiphy.regulatory_flags & REGULATORY_CUSTOM_REG) |
| 1892 | restore_custom_reg_settings(&rdev->wiphy); | 2051 | restore_custom_reg_settings(&rdev->wiphy); |
| 1893 | } | 2052 | } |
| 1894 | 2053 | ||
| @@ -2016,7 +2175,7 @@ static void print_rd_rules(const struct ieee80211_regdomain *rd) | |||
| 2016 | } | 2175 | } |
| 2017 | } | 2176 | } |
| 2018 | 2177 | ||
| 2019 | bool reg_supported_dfs_region(u8 dfs_region) | 2178 | bool reg_supported_dfs_region(enum nl80211_dfs_regions dfs_region) |
| 2020 | { | 2179 | { |
| 2021 | switch (dfs_region) { | 2180 | switch (dfs_region) { |
| 2022 | case NL80211_DFS_UNSET: | 2181 | case NL80211_DFS_UNSET: |
| @@ -2031,27 +2190,6 @@ bool reg_supported_dfs_region(u8 dfs_region) | |||
| 2031 | } | 2190 | } |
| 2032 | } | 2191 | } |
| 2033 | 2192 | ||
| 2034 | static void print_dfs_region(u8 dfs_region) | ||
| 2035 | { | ||
| 2036 | if (!dfs_region) | ||
| 2037 | return; | ||
| 2038 | |||
| 2039 | switch (dfs_region) { | ||
| 2040 | case NL80211_DFS_FCC: | ||
| 2041 | pr_info(" DFS Master region FCC"); | ||
| 2042 | break; | ||
| 2043 | case NL80211_DFS_ETSI: | ||
| 2044 | pr_info(" DFS Master region ETSI"); | ||
| 2045 | break; | ||
| 2046 | case NL80211_DFS_JP: | ||
| 2047 | pr_info(" DFS Master region JP"); | ||
| 2048 | break; | ||
| 2049 | default: | ||
| 2050 | pr_info(" DFS Master region Unknown"); | ||
| 2051 | break; | ||
| 2052 | } | ||
| 2053 | } | ||
| 2054 | |||
| 2055 | static void print_regdomain(const struct ieee80211_regdomain *rd) | 2193 | static void print_regdomain(const struct ieee80211_regdomain *rd) |
| 2056 | { | 2194 | { |
| 2057 | struct regulatory_request *lr = get_last_request(); | 2195 | struct regulatory_request *lr = get_last_request(); |
| @@ -2083,7 +2221,7 @@ static void print_regdomain(const struct ieee80211_regdomain *rd) | |||
| 2083 | } | 2221 | } |
| 2084 | } | 2222 | } |
| 2085 | 2223 | ||
| 2086 | print_dfs_region(rd->dfs_region); | 2224 | pr_info(" DFS Master region: %s", reg_dfs_region_str(rd->dfs_region)); |
| 2087 | print_rd_rules(rd); | 2225 | print_rd_rules(rd); |
| 2088 | } | 2226 | } |
| 2089 | 2227 | ||
| @@ -2093,48 +2231,60 @@ static void print_regdomain_info(const struct ieee80211_regdomain *rd) | |||
| 2093 | print_rd_rules(rd); | 2231 | print_rd_rules(rd); |
| 2094 | } | 2232 | } |
| 2095 | 2233 | ||
| 2096 | /* Takes ownership of rd only if it doesn't fail */ | 2234 | static int reg_set_rd_core(const struct ieee80211_regdomain *rd) |
| 2097 | static int __set_regdom(const struct ieee80211_regdomain *rd) | 2235 | { |
| 2236 | if (!is_world_regdom(rd->alpha2)) | ||
| 2237 | return -EINVAL; | ||
| 2238 | update_world_regdomain(rd); | ||
| 2239 | return 0; | ||
| 2240 | } | ||
| 2241 | |||
| 2242 | static int reg_set_rd_user(const struct ieee80211_regdomain *rd, | ||
| 2243 | struct regulatory_request *user_request) | ||
| 2098 | { | 2244 | { |
| 2099 | const struct ieee80211_regdomain *regd; | ||
| 2100 | const struct ieee80211_regdomain *intersected_rd = NULL; | 2245 | const struct ieee80211_regdomain *intersected_rd = NULL; |
| 2101 | struct wiphy *request_wiphy; | ||
| 2102 | struct regulatory_request *lr = get_last_request(); | ||
| 2103 | 2246 | ||
| 2104 | /* Some basic sanity checks first */ | 2247 | if (is_world_regdom(rd->alpha2)) |
| 2248 | return -EINVAL; | ||
| 2249 | |||
| 2250 | if (!regdom_changes(rd->alpha2)) | ||
| 2251 | return -EALREADY; | ||
| 2105 | 2252 | ||
| 2106 | if (!reg_is_valid_request(rd->alpha2)) | 2253 | if (!is_valid_rd(rd)) { |
| 2254 | pr_err("Invalid regulatory domain detected:\n"); | ||
| 2255 | print_regdomain_info(rd); | ||
| 2107 | return -EINVAL; | 2256 | return -EINVAL; |
| 2257 | } | ||
| 2108 | 2258 | ||
| 2109 | if (is_world_regdom(rd->alpha2)) { | 2259 | if (!user_request->intersect) { |
| 2110 | update_world_regdomain(rd); | 2260 | reset_regdomains(false, rd); |
| 2111 | return 0; | 2261 | return 0; |
| 2112 | } | 2262 | } |
| 2113 | 2263 | ||
| 2114 | if (!is_alpha2_set(rd->alpha2) && !is_an_alpha2(rd->alpha2) && | 2264 | intersected_rd = regdom_intersect(rd, get_cfg80211_regdom()); |
| 2115 | !is_unknown_alpha2(rd->alpha2)) | 2265 | if (!intersected_rd) |
| 2116 | return -EINVAL; | 2266 | return -EINVAL; |
| 2117 | 2267 | ||
| 2118 | /* | 2268 | kfree(rd); |
| 2119 | * Lets only bother proceeding on the same alpha2 if the current | 2269 | rd = NULL; |
| 2120 | * rd is non static (it means CRDA was present and was used last) | 2270 | reset_regdomains(false, intersected_rd); |
| 2121 | * and the pending request came in from a country IE | ||
| 2122 | */ | ||
| 2123 | if (lr->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE) { | ||
| 2124 | /* | ||
| 2125 | * If someone else asked us to change the rd lets only bother | ||
| 2126 | * checking if the alpha2 changes if CRDA was already called | ||
| 2127 | */ | ||
| 2128 | if (!regdom_changes(rd->alpha2)) | ||
| 2129 | return -EALREADY; | ||
| 2130 | } | ||
| 2131 | 2271 | ||
| 2132 | /* | 2272 | return 0; |
| 2133 | * Now lets set the regulatory domain, update all driver channels | 2273 | } |
| 2134 | * and finally inform them of what we have done, in case they want | 2274 | |
| 2135 | * to review or adjust their own settings based on their own | 2275 | static int reg_set_rd_driver(const struct ieee80211_regdomain *rd, |
| 2136 | * internal EEPROM data | 2276 | struct regulatory_request *driver_request) |
| 2137 | */ | 2277 | { |
| 2278 | const struct ieee80211_regdomain *regd; | ||
| 2279 | const struct ieee80211_regdomain *intersected_rd = NULL; | ||
| 2280 | const struct ieee80211_regdomain *tmp; | ||
| 2281 | struct wiphy *request_wiphy; | ||
| 2282 | |||
| 2283 | if (is_world_regdom(rd->alpha2)) | ||
| 2284 | return -EINVAL; | ||
| 2285 | |||
| 2286 | if (!regdom_changes(rd->alpha2)) | ||
| 2287 | return -EALREADY; | ||
| 2138 | 2288 | ||
| 2139 | if (!is_valid_rd(rd)) { | 2289 | if (!is_valid_rd(rd)) { |
| 2140 | pr_err("Invalid regulatory domain detected:\n"); | 2290 | pr_err("Invalid regulatory domain detected:\n"); |
| @@ -2142,29 +2292,13 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) | |||
| 2142 | return -EINVAL; | 2292 | return -EINVAL; |
| 2143 | } | 2293 | } |
| 2144 | 2294 | ||
| 2145 | request_wiphy = wiphy_idx_to_wiphy(lr->wiphy_idx); | 2295 | request_wiphy = wiphy_idx_to_wiphy(driver_request->wiphy_idx); |
| 2146 | if (!request_wiphy && | 2296 | if (!request_wiphy) { |
| 2147 | (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER || | ||
| 2148 | lr->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE)) { | ||
| 2149 | schedule_delayed_work(®_timeout, 0); | 2297 | schedule_delayed_work(®_timeout, 0); |
| 2150 | return -ENODEV; | 2298 | return -ENODEV; |
| 2151 | } | 2299 | } |
| 2152 | 2300 | ||
| 2153 | if (!lr->intersect) { | 2301 | if (!driver_request->intersect) { |
| 2154 | if (lr->initiator != NL80211_REGDOM_SET_BY_DRIVER) { | ||
| 2155 | reset_regdomains(false, rd); | ||
| 2156 | return 0; | ||
| 2157 | } | ||
| 2158 | |||
| 2159 | /* | ||
| 2160 | * For a driver hint, lets copy the regulatory domain the | ||
| 2161 | * driver wanted to the wiphy to deal with conflicts | ||
| 2162 | */ | ||
| 2163 | |||
| 2164 | /* | ||
| 2165 | * Userspace could have sent two replies with only | ||
| 2166 | * one kernel request. | ||
| 2167 | */ | ||
| 2168 | if (request_wiphy->regd) | 2302 | if (request_wiphy->regd) |
| 2169 | return -EALREADY; | 2303 | return -EALREADY; |
| 2170 | 2304 | ||
| @@ -2177,38 +2311,59 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) | |||
| 2177 | return 0; | 2311 | return 0; |
| 2178 | } | 2312 | } |
| 2179 | 2313 | ||
| 2180 | /* Intersection requires a bit more work */ | 2314 | intersected_rd = regdom_intersect(rd, get_cfg80211_regdom()); |
| 2315 | if (!intersected_rd) | ||
| 2316 | return -EINVAL; | ||
| 2181 | 2317 | ||
| 2182 | if (lr->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE) { | 2318 | /* |
| 2183 | intersected_rd = regdom_intersect(rd, get_cfg80211_regdom()); | 2319 | * We can trash what CRDA provided now. |
| 2184 | if (!intersected_rd) | 2320 | * However if a driver requested this specific regulatory |
| 2185 | return -EINVAL; | 2321 | * domain we keep it for its private use |
| 2322 | */ | ||
| 2323 | tmp = get_wiphy_regdom(request_wiphy); | ||
| 2324 | rcu_assign_pointer(request_wiphy->regd, rd); | ||
| 2325 | rcu_free_regdom(tmp); | ||
| 2186 | 2326 | ||
| 2187 | /* | 2327 | rd = NULL; |
| 2188 | * We can trash what CRDA provided now. | ||
| 2189 | * However if a driver requested this specific regulatory | ||
| 2190 | * domain we keep it for its private use | ||
| 2191 | */ | ||
| 2192 | if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER) { | ||
| 2193 | const struct ieee80211_regdomain *tmp; | ||
| 2194 | 2328 | ||
| 2195 | tmp = get_wiphy_regdom(request_wiphy); | 2329 | reset_regdomains(false, intersected_rd); |
| 2196 | rcu_assign_pointer(request_wiphy->regd, rd); | 2330 | |
| 2197 | rcu_free_regdom(tmp); | 2331 | return 0; |
| 2198 | } else { | 2332 | } |
| 2199 | kfree(rd); | ||
| 2200 | } | ||
| 2201 | 2333 | ||
| 2202 | rd = NULL; | 2334 | static int reg_set_rd_country_ie(const struct ieee80211_regdomain *rd, |
| 2335 | struct regulatory_request *country_ie_request) | ||
| 2336 | { | ||
| 2337 | struct wiphy *request_wiphy; | ||
| 2203 | 2338 | ||
| 2204 | reset_regdomains(false, intersected_rd); | 2339 | if (!is_alpha2_set(rd->alpha2) && !is_an_alpha2(rd->alpha2) && |
| 2340 | !is_unknown_alpha2(rd->alpha2)) | ||
| 2341 | return -EINVAL; | ||
| 2205 | 2342 | ||
| 2206 | return 0; | 2343 | /* |
| 2344 | * Lets only bother proceeding on the same alpha2 if the current | ||
| 2345 | * rd is non static (it means CRDA was present and was used last) | ||
| 2346 | * and the pending request came in from a country IE | ||
| 2347 | */ | ||
| 2348 | |||
| 2349 | if (!is_valid_rd(rd)) { | ||
| 2350 | pr_err("Invalid regulatory domain detected:\n"); | ||
| 2351 | print_regdomain_info(rd); | ||
| 2352 | return -EINVAL; | ||
| 2207 | } | 2353 | } |
| 2208 | 2354 | ||
| 2209 | return -EINVAL; | 2355 | request_wiphy = wiphy_idx_to_wiphy(country_ie_request->wiphy_idx); |
| 2210 | } | 2356 | if (!request_wiphy) { |
| 2357 | schedule_delayed_work(®_timeout, 0); | ||
| 2358 | return -ENODEV; | ||
| 2359 | } | ||
| 2360 | |||
| 2361 | if (country_ie_request->intersect) | ||
| 2362 | return -EINVAL; | ||
| 2211 | 2363 | ||
| 2364 | reset_regdomains(false, rd); | ||
| 2365 | return 0; | ||
| 2366 | } | ||
| 2212 | 2367 | ||
| 2213 | /* | 2368 | /* |
| 2214 | * Use this call to set the current regulatory domain. Conflicts with | 2369 | * Use this call to set the current regulatory domain. Conflicts with |
| @@ -2220,10 +2375,32 @@ int set_regdom(const struct ieee80211_regdomain *rd) | |||
| 2220 | struct regulatory_request *lr; | 2375 | struct regulatory_request *lr; |
| 2221 | int r; | 2376 | int r; |
| 2222 | 2377 | ||
| 2378 | if (!reg_is_valid_request(rd->alpha2)) { | ||
| 2379 | kfree(rd); | ||
| 2380 | return -EINVAL; | ||
| 2381 | } | ||
| 2382 | |||
| 2223 | lr = get_last_request(); | 2383 | lr = get_last_request(); |
| 2224 | 2384 | ||
| 2225 | /* Note that this doesn't update the wiphys, this is done below */ | 2385 | /* Note that this doesn't update the wiphys, this is done below */ |
| 2226 | r = __set_regdom(rd); | 2386 | switch (lr->initiator) { |
| 2387 | case NL80211_REGDOM_SET_BY_CORE: | ||
| 2388 | r = reg_set_rd_core(rd); | ||
| 2389 | break; | ||
| 2390 | case NL80211_REGDOM_SET_BY_USER: | ||
| 2391 | r = reg_set_rd_user(rd, lr); | ||
| 2392 | break; | ||
| 2393 | case NL80211_REGDOM_SET_BY_DRIVER: | ||
| 2394 | r = reg_set_rd_driver(rd, lr); | ||
| 2395 | break; | ||
| 2396 | case NL80211_REGDOM_SET_BY_COUNTRY_IE: | ||
| 2397 | r = reg_set_rd_country_ie(rd, lr); | ||
| 2398 | break; | ||
| 2399 | default: | ||
| 2400 | WARN(1, "invalid initiator %d\n", lr->initiator); | ||
| 2401 | return -EINVAL; | ||
| 2402 | } | ||
| 2403 | |||
| 2227 | if (r) { | 2404 | if (r) { |
| 2228 | if (r == -EALREADY) | 2405 | if (r == -EALREADY) |
| 2229 | reg_set_request_processed(); | 2406 | reg_set_request_processed(); |
diff --git a/net/wireless/reg.h b/net/wireless/reg.h index 9677e3c13da9..02bd8f4b0921 100644 --- a/net/wireless/reg.h +++ b/net/wireless/reg.h | |||
| @@ -18,8 +18,10 @@ | |||
| 18 | 18 | ||
| 19 | extern const struct ieee80211_regdomain __rcu *cfg80211_regdomain; | 19 | extern const struct ieee80211_regdomain __rcu *cfg80211_regdomain; |
| 20 | 20 | ||
| 21 | bool reg_is_valid_request(const char *alpha2); | ||
| 21 | bool is_world_regdom(const char *alpha2); | 22 | bool is_world_regdom(const char *alpha2); |
| 22 | bool reg_supported_dfs_region(u8 dfs_region); | 23 | bool reg_supported_dfs_region(enum nl80211_dfs_regions dfs_region); |
| 24 | enum nl80211_dfs_regions reg_get_dfs_region(struct wiphy *wiphy); | ||
| 23 | 25 | ||
| 24 | int regulatory_hint_user(const char *alpha2, | 26 | int regulatory_hint_user(const char *alpha2, |
| 25 | enum nl80211_user_reg_hint_type user_reg_hint_type); | 27 | enum nl80211_user_reg_hint_type user_reg_hint_type); |
diff --git a/net/wireless/scan.c b/net/wireless/scan.c index d4397eba5408..b528e31da2cf 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c | |||
| @@ -161,7 +161,7 @@ static void __cfg80211_bss_expire(struct cfg80211_registered_device *dev, | |||
| 161 | dev->bss_generation++; | 161 | dev->bss_generation++; |
| 162 | } | 162 | } |
| 163 | 163 | ||
| 164 | void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak) | 164 | void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev) |
| 165 | { | 165 | { |
| 166 | struct cfg80211_scan_request *request; | 166 | struct cfg80211_scan_request *request; |
| 167 | struct wireless_dev *wdev; | 167 | struct wireless_dev *wdev; |
| @@ -210,17 +210,7 @@ void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak) | |||
| 210 | dev_put(wdev->netdev); | 210 | dev_put(wdev->netdev); |
| 211 | 211 | ||
| 212 | rdev->scan_req = NULL; | 212 | rdev->scan_req = NULL; |
| 213 | 213 | kfree(request); | |
| 214 | /* | ||
| 215 | * OK. If this is invoked with "leak" then we can't | ||
| 216 | * free this ... but we've cleaned it up anyway. The | ||
| 217 | * driver failed to call the scan_done callback, so | ||
| 218 | * all bets are off, it might still be trying to use | ||
| 219 | * the scan request or not ... if it accesses the dev | ||
| 220 | * in there (it shouldn't anyway) then it may crash. | ||
| 221 | */ | ||
| 222 | if (!leak) | ||
| 223 | kfree(request); | ||
| 224 | } | 214 | } |
| 225 | 215 | ||
| 226 | void __cfg80211_scan_done(struct work_struct *wk) | 216 | void __cfg80211_scan_done(struct work_struct *wk) |
| @@ -231,7 +221,7 @@ void __cfg80211_scan_done(struct work_struct *wk) | |||
| 231 | scan_done_wk); | 221 | scan_done_wk); |
| 232 | 222 | ||
| 233 | rtnl_lock(); | 223 | rtnl_lock(); |
| 234 | ___cfg80211_scan_done(rdev, false); | 224 | ___cfg80211_scan_done(rdev); |
| 235 | rtnl_unlock(); | 225 | rtnl_unlock(); |
| 236 | } | 226 | } |
| 237 | 227 | ||
| @@ -1099,11 +1089,8 @@ int cfg80211_wext_siwscan(struct net_device *dev, | |||
| 1099 | /* Determine number of channels, needed to allocate creq */ | 1089 | /* Determine number of channels, needed to allocate creq */ |
| 1100 | if (wreq && wreq->num_channels) | 1090 | if (wreq && wreq->num_channels) |
| 1101 | n_channels = wreq->num_channels; | 1091 | n_channels = wreq->num_channels; |
| 1102 | else { | 1092 | else |
| 1103 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) | 1093 | n_channels = ieee80211_get_num_supported_channels(wiphy); |
| 1104 | if (wiphy->bands[band]) | ||
| 1105 | n_channels += wiphy->bands[band]->n_channels; | ||
| 1106 | } | ||
| 1107 | 1094 | ||
| 1108 | creq = kzalloc(sizeof(*creq) + sizeof(struct cfg80211_ssid) + | 1095 | creq = kzalloc(sizeof(*creq) + sizeof(struct cfg80211_ssid) + |
| 1109 | n_channels * sizeof(void *), | 1096 | n_channels * sizeof(void *), |
diff --git a/net/wireless/sme.c b/net/wireless/sme.c index d3c5bd7c6b51..a63509118508 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c | |||
| @@ -70,18 +70,11 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev) | |||
| 70 | if (rdev->scan_req) | 70 | if (rdev->scan_req) |
| 71 | return -EBUSY; | 71 | return -EBUSY; |
| 72 | 72 | ||
| 73 | if (wdev->conn->params.channel) { | 73 | if (wdev->conn->params.channel) |
| 74 | n_channels = 1; | 74 | n_channels = 1; |
| 75 | } else { | 75 | else |
| 76 | enum ieee80211_band band; | 76 | n_channels = ieee80211_get_num_supported_channels(wdev->wiphy); |
| 77 | n_channels = 0; | ||
| 78 | 77 | ||
| 79 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { | ||
| 80 | if (!wdev->wiphy->bands[band]) | ||
| 81 | continue; | ||
| 82 | n_channels += wdev->wiphy->bands[band]->n_channels; | ||
| 83 | } | ||
| 84 | } | ||
| 85 | request = kzalloc(sizeof(*request) + sizeof(request->ssids[0]) + | 78 | request = kzalloc(sizeof(*request) + sizeof(request->ssids[0]) + |
| 86 | sizeof(request->channels[0]) * n_channels, | 79 | sizeof(request->channels[0]) * n_channels, |
| 87 | GFP_KERNEL); | 80 | GFP_KERNEL); |
| @@ -872,6 +865,8 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie, | |||
| 872 | for (i = 0; i < 6; i++) | 865 | for (i = 0; i < 6; i++) |
| 873 | rdev_del_key(rdev, dev, i, false, NULL); | 866 | rdev_del_key(rdev, dev, i, false, NULL); |
| 874 | 867 | ||
| 868 | rdev_set_qos_map(rdev, dev, NULL); | ||
| 869 | |||
| 875 | #ifdef CONFIG_CFG80211_WEXT | 870 | #ifdef CONFIG_CFG80211_WEXT |
| 876 | memset(&wrqu, 0, sizeof(wrqu)); | 871 | memset(&wrqu, 0, sizeof(wrqu)); |
| 877 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; | 872 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; |
diff --git a/net/wireless/trace.h b/net/wireless/trace.h index ba5f0d6614d5..fbcc23edee54 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h | |||
| @@ -186,6 +186,28 @@ | |||
| 186 | 186 | ||
| 187 | #define BOOL_TO_STR(bo) (bo) ? "true" : "false" | 187 | #define BOOL_TO_STR(bo) (bo) ? "true" : "false" |
| 188 | 188 | ||
| 189 | #define QOS_MAP_ENTRY __field(u8, num_des) \ | ||
| 190 | __array(u8, dscp_exception, \ | ||
| 191 | 2 * IEEE80211_QOS_MAP_MAX_EX) \ | ||
| 192 | __array(u8, up, IEEE80211_QOS_MAP_LEN_MIN) | ||
| 193 | #define QOS_MAP_ASSIGN(qos_map) \ | ||
| 194 | do { \ | ||
| 195 | if ((qos_map)) { \ | ||
| 196 | __entry->num_des = (qos_map)->num_des; \ | ||
| 197 | memcpy(__entry->dscp_exception, \ | ||
| 198 | &(qos_map)->dscp_exception, \ | ||
| 199 | 2 * IEEE80211_QOS_MAP_MAX_EX); \ | ||
| 200 | memcpy(__entry->up, &(qos_map)->up, \ | ||
| 201 | IEEE80211_QOS_MAP_LEN_MIN); \ | ||
| 202 | } else { \ | ||
| 203 | __entry->num_des = 0; \ | ||
| 204 | memset(__entry->dscp_exception, 0, \ | ||
| 205 | 2 * IEEE80211_QOS_MAP_MAX_EX); \ | ||
| 206 | memset(__entry->up, 0, \ | ||
| 207 | IEEE80211_QOS_MAP_LEN_MIN); \ | ||
| 208 | } \ | ||
| 209 | } while (0) | ||
| 210 | |||
| 189 | /************************************************************* | 211 | /************************************************************* |
| 190 | * rdev->ops traces * | 212 | * rdev->ops traces * |
| 191 | *************************************************************/ | 213 | *************************************************************/ |
| @@ -1653,9 +1675,8 @@ TRACE_EVENT(rdev_cancel_remain_on_channel, | |||
| 1653 | 1675 | ||
| 1654 | TRACE_EVENT(rdev_mgmt_tx, | 1676 | TRACE_EVENT(rdev_mgmt_tx, |
| 1655 | TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev, | 1677 | TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev, |
| 1656 | struct ieee80211_channel *chan, bool offchan, | 1678 | struct cfg80211_mgmt_tx_params *params), |
| 1657 | unsigned int wait, bool no_cck, bool dont_wait_for_ack), | 1679 | TP_ARGS(wiphy, wdev, params), |
| 1658 | TP_ARGS(wiphy, wdev, chan, offchan, wait, no_cck, dont_wait_for_ack), | ||
| 1659 | TP_STRUCT__entry( | 1680 | TP_STRUCT__entry( |
| 1660 | WIPHY_ENTRY | 1681 | WIPHY_ENTRY |
| 1661 | WDEV_ENTRY | 1682 | WDEV_ENTRY |
| @@ -1668,11 +1689,11 @@ TRACE_EVENT(rdev_mgmt_tx, | |||
| 1668 | TP_fast_assign( | 1689 | TP_fast_assign( |
| 1669 | WIPHY_ASSIGN; | 1690 | WIPHY_ASSIGN; |
| 1670 | WDEV_ASSIGN; | 1691 | WDEV_ASSIGN; |
| 1671 | CHAN_ASSIGN(chan); | 1692 | CHAN_ASSIGN(params->chan); |
| 1672 | __entry->offchan = offchan; | 1693 | __entry->offchan = params->offchan; |
| 1673 | __entry->wait = wait; | 1694 | __entry->wait = params->wait; |
| 1674 | __entry->no_cck = no_cck; | 1695 | __entry->no_cck = params->no_cck; |
| 1675 | __entry->dont_wait_for_ack = dont_wait_for_ack; | 1696 | __entry->dont_wait_for_ack = params->dont_wait_for_ack; |
| 1676 | ), | 1697 | ), |
| 1677 | TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT ", " CHAN_PR_FMT ", offchan: %s," | 1698 | TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT ", " CHAN_PR_FMT ", offchan: %s," |
| 1678 | " wait: %u, no cck: %s, dont wait for ack: %s", | 1699 | " wait: %u, no cck: %s, dont wait for ack: %s", |
| @@ -1876,6 +1897,24 @@ TRACE_EVENT(rdev_channel_switch, | |||
| 1876 | __entry->counter_offset_presp) | 1897 | __entry->counter_offset_presp) |
| 1877 | ); | 1898 | ); |
| 1878 | 1899 | ||
| 1900 | TRACE_EVENT(rdev_set_qos_map, | ||
| 1901 | TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, | ||
| 1902 | struct cfg80211_qos_map *qos_map), | ||
| 1903 | TP_ARGS(wiphy, netdev, qos_map), | ||
| 1904 | TP_STRUCT__entry( | ||
| 1905 | WIPHY_ENTRY | ||
| 1906 | NETDEV_ENTRY | ||
| 1907 | QOS_MAP_ENTRY | ||
| 1908 | ), | ||
| 1909 | TP_fast_assign( | ||
| 1910 | WIPHY_ASSIGN; | ||
| 1911 | NETDEV_ASSIGN; | ||
| 1912 | QOS_MAP_ASSIGN(qos_map); | ||
| 1913 | ), | ||
| 1914 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", num_des: %u", | ||
| 1915 | WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->num_des) | ||
| 1916 | ); | ||
| 1917 | |||
| 1879 | /************************************************************* | 1918 | /************************************************************* |
| 1880 | * cfg80211 exported functions traces * | 1919 | * cfg80211 exported functions traces * |
| 1881 | *************************************************************/ | 1920 | *************************************************************/ |
diff --git a/net/wireless/util.c b/net/wireless/util.c index 935dea9485da..d39c37104ae2 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c | |||
| @@ -689,7 +689,8 @@ void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list, | |||
| 689 | EXPORT_SYMBOL(ieee80211_amsdu_to_8023s); | 689 | EXPORT_SYMBOL(ieee80211_amsdu_to_8023s); |
| 690 | 690 | ||
| 691 | /* Given a data frame determine the 802.1p/1d tag to use. */ | 691 | /* Given a data frame determine the 802.1p/1d tag to use. */ |
| 692 | unsigned int cfg80211_classify8021d(struct sk_buff *skb) | 692 | unsigned int cfg80211_classify8021d(struct sk_buff *skb, |
| 693 | struct cfg80211_qos_map *qos_map) | ||
| 693 | { | 694 | { |
| 694 | unsigned int dscp; | 695 | unsigned int dscp; |
| 695 | unsigned char vlan_priority; | 696 | unsigned char vlan_priority; |
| @@ -720,6 +721,21 @@ unsigned int cfg80211_classify8021d(struct sk_buff *skb) | |||
| 720 | return 0; | 721 | return 0; |
| 721 | } | 722 | } |
| 722 | 723 | ||
| 724 | if (qos_map) { | ||
| 725 | unsigned int i, tmp_dscp = dscp >> 2; | ||
| 726 | |||
| 727 | for (i = 0; i < qos_map->num_des; i++) { | ||
| 728 | if (tmp_dscp == qos_map->dscp_exception[i].dscp) | ||
| 729 | return qos_map->dscp_exception[i].up; | ||
| 730 | } | ||
| 731 | |||
| 732 | for (i = 0; i < 8; i++) { | ||
| 733 | if (tmp_dscp >= qos_map->up[i].low && | ||
| 734 | tmp_dscp <= qos_map->up[i].high) | ||
| 735 | return i; | ||
| 736 | } | ||
| 737 | } | ||
| 738 | |||
| 723 | return dscp >> 5; | 739 | return dscp >> 5; |
| 724 | } | 740 | } |
| 725 | EXPORT_SYMBOL(cfg80211_classify8021d); | 741 | EXPORT_SYMBOL(cfg80211_classify8021d); |
| @@ -863,6 +879,9 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, | |||
| 863 | 879 | ||
| 864 | dev->ieee80211_ptr->use_4addr = false; | 880 | dev->ieee80211_ptr->use_4addr = false; |
| 865 | dev->ieee80211_ptr->mesh_id_up_len = 0; | 881 | dev->ieee80211_ptr->mesh_id_up_len = 0; |
| 882 | wdev_lock(dev->ieee80211_ptr); | ||
| 883 | rdev_set_qos_map(rdev, dev, NULL); | ||
| 884 | wdev_unlock(dev->ieee80211_ptr); | ||
| 866 | 885 | ||
| 867 | switch (otype) { | 886 | switch (otype) { |
| 868 | case NL80211_IFTYPE_AP: | 887 | case NL80211_IFTYPE_AP: |
| @@ -1462,6 +1481,19 @@ int ieee80211_get_ratemask(struct ieee80211_supported_band *sband, | |||
| 1462 | return 0; | 1481 | return 0; |
| 1463 | } | 1482 | } |
| 1464 | 1483 | ||
| 1484 | unsigned int ieee80211_get_num_supported_channels(struct wiphy *wiphy) | ||
| 1485 | { | ||
| 1486 | enum ieee80211_band band; | ||
| 1487 | unsigned int n_channels = 0; | ||
| 1488 | |||
| 1489 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) | ||
| 1490 | if (wiphy->bands[band]) | ||
| 1491 | n_channels += wiphy->bands[band]->n_channels; | ||
| 1492 | |||
| 1493 | return n_channels; | ||
| 1494 | } | ||
| 1495 | EXPORT_SYMBOL(ieee80211_get_num_supported_channels); | ||
| 1496 | |||
| 1465 | /* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */ | 1497 | /* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */ |
| 1466 | /* Ethernet-II snap header (RFC1042 for most EtherTypes) */ | 1498 | /* Ethernet-II snap header (RFC1042 for most EtherTypes) */ |
| 1467 | const unsigned char rfc1042_header[] __aligned(2) = | 1499 | const unsigned char rfc1042_header[] __aligned(2) = |
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index e7c6e862580d..5661a54ac7ee 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c | |||
| @@ -370,7 +370,7 @@ static int cfg80211_wext_siwretry(struct net_device *dev, | |||
| 370 | u8 oshort = wdev->wiphy->retry_short; | 370 | u8 oshort = wdev->wiphy->retry_short; |
| 371 | int err; | 371 | int err; |
| 372 | 372 | ||
| 373 | if (retry->disabled || | 373 | if (retry->disabled || retry->value < 1 || retry->value > 255 || |
| 374 | (retry->flags & IW_RETRY_TYPE) != IW_RETRY_LIMIT) | 374 | (retry->flags & IW_RETRY_TYPE) != IW_RETRY_LIMIT) |
| 375 | return -EINVAL; | 375 | return -EINVAL; |
| 376 | 376 | ||
| @@ -412,9 +412,9 @@ int cfg80211_wext_giwretry(struct net_device *dev, | |||
| 412 | * First return short value, iwconfig will ask long value | 412 | * First return short value, iwconfig will ask long value |
| 413 | * later if needed | 413 | * later if needed |
| 414 | */ | 414 | */ |
| 415 | retry->flags |= IW_RETRY_LIMIT; | 415 | retry->flags |= IW_RETRY_LIMIT | IW_RETRY_SHORT; |
| 416 | retry->value = wdev->wiphy->retry_short; | 416 | retry->value = wdev->wiphy->retry_short; |
| 417 | if (wdev->wiphy->retry_long != wdev->wiphy->retry_short) | 417 | if (wdev->wiphy->retry_long == wdev->wiphy->retry_short) |
| 418 | retry->flags |= IW_RETRY_LONG; | 418 | retry->flags |= IW_RETRY_LONG; |
| 419 | 419 | ||
| 420 | return 0; | 420 | return 0; |
diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c index 7622789d3750..6177479c7de9 100644 --- a/net/x25/af_x25.c +++ b/net/x25/af_x25.c | |||
| @@ -35,6 +35,8 @@ | |||
| 35 | * response | 35 | * response |
| 36 | */ | 36 | */ |
| 37 | 37 | ||
| 38 | #define pr_fmt(fmt) "X25: " fmt | ||
| 39 | |||
| 38 | #include <linux/module.h> | 40 | #include <linux/module.h> |
| 39 | #include <linux/capability.h> | 41 | #include <linux/capability.h> |
| 40 | #include <linux/errno.h> | 42 | #include <linux/errno.h> |
| @@ -1080,7 +1082,7 @@ static int x25_sendmsg(struct kiocb *iocb, struct socket *sock, | |||
| 1080 | { | 1082 | { |
| 1081 | struct sock *sk = sock->sk; | 1083 | struct sock *sk = sock->sk; |
| 1082 | struct x25_sock *x25 = x25_sk(sk); | 1084 | struct x25_sock *x25 = x25_sk(sk); |
| 1083 | struct sockaddr_x25 *usx25 = (struct sockaddr_x25 *)msg->msg_name; | 1085 | DECLARE_SOCKADDR(struct sockaddr_x25 *, usx25, msg->msg_name); |
| 1084 | struct sockaddr_x25 sx25; | 1086 | struct sockaddr_x25 sx25; |
| 1085 | struct sk_buff *skb; | 1087 | struct sk_buff *skb; |
| 1086 | unsigned char *asmptr; | 1088 | unsigned char *asmptr; |
| @@ -1256,7 +1258,7 @@ static int x25_recvmsg(struct kiocb *iocb, struct socket *sock, | |||
| 1256 | { | 1258 | { |
| 1257 | struct sock *sk = sock->sk; | 1259 | struct sock *sk = sock->sk; |
| 1258 | struct x25_sock *x25 = x25_sk(sk); | 1260 | struct x25_sock *x25 = x25_sk(sk); |
| 1259 | struct sockaddr_x25 *sx25 = (struct sockaddr_x25 *)msg->msg_name; | 1261 | DECLARE_SOCKADDR(struct sockaddr_x25 *, sx25, msg->msg_name); |
| 1260 | size_t copied; | 1262 | size_t copied; |
| 1261 | int qbit, header_len; | 1263 | int qbit, header_len; |
| 1262 | struct sk_buff *skb; | 1264 | struct sk_buff *skb; |
| @@ -1809,7 +1811,7 @@ static int __init x25_init(void) | |||
| 1809 | if (rc != 0) | 1811 | if (rc != 0) |
| 1810 | goto out_sock; | 1812 | goto out_sock; |
| 1811 | 1813 | ||
| 1812 | printk(KERN_INFO "X.25 for Linux Version 0.2\n"); | 1814 | pr_info("Linux Version 0.2\n"); |
| 1813 | 1815 | ||
| 1814 | x25_register_sysctl(); | 1816 | x25_register_sysctl(); |
| 1815 | rc = x25_proc_init(); | 1817 | rc = x25_proc_init(); |
diff --git a/net/x25/x25_dev.c b/net/x25/x25_dev.c index a8a236338e61..39231237e1c3 100644 --- a/net/x25/x25_dev.c +++ b/net/x25/x25_dev.c | |||
| @@ -17,6 +17,8 @@ | |||
| 17 | * 2000-09-04 Henner Eisen Prevent freeing a dangling skb. | 17 | * 2000-09-04 Henner Eisen Prevent freeing a dangling skb. |
| 18 | */ | 18 | */ |
| 19 | 19 | ||
| 20 | #define pr_fmt(fmt) "X25: " fmt | ||
| 21 | |||
| 20 | #include <linux/kernel.h> | 22 | #include <linux/kernel.h> |
| 21 | #include <linux/netdevice.h> | 23 | #include <linux/netdevice.h> |
| 22 | #include <linux/skbuff.h> | 24 | #include <linux/skbuff.h> |
| @@ -89,7 +91,7 @@ static int x25_receive_data(struct sk_buff *skb, struct x25_neigh *nb) | |||
| 89 | */ | 91 | */ |
| 90 | 92 | ||
| 91 | if (frametype != X25_CLEAR_CONFIRMATION) | 93 | if (frametype != X25_CLEAR_CONFIRMATION) |
| 92 | printk(KERN_DEBUG "x25_receive_data(): unknown frame type %2x\n",frametype); | 94 | pr_debug("x25_receive_data(): unknown frame type %2x\n",frametype); |
| 93 | 95 | ||
| 94 | return 0; | 96 | return 0; |
| 95 | } | 97 | } |
| @@ -114,7 +116,7 @@ int x25_lapb_receive_frame(struct sk_buff *skb, struct net_device *dev, | |||
| 114 | */ | 116 | */ |
| 115 | nb = x25_get_neigh(dev); | 117 | nb = x25_get_neigh(dev); |
| 116 | if (!nb) { | 118 | if (!nb) { |
| 117 | printk(KERN_DEBUG "X.25: unknown neighbour - %s\n", dev->name); | 119 | pr_debug("unknown neighbour - %s\n", dev->name); |
| 118 | goto drop; | 120 | goto drop; |
| 119 | } | 121 | } |
| 120 | 122 | ||
| @@ -154,7 +156,7 @@ void x25_establish_link(struct x25_neigh *nb) | |||
| 154 | switch (nb->dev->type) { | 156 | switch (nb->dev->type) { |
| 155 | case ARPHRD_X25: | 157 | case ARPHRD_X25: |
| 156 | if ((skb = alloc_skb(1, GFP_ATOMIC)) == NULL) { | 158 | if ((skb = alloc_skb(1, GFP_ATOMIC)) == NULL) { |
| 157 | printk(KERN_ERR "x25_dev: out of memory\n"); | 159 | pr_err("x25_dev: out of memory\n"); |
| 158 | return; | 160 | return; |
| 159 | } | 161 | } |
| 160 | ptr = skb_put(skb, 1); | 162 | ptr = skb_put(skb, 1); |
| @@ -189,7 +191,7 @@ void x25_terminate_link(struct x25_neigh *nb) | |||
| 189 | 191 | ||
| 190 | skb = alloc_skb(1, GFP_ATOMIC); | 192 | skb = alloc_skb(1, GFP_ATOMIC); |
| 191 | if (!skb) { | 193 | if (!skb) { |
| 192 | printk(KERN_ERR "x25_dev: out of memory\n"); | 194 | pr_err("x25_dev: out of memory\n"); |
| 193 | return; | 195 | return; |
| 194 | } | 196 | } |
| 195 | 197 | ||
diff --git a/net/x25/x25_facilities.c b/net/x25/x25_facilities.c index b8253250d723..7ecd04c21360 100644 --- a/net/x25/x25_facilities.c +++ b/net/x25/x25_facilities.c | |||
| @@ -21,6 +21,8 @@ | |||
| 21 | * on response. | 21 | * on response. |
| 22 | */ | 22 | */ |
| 23 | 23 | ||
| 24 | #define pr_fmt(fmt) "X25: " fmt | ||
| 25 | |||
| 24 | #include <linux/kernel.h> | 26 | #include <linux/kernel.h> |
| 25 | #include <linux/string.h> | 27 | #include <linux/string.h> |
| 26 | #include <linux/skbuff.h> | 28 | #include <linux/skbuff.h> |
| @@ -109,7 +111,7 @@ int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities, | |||
| 109 | case X25_MARKER: | 111 | case X25_MARKER: |
| 110 | break; | 112 | break; |
| 111 | default: | 113 | default: |
| 112 | printk(KERN_DEBUG "X.25: unknown facility " | 114 | pr_debug("unknown facility " |
| 113 | "%02X, value %02X\n", | 115 | "%02X, value %02X\n", |
| 114 | p[0], p[1]); | 116 | p[0], p[1]); |
| 115 | break; | 117 | break; |
| @@ -132,7 +134,7 @@ int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities, | |||
| 132 | *vc_fac_mask |= X25_MASK_WINDOW_SIZE; | 134 | *vc_fac_mask |= X25_MASK_WINDOW_SIZE; |
| 133 | break; | 135 | break; |
| 134 | default: | 136 | default: |
| 135 | printk(KERN_DEBUG "X.25: unknown facility " | 137 | pr_debug("unknown facility " |
| 136 | "%02X, values %02X, %02X\n", | 138 | "%02X, values %02X, %02X\n", |
| 137 | p[0], p[1], p[2]); | 139 | p[0], p[1], p[2]); |
| 138 | break; | 140 | break; |
| @@ -143,7 +145,7 @@ int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities, | |||
| 143 | case X25_FAC_CLASS_C: | 145 | case X25_FAC_CLASS_C: |
| 144 | if (len < 4) | 146 | if (len < 4) |
| 145 | return -1; | 147 | return -1; |
| 146 | printk(KERN_DEBUG "X.25: unknown facility %02X, " | 148 | pr_debug("unknown facility %02X, " |
| 147 | "values %02X, %02X, %02X\n", | 149 | "values %02X, %02X, %02X\n", |
| 148 | p[0], p[1], p[2], p[3]); | 150 | p[0], p[1], p[2], p[3]); |
| 149 | p += 4; | 151 | p += 4; |
| @@ -172,7 +174,7 @@ int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities, | |||
| 172 | *vc_fac_mask |= X25_MASK_CALLED_AE; | 174 | *vc_fac_mask |= X25_MASK_CALLED_AE; |
| 173 | break; | 175 | break; |
| 174 | default: | 176 | default: |
| 175 | printk(KERN_DEBUG "X.25: unknown facility %02X," | 177 | pr_debug("unknown facility %02X," |
| 176 | "length %d\n", p[0], p[1]); | 178 | "length %d\n", p[0], p[1]); |
| 177 | break; | 179 | break; |
| 178 | } | 180 | } |
| @@ -341,12 +343,12 @@ void x25_limit_facilities(struct x25_facilities *facilities, | |||
| 341 | 343 | ||
| 342 | if (!nb->extended) { | 344 | if (!nb->extended) { |
| 343 | if (facilities->winsize_in > 7) { | 345 | if (facilities->winsize_in > 7) { |
| 344 | printk(KERN_DEBUG "X.25: incoming winsize limited to 7\n"); | 346 | pr_debug("incoming winsize limited to 7\n"); |
| 345 | facilities->winsize_in = 7; | 347 | facilities->winsize_in = 7; |
| 346 | } | 348 | } |
| 347 | if (facilities->winsize_out > 7) { | 349 | if (facilities->winsize_out > 7) { |
| 348 | facilities->winsize_out = 7; | 350 | facilities->winsize_out = 7; |
| 349 | printk( KERN_DEBUG "X.25: outgoing winsize limited to 7\n"); | 351 | pr_debug("outgoing winsize limited to 7\n"); |
| 350 | } | 352 | } |
| 351 | } | 353 | } |
| 352 | } | 354 | } |
diff --git a/net/x25/x25_forward.c b/net/x25/x25_forward.c index c541b622ae16..cf561f1613e1 100644 --- a/net/x25/x25_forward.c +++ b/net/x25/x25_forward.c | |||
| @@ -8,6 +8,9 @@ | |||
| 8 | * History | 8 | * History |
| 9 | * 03-01-2007 Added forwarding for x.25 Andrew Hendry | 9 | * 03-01-2007 Added forwarding for x.25 Andrew Hendry |
| 10 | */ | 10 | */ |
| 11 | |||
| 12 | #define pr_fmt(fmt) "X25: " fmt | ||
| 13 | |||
| 11 | #include <linux/if_arp.h> | 14 | #include <linux/if_arp.h> |
| 12 | #include <linux/init.h> | 15 | #include <linux/init.h> |
| 13 | #include <linux/slab.h> | 16 | #include <linux/slab.h> |
| @@ -51,7 +54,7 @@ int x25_forward_call(struct x25_address *dest_addr, struct x25_neigh *from, | |||
| 51 | list_for_each(entry, &x25_forward_list) { | 54 | list_for_each(entry, &x25_forward_list) { |
| 52 | x25_frwd = list_entry(entry, struct x25_forward, node); | 55 | x25_frwd = list_entry(entry, struct x25_forward, node); |
| 53 | if (x25_frwd->lci == lci) { | 56 | if (x25_frwd->lci == lci) { |
| 54 | printk(KERN_WARNING "X.25: call request for lci which is already registered!, transmitting but not registering new pair\n"); | 57 | pr_warn("call request for lci which is already registered!, transmitting but not registering new pair\n"); |
| 55 | same_lci = 1; | 58 | same_lci = 1; |
| 56 | } | 59 | } |
| 57 | } | 60 | } |
diff --git a/net/x25/x25_in.c b/net/x25/x25_in.c index a49cd4ec551a..d1b0dc79bb6f 100644 --- a/net/x25/x25_in.c +++ b/net/x25/x25_in.c | |||
| @@ -23,6 +23,8 @@ | |||
| 23 | * i-frames. | 23 | * i-frames. |
| 24 | */ | 24 | */ |
| 25 | 25 | ||
| 26 | #define pr_fmt(fmt) "X25: " fmt | ||
| 27 | |||
| 26 | #include <linux/slab.h> | 28 | #include <linux/slab.h> |
| 27 | #include <linux/errno.h> | 29 | #include <linux/errno.h> |
| 28 | #include <linux/kernel.h> | 30 | #include <linux/kernel.h> |
| @@ -317,7 +319,7 @@ static int x25_state3_machine(struct sock *sk, struct sk_buff *skb, int frametyp | |||
| 317 | break; | 319 | break; |
| 318 | 320 | ||
| 319 | default: | 321 | default: |
| 320 | printk(KERN_WARNING "x25: unknown %02X in state 3\n", frametype); | 322 | pr_warn("unknown %02X in state 3\n", frametype); |
| 321 | break; | 323 | break; |
| 322 | } | 324 | } |
| 323 | 325 | ||
diff --git a/net/x25/x25_link.c b/net/x25/x25_link.c index 4acacf3c6617..fd5ffb25873f 100644 --- a/net/x25/x25_link.c +++ b/net/x25/x25_link.c | |||
| @@ -21,6 +21,8 @@ | |||
| 21 | * 2000-09-04 Henner Eisen dev_hold() / dev_put() for x25_neigh. | 21 | * 2000-09-04 Henner Eisen dev_hold() / dev_put() for x25_neigh. |
| 22 | */ | 22 | */ |
| 23 | 23 | ||
| 24 | #define pr_fmt(fmt) "X25: " fmt | ||
| 25 | |||
| 24 | #include <linux/kernel.h> | 26 | #include <linux/kernel.h> |
| 25 | #include <linux/jiffies.h> | 27 | #include <linux/jiffies.h> |
| 26 | #include <linux/timer.h> | 28 | #include <linux/timer.h> |
| @@ -93,13 +95,13 @@ void x25_link_control(struct sk_buff *skb, struct x25_neigh *nb, | |||
| 93 | if (!pskb_may_pull(skb, X25_STD_MIN_LEN + 4)) | 95 | if (!pskb_may_pull(skb, X25_STD_MIN_LEN + 4)) |
| 94 | break; | 96 | break; |
| 95 | 97 | ||
| 96 | printk(KERN_WARNING "x25: diagnostic #%d - %02X %02X %02X\n", | 98 | pr_warn("diagnostic #%d - %02X %02X %02X\n", |
| 97 | skb->data[3], skb->data[4], | 99 | skb->data[3], skb->data[4], |
| 98 | skb->data[5], skb->data[6]); | 100 | skb->data[5], skb->data[6]); |
| 99 | break; | 101 | break; |
| 100 | 102 | ||
| 101 | default: | 103 | default: |
| 102 | printk(KERN_WARNING "x25: received unknown %02X with LCI 000\n", | 104 | pr_warn("received unknown %02X with LCI 000\n", |
| 103 | frametype); | 105 | frametype); |
| 104 | break; | 106 | break; |
| 105 | } | 107 | } |
diff --git a/net/x25/x25_subr.c b/net/x25/x25_subr.c index 5170d52bfd96..6b5af65f491f 100644 --- a/net/x25/x25_subr.c +++ b/net/x25/x25_subr.c | |||
| @@ -23,6 +23,8 @@ | |||
| 23 | * restriction on response. | 23 | * restriction on response. |
| 24 | */ | 24 | */ |
| 25 | 25 | ||
| 26 | #define pr_fmt(fmt) "X25: " fmt | ||
| 27 | |||
| 26 | #include <linux/slab.h> | 28 | #include <linux/slab.h> |
| 27 | #include <linux/kernel.h> | 29 | #include <linux/kernel.h> |
| 28 | #include <linux/string.h> | 30 | #include <linux/string.h> |
| @@ -148,7 +150,7 @@ void x25_write_internal(struct sock *sk, int frametype) | |||
| 148 | case X25_RESET_CONFIRMATION: | 150 | case X25_RESET_CONFIRMATION: |
| 149 | break; | 151 | break; |
| 150 | default: | 152 | default: |
| 151 | printk(KERN_ERR "X.25: invalid frame type %02X\n", frametype); | 153 | pr_err("invalid frame type %02X\n", frametype); |
| 152 | return; | 154 | return; |
| 153 | } | 155 | } |
| 154 | 156 | ||
| @@ -338,7 +340,7 @@ int x25_decode(struct sock *sk, struct sk_buff *skb, int *ns, int *nr, int *q, | |||
| 338 | } | 340 | } |
| 339 | } | 341 | } |
| 340 | 342 | ||
| 341 | printk(KERN_DEBUG "X.25: invalid PLP frame %02X %02X %02X\n", | 343 | pr_debug("invalid PLP frame %02X %02X %02X\n", |
| 342 | frame[0], frame[1], frame[2]); | 344 | frame[0], frame[1], frame[2]); |
| 343 | 345 | ||
| 344 | return X25_ILLEGAL; | 346 | return X25_ILLEGAL; |
diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c index 88843996f935..6c7ac016ce3a 100644 --- a/net/xfrm/xfrm_input.c +++ b/net/xfrm/xfrm_input.c | |||
| @@ -67,7 +67,7 @@ int xfrm_parse_spi(struct sk_buff *skb, u8 nexthdr, __be32 *spi, __be32 *seq) | |||
| 67 | case IPPROTO_COMP: | 67 | case IPPROTO_COMP: |
| 68 | if (!pskb_may_pull(skb, sizeof(struct ip_comp_hdr))) | 68 | if (!pskb_may_pull(skb, sizeof(struct ip_comp_hdr))) |
| 69 | return -EINVAL; | 69 | return -EINVAL; |
| 70 | *spi = htonl(ntohs(*(__be16*)(skb_transport_header(skb) + 2))); | 70 | *spi = htonl(ntohs(*(__be16 *)(skb_transport_header(skb) + 2))); |
| 71 | *seq = 0; | 71 | *seq = 0; |
| 72 | return 0; | 72 | return 0; |
| 73 | default: | 73 | default: |
| @@ -77,8 +77,8 @@ int xfrm_parse_spi(struct sk_buff *skb, u8 nexthdr, __be32 *spi, __be32 *seq) | |||
| 77 | if (!pskb_may_pull(skb, hlen)) | 77 | if (!pskb_may_pull(skb, hlen)) |
| 78 | return -EINVAL; | 78 | return -EINVAL; |
| 79 | 79 | ||
| 80 | *spi = *(__be32*)(skb_transport_header(skb) + offset); | 80 | *spi = *(__be32 *)(skb_transport_header(skb) + offset); |
| 81 | *seq = *(__be32*)(skb_transport_header(skb) + offset_seq); | 81 | *seq = *(__be32 *)(skb_transport_header(skb) + offset_seq); |
| 82 | return 0; | 82 | return 0; |
| 83 | } | 83 | } |
| 84 | 84 | ||
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 9a91f7431c41..4b98b25793c5 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c | |||
| @@ -39,12 +39,7 @@ | |||
| 39 | #define XFRM_QUEUE_TMO_MAX ((unsigned)(60*HZ)) | 39 | #define XFRM_QUEUE_TMO_MAX ((unsigned)(60*HZ)) |
| 40 | #define XFRM_MAX_QUEUE_LEN 100 | 40 | #define XFRM_MAX_QUEUE_LEN 100 |
| 41 | 41 | ||
| 42 | DEFINE_MUTEX(xfrm_cfg_mutex); | ||
| 43 | EXPORT_SYMBOL(xfrm_cfg_mutex); | ||
| 44 | |||
| 45 | static DEFINE_SPINLOCK(xfrm_policy_sk_bundle_lock); | ||
| 46 | static struct dst_entry *xfrm_policy_sk_bundles; | 42 | static struct dst_entry *xfrm_policy_sk_bundles; |
| 47 | static DEFINE_RWLOCK(xfrm_policy_lock); | ||
| 48 | 43 | ||
| 49 | static DEFINE_SPINLOCK(xfrm_policy_afinfo_lock); | 44 | static DEFINE_SPINLOCK(xfrm_policy_afinfo_lock); |
| 50 | static struct xfrm_policy_afinfo __rcu *xfrm_policy_afinfo[NPROTO] | 45 | static struct xfrm_policy_afinfo __rcu *xfrm_policy_afinfo[NPROTO] |
| @@ -176,7 +171,7 @@ static inline unsigned long make_jiffies(long secs) | |||
| 176 | 171 | ||
| 177 | static void xfrm_policy_timer(unsigned long data) | 172 | static void xfrm_policy_timer(unsigned long data) |
| 178 | { | 173 | { |
| 179 | struct xfrm_policy *xp = (struct xfrm_policy*)data; | 174 | struct xfrm_policy *xp = (struct xfrm_policy *)data; |
| 180 | unsigned long now = get_seconds(); | 175 | unsigned long now = get_seconds(); |
| 181 | long next = LONG_MAX; | 176 | long next = LONG_MAX; |
| 182 | int warn = 0; | 177 | int warn = 0; |
| @@ -438,7 +433,7 @@ static void xfrm_bydst_resize(struct net *net, int dir) | |||
| 438 | if (!ndst) | 433 | if (!ndst) |
| 439 | return; | 434 | return; |
| 440 | 435 | ||
| 441 | write_lock_bh(&xfrm_policy_lock); | 436 | write_lock_bh(&net->xfrm.xfrm_policy_lock); |
| 442 | 437 | ||
| 443 | for (i = hmask; i >= 0; i--) | 438 | for (i = hmask; i >= 0; i--) |
| 444 | xfrm_dst_hash_transfer(odst + i, ndst, nhashmask); | 439 | xfrm_dst_hash_transfer(odst + i, ndst, nhashmask); |
| @@ -446,7 +441,7 @@ static void xfrm_bydst_resize(struct net *net, int dir) | |||
| 446 | net->xfrm.policy_bydst[dir].table = ndst; | 441 | net->xfrm.policy_bydst[dir].table = ndst; |
| 447 | net->xfrm.policy_bydst[dir].hmask = nhashmask; | 442 | net->xfrm.policy_bydst[dir].hmask = nhashmask; |
| 448 | 443 | ||
| 449 | write_unlock_bh(&xfrm_policy_lock); | 444 | write_unlock_bh(&net->xfrm.xfrm_policy_lock); |
| 450 | 445 | ||
| 451 | xfrm_hash_free(odst, (hmask + 1) * sizeof(struct hlist_head)); | 446 | xfrm_hash_free(odst, (hmask + 1) * sizeof(struct hlist_head)); |
| 452 | } | 447 | } |
| @@ -463,7 +458,7 @@ static void xfrm_byidx_resize(struct net *net, int total) | |||
| 463 | if (!nidx) | 458 | if (!nidx) |
| 464 | return; | 459 | return; |
| 465 | 460 | ||
| 466 | write_lock_bh(&xfrm_policy_lock); | 461 | write_lock_bh(&net->xfrm.xfrm_policy_lock); |
| 467 | 462 | ||
| 468 | for (i = hmask; i >= 0; i--) | 463 | for (i = hmask; i >= 0; i--) |
| 469 | xfrm_idx_hash_transfer(oidx + i, nidx, nhashmask); | 464 | xfrm_idx_hash_transfer(oidx + i, nidx, nhashmask); |
| @@ -471,7 +466,7 @@ static void xfrm_byidx_resize(struct net *net, int total) | |||
| 471 | net->xfrm.policy_byidx = nidx; | 466 | net->xfrm.policy_byidx = nidx; |
| 472 | net->xfrm.policy_idx_hmask = nhashmask; | 467 | net->xfrm.policy_idx_hmask = nhashmask; |
| 473 | 468 | ||
| 474 | write_unlock_bh(&xfrm_policy_lock); | 469 | write_unlock_bh(&net->xfrm.xfrm_policy_lock); |
| 475 | 470 | ||
| 476 | xfrm_hash_free(oidx, (hmask + 1) * sizeof(struct hlist_head)); | 471 | xfrm_hash_free(oidx, (hmask + 1) * sizeof(struct hlist_head)); |
| 477 | } | 472 | } |
| @@ -504,7 +499,7 @@ static inline int xfrm_byidx_should_resize(struct net *net, int total) | |||
| 504 | 499 | ||
| 505 | void xfrm_spd_getinfo(struct net *net, struct xfrmk_spdinfo *si) | 500 | void xfrm_spd_getinfo(struct net *net, struct xfrmk_spdinfo *si) |
| 506 | { | 501 | { |
| 507 | read_lock_bh(&xfrm_policy_lock); | 502 | read_lock_bh(&net->xfrm.xfrm_policy_lock); |
| 508 | si->incnt = net->xfrm.policy_count[XFRM_POLICY_IN]; | 503 | si->incnt = net->xfrm.policy_count[XFRM_POLICY_IN]; |
| 509 | si->outcnt = net->xfrm.policy_count[XFRM_POLICY_OUT]; | 504 | si->outcnt = net->xfrm.policy_count[XFRM_POLICY_OUT]; |
| 510 | si->fwdcnt = net->xfrm.policy_count[XFRM_POLICY_FWD]; | 505 | si->fwdcnt = net->xfrm.policy_count[XFRM_POLICY_FWD]; |
| @@ -513,7 +508,7 @@ void xfrm_spd_getinfo(struct net *net, struct xfrmk_spdinfo *si) | |||
| 513 | si->fwdscnt = net->xfrm.policy_count[XFRM_POLICY_FWD+XFRM_POLICY_MAX]; | 508 | si->fwdscnt = net->xfrm.policy_count[XFRM_POLICY_FWD+XFRM_POLICY_MAX]; |
| 514 | si->spdhcnt = net->xfrm.policy_idx_hmask; | 509 | si->spdhcnt = net->xfrm.policy_idx_hmask; |
| 515 | si->spdhmcnt = xfrm_policy_hashmax; | 510 | si->spdhmcnt = xfrm_policy_hashmax; |
| 516 | read_unlock_bh(&xfrm_policy_lock); | 511 | read_unlock_bh(&net->xfrm.xfrm_policy_lock); |
| 517 | } | 512 | } |
| 518 | EXPORT_SYMBOL(xfrm_spd_getinfo); | 513 | EXPORT_SYMBOL(xfrm_spd_getinfo); |
| 519 | 514 | ||
| @@ -538,7 +533,7 @@ static void xfrm_hash_resize(struct work_struct *work) | |||
| 538 | 533 | ||
| 539 | /* Generate new index... KAME seems to generate them ordered by cost | 534 | /* Generate new index... KAME seems to generate them ordered by cost |
| 540 | * of an absolute inpredictability of ordering of rules. This will not pass. */ | 535 | * of an absolute inpredictability of ordering of rules. This will not pass. */ |
| 541 | static u32 xfrm_gen_index(struct net *net, int dir) | 536 | static u32 xfrm_gen_index(struct net *net, int dir, u32 index) |
| 542 | { | 537 | { |
| 543 | static u32 idx_generator; | 538 | static u32 idx_generator; |
| 544 | 539 | ||
| @@ -548,8 +543,14 @@ static u32 xfrm_gen_index(struct net *net, int dir) | |||
| 548 | u32 idx; | 543 | u32 idx; |
| 549 | int found; | 544 | int found; |
| 550 | 545 | ||
| 551 | idx = (idx_generator | dir); | 546 | if (!index) { |
| 552 | idx_generator += 8; | 547 | idx = (idx_generator | dir); |
| 548 | idx_generator += 8; | ||
| 549 | } else { | ||
| 550 | idx = index; | ||
| 551 | index = 0; | ||
| 552 | } | ||
| 553 | |||
| 553 | if (idx == 0) | 554 | if (idx == 0) |
| 554 | idx = 8; | 555 | idx = 8; |
| 555 | list = net->xfrm.policy_byidx + idx_hash(net, idx); | 556 | list = net->xfrm.policy_byidx + idx_hash(net, idx); |
| @@ -630,7 +631,7 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) | |||
| 630 | struct hlist_head *chain; | 631 | struct hlist_head *chain; |
| 631 | struct hlist_node *newpos; | 632 | struct hlist_node *newpos; |
| 632 | 633 | ||
| 633 | write_lock_bh(&xfrm_policy_lock); | 634 | write_lock_bh(&net->xfrm.xfrm_policy_lock); |
| 634 | chain = policy_hash_bysel(net, &policy->selector, policy->family, dir); | 635 | chain = policy_hash_bysel(net, &policy->selector, policy->family, dir); |
| 635 | delpol = NULL; | 636 | delpol = NULL; |
| 636 | newpos = NULL; | 637 | newpos = NULL; |
| @@ -641,7 +642,7 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) | |||
| 641 | xfrm_sec_ctx_match(pol->security, policy->security) && | 642 | xfrm_sec_ctx_match(pol->security, policy->security) && |
| 642 | !WARN_ON(delpol)) { | 643 | !WARN_ON(delpol)) { |
| 643 | if (excl) { | 644 | if (excl) { |
| 644 | write_unlock_bh(&xfrm_policy_lock); | 645 | write_unlock_bh(&net->xfrm.xfrm_policy_lock); |
| 645 | return -EEXIST; | 646 | return -EEXIST; |
| 646 | } | 647 | } |
| 647 | delpol = pol; | 648 | delpol = pol; |
| @@ -672,14 +673,14 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) | |||
| 672 | xfrm_policy_requeue(delpol, policy); | 673 | xfrm_policy_requeue(delpol, policy); |
| 673 | __xfrm_policy_unlink(delpol, dir); | 674 | __xfrm_policy_unlink(delpol, dir); |
| 674 | } | 675 | } |
| 675 | policy->index = delpol ? delpol->index : xfrm_gen_index(net, dir); | 676 | policy->index = delpol ? delpol->index : xfrm_gen_index(net, dir, policy->index); |
| 676 | hlist_add_head(&policy->byidx, net->xfrm.policy_byidx+idx_hash(net, policy->index)); | 677 | hlist_add_head(&policy->byidx, net->xfrm.policy_byidx+idx_hash(net, policy->index)); |
| 677 | policy->curlft.add_time = get_seconds(); | 678 | policy->curlft.add_time = get_seconds(); |
| 678 | policy->curlft.use_time = 0; | 679 | policy->curlft.use_time = 0; |
| 679 | if (!mod_timer(&policy->timer, jiffies + HZ)) | 680 | if (!mod_timer(&policy->timer, jiffies + HZ)) |
| 680 | xfrm_pol_hold(policy); | 681 | xfrm_pol_hold(policy); |
| 681 | list_add(&policy->walk.all, &net->xfrm.policy_all); | 682 | list_add(&policy->walk.all, &net->xfrm.policy_all); |
| 682 | write_unlock_bh(&xfrm_policy_lock); | 683 | write_unlock_bh(&net->xfrm.xfrm_policy_lock); |
| 683 | 684 | ||
| 684 | if (delpol) | 685 | if (delpol) |
| 685 | xfrm_policy_kill(delpol); | 686 | xfrm_policy_kill(delpol); |
| @@ -699,7 +700,7 @@ struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u32 mark, u8 type, | |||
| 699 | struct hlist_head *chain; | 700 | struct hlist_head *chain; |
| 700 | 701 | ||
| 701 | *err = 0; | 702 | *err = 0; |
| 702 | write_lock_bh(&xfrm_policy_lock); | 703 | write_lock_bh(&net->xfrm.xfrm_policy_lock); |
| 703 | chain = policy_hash_bysel(net, sel, sel->family, dir); | 704 | chain = policy_hash_bysel(net, sel, sel->family, dir); |
| 704 | ret = NULL; | 705 | ret = NULL; |
| 705 | hlist_for_each_entry(pol, chain, bydst) { | 706 | hlist_for_each_entry(pol, chain, bydst) { |
| @@ -712,7 +713,7 @@ struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u32 mark, u8 type, | |||
| 712 | *err = security_xfrm_policy_delete( | 713 | *err = security_xfrm_policy_delete( |
| 713 | pol->security); | 714 | pol->security); |
| 714 | if (*err) { | 715 | if (*err) { |
| 715 | write_unlock_bh(&xfrm_policy_lock); | 716 | write_unlock_bh(&net->xfrm.xfrm_policy_lock); |
| 716 | return pol; | 717 | return pol; |
| 717 | } | 718 | } |
| 718 | __xfrm_policy_unlink(pol, dir); | 719 | __xfrm_policy_unlink(pol, dir); |
| @@ -721,7 +722,7 @@ struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u32 mark, u8 type, | |||
| 721 | break; | 722 | break; |
| 722 | } | 723 | } |
| 723 | } | 724 | } |
| 724 | write_unlock_bh(&xfrm_policy_lock); | 725 | write_unlock_bh(&net->xfrm.xfrm_policy_lock); |
| 725 | 726 | ||
| 726 | if (ret && delete) | 727 | if (ret && delete) |
| 727 | xfrm_policy_kill(ret); | 728 | xfrm_policy_kill(ret); |
| @@ -740,7 +741,7 @@ struct xfrm_policy *xfrm_policy_byid(struct net *net, u32 mark, u8 type, | |||
| 740 | return NULL; | 741 | return NULL; |
| 741 | 742 | ||
| 742 | *err = 0; | 743 | *err = 0; |
| 743 | write_lock_bh(&xfrm_policy_lock); | 744 | write_lock_bh(&net->xfrm.xfrm_policy_lock); |
| 744 | chain = net->xfrm.policy_byidx + idx_hash(net, id); | 745 | chain = net->xfrm.policy_byidx + idx_hash(net, id); |
| 745 | ret = NULL; | 746 | ret = NULL; |
| 746 | hlist_for_each_entry(pol, chain, byidx) { | 747 | hlist_for_each_entry(pol, chain, byidx) { |
| @@ -751,7 +752,7 @@ struct xfrm_policy *xfrm_policy_byid(struct net *net, u32 mark, u8 type, | |||
| 751 | *err = security_xfrm_policy_delete( | 752 | *err = security_xfrm_policy_delete( |
| 752 | pol->security); | 753 | pol->security); |
| 753 | if (*err) { | 754 | if (*err) { |
| 754 | write_unlock_bh(&xfrm_policy_lock); | 755 | write_unlock_bh(&net->xfrm.xfrm_policy_lock); |
| 755 | return pol; | 756 | return pol; |
| 756 | } | 757 | } |
| 757 | __xfrm_policy_unlink(pol, dir); | 758 | __xfrm_policy_unlink(pol, dir); |
| @@ -760,7 +761,7 @@ struct xfrm_policy *xfrm_policy_byid(struct net *net, u32 mark, u8 type, | |||
| 760 | break; | 761 | break; |
| 761 | } | 762 | } |
| 762 | } | 763 | } |
| 763 | write_unlock_bh(&xfrm_policy_lock); | 764 | write_unlock_bh(&net->xfrm.xfrm_policy_lock); |
| 764 | 765 | ||
| 765 | if (ret && delete) | 766 | if (ret && delete) |
| 766 | xfrm_policy_kill(ret); | 767 | xfrm_policy_kill(ret); |
| @@ -823,7 +824,7 @@ int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info) | |||
| 823 | { | 824 | { |
| 824 | int dir, err = 0, cnt = 0; | 825 | int dir, err = 0, cnt = 0; |
| 825 | 826 | ||
| 826 | write_lock_bh(&xfrm_policy_lock); | 827 | write_lock_bh(&net->xfrm.xfrm_policy_lock); |
| 827 | 828 | ||
| 828 | err = xfrm_policy_flush_secctx_check(net, type, audit_info); | 829 | err = xfrm_policy_flush_secctx_check(net, type, audit_info); |
| 829 | if (err) | 830 | if (err) |
| @@ -839,7 +840,7 @@ int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info) | |||
| 839 | if (pol->type != type) | 840 | if (pol->type != type) |
| 840 | continue; | 841 | continue; |
| 841 | __xfrm_policy_unlink(pol, dir); | 842 | __xfrm_policy_unlink(pol, dir); |
| 842 | write_unlock_bh(&xfrm_policy_lock); | 843 | write_unlock_bh(&net->xfrm.xfrm_policy_lock); |
| 843 | cnt++; | 844 | cnt++; |
| 844 | 845 | ||
| 845 | xfrm_audit_policy_delete(pol, 1, audit_info->loginuid, | 846 | xfrm_audit_policy_delete(pol, 1, audit_info->loginuid, |
| @@ -848,7 +849,7 @@ int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info) | |||
| 848 | 849 | ||
| 849 | xfrm_policy_kill(pol); | 850 | xfrm_policy_kill(pol); |
| 850 | 851 | ||
| 851 | write_lock_bh(&xfrm_policy_lock); | 852 | write_lock_bh(&net->xfrm.xfrm_policy_lock); |
| 852 | goto again1; | 853 | goto again1; |
| 853 | } | 854 | } |
| 854 | 855 | ||
| @@ -860,7 +861,7 @@ int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info) | |||
| 860 | if (pol->type != type) | 861 | if (pol->type != type) |
| 861 | continue; | 862 | continue; |
| 862 | __xfrm_policy_unlink(pol, dir); | 863 | __xfrm_policy_unlink(pol, dir); |
| 863 | write_unlock_bh(&xfrm_policy_lock); | 864 | write_unlock_bh(&net->xfrm.xfrm_policy_lock); |
| 864 | cnt++; | 865 | cnt++; |
| 865 | 866 | ||
| 866 | xfrm_audit_policy_delete(pol, 1, | 867 | xfrm_audit_policy_delete(pol, 1, |
| @@ -869,7 +870,7 @@ int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info) | |||
| 869 | audit_info->secid); | 870 | audit_info->secid); |
| 870 | xfrm_policy_kill(pol); | 871 | xfrm_policy_kill(pol); |
| 871 | 872 | ||
| 872 | write_lock_bh(&xfrm_policy_lock); | 873 | write_lock_bh(&net->xfrm.xfrm_policy_lock); |
| 873 | goto again2; | 874 | goto again2; |
| 874 | } | 875 | } |
| 875 | } | 876 | } |
| @@ -878,7 +879,7 @@ int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info) | |||
| 878 | if (!cnt) | 879 | if (!cnt) |
| 879 | err = -ESRCH; | 880 | err = -ESRCH; |
| 880 | out: | 881 | out: |
| 881 | write_unlock_bh(&xfrm_policy_lock); | 882 | write_unlock_bh(&net->xfrm.xfrm_policy_lock); |
| 882 | return err; | 883 | return err; |
| 883 | } | 884 | } |
| 884 | EXPORT_SYMBOL(xfrm_policy_flush); | 885 | EXPORT_SYMBOL(xfrm_policy_flush); |
| @@ -898,7 +899,7 @@ int xfrm_policy_walk(struct net *net, struct xfrm_policy_walk *walk, | |||
| 898 | if (list_empty(&walk->walk.all) && walk->seq != 0) | 899 | if (list_empty(&walk->walk.all) && walk->seq != 0) |
| 899 | return 0; | 900 | return 0; |
| 900 | 901 | ||
| 901 | write_lock_bh(&xfrm_policy_lock); | 902 | write_lock_bh(&net->xfrm.xfrm_policy_lock); |
| 902 | if (list_empty(&walk->walk.all)) | 903 | if (list_empty(&walk->walk.all)) |
| 903 | x = list_first_entry(&net->xfrm.policy_all, struct xfrm_policy_walk_entry, all); | 904 | x = list_first_entry(&net->xfrm.policy_all, struct xfrm_policy_walk_entry, all); |
| 904 | else | 905 | else |
| @@ -924,7 +925,7 @@ int xfrm_policy_walk(struct net *net, struct xfrm_policy_walk *walk, | |||
| 924 | } | 925 | } |
| 925 | list_del_init(&walk->walk.all); | 926 | list_del_init(&walk->walk.all); |
| 926 | out: | 927 | out: |
| 927 | write_unlock_bh(&xfrm_policy_lock); | 928 | write_unlock_bh(&net->xfrm.xfrm_policy_lock); |
| 928 | return error; | 929 | return error; |
| 929 | } | 930 | } |
| 930 | EXPORT_SYMBOL(xfrm_policy_walk); | 931 | EXPORT_SYMBOL(xfrm_policy_walk); |
| @@ -938,14 +939,14 @@ void xfrm_policy_walk_init(struct xfrm_policy_walk *walk, u8 type) | |||
| 938 | } | 939 | } |
| 939 | EXPORT_SYMBOL(xfrm_policy_walk_init); | 940 | EXPORT_SYMBOL(xfrm_policy_walk_init); |
| 940 | 941 | ||
| 941 | void xfrm_policy_walk_done(struct xfrm_policy_walk *walk) | 942 | void xfrm_policy_walk_done(struct xfrm_policy_walk *walk, struct net *net) |
| 942 | { | 943 | { |
| 943 | if (list_empty(&walk->walk.all)) | 944 | if (list_empty(&walk->walk.all)) |
| 944 | return; | 945 | return; |
| 945 | 946 | ||
| 946 | write_lock_bh(&xfrm_policy_lock); | 947 | write_lock_bh(&net->xfrm.xfrm_policy_lock); /*FIXME where is net? */ |
| 947 | list_del(&walk->walk.all); | 948 | list_del(&walk->walk.all); |
| 948 | write_unlock_bh(&xfrm_policy_lock); | 949 | write_unlock_bh(&net->xfrm.xfrm_policy_lock); |
| 949 | } | 950 | } |
| 950 | EXPORT_SYMBOL(xfrm_policy_walk_done); | 951 | EXPORT_SYMBOL(xfrm_policy_walk_done); |
| 951 | 952 | ||
| @@ -990,7 +991,7 @@ static struct xfrm_policy *xfrm_policy_lookup_bytype(struct net *net, u8 type, | |||
| 990 | if (unlikely(!daddr || !saddr)) | 991 | if (unlikely(!daddr || !saddr)) |
| 991 | return NULL; | 992 | return NULL; |
| 992 | 993 | ||
| 993 | read_lock_bh(&xfrm_policy_lock); | 994 | read_lock_bh(&net->xfrm.xfrm_policy_lock); |
| 994 | chain = policy_hash_direct(net, daddr, saddr, family, dir); | 995 | chain = policy_hash_direct(net, daddr, saddr, family, dir); |
| 995 | ret = NULL; | 996 | ret = NULL; |
| 996 | hlist_for_each_entry(pol, chain, bydst) { | 997 | hlist_for_each_entry(pol, chain, bydst) { |
| @@ -1026,7 +1027,7 @@ static struct xfrm_policy *xfrm_policy_lookup_bytype(struct net *net, u8 type, | |||
| 1026 | if (ret) | 1027 | if (ret) |
| 1027 | xfrm_pol_hold(ret); | 1028 | xfrm_pol_hold(ret); |
| 1028 | fail: | 1029 | fail: |
| 1029 | read_unlock_bh(&xfrm_policy_lock); | 1030 | read_unlock_bh(&net->xfrm.xfrm_policy_lock); |
| 1030 | 1031 | ||
| 1031 | return ret; | 1032 | return ret; |
| 1032 | } | 1033 | } |
| @@ -1103,8 +1104,9 @@ static struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir, | |||
| 1103 | const struct flowi *fl) | 1104 | const struct flowi *fl) |
| 1104 | { | 1105 | { |
| 1105 | struct xfrm_policy *pol; | 1106 | struct xfrm_policy *pol; |
| 1107 | struct net *net = sock_net(sk); | ||
| 1106 | 1108 | ||
| 1107 | read_lock_bh(&xfrm_policy_lock); | 1109 | read_lock_bh(&net->xfrm.xfrm_policy_lock); |
| 1108 | if ((pol = sk->sk_policy[dir]) != NULL) { | 1110 | if ((pol = sk->sk_policy[dir]) != NULL) { |
| 1109 | bool match = xfrm_selector_match(&pol->selector, fl, | 1111 | bool match = xfrm_selector_match(&pol->selector, fl, |
| 1110 | sk->sk_family); | 1112 | sk->sk_family); |
| @@ -1128,7 +1130,7 @@ static struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir, | |||
| 1128 | pol = NULL; | 1130 | pol = NULL; |
| 1129 | } | 1131 | } |
| 1130 | out: | 1132 | out: |
| 1131 | read_unlock_bh(&xfrm_policy_lock); | 1133 | read_unlock_bh(&net->xfrm.xfrm_policy_lock); |
| 1132 | return pol; | 1134 | return pol; |
| 1133 | } | 1135 | } |
| 1134 | 1136 | ||
| @@ -1166,9 +1168,11 @@ static struct xfrm_policy *__xfrm_policy_unlink(struct xfrm_policy *pol, | |||
| 1166 | 1168 | ||
| 1167 | int xfrm_policy_delete(struct xfrm_policy *pol, int dir) | 1169 | int xfrm_policy_delete(struct xfrm_policy *pol, int dir) |
| 1168 | { | 1170 | { |
| 1169 | write_lock_bh(&xfrm_policy_lock); | 1171 | struct net *net = xp_net(pol); |
| 1172 | |||
| 1173 | write_lock_bh(&net->xfrm.xfrm_policy_lock); | ||
| 1170 | pol = __xfrm_policy_unlink(pol, dir); | 1174 | pol = __xfrm_policy_unlink(pol, dir); |
| 1171 | write_unlock_bh(&xfrm_policy_lock); | 1175 | write_unlock_bh(&net->xfrm.xfrm_policy_lock); |
| 1172 | if (pol) { | 1176 | if (pol) { |
| 1173 | xfrm_policy_kill(pol); | 1177 | xfrm_policy_kill(pol); |
| 1174 | return 0; | 1178 | return 0; |
| @@ -1187,12 +1191,12 @@ int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol) | |||
| 1187 | return -EINVAL; | 1191 | return -EINVAL; |
| 1188 | #endif | 1192 | #endif |
| 1189 | 1193 | ||
| 1190 | write_lock_bh(&xfrm_policy_lock); | 1194 | write_lock_bh(&net->xfrm.xfrm_policy_lock); |
| 1191 | old_pol = sk->sk_policy[dir]; | 1195 | old_pol = sk->sk_policy[dir]; |
| 1192 | sk->sk_policy[dir] = pol; | 1196 | sk->sk_policy[dir] = pol; |
| 1193 | if (pol) { | 1197 | if (pol) { |
| 1194 | pol->curlft.add_time = get_seconds(); | 1198 | pol->curlft.add_time = get_seconds(); |
| 1195 | pol->index = xfrm_gen_index(net, XFRM_POLICY_MAX+dir); | 1199 | pol->index = xfrm_gen_index(net, XFRM_POLICY_MAX+dir, 0); |
| 1196 | __xfrm_policy_link(pol, XFRM_POLICY_MAX+dir); | 1200 | __xfrm_policy_link(pol, XFRM_POLICY_MAX+dir); |
| 1197 | } | 1201 | } |
| 1198 | if (old_pol) { | 1202 | if (old_pol) { |
| @@ -1204,7 +1208,7 @@ int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol) | |||
| 1204 | */ | 1208 | */ |
| 1205 | __xfrm_policy_unlink(old_pol, XFRM_POLICY_MAX+dir); | 1209 | __xfrm_policy_unlink(old_pol, XFRM_POLICY_MAX+dir); |
| 1206 | } | 1210 | } |
| 1207 | write_unlock_bh(&xfrm_policy_lock); | 1211 | write_unlock_bh(&net->xfrm.xfrm_policy_lock); |
| 1208 | 1212 | ||
| 1209 | if (old_pol) { | 1213 | if (old_pol) { |
| 1210 | xfrm_policy_kill(old_pol); | 1214 | xfrm_policy_kill(old_pol); |
| @@ -1215,6 +1219,7 @@ int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol) | |||
| 1215 | static struct xfrm_policy *clone_policy(const struct xfrm_policy *old, int dir) | 1219 | static struct xfrm_policy *clone_policy(const struct xfrm_policy *old, int dir) |
| 1216 | { | 1220 | { |
| 1217 | struct xfrm_policy *newp = xfrm_policy_alloc(xp_net(old), GFP_ATOMIC); | 1221 | struct xfrm_policy *newp = xfrm_policy_alloc(xp_net(old), GFP_ATOMIC); |
| 1222 | struct net *net = xp_net(old); | ||
| 1218 | 1223 | ||
| 1219 | if (newp) { | 1224 | if (newp) { |
| 1220 | newp->selector = old->selector; | 1225 | newp->selector = old->selector; |
| @@ -1233,9 +1238,9 @@ static struct xfrm_policy *clone_policy(const struct xfrm_policy *old, int dir) | |||
| 1233 | newp->type = old->type; | 1238 | newp->type = old->type; |
| 1234 | memcpy(newp->xfrm_vec, old->xfrm_vec, | 1239 | memcpy(newp->xfrm_vec, old->xfrm_vec, |
| 1235 | newp->xfrm_nr*sizeof(struct xfrm_tmpl)); | 1240 | newp->xfrm_nr*sizeof(struct xfrm_tmpl)); |
| 1236 | write_lock_bh(&xfrm_policy_lock); | 1241 | write_lock_bh(&net->xfrm.xfrm_policy_lock); |
| 1237 | __xfrm_policy_link(newp, XFRM_POLICY_MAX+dir); | 1242 | __xfrm_policy_link(newp, XFRM_POLICY_MAX+dir); |
| 1238 | write_unlock_bh(&xfrm_policy_lock); | 1243 | write_unlock_bh(&net->xfrm.xfrm_policy_lock); |
| 1239 | xfrm_pol_put(newp); | 1244 | xfrm_pol_put(newp); |
| 1240 | } | 1245 | } |
| 1241 | return newp; | 1246 | return newp; |
| @@ -1281,7 +1286,7 @@ xfrm_tmpl_resolve_one(struct xfrm_policy *policy, const struct flowi *fl, | |||
| 1281 | xfrm_address_t *saddr = xfrm_flowi_saddr(fl, family); | 1286 | xfrm_address_t *saddr = xfrm_flowi_saddr(fl, family); |
| 1282 | xfrm_address_t tmp; | 1287 | xfrm_address_t tmp; |
| 1283 | 1288 | ||
| 1284 | for (nx=0, i = 0; i < policy->xfrm_nr; i++) { | 1289 | for (nx = 0, i = 0; i < policy->xfrm_nr; i++) { |
| 1285 | struct xfrm_state *x; | 1290 | struct xfrm_state *x; |
| 1286 | xfrm_address_t *remote = daddr; | 1291 | xfrm_address_t *remote = daddr; |
| 1287 | xfrm_address_t *local = saddr; | 1292 | xfrm_address_t *local = saddr; |
| @@ -1311,9 +1316,9 @@ xfrm_tmpl_resolve_one(struct xfrm_policy *policy, const struct flowi *fl, | |||
| 1311 | error = (x->km.state == XFRM_STATE_ERROR ? | 1316 | error = (x->km.state == XFRM_STATE_ERROR ? |
| 1312 | -EINVAL : -EAGAIN); | 1317 | -EINVAL : -EAGAIN); |
| 1313 | xfrm_state_put(x); | 1318 | xfrm_state_put(x); |
| 1314 | } | 1319 | } else if (error == -ESRCH) { |
| 1315 | else if (error == -ESRCH) | ||
| 1316 | error = -EAGAIN; | 1320 | error = -EAGAIN; |
| 1321 | } | ||
| 1317 | 1322 | ||
| 1318 | if (!tmpl->optional) | 1323 | if (!tmpl->optional) |
| 1319 | goto fail; | 1324 | goto fail; |
| @@ -1321,7 +1326,7 @@ xfrm_tmpl_resolve_one(struct xfrm_policy *policy, const struct flowi *fl, | |||
| 1321 | return nx; | 1326 | return nx; |
| 1322 | 1327 | ||
| 1323 | fail: | 1328 | fail: |
| 1324 | for (nx--; nx>=0; nx--) | 1329 | for (nx--; nx >= 0; nx--) |
| 1325 | xfrm_state_put(xfrm[nx]); | 1330 | xfrm_state_put(xfrm[nx]); |
| 1326 | return error; | 1331 | return error; |
| 1327 | } | 1332 | } |
| @@ -1358,7 +1363,7 @@ xfrm_tmpl_resolve(struct xfrm_policy **pols, int npols, const struct flowi *fl, | |||
| 1358 | return cnx; | 1363 | return cnx; |
| 1359 | 1364 | ||
| 1360 | fail: | 1365 | fail: |
| 1361 | for (cnx--; cnx>=0; cnx--) | 1366 | for (cnx--; cnx >= 0; cnx--) |
| 1362 | xfrm_state_put(tpp[cnx]); | 1367 | xfrm_state_put(tpp[cnx]); |
| 1363 | return error; | 1368 | return error; |
| 1364 | 1369 | ||
| @@ -1636,20 +1641,22 @@ free_dst: | |||
| 1636 | goto out; | 1641 | goto out; |
| 1637 | } | 1642 | } |
| 1638 | 1643 | ||
| 1639 | static int inline | 1644 | #ifdef CONFIG_XFRM_SUB_POLICY |
| 1640 | xfrm_dst_alloc_copy(void **target, const void *src, int size) | 1645 | static int xfrm_dst_alloc_copy(void **target, const void *src, int size) |
| 1641 | { | 1646 | { |
| 1642 | if (!*target) { | 1647 | if (!*target) { |
| 1643 | *target = kmalloc(size, GFP_ATOMIC); | 1648 | *target = kmalloc(size, GFP_ATOMIC); |
| 1644 | if (!*target) | 1649 | if (!*target) |
| 1645 | return -ENOMEM; | 1650 | return -ENOMEM; |
| 1646 | } | 1651 | } |
| 1652 | |||
| 1647 | memcpy(*target, src, size); | 1653 | memcpy(*target, src, size); |
| 1648 | return 0; | 1654 | return 0; |
| 1649 | } | 1655 | } |
| 1656 | #endif | ||
| 1650 | 1657 | ||
| 1651 | static int inline | 1658 | static int xfrm_dst_update_parent(struct dst_entry *dst, |
| 1652 | xfrm_dst_update_parent(struct dst_entry *dst, const struct xfrm_selector *sel) | 1659 | const struct xfrm_selector *sel) |
| 1653 | { | 1660 | { |
| 1654 | #ifdef CONFIG_XFRM_SUB_POLICY | 1661 | #ifdef CONFIG_XFRM_SUB_POLICY |
| 1655 | struct xfrm_dst *xdst = (struct xfrm_dst *)dst; | 1662 | struct xfrm_dst *xdst = (struct xfrm_dst *)dst; |
| @@ -1660,8 +1667,8 @@ xfrm_dst_update_parent(struct dst_entry *dst, const struct xfrm_selector *sel) | |||
| 1660 | #endif | 1667 | #endif |
| 1661 | } | 1668 | } |
| 1662 | 1669 | ||
| 1663 | static int inline | 1670 | static int xfrm_dst_update_origin(struct dst_entry *dst, |
| 1664 | xfrm_dst_update_origin(struct dst_entry *dst, const struct flowi *fl) | 1671 | const struct flowi *fl) |
| 1665 | { | 1672 | { |
| 1666 | #ifdef CONFIG_XFRM_SUB_POLICY | 1673 | #ifdef CONFIG_XFRM_SUB_POLICY |
| 1667 | struct xfrm_dst *xdst = (struct xfrm_dst *)dst; | 1674 | struct xfrm_dst *xdst = (struct xfrm_dst *)dst; |
| @@ -1699,7 +1706,7 @@ static int xfrm_expand_policies(const struct flowi *fl, u16 family, | |||
| 1699 | xfrm_pols_put(pols, *num_pols); | 1706 | xfrm_pols_put(pols, *num_pols); |
| 1700 | return PTR_ERR(pols[1]); | 1707 | return PTR_ERR(pols[1]); |
| 1701 | } | 1708 | } |
| 1702 | (*num_pols) ++; | 1709 | (*num_pols)++; |
| 1703 | (*num_xfrms) += pols[1]->xfrm_nr; | 1710 | (*num_xfrms) += pols[1]->xfrm_nr; |
| 1704 | } | 1711 | } |
| 1705 | } | 1712 | } |
| @@ -1753,7 +1760,7 @@ xfrm_resolve_and_create_bundle(struct xfrm_policy **pols, int num_pols, | |||
| 1753 | } | 1760 | } |
| 1754 | 1761 | ||
| 1755 | xdst->num_pols = num_pols; | 1762 | xdst->num_pols = num_pols; |
| 1756 | memcpy(xdst->pols, pols, sizeof(struct xfrm_policy*) * num_pols); | 1763 | memcpy(xdst->pols, pols, sizeof(struct xfrm_policy *) * num_pols); |
| 1757 | xdst->policy_genid = atomic_read(&pols[0]->genid); | 1764 | xdst->policy_genid = atomic_read(&pols[0]->genid); |
| 1758 | 1765 | ||
| 1759 | return xdst; | 1766 | return xdst; |
| @@ -1896,8 +1903,7 @@ static struct xfrm_dst *xfrm_create_dummy_bundle(struct net *net, | |||
| 1896 | if (IS_ERR(xdst)) | 1903 | if (IS_ERR(xdst)) |
| 1897 | return xdst; | 1904 | return xdst; |
| 1898 | 1905 | ||
| 1899 | if (net->xfrm.sysctl_larval_drop || num_xfrms <= 0 || | 1906 | if (net->xfrm.sysctl_larval_drop || num_xfrms <= 0) |
| 1900 | (fl->flowi_flags & FLOWI_FLAG_CAN_SLEEP)) | ||
| 1901 | return xdst; | 1907 | return xdst; |
| 1902 | 1908 | ||
| 1903 | dst1 = &xdst->u.dst; | 1909 | dst1 = &xdst->u.dst; |
| @@ -2023,7 +2029,7 @@ make_dummy_bundle: | |||
| 2023 | } | 2029 | } |
| 2024 | xdst->num_pols = num_pols; | 2030 | xdst->num_pols = num_pols; |
| 2025 | xdst->num_xfrms = num_xfrms; | 2031 | xdst->num_xfrms = num_xfrms; |
| 2026 | memcpy(xdst->pols, pols, sizeof(struct xfrm_policy*) * num_pols); | 2032 | memcpy(xdst->pols, pols, sizeof(struct xfrm_policy *) * num_pols); |
| 2027 | 2033 | ||
| 2028 | dst_hold(&xdst->u.dst); | 2034 | dst_hold(&xdst->u.dst); |
| 2029 | return &xdst->flo; | 2035 | return &xdst->flo; |
| @@ -2072,7 +2078,6 @@ struct dst_entry *xfrm_lookup(struct net *net, struct dst_entry *dst_orig, | |||
| 2072 | u8 dir = policy_to_flow_dir(XFRM_POLICY_OUT); | 2078 | u8 dir = policy_to_flow_dir(XFRM_POLICY_OUT); |
| 2073 | int i, err, num_pols, num_xfrms = 0, drop_pols = 0; | 2079 | int i, err, num_pols, num_xfrms = 0, drop_pols = 0; |
| 2074 | 2080 | ||
| 2075 | restart: | ||
| 2076 | dst = NULL; | 2081 | dst = NULL; |
| 2077 | xdst = NULL; | 2082 | xdst = NULL; |
| 2078 | route = NULL; | 2083 | route = NULL; |
| @@ -2106,10 +2111,10 @@ restart: | |||
| 2106 | 2111 | ||
| 2107 | dst_hold(&xdst->u.dst); | 2112 | dst_hold(&xdst->u.dst); |
| 2108 | 2113 | ||
| 2109 | spin_lock_bh(&xfrm_policy_sk_bundle_lock); | 2114 | spin_lock_bh(&net->xfrm.xfrm_policy_sk_bundle_lock); |
| 2110 | xdst->u.dst.next = xfrm_policy_sk_bundles; | 2115 | xdst->u.dst.next = xfrm_policy_sk_bundles; |
| 2111 | xfrm_policy_sk_bundles = &xdst->u.dst; | 2116 | xfrm_policy_sk_bundles = &xdst->u.dst; |
| 2112 | spin_unlock_bh(&xfrm_policy_sk_bundle_lock); | 2117 | spin_unlock_bh(&net->xfrm.xfrm_policy_sk_bundle_lock); |
| 2113 | 2118 | ||
| 2114 | route = xdst->route; | 2119 | route = xdst->route; |
| 2115 | } | 2120 | } |
| @@ -2133,7 +2138,7 @@ restart: | |||
| 2133 | 2138 | ||
| 2134 | num_pols = xdst->num_pols; | 2139 | num_pols = xdst->num_pols; |
| 2135 | num_xfrms = xdst->num_xfrms; | 2140 | num_xfrms = xdst->num_xfrms; |
| 2136 | memcpy(pols, xdst->pols, sizeof(struct xfrm_policy*) * num_pols); | 2141 | memcpy(pols, xdst->pols, sizeof(struct xfrm_policy *) * num_pols); |
| 2137 | route = xdst->route; | 2142 | route = xdst->route; |
| 2138 | } | 2143 | } |
| 2139 | 2144 | ||
| @@ -2152,23 +2157,8 @@ restart: | |||
| 2152 | 2157 | ||
| 2153 | return make_blackhole(net, family, dst_orig); | 2158 | return make_blackhole(net, family, dst_orig); |
| 2154 | } | 2159 | } |
| 2155 | if (fl->flowi_flags & FLOWI_FLAG_CAN_SLEEP) { | ||
| 2156 | DECLARE_WAITQUEUE(wait, current); | ||
| 2157 | 2160 | ||
| 2158 | add_wait_queue(&net->xfrm.km_waitq, &wait); | 2161 | err = -EAGAIN; |
| 2159 | set_current_state(TASK_INTERRUPTIBLE); | ||
| 2160 | schedule(); | ||
| 2161 | set_current_state(TASK_RUNNING); | ||
| 2162 | remove_wait_queue(&net->xfrm.km_waitq, &wait); | ||
| 2163 | |||
| 2164 | if (!signal_pending(current)) { | ||
| 2165 | dst_release(dst); | ||
| 2166 | goto restart; | ||
| 2167 | } | ||
| 2168 | |||
| 2169 | err = -ERESTART; | ||
| 2170 | } else | ||
| 2171 | err = -EAGAIN; | ||
| 2172 | 2162 | ||
| 2173 | XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTNOSTATES); | 2163 | XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTNOSTATES); |
| 2174 | goto error; | 2164 | goto error; |
| @@ -2344,7 +2334,7 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, | |||
| 2344 | if (skb->sp) { | 2334 | if (skb->sp) { |
| 2345 | int i; | 2335 | int i; |
| 2346 | 2336 | ||
| 2347 | for (i=skb->sp->len-1; i>=0; i--) { | 2337 | for (i = skb->sp->len-1; i >= 0; i--) { |
| 2348 | struct xfrm_state *x = skb->sp->xvec[i]; | 2338 | struct xfrm_state *x = skb->sp->xvec[i]; |
| 2349 | if (!xfrm_selector_match(&x->sel, &fl, family)) { | 2339 | if (!xfrm_selector_match(&x->sel, &fl, family)) { |
| 2350 | XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEMISMATCH); | 2340 | XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEMISMATCH); |
| @@ -2390,7 +2380,7 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, | |||
| 2390 | pol->curlft.use_time = get_seconds(); | 2380 | pol->curlft.use_time = get_seconds(); |
| 2391 | 2381 | ||
| 2392 | pols[0] = pol; | 2382 | pols[0] = pol; |
| 2393 | npols ++; | 2383 | npols++; |
| 2394 | #ifdef CONFIG_XFRM_SUB_POLICY | 2384 | #ifdef CONFIG_XFRM_SUB_POLICY |
| 2395 | if (pols[0]->type != XFRM_POLICY_TYPE_MAIN) { | 2385 | if (pols[0]->type != XFRM_POLICY_TYPE_MAIN) { |
| 2396 | pols[1] = xfrm_policy_lookup_bytype(net, XFRM_POLICY_TYPE_MAIN, | 2386 | pols[1] = xfrm_policy_lookup_bytype(net, XFRM_POLICY_TYPE_MAIN, |
| @@ -2402,7 +2392,7 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, | |||
| 2402 | return 0; | 2392 | return 0; |
| 2403 | } | 2393 | } |
| 2404 | pols[1]->curlft.use_time = get_seconds(); | 2394 | pols[1]->curlft.use_time = get_seconds(); |
| 2405 | npols ++; | 2395 | npols++; |
| 2406 | } | 2396 | } |
| 2407 | } | 2397 | } |
| 2408 | #endif | 2398 | #endif |
| @@ -2434,7 +2424,7 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, | |||
| 2434 | } | 2424 | } |
| 2435 | xfrm_nr = ti; | 2425 | xfrm_nr = ti; |
| 2436 | if (npols > 1) { | 2426 | if (npols > 1) { |
| 2437 | xfrm_tmpl_sort(stp, tpp, xfrm_nr, family); | 2427 | xfrm_tmpl_sort(stp, tpp, xfrm_nr, family, net); |
| 2438 | tpp = stp; | 2428 | tpp = stp; |
| 2439 | } | 2429 | } |
| 2440 | 2430 | ||
| @@ -2563,10 +2553,10 @@ static void __xfrm_garbage_collect(struct net *net) | |||
| 2563 | { | 2553 | { |
| 2564 | struct dst_entry *head, *next; | 2554 | struct dst_entry *head, *next; |
| 2565 | 2555 | ||
| 2566 | spin_lock_bh(&xfrm_policy_sk_bundle_lock); | 2556 | spin_lock_bh(&net->xfrm.xfrm_policy_sk_bundle_lock); |
| 2567 | head = xfrm_policy_sk_bundles; | 2557 | head = xfrm_policy_sk_bundles; |
| 2568 | xfrm_policy_sk_bundles = NULL; | 2558 | xfrm_policy_sk_bundles = NULL; |
| 2569 | spin_unlock_bh(&xfrm_policy_sk_bundle_lock); | 2559 | spin_unlock_bh(&net->xfrm.xfrm_policy_sk_bundle_lock); |
| 2570 | 2560 | ||
| 2571 | while (head) { | 2561 | while (head) { |
| 2572 | next = head->next; | 2562 | next = head->next; |
| @@ -2906,12 +2896,12 @@ static void xfrm_policy_fini(struct net *net) | |||
| 2906 | flush_work(&net->xfrm.policy_hash_work); | 2896 | flush_work(&net->xfrm.policy_hash_work); |
| 2907 | #ifdef CONFIG_XFRM_SUB_POLICY | 2897 | #ifdef CONFIG_XFRM_SUB_POLICY |
| 2908 | audit_info.loginuid = INVALID_UID; | 2898 | audit_info.loginuid = INVALID_UID; |
| 2909 | audit_info.sessionid = -1; | 2899 | audit_info.sessionid = (unsigned int)-1; |
| 2910 | audit_info.secid = 0; | 2900 | audit_info.secid = 0; |
| 2911 | xfrm_policy_flush(net, XFRM_POLICY_TYPE_SUB, &audit_info); | 2901 | xfrm_policy_flush(net, XFRM_POLICY_TYPE_SUB, &audit_info); |
| 2912 | #endif | 2902 | #endif |
| 2913 | audit_info.loginuid = INVALID_UID; | 2903 | audit_info.loginuid = INVALID_UID; |
| 2914 | audit_info.sessionid = -1; | 2904 | audit_info.sessionid = (unsigned int)-1; |
| 2915 | audit_info.secid = 0; | 2905 | audit_info.secid = 0; |
| 2916 | xfrm_policy_flush(net, XFRM_POLICY_TYPE_MAIN, &audit_info); | 2906 | xfrm_policy_flush(net, XFRM_POLICY_TYPE_MAIN, &audit_info); |
| 2917 | 2907 | ||
| @@ -2950,6 +2940,13 @@ static int __net_init xfrm_net_init(struct net *net) | |||
| 2950 | rv = xfrm_sysctl_init(net); | 2940 | rv = xfrm_sysctl_init(net); |
| 2951 | if (rv < 0) | 2941 | if (rv < 0) |
| 2952 | goto out_sysctl; | 2942 | goto out_sysctl; |
| 2943 | |||
| 2944 | /* Initialize the per-net locks here */ | ||
| 2945 | spin_lock_init(&net->xfrm.xfrm_state_lock); | ||
| 2946 | rwlock_init(&net->xfrm.xfrm_policy_lock); | ||
| 2947 | spin_lock_init(&net->xfrm.xfrm_policy_sk_bundle_lock); | ||
| 2948 | mutex_init(&net->xfrm.xfrm_cfg_mutex); | ||
| 2949 | |||
| 2953 | return 0; | 2950 | return 0; |
| 2954 | 2951 | ||
| 2955 | out_sysctl: | 2952 | out_sysctl: |
| @@ -2992,7 +2989,7 @@ static void xfrm_audit_common_policyinfo(struct xfrm_policy *xp, | |||
| 2992 | audit_log_format(audit_buf, " sec_alg=%u sec_doi=%u sec_obj=%s", | 2989 | audit_log_format(audit_buf, " sec_alg=%u sec_doi=%u sec_obj=%s", |
| 2993 | ctx->ctx_alg, ctx->ctx_doi, ctx->ctx_str); | 2990 | ctx->ctx_alg, ctx->ctx_doi, ctx->ctx_str); |
| 2994 | 2991 | ||
| 2995 | switch(sel->family) { | 2992 | switch (sel->family) { |
| 2996 | case AF_INET: | 2993 | case AF_INET: |
| 2997 | audit_log_format(audit_buf, " src=%pI4", &sel->saddr.a4); | 2994 | audit_log_format(audit_buf, " src=%pI4", &sel->saddr.a4); |
| 2998 | if (sel->prefixlen_s != 32) | 2995 | if (sel->prefixlen_s != 32) |
| @@ -3017,7 +3014,7 @@ static void xfrm_audit_common_policyinfo(struct xfrm_policy *xp, | |||
| 3017 | } | 3014 | } |
| 3018 | 3015 | ||
| 3019 | void xfrm_audit_policy_add(struct xfrm_policy *xp, int result, | 3016 | void xfrm_audit_policy_add(struct xfrm_policy *xp, int result, |
| 3020 | kuid_t auid, u32 sessionid, u32 secid) | 3017 | kuid_t auid, unsigned int sessionid, u32 secid) |
| 3021 | { | 3018 | { |
| 3022 | struct audit_buffer *audit_buf; | 3019 | struct audit_buffer *audit_buf; |
| 3023 | 3020 | ||
| @@ -3032,7 +3029,7 @@ void xfrm_audit_policy_add(struct xfrm_policy *xp, int result, | |||
| 3032 | EXPORT_SYMBOL_GPL(xfrm_audit_policy_add); | 3029 | EXPORT_SYMBOL_GPL(xfrm_audit_policy_add); |
| 3033 | 3030 | ||
| 3034 | void xfrm_audit_policy_delete(struct xfrm_policy *xp, int result, | 3031 | void xfrm_audit_policy_delete(struct xfrm_policy *xp, int result, |
| 3035 | kuid_t auid, u32 sessionid, u32 secid) | 3032 | kuid_t auid, unsigned int sessionid, u32 secid) |
| 3036 | { | 3033 | { |
| 3037 | struct audit_buffer *audit_buf; | 3034 | struct audit_buffer *audit_buf; |
| 3038 | 3035 | ||
| @@ -3069,15 +3066,15 @@ static bool xfrm_migrate_selector_match(const struct xfrm_selector *sel_cmp, | |||
| 3069 | return false; | 3066 | return false; |
| 3070 | } | 3067 | } |
| 3071 | 3068 | ||
| 3072 | static struct xfrm_policy * xfrm_migrate_policy_find(const struct xfrm_selector *sel, | 3069 | static struct xfrm_policy *xfrm_migrate_policy_find(const struct xfrm_selector *sel, |
| 3073 | u8 dir, u8 type) | 3070 | u8 dir, u8 type, struct net *net) |
| 3074 | { | 3071 | { |
| 3075 | struct xfrm_policy *pol, *ret = NULL; | 3072 | struct xfrm_policy *pol, *ret = NULL; |
| 3076 | struct hlist_head *chain; | 3073 | struct hlist_head *chain; |
| 3077 | u32 priority = ~0U; | 3074 | u32 priority = ~0U; |
| 3078 | 3075 | ||
| 3079 | read_lock_bh(&xfrm_policy_lock); | 3076 | read_lock_bh(&net->xfrm.xfrm_policy_lock); /*FIXME*/ |
| 3080 | chain = policy_hash_direct(&init_net, &sel->daddr, &sel->saddr, sel->family, dir); | 3077 | chain = policy_hash_direct(net, &sel->daddr, &sel->saddr, sel->family, dir); |
| 3081 | hlist_for_each_entry(pol, chain, bydst) { | 3078 | hlist_for_each_entry(pol, chain, bydst) { |
| 3082 | if (xfrm_migrate_selector_match(sel, &pol->selector) && | 3079 | if (xfrm_migrate_selector_match(sel, &pol->selector) && |
| 3083 | pol->type == type) { | 3080 | pol->type == type) { |
| @@ -3086,7 +3083,7 @@ static struct xfrm_policy * xfrm_migrate_policy_find(const struct xfrm_selector | |||
| 3086 | break; | 3083 | break; |
| 3087 | } | 3084 | } |
| 3088 | } | 3085 | } |
| 3089 | chain = &init_net.xfrm.policy_inexact[dir]; | 3086 | chain = &net->xfrm.policy_inexact[dir]; |
| 3090 | hlist_for_each_entry(pol, chain, bydst) { | 3087 | hlist_for_each_entry(pol, chain, bydst) { |
| 3091 | if (xfrm_migrate_selector_match(sel, &pol->selector) && | 3088 | if (xfrm_migrate_selector_match(sel, &pol->selector) && |
| 3092 | pol->type == type && | 3089 | pol->type == type && |
| @@ -3099,7 +3096,7 @@ static struct xfrm_policy * xfrm_migrate_policy_find(const struct xfrm_selector | |||
| 3099 | if (ret) | 3096 | if (ret) |
| 3100 | xfrm_pol_hold(ret); | 3097 | xfrm_pol_hold(ret); |
| 3101 | 3098 | ||
| 3102 | read_unlock_bh(&xfrm_policy_lock); | 3099 | read_unlock_bh(&net->xfrm.xfrm_policy_lock); |
| 3103 | 3100 | ||
| 3104 | return ret; | 3101 | return ret; |
| 3105 | } | 3102 | } |
| @@ -3210,7 +3207,7 @@ static int xfrm_migrate_check(const struct xfrm_migrate *m, int num_migrate) | |||
| 3210 | 3207 | ||
| 3211 | int xfrm_migrate(const struct xfrm_selector *sel, u8 dir, u8 type, | 3208 | int xfrm_migrate(const struct xfrm_selector *sel, u8 dir, u8 type, |
| 3212 | struct xfrm_migrate *m, int num_migrate, | 3209 | struct xfrm_migrate *m, int num_migrate, |
| 3213 | struct xfrm_kmaddress *k) | 3210 | struct xfrm_kmaddress *k, struct net *net) |
| 3214 | { | 3211 | { |
| 3215 | int i, err, nx_cur = 0, nx_new = 0; | 3212 | int i, err, nx_cur = 0, nx_new = 0; |
| 3216 | struct xfrm_policy *pol = NULL; | 3213 | struct xfrm_policy *pol = NULL; |
| @@ -3223,14 +3220,14 @@ int xfrm_migrate(const struct xfrm_selector *sel, u8 dir, u8 type, | |||
| 3223 | goto out; | 3220 | goto out; |
| 3224 | 3221 | ||
| 3225 | /* Stage 1 - find policy */ | 3222 | /* Stage 1 - find policy */ |
| 3226 | if ((pol = xfrm_migrate_policy_find(sel, dir, type)) == NULL) { | 3223 | if ((pol = xfrm_migrate_policy_find(sel, dir, type, net)) == NULL) { |
| 3227 | err = -ENOENT; | 3224 | err = -ENOENT; |
| 3228 | goto out; | 3225 | goto out; |
| 3229 | } | 3226 | } |
| 3230 | 3227 | ||
| 3231 | /* Stage 2 - find and update state(s) */ | 3228 | /* Stage 2 - find and update state(s) */ |
| 3232 | for (i = 0, mp = m; i < num_migrate; i++, mp++) { | 3229 | for (i = 0, mp = m; i < num_migrate; i++, mp++) { |
| 3233 | if ((x = xfrm_migrate_state_find(mp))) { | 3230 | if ((x = xfrm_migrate_state_find(mp, net))) { |
| 3234 | x_cur[nx_cur] = x; | 3231 | x_cur[nx_cur] = x; |
| 3235 | nx_cur++; | 3232 | nx_cur++; |
| 3236 | if ((xc = xfrm_state_migrate(x, mp))) { | 3233 | if ((xc = xfrm_state_migrate(x, mp))) { |
diff --git a/net/xfrm/xfrm_proc.c b/net/xfrm/xfrm_proc.c index 80cd1e55b834..fc5abd0b456f 100644 --- a/net/xfrm/xfrm_proc.c +++ b/net/xfrm/xfrm_proc.c | |||
| @@ -52,7 +52,7 @@ static int xfrm_statistics_seq_show(struct seq_file *seq, void *v) | |||
| 52 | { | 52 | { |
| 53 | struct net *net = seq->private; | 53 | struct net *net = seq->private; |
| 54 | int i; | 54 | int i; |
| 55 | for (i=0; xfrm_mib_list[i].name; i++) | 55 | for (i = 0; xfrm_mib_list[i].name; i++) |
| 56 | seq_printf(seq, "%-24s\t%lu\n", xfrm_mib_list[i].name, | 56 | seq_printf(seq, "%-24s\t%lu\n", xfrm_mib_list[i].name, |
| 57 | snmp_fold_field((void __percpu **) | 57 | snmp_fold_field((void __percpu **) |
| 58 | net->mib.xfrm_statistics, | 58 | net->mib.xfrm_statistics, |
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index 68c2f357a183..a26b7aa79475 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c | |||
| @@ -35,8 +35,6 @@ | |||
| 35 | destination/tunnel endpoint. (output) | 35 | destination/tunnel endpoint. (output) |
| 36 | */ | 36 | */ |
| 37 | 37 | ||
| 38 | static DEFINE_SPINLOCK(xfrm_state_lock); | ||
| 39 | |||
| 40 | static unsigned int xfrm_state_hashmax __read_mostly = 1 * 1024 * 1024; | 38 | static unsigned int xfrm_state_hashmax __read_mostly = 1 * 1024 * 1024; |
| 41 | 39 | ||
| 42 | static inline unsigned int xfrm_dst_hash(struct net *net, | 40 | static inline unsigned int xfrm_dst_hash(struct net *net, |
| @@ -127,7 +125,7 @@ static void xfrm_hash_resize(struct work_struct *work) | |||
| 127 | goto out_unlock; | 125 | goto out_unlock; |
| 128 | } | 126 | } |
| 129 | 127 | ||
| 130 | spin_lock_bh(&xfrm_state_lock); | 128 | spin_lock_bh(&net->xfrm.xfrm_state_lock); |
| 131 | 129 | ||
| 132 | nhashmask = (nsize / sizeof(struct hlist_head)) - 1U; | 130 | nhashmask = (nsize / sizeof(struct hlist_head)) - 1U; |
| 133 | for (i = net->xfrm.state_hmask; i >= 0; i--) | 131 | for (i = net->xfrm.state_hmask; i >= 0; i--) |
| @@ -144,7 +142,7 @@ static void xfrm_hash_resize(struct work_struct *work) | |||
| 144 | net->xfrm.state_byspi = nspi; | 142 | net->xfrm.state_byspi = nspi; |
| 145 | net->xfrm.state_hmask = nhashmask; | 143 | net->xfrm.state_hmask = nhashmask; |
| 146 | 144 | ||
| 147 | spin_unlock_bh(&xfrm_state_lock); | 145 | spin_unlock_bh(&net->xfrm.xfrm_state_lock); |
| 148 | 146 | ||
| 149 | osize = (ohashmask + 1) * sizeof(struct hlist_head); | 147 | osize = (ohashmask + 1) * sizeof(struct hlist_head); |
| 150 | xfrm_hash_free(odst, osize); | 148 | xfrm_hash_free(odst, osize); |
| @@ -374,8 +372,6 @@ static void xfrm_state_gc_task(struct work_struct *work) | |||
| 374 | 372 | ||
| 375 | hlist_for_each_entry_safe(x, tmp, &gc_list, gclist) | 373 | hlist_for_each_entry_safe(x, tmp, &gc_list, gclist) |
| 376 | xfrm_state_gc_destroy(x); | 374 | xfrm_state_gc_destroy(x); |
| 377 | |||
| 378 | wake_up(&net->xfrm.km_waitq); | ||
| 379 | } | 375 | } |
| 380 | 376 | ||
| 381 | static inline unsigned long make_jiffies(long secs) | 377 | static inline unsigned long make_jiffies(long secs) |
| @@ -386,11 +382,10 @@ static inline unsigned long make_jiffies(long secs) | |||
| 386 | return secs*HZ; | 382 | return secs*HZ; |
| 387 | } | 383 | } |
| 388 | 384 | ||
| 389 | static enum hrtimer_restart xfrm_timer_handler(struct hrtimer * me) | 385 | static enum hrtimer_restart xfrm_timer_handler(struct hrtimer *me) |
| 390 | { | 386 | { |
| 391 | struct tasklet_hrtimer *thr = container_of(me, struct tasklet_hrtimer, timer); | 387 | struct tasklet_hrtimer *thr = container_of(me, struct tasklet_hrtimer, timer); |
| 392 | struct xfrm_state *x = container_of(thr, struct xfrm_state, mtimer); | 388 | struct xfrm_state *x = container_of(thr, struct xfrm_state, mtimer); |
| 393 | struct net *net = xs_net(x); | ||
| 394 | unsigned long now = get_seconds(); | 389 | unsigned long now = get_seconds(); |
| 395 | long next = LONG_MAX; | 390 | long next = LONG_MAX; |
| 396 | int warn = 0; | 391 | int warn = 0; |
| @@ -453,19 +448,15 @@ static enum hrtimer_restart xfrm_timer_handler(struct hrtimer * me) | |||
| 453 | if (warn) | 448 | if (warn) |
| 454 | km_state_expired(x, 0, 0); | 449 | km_state_expired(x, 0, 0); |
| 455 | resched: | 450 | resched: |
| 456 | if (next != LONG_MAX){ | 451 | if (next != LONG_MAX) { |
| 457 | tasklet_hrtimer_start(&x->mtimer, ktime_set(next, 0), HRTIMER_MODE_REL); | 452 | tasklet_hrtimer_start(&x->mtimer, ktime_set(next, 0), HRTIMER_MODE_REL); |
| 458 | } | 453 | } |
| 459 | 454 | ||
| 460 | goto out; | 455 | goto out; |
| 461 | 456 | ||
| 462 | expired: | 457 | expired: |
| 463 | if (x->km.state == XFRM_STATE_ACQ && x->id.spi == 0) { | 458 | if (x->km.state == XFRM_STATE_ACQ && x->id.spi == 0) |
| 464 | x->km.state = XFRM_STATE_EXPIRED; | 459 | x->km.state = XFRM_STATE_EXPIRED; |
| 465 | wake_up(&net->xfrm.km_waitq); | ||
| 466 | next = 2; | ||
| 467 | goto resched; | ||
| 468 | } | ||
| 469 | 460 | ||
| 470 | err = __xfrm_state_delete(x); | 461 | err = __xfrm_state_delete(x); |
| 471 | if (!err) | 462 | if (!err) |
| @@ -535,14 +526,14 @@ int __xfrm_state_delete(struct xfrm_state *x) | |||
| 535 | 526 | ||
| 536 | if (x->km.state != XFRM_STATE_DEAD) { | 527 | if (x->km.state != XFRM_STATE_DEAD) { |
| 537 | x->km.state = XFRM_STATE_DEAD; | 528 | x->km.state = XFRM_STATE_DEAD; |
| 538 | spin_lock(&xfrm_state_lock); | 529 | spin_lock(&net->xfrm.xfrm_state_lock); |
| 539 | list_del(&x->km.all); | 530 | list_del(&x->km.all); |
| 540 | hlist_del(&x->bydst); | 531 | hlist_del(&x->bydst); |
| 541 | hlist_del(&x->bysrc); | 532 | hlist_del(&x->bysrc); |
| 542 | if (x->id.spi) | 533 | if (x->id.spi) |
| 543 | hlist_del(&x->byspi); | 534 | hlist_del(&x->byspi); |
| 544 | net->xfrm.state_num--; | 535 | net->xfrm.state_num--; |
| 545 | spin_unlock(&xfrm_state_lock); | 536 | spin_unlock(&net->xfrm.xfrm_state_lock); |
| 546 | 537 | ||
| 547 | /* All xfrm_state objects are created by xfrm_state_alloc. | 538 | /* All xfrm_state objects are created by xfrm_state_alloc. |
| 548 | * The xfrm_state_alloc call gives a reference, and that | 539 | * The xfrm_state_alloc call gives a reference, and that |
| @@ -603,7 +594,7 @@ int xfrm_state_flush(struct net *net, u8 proto, struct xfrm_audit *audit_info) | |||
| 603 | { | 594 | { |
| 604 | int i, err = 0, cnt = 0; | 595 | int i, err = 0, cnt = 0; |
| 605 | 596 | ||
| 606 | spin_lock_bh(&xfrm_state_lock); | 597 | spin_lock_bh(&net->xfrm.xfrm_state_lock); |
| 607 | err = xfrm_state_flush_secctx_check(net, proto, audit_info); | 598 | err = xfrm_state_flush_secctx_check(net, proto, audit_info); |
| 608 | if (err) | 599 | if (err) |
| 609 | goto out; | 600 | goto out; |
| @@ -616,7 +607,7 @@ restart: | |||
| 616 | if (!xfrm_state_kern(x) && | 607 | if (!xfrm_state_kern(x) && |
| 617 | xfrm_id_proto_match(x->id.proto, proto)) { | 608 | xfrm_id_proto_match(x->id.proto, proto)) { |
| 618 | xfrm_state_hold(x); | 609 | xfrm_state_hold(x); |
| 619 | spin_unlock_bh(&xfrm_state_lock); | 610 | spin_unlock_bh(&net->xfrm.xfrm_state_lock); |
| 620 | 611 | ||
| 621 | err = xfrm_state_delete(x); | 612 | err = xfrm_state_delete(x); |
| 622 | xfrm_audit_state_delete(x, err ? 0 : 1, | 613 | xfrm_audit_state_delete(x, err ? 0 : 1, |
| @@ -627,7 +618,7 @@ restart: | |||
| 627 | if (!err) | 618 | if (!err) |
| 628 | cnt++; | 619 | cnt++; |
| 629 | 620 | ||
| 630 | spin_lock_bh(&xfrm_state_lock); | 621 | spin_lock_bh(&net->xfrm.xfrm_state_lock); |
| 631 | goto restart; | 622 | goto restart; |
| 632 | } | 623 | } |
| 633 | } | 624 | } |
| @@ -636,19 +627,18 @@ restart: | |||
| 636 | err = 0; | 627 | err = 0; |
| 637 | 628 | ||
| 638 | out: | 629 | out: |
| 639 | spin_unlock_bh(&xfrm_state_lock); | 630 | spin_unlock_bh(&net->xfrm.xfrm_state_lock); |
| 640 | wake_up(&net->xfrm.km_waitq); | ||
| 641 | return err; | 631 | return err; |
| 642 | } | 632 | } |
| 643 | EXPORT_SYMBOL(xfrm_state_flush); | 633 | EXPORT_SYMBOL(xfrm_state_flush); |
| 644 | 634 | ||
| 645 | void xfrm_sad_getinfo(struct net *net, struct xfrmk_sadinfo *si) | 635 | void xfrm_sad_getinfo(struct net *net, struct xfrmk_sadinfo *si) |
| 646 | { | 636 | { |
| 647 | spin_lock_bh(&xfrm_state_lock); | 637 | spin_lock_bh(&net->xfrm.xfrm_state_lock); |
| 648 | si->sadcnt = net->xfrm.state_num; | 638 | si->sadcnt = net->xfrm.state_num; |
| 649 | si->sadhcnt = net->xfrm.state_hmask; | 639 | si->sadhcnt = net->xfrm.state_hmask; |
| 650 | si->sadhmcnt = xfrm_state_hashmax; | 640 | si->sadhmcnt = xfrm_state_hashmax; |
| 651 | spin_unlock_bh(&xfrm_state_lock); | 641 | spin_unlock_bh(&net->xfrm.xfrm_state_lock); |
| 652 | } | 642 | } |
| 653 | EXPORT_SYMBOL(xfrm_sad_getinfo); | 643 | EXPORT_SYMBOL(xfrm_sad_getinfo); |
| 654 | 644 | ||
| @@ -801,7 +791,7 @@ xfrm_state_find(const xfrm_address_t *daddr, const xfrm_address_t *saddr, | |||
| 801 | 791 | ||
| 802 | to_put = NULL; | 792 | to_put = NULL; |
| 803 | 793 | ||
| 804 | spin_lock_bh(&xfrm_state_lock); | 794 | spin_lock_bh(&net->xfrm.xfrm_state_lock); |
| 805 | h = xfrm_dst_hash(net, daddr, saddr, tmpl->reqid, encap_family); | 795 | h = xfrm_dst_hash(net, daddr, saddr, tmpl->reqid, encap_family); |
| 806 | hlist_for_each_entry(x, net->xfrm.state_bydst+h, bydst) { | 796 | hlist_for_each_entry(x, net->xfrm.state_bydst+h, bydst) { |
| 807 | if (x->props.family == encap_family && | 797 | if (x->props.family == encap_family && |
| @@ -886,7 +876,7 @@ out: | |||
| 886 | xfrm_state_hold(x); | 876 | xfrm_state_hold(x); |
| 887 | else | 877 | else |
| 888 | *err = acquire_in_progress ? -EAGAIN : error; | 878 | *err = acquire_in_progress ? -EAGAIN : error; |
| 889 | spin_unlock_bh(&xfrm_state_lock); | 879 | spin_unlock_bh(&net->xfrm.xfrm_state_lock); |
| 890 | if (to_put) | 880 | if (to_put) |
| 891 | xfrm_state_put(to_put); | 881 | xfrm_state_put(to_put); |
| 892 | return x; | 882 | return x; |
| @@ -900,7 +890,7 @@ xfrm_stateonly_find(struct net *net, u32 mark, | |||
| 900 | unsigned int h; | 890 | unsigned int h; |
| 901 | struct xfrm_state *rx = NULL, *x = NULL; | 891 | struct xfrm_state *rx = NULL, *x = NULL; |
| 902 | 892 | ||
| 903 | spin_lock(&xfrm_state_lock); | 893 | spin_lock_bh(&net->xfrm.xfrm_state_lock); |
| 904 | h = xfrm_dst_hash(net, daddr, saddr, reqid, family); | 894 | h = xfrm_dst_hash(net, daddr, saddr, reqid, family); |
| 905 | hlist_for_each_entry(x, net->xfrm.state_bydst+h, bydst) { | 895 | hlist_for_each_entry(x, net->xfrm.state_bydst+h, bydst) { |
| 906 | if (x->props.family == family && | 896 | if (x->props.family == family && |
| @@ -918,13 +908,35 @@ xfrm_stateonly_find(struct net *net, u32 mark, | |||
| 918 | 908 | ||
| 919 | if (rx) | 909 | if (rx) |
| 920 | xfrm_state_hold(rx); | 910 | xfrm_state_hold(rx); |
| 921 | spin_unlock(&xfrm_state_lock); | 911 | spin_unlock_bh(&net->xfrm.xfrm_state_lock); |
| 922 | 912 | ||
| 923 | 913 | ||
| 924 | return rx; | 914 | return rx; |
| 925 | } | 915 | } |
| 926 | EXPORT_SYMBOL(xfrm_stateonly_find); | 916 | EXPORT_SYMBOL(xfrm_stateonly_find); |
| 927 | 917 | ||
| 918 | struct xfrm_state *xfrm_state_lookup_byspi(struct net *net, __be32 spi, | ||
| 919 | unsigned short family) | ||
| 920 | { | ||
| 921 | struct xfrm_state *x; | ||
| 922 | struct xfrm_state_walk *w; | ||
| 923 | |||
| 924 | spin_lock_bh(&net->xfrm.xfrm_state_lock); | ||
| 925 | list_for_each_entry(w, &net->xfrm.state_all, all) { | ||
| 926 | x = container_of(w, struct xfrm_state, km); | ||
| 927 | if (x->props.family != family || | ||
| 928 | x->id.spi != spi) | ||
| 929 | continue; | ||
| 930 | |||
| 931 | spin_unlock_bh(&net->xfrm.xfrm_state_lock); | ||
| 932 | xfrm_state_hold(x); | ||
| 933 | return x; | ||
| 934 | } | ||
| 935 | spin_unlock_bh(&net->xfrm.xfrm_state_lock); | ||
| 936 | return NULL; | ||
| 937 | } | ||
| 938 | EXPORT_SYMBOL(xfrm_state_lookup_byspi); | ||
| 939 | |||
| 928 | static void __xfrm_state_insert(struct xfrm_state *x) | 940 | static void __xfrm_state_insert(struct xfrm_state *x) |
| 929 | { | 941 | { |
| 930 | struct net *net = xs_net(x); | 942 | struct net *net = xs_net(x); |
| @@ -950,14 +962,12 @@ static void __xfrm_state_insert(struct xfrm_state *x) | |||
| 950 | if (x->replay_maxage) | 962 | if (x->replay_maxage) |
| 951 | mod_timer(&x->rtimer, jiffies + x->replay_maxage); | 963 | mod_timer(&x->rtimer, jiffies + x->replay_maxage); |
| 952 | 964 | ||
| 953 | wake_up(&net->xfrm.km_waitq); | ||
| 954 | |||
| 955 | net->xfrm.state_num++; | 965 | net->xfrm.state_num++; |
| 956 | 966 | ||
| 957 | xfrm_hash_grow_check(net, x->bydst.next != NULL); | 967 | xfrm_hash_grow_check(net, x->bydst.next != NULL); |
| 958 | } | 968 | } |
| 959 | 969 | ||
| 960 | /* xfrm_state_lock is held */ | 970 | /* net->xfrm.xfrm_state_lock is held */ |
| 961 | static void __xfrm_state_bump_genids(struct xfrm_state *xnew) | 971 | static void __xfrm_state_bump_genids(struct xfrm_state *xnew) |
| 962 | { | 972 | { |
| 963 | struct net *net = xs_net(xnew); | 973 | struct net *net = xs_net(xnew); |
| @@ -980,14 +990,16 @@ static void __xfrm_state_bump_genids(struct xfrm_state *xnew) | |||
| 980 | 990 | ||
| 981 | void xfrm_state_insert(struct xfrm_state *x) | 991 | void xfrm_state_insert(struct xfrm_state *x) |
| 982 | { | 992 | { |
| 983 | spin_lock_bh(&xfrm_state_lock); | 993 | struct net *net = xs_net(x); |
| 994 | |||
| 995 | spin_lock_bh(&net->xfrm.xfrm_state_lock); | ||
| 984 | __xfrm_state_bump_genids(x); | 996 | __xfrm_state_bump_genids(x); |
| 985 | __xfrm_state_insert(x); | 997 | __xfrm_state_insert(x); |
| 986 | spin_unlock_bh(&xfrm_state_lock); | 998 | spin_unlock_bh(&net->xfrm.xfrm_state_lock); |
| 987 | } | 999 | } |
| 988 | EXPORT_SYMBOL(xfrm_state_insert); | 1000 | EXPORT_SYMBOL(xfrm_state_insert); |
| 989 | 1001 | ||
| 990 | /* xfrm_state_lock is held */ | 1002 | /* net->xfrm.xfrm_state_lock is held */ |
| 991 | static struct xfrm_state *__find_acq_core(struct net *net, | 1003 | static struct xfrm_state *__find_acq_core(struct net *net, |
| 992 | const struct xfrm_mark *m, | 1004 | const struct xfrm_mark *m, |
| 993 | unsigned short family, u8 mode, | 1005 | unsigned short family, u8 mode, |
| @@ -1079,7 +1091,7 @@ int xfrm_state_add(struct xfrm_state *x) | |||
| 1079 | 1091 | ||
| 1080 | to_put = NULL; | 1092 | to_put = NULL; |
| 1081 | 1093 | ||
| 1082 | spin_lock_bh(&xfrm_state_lock); | 1094 | spin_lock_bh(&net->xfrm.xfrm_state_lock); |
| 1083 | 1095 | ||
| 1084 | x1 = __xfrm_state_locate(x, use_spi, family); | 1096 | x1 = __xfrm_state_locate(x, use_spi, family); |
| 1085 | if (x1) { | 1097 | if (x1) { |
| @@ -1108,7 +1120,7 @@ int xfrm_state_add(struct xfrm_state *x) | |||
| 1108 | err = 0; | 1120 | err = 0; |
| 1109 | 1121 | ||
| 1110 | out: | 1122 | out: |
| 1111 | spin_unlock_bh(&xfrm_state_lock); | 1123 | spin_unlock_bh(&net->xfrm.xfrm_state_lock); |
| 1112 | 1124 | ||
| 1113 | if (x1) { | 1125 | if (x1) { |
| 1114 | xfrm_state_delete(x1); | 1126 | xfrm_state_delete(x1); |
| @@ -1203,16 +1215,16 @@ out: | |||
| 1203 | return NULL; | 1215 | return NULL; |
| 1204 | } | 1216 | } |
| 1205 | 1217 | ||
| 1206 | /* xfrm_state_lock is held */ | 1218 | /* net->xfrm.xfrm_state_lock is held */ |
| 1207 | struct xfrm_state * xfrm_migrate_state_find(struct xfrm_migrate *m) | 1219 | struct xfrm_state *xfrm_migrate_state_find(struct xfrm_migrate *m, struct net *net) |
| 1208 | { | 1220 | { |
| 1209 | unsigned int h; | 1221 | unsigned int h; |
| 1210 | struct xfrm_state *x; | 1222 | struct xfrm_state *x; |
| 1211 | 1223 | ||
| 1212 | if (m->reqid) { | 1224 | if (m->reqid) { |
| 1213 | h = xfrm_dst_hash(&init_net, &m->old_daddr, &m->old_saddr, | 1225 | h = xfrm_dst_hash(net, &m->old_daddr, &m->old_saddr, |
| 1214 | m->reqid, m->old_family); | 1226 | m->reqid, m->old_family); |
| 1215 | hlist_for_each_entry(x, init_net.xfrm.state_bydst+h, bydst) { | 1227 | hlist_for_each_entry(x, net->xfrm.state_bydst+h, bydst) { |
| 1216 | if (x->props.mode != m->mode || | 1228 | if (x->props.mode != m->mode || |
| 1217 | x->id.proto != m->proto) | 1229 | x->id.proto != m->proto) |
| 1218 | continue; | 1230 | continue; |
| @@ -1227,9 +1239,9 @@ struct xfrm_state * xfrm_migrate_state_find(struct xfrm_migrate *m) | |||
| 1227 | return x; | 1239 | return x; |
| 1228 | } | 1240 | } |
| 1229 | } else { | 1241 | } else { |
| 1230 | h = xfrm_src_hash(&init_net, &m->old_daddr, &m->old_saddr, | 1242 | h = xfrm_src_hash(net, &m->old_daddr, &m->old_saddr, |
| 1231 | m->old_family); | 1243 | m->old_family); |
| 1232 | hlist_for_each_entry(x, init_net.xfrm.state_bysrc+h, bysrc) { | 1244 | hlist_for_each_entry(x, net->xfrm.state_bysrc+h, bysrc) { |
| 1233 | if (x->props.mode != m->mode || | 1245 | if (x->props.mode != m->mode || |
| 1234 | x->id.proto != m->proto) | 1246 | x->id.proto != m->proto) |
| 1235 | continue; | 1247 | continue; |
| @@ -1247,8 +1259,8 @@ struct xfrm_state * xfrm_migrate_state_find(struct xfrm_migrate *m) | |||
| 1247 | } | 1259 | } |
| 1248 | EXPORT_SYMBOL(xfrm_migrate_state_find); | 1260 | EXPORT_SYMBOL(xfrm_migrate_state_find); |
| 1249 | 1261 | ||
| 1250 | struct xfrm_state * xfrm_state_migrate(struct xfrm_state *x, | 1262 | struct xfrm_state *xfrm_state_migrate(struct xfrm_state *x, |
| 1251 | struct xfrm_migrate *m) | 1263 | struct xfrm_migrate *m) |
| 1252 | { | 1264 | { |
| 1253 | struct xfrm_state *xc; | 1265 | struct xfrm_state *xc; |
| 1254 | int err; | 1266 | int err; |
| @@ -1283,10 +1295,11 @@ int xfrm_state_update(struct xfrm_state *x) | |||
| 1283 | struct xfrm_state *x1, *to_put; | 1295 | struct xfrm_state *x1, *to_put; |
| 1284 | int err; | 1296 | int err; |
| 1285 | int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY); | 1297 | int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY); |
| 1298 | struct net *net = xs_net(x); | ||
| 1286 | 1299 | ||
| 1287 | to_put = NULL; | 1300 | to_put = NULL; |
| 1288 | 1301 | ||
| 1289 | spin_lock_bh(&xfrm_state_lock); | 1302 | spin_lock_bh(&net->xfrm.xfrm_state_lock); |
| 1290 | x1 = __xfrm_state_locate(x, use_spi, x->props.family); | 1303 | x1 = __xfrm_state_locate(x, use_spi, x->props.family); |
| 1291 | 1304 | ||
| 1292 | err = -ESRCH; | 1305 | err = -ESRCH; |
| @@ -1306,7 +1319,7 @@ int xfrm_state_update(struct xfrm_state *x) | |||
| 1306 | err = 0; | 1319 | err = 0; |
| 1307 | 1320 | ||
| 1308 | out: | 1321 | out: |
| 1309 | spin_unlock_bh(&xfrm_state_lock); | 1322 | spin_unlock_bh(&net->xfrm.xfrm_state_lock); |
| 1310 | 1323 | ||
| 1311 | if (to_put) | 1324 | if (to_put) |
| 1312 | xfrm_state_put(to_put); | 1325 | xfrm_state_put(to_put); |
| @@ -1357,7 +1370,7 @@ int xfrm_state_check_expire(struct xfrm_state *x) | |||
| 1357 | if (x->curlft.bytes >= x->lft.hard_byte_limit || | 1370 | if (x->curlft.bytes >= x->lft.hard_byte_limit || |
| 1358 | x->curlft.packets >= x->lft.hard_packet_limit) { | 1371 | x->curlft.packets >= x->lft.hard_packet_limit) { |
| 1359 | x->km.state = XFRM_STATE_EXPIRED; | 1372 | x->km.state = XFRM_STATE_EXPIRED; |
| 1360 | tasklet_hrtimer_start(&x->mtimer, ktime_set(0,0), HRTIMER_MODE_REL); | 1373 | tasklet_hrtimer_start(&x->mtimer, ktime_set(0, 0), HRTIMER_MODE_REL); |
| 1361 | return -EINVAL; | 1374 | return -EINVAL; |
| 1362 | } | 1375 | } |
| 1363 | 1376 | ||
| @@ -1377,9 +1390,9 @@ xfrm_state_lookup(struct net *net, u32 mark, const xfrm_address_t *daddr, __be32 | |||
| 1377 | { | 1390 | { |
| 1378 | struct xfrm_state *x; | 1391 | struct xfrm_state *x; |
| 1379 | 1392 | ||
| 1380 | spin_lock_bh(&xfrm_state_lock); | 1393 | spin_lock_bh(&net->xfrm.xfrm_state_lock); |
| 1381 | x = __xfrm_state_lookup(net, mark, daddr, spi, proto, family); | 1394 | x = __xfrm_state_lookup(net, mark, daddr, spi, proto, family); |
| 1382 | spin_unlock_bh(&xfrm_state_lock); | 1395 | spin_unlock_bh(&net->xfrm.xfrm_state_lock); |
| 1383 | return x; | 1396 | return x; |
| 1384 | } | 1397 | } |
| 1385 | EXPORT_SYMBOL(xfrm_state_lookup); | 1398 | EXPORT_SYMBOL(xfrm_state_lookup); |
| @@ -1391,9 +1404,9 @@ xfrm_state_lookup_byaddr(struct net *net, u32 mark, | |||
| 1391 | { | 1404 | { |
| 1392 | struct xfrm_state *x; | 1405 | struct xfrm_state *x; |
| 1393 | 1406 | ||
| 1394 | spin_lock_bh(&xfrm_state_lock); | 1407 | spin_lock_bh(&net->xfrm.xfrm_state_lock); |
| 1395 | x = __xfrm_state_lookup_byaddr(net, mark, daddr, saddr, proto, family); | 1408 | x = __xfrm_state_lookup_byaddr(net, mark, daddr, saddr, proto, family); |
| 1396 | spin_unlock_bh(&xfrm_state_lock); | 1409 | spin_unlock_bh(&net->xfrm.xfrm_state_lock); |
| 1397 | return x; | 1410 | return x; |
| 1398 | } | 1411 | } |
| 1399 | EXPORT_SYMBOL(xfrm_state_lookup_byaddr); | 1412 | EXPORT_SYMBOL(xfrm_state_lookup_byaddr); |
| @@ -1405,9 +1418,9 @@ xfrm_find_acq(struct net *net, const struct xfrm_mark *mark, u8 mode, u32 reqid, | |||
| 1405 | { | 1418 | { |
| 1406 | struct xfrm_state *x; | 1419 | struct xfrm_state *x; |
| 1407 | 1420 | ||
| 1408 | spin_lock_bh(&xfrm_state_lock); | 1421 | spin_lock_bh(&net->xfrm.xfrm_state_lock); |
| 1409 | x = __find_acq_core(net, mark, family, mode, reqid, proto, daddr, saddr, create); | 1422 | x = __find_acq_core(net, mark, family, mode, reqid, proto, daddr, saddr, create); |
| 1410 | spin_unlock_bh(&xfrm_state_lock); | 1423 | spin_unlock_bh(&net->xfrm.xfrm_state_lock); |
| 1411 | 1424 | ||
| 1412 | return x; | 1425 | return x; |
| 1413 | } | 1426 | } |
| @@ -1416,17 +1429,17 @@ EXPORT_SYMBOL(xfrm_find_acq); | |||
| 1416 | #ifdef CONFIG_XFRM_SUB_POLICY | 1429 | #ifdef CONFIG_XFRM_SUB_POLICY |
| 1417 | int | 1430 | int |
| 1418 | xfrm_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n, | 1431 | xfrm_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n, |
| 1419 | unsigned short family) | 1432 | unsigned short family, struct net *net) |
| 1420 | { | 1433 | { |
| 1421 | int err = 0; | 1434 | int err = 0; |
| 1422 | struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family); | 1435 | struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family); |
| 1423 | if (!afinfo) | 1436 | if (!afinfo) |
| 1424 | return -EAFNOSUPPORT; | 1437 | return -EAFNOSUPPORT; |
| 1425 | 1438 | ||
| 1426 | spin_lock_bh(&xfrm_state_lock); | 1439 | spin_lock_bh(&net->xfrm.xfrm_state_lock); /*FIXME*/ |
| 1427 | if (afinfo->tmpl_sort) | 1440 | if (afinfo->tmpl_sort) |
| 1428 | err = afinfo->tmpl_sort(dst, src, n); | 1441 | err = afinfo->tmpl_sort(dst, src, n); |
| 1429 | spin_unlock_bh(&xfrm_state_lock); | 1442 | spin_unlock_bh(&net->xfrm.xfrm_state_lock); |
| 1430 | xfrm_state_put_afinfo(afinfo); | 1443 | xfrm_state_put_afinfo(afinfo); |
| 1431 | return err; | 1444 | return err; |
| 1432 | } | 1445 | } |
| @@ -1438,13 +1451,15 @@ xfrm_state_sort(struct xfrm_state **dst, struct xfrm_state **src, int n, | |||
| 1438 | { | 1451 | { |
| 1439 | int err = 0; | 1452 | int err = 0; |
| 1440 | struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family); | 1453 | struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family); |
| 1454 | struct net *net = xs_net(*dst); | ||
| 1455 | |||
| 1441 | if (!afinfo) | 1456 | if (!afinfo) |
| 1442 | return -EAFNOSUPPORT; | 1457 | return -EAFNOSUPPORT; |
| 1443 | 1458 | ||
| 1444 | spin_lock_bh(&xfrm_state_lock); | 1459 | spin_lock_bh(&net->xfrm.xfrm_state_lock); |
| 1445 | if (afinfo->state_sort) | 1460 | if (afinfo->state_sort) |
| 1446 | err = afinfo->state_sort(dst, src, n); | 1461 | err = afinfo->state_sort(dst, src, n); |
| 1447 | spin_unlock_bh(&xfrm_state_lock); | 1462 | spin_unlock_bh(&net->xfrm.xfrm_state_lock); |
| 1448 | xfrm_state_put_afinfo(afinfo); | 1463 | xfrm_state_put_afinfo(afinfo); |
| 1449 | return err; | 1464 | return err; |
| 1450 | } | 1465 | } |
| @@ -1476,9 +1491,9 @@ struct xfrm_state *xfrm_find_acq_byseq(struct net *net, u32 mark, u32 seq) | |||
| 1476 | { | 1491 | { |
| 1477 | struct xfrm_state *x; | 1492 | struct xfrm_state *x; |
| 1478 | 1493 | ||
| 1479 | spin_lock_bh(&xfrm_state_lock); | 1494 | spin_lock_bh(&net->xfrm.xfrm_state_lock); |
| 1480 | x = __xfrm_find_acq_byseq(net, mark, seq); | 1495 | x = __xfrm_find_acq_byseq(net, mark, seq); |
| 1481 | spin_unlock_bh(&xfrm_state_lock); | 1496 | spin_unlock_bh(&net->xfrm.xfrm_state_lock); |
| 1482 | return x; | 1497 | return x; |
| 1483 | } | 1498 | } |
| 1484 | EXPORT_SYMBOL(xfrm_find_acq_byseq); | 1499 | EXPORT_SYMBOL(xfrm_find_acq_byseq); |
| @@ -1496,6 +1511,30 @@ u32 xfrm_get_acqseq(void) | |||
| 1496 | } | 1511 | } |
| 1497 | EXPORT_SYMBOL(xfrm_get_acqseq); | 1512 | EXPORT_SYMBOL(xfrm_get_acqseq); |
| 1498 | 1513 | ||
| 1514 | int verify_spi_info(u8 proto, u32 min, u32 max) | ||
| 1515 | { | ||
| 1516 | switch (proto) { | ||
| 1517 | case IPPROTO_AH: | ||
| 1518 | case IPPROTO_ESP: | ||
| 1519 | break; | ||
| 1520 | |||
| 1521 | case IPPROTO_COMP: | ||
| 1522 | /* IPCOMP spi is 16-bits. */ | ||
| 1523 | if (max >= 0x10000) | ||
| 1524 | return -EINVAL; | ||
| 1525 | break; | ||
| 1526 | |||
| 1527 | default: | ||
| 1528 | return -EINVAL; | ||
| 1529 | } | ||
| 1530 | |||
| 1531 | if (min > max) | ||
| 1532 | return -EINVAL; | ||
| 1533 | |||
| 1534 | return 0; | ||
| 1535 | } | ||
| 1536 | EXPORT_SYMBOL(verify_spi_info); | ||
| 1537 | |||
| 1499 | int xfrm_alloc_spi(struct xfrm_state *x, u32 low, u32 high) | 1538 | int xfrm_alloc_spi(struct xfrm_state *x, u32 low, u32 high) |
| 1500 | { | 1539 | { |
| 1501 | struct net *net = xs_net(x); | 1540 | struct net *net = xs_net(x); |
| @@ -1525,8 +1564,8 @@ int xfrm_alloc_spi(struct xfrm_state *x, u32 low, u32 high) | |||
| 1525 | x->id.spi = minspi; | 1564 | x->id.spi = minspi; |
| 1526 | } else { | 1565 | } else { |
| 1527 | u32 spi = 0; | 1566 | u32 spi = 0; |
| 1528 | for (h=0; h<high-low+1; h++) { | 1567 | for (h = 0; h < high-low+1; h++) { |
| 1529 | spi = low + net_random()%(high-low+1); | 1568 | spi = low + prandom_u32()%(high-low+1); |
| 1530 | x0 = xfrm_state_lookup(net, mark, &x->id.daddr, htonl(spi), x->id.proto, x->props.family); | 1569 | x0 = xfrm_state_lookup(net, mark, &x->id.daddr, htonl(spi), x->id.proto, x->props.family); |
| 1531 | if (x0 == NULL) { | 1570 | if (x0 == NULL) { |
| 1532 | x->id.spi = htonl(spi); | 1571 | x->id.spi = htonl(spi); |
| @@ -1536,10 +1575,10 @@ int xfrm_alloc_spi(struct xfrm_state *x, u32 low, u32 high) | |||
| 1536 | } | 1575 | } |
| 1537 | } | 1576 | } |
| 1538 | if (x->id.spi) { | 1577 | if (x->id.spi) { |
| 1539 | spin_lock_bh(&xfrm_state_lock); | 1578 | spin_lock_bh(&net->xfrm.xfrm_state_lock); |
| 1540 | h = xfrm_spi_hash(net, &x->id.daddr, x->id.spi, x->id.proto, x->props.family); | 1579 | h = xfrm_spi_hash(net, &x->id.daddr, x->id.spi, x->id.proto, x->props.family); |
| 1541 | hlist_add_head(&x->byspi, net->xfrm.state_byspi+h); | 1580 | hlist_add_head(&x->byspi, net->xfrm.state_byspi+h); |
| 1542 | spin_unlock_bh(&xfrm_state_lock); | 1581 | spin_unlock_bh(&net->xfrm.xfrm_state_lock); |
| 1543 | 1582 | ||
| 1544 | err = 0; | 1583 | err = 0; |
| 1545 | } | 1584 | } |
| @@ -1562,7 +1601,7 @@ int xfrm_state_walk(struct net *net, struct xfrm_state_walk *walk, | |||
| 1562 | if (walk->seq != 0 && list_empty(&walk->all)) | 1601 | if (walk->seq != 0 && list_empty(&walk->all)) |
| 1563 | return 0; | 1602 | return 0; |
| 1564 | 1603 | ||
| 1565 | spin_lock_bh(&xfrm_state_lock); | 1604 | spin_lock_bh(&net->xfrm.xfrm_state_lock); |
| 1566 | if (list_empty(&walk->all)) | 1605 | if (list_empty(&walk->all)) |
| 1567 | x = list_first_entry(&net->xfrm.state_all, struct xfrm_state_walk, all); | 1606 | x = list_first_entry(&net->xfrm.state_all, struct xfrm_state_walk, all); |
| 1568 | else | 1607 | else |
| @@ -1586,7 +1625,7 @@ int xfrm_state_walk(struct net *net, struct xfrm_state_walk *walk, | |||
| 1586 | } | 1625 | } |
| 1587 | list_del_init(&walk->all); | 1626 | list_del_init(&walk->all); |
| 1588 | out: | 1627 | out: |
| 1589 | spin_unlock_bh(&xfrm_state_lock); | 1628 | spin_unlock_bh(&net->xfrm.xfrm_state_lock); |
| 1590 | return err; | 1629 | return err; |
| 1591 | } | 1630 | } |
| 1592 | EXPORT_SYMBOL(xfrm_state_walk); | 1631 | EXPORT_SYMBOL(xfrm_state_walk); |
| @@ -1600,20 +1639,20 @@ void xfrm_state_walk_init(struct xfrm_state_walk *walk, u8 proto) | |||
| 1600 | } | 1639 | } |
| 1601 | EXPORT_SYMBOL(xfrm_state_walk_init); | 1640 | EXPORT_SYMBOL(xfrm_state_walk_init); |
| 1602 | 1641 | ||
| 1603 | void xfrm_state_walk_done(struct xfrm_state_walk *walk) | 1642 | void xfrm_state_walk_done(struct xfrm_state_walk *walk, struct net *net) |
| 1604 | { | 1643 | { |
| 1605 | if (list_empty(&walk->all)) | 1644 | if (list_empty(&walk->all)) |
| 1606 | return; | 1645 | return; |
| 1607 | 1646 | ||
| 1608 | spin_lock_bh(&xfrm_state_lock); | 1647 | spin_lock_bh(&net->xfrm.xfrm_state_lock); |
| 1609 | list_del(&walk->all); | 1648 | list_del(&walk->all); |
| 1610 | spin_unlock_bh(&xfrm_state_lock); | 1649 | spin_unlock_bh(&net->xfrm.xfrm_state_lock); |
| 1611 | } | 1650 | } |
| 1612 | EXPORT_SYMBOL(xfrm_state_walk_done); | 1651 | EXPORT_SYMBOL(xfrm_state_walk_done); |
| 1613 | 1652 | ||
| 1614 | static void xfrm_replay_timer_handler(unsigned long data) | 1653 | static void xfrm_replay_timer_handler(unsigned long data) |
| 1615 | { | 1654 | { |
| 1616 | struct xfrm_state *x = (struct xfrm_state*)data; | 1655 | struct xfrm_state *x = (struct xfrm_state *)data; |
| 1617 | 1656 | ||
| 1618 | spin_lock(&x->lock); | 1657 | spin_lock(&x->lock); |
| 1619 | 1658 | ||
| @@ -1655,16 +1694,12 @@ EXPORT_SYMBOL(km_state_notify); | |||
| 1655 | 1694 | ||
| 1656 | void km_state_expired(struct xfrm_state *x, int hard, u32 portid) | 1695 | void km_state_expired(struct xfrm_state *x, int hard, u32 portid) |
| 1657 | { | 1696 | { |
| 1658 | struct net *net = xs_net(x); | ||
| 1659 | struct km_event c; | 1697 | struct km_event c; |
| 1660 | 1698 | ||
| 1661 | c.data.hard = hard; | 1699 | c.data.hard = hard; |
| 1662 | c.portid = portid; | 1700 | c.portid = portid; |
| 1663 | c.event = XFRM_MSG_EXPIRE; | 1701 | c.event = XFRM_MSG_EXPIRE; |
| 1664 | km_state_notify(x, &c); | 1702 | km_state_notify(x, &c); |
| 1665 | |||
| 1666 | if (hard) | ||
| 1667 | wake_up(&net->xfrm.km_waitq); | ||
| 1668 | } | 1703 | } |
| 1669 | 1704 | ||
| 1670 | EXPORT_SYMBOL(km_state_expired); | 1705 | EXPORT_SYMBOL(km_state_expired); |
| @@ -1707,16 +1742,12 @@ EXPORT_SYMBOL(km_new_mapping); | |||
| 1707 | 1742 | ||
| 1708 | void km_policy_expired(struct xfrm_policy *pol, int dir, int hard, u32 portid) | 1743 | void km_policy_expired(struct xfrm_policy *pol, int dir, int hard, u32 portid) |
| 1709 | { | 1744 | { |
| 1710 | struct net *net = xp_net(pol); | ||
| 1711 | struct km_event c; | 1745 | struct km_event c; |
| 1712 | 1746 | ||
| 1713 | c.data.hard = hard; | 1747 | c.data.hard = hard; |
| 1714 | c.portid = portid; | 1748 | c.portid = portid; |
| 1715 | c.event = XFRM_MSG_POLEXPIRE; | 1749 | c.event = XFRM_MSG_POLEXPIRE; |
| 1716 | km_policy_notify(pol, dir, &c); | 1750 | km_policy_notify(pol, dir, &c); |
| 1717 | |||
| 1718 | if (hard) | ||
| 1719 | wake_up(&net->xfrm.km_waitq); | ||
| 1720 | } | 1751 | } |
| 1721 | EXPORT_SYMBOL(km_policy_expired); | 1752 | EXPORT_SYMBOL(km_policy_expired); |
| 1722 | 1753 | ||
| @@ -2025,7 +2056,7 @@ int __net_init xfrm_state_init(struct net *net) | |||
| 2025 | INIT_WORK(&net->xfrm.state_hash_work, xfrm_hash_resize); | 2056 | INIT_WORK(&net->xfrm.state_hash_work, xfrm_hash_resize); |
| 2026 | INIT_HLIST_HEAD(&net->xfrm.state_gc_list); | 2057 | INIT_HLIST_HEAD(&net->xfrm.state_gc_list); |
| 2027 | INIT_WORK(&net->xfrm.state_gc_work, xfrm_state_gc_task); | 2058 | INIT_WORK(&net->xfrm.state_gc_work, xfrm_state_gc_task); |
| 2028 | init_waitqueue_head(&net->xfrm.km_waitq); | 2059 | spin_lock_init(&net->xfrm.xfrm_state_lock); |
| 2029 | return 0; | 2060 | return 0; |
| 2030 | 2061 | ||
| 2031 | out_byspi: | 2062 | out_byspi: |
| @@ -2043,7 +2074,7 @@ void xfrm_state_fini(struct net *net) | |||
| 2043 | 2074 | ||
| 2044 | flush_work(&net->xfrm.state_hash_work); | 2075 | flush_work(&net->xfrm.state_hash_work); |
| 2045 | audit_info.loginuid = INVALID_UID; | 2076 | audit_info.loginuid = INVALID_UID; |
| 2046 | audit_info.sessionid = -1; | 2077 | audit_info.sessionid = (unsigned int)-1; |
| 2047 | audit_info.secid = 0; | 2078 | audit_info.secid = 0; |
| 2048 | xfrm_state_flush(net, IPSEC_PROTO_ANY, &audit_info); | 2079 | xfrm_state_flush(net, IPSEC_PROTO_ANY, &audit_info); |
| 2049 | flush_work(&net->xfrm.state_gc_work); | 2080 | flush_work(&net->xfrm.state_gc_work); |
| @@ -2070,7 +2101,7 @@ static void xfrm_audit_helper_sainfo(struct xfrm_state *x, | |||
| 2070 | audit_log_format(audit_buf, " sec_alg=%u sec_doi=%u sec_obj=%s", | 2101 | audit_log_format(audit_buf, " sec_alg=%u sec_doi=%u sec_obj=%s", |
| 2071 | ctx->ctx_alg, ctx->ctx_doi, ctx->ctx_str); | 2102 | ctx->ctx_alg, ctx->ctx_doi, ctx->ctx_str); |
| 2072 | 2103 | ||
| 2073 | switch(x->props.family) { | 2104 | switch (x->props.family) { |
| 2074 | case AF_INET: | 2105 | case AF_INET: |
| 2075 | audit_log_format(audit_buf, " src=%pI4 dst=%pI4", | 2106 | audit_log_format(audit_buf, " src=%pI4 dst=%pI4", |
| 2076 | &x->props.saddr.a4, &x->id.daddr.a4); | 2107 | &x->props.saddr.a4, &x->id.daddr.a4); |
| @@ -2100,7 +2131,7 @@ static void xfrm_audit_helper_pktinfo(struct sk_buff *skb, u16 family, | |||
| 2100 | iph6 = ipv6_hdr(skb); | 2131 | iph6 = ipv6_hdr(skb); |
| 2101 | audit_log_format(audit_buf, | 2132 | audit_log_format(audit_buf, |
| 2102 | " src=%pI6 dst=%pI6 flowlbl=0x%x%02x%02x", | 2133 | " src=%pI6 dst=%pI6 flowlbl=0x%x%02x%02x", |
| 2103 | &iph6->saddr,&iph6->daddr, | 2134 | &iph6->saddr, &iph6->daddr, |
| 2104 | iph6->flow_lbl[0] & 0x0f, | 2135 | iph6->flow_lbl[0] & 0x0f, |
| 2105 | iph6->flow_lbl[1], | 2136 | iph6->flow_lbl[1], |
| 2106 | iph6->flow_lbl[2]); | 2137 | iph6->flow_lbl[2]); |
| @@ -2109,7 +2140,7 @@ static void xfrm_audit_helper_pktinfo(struct sk_buff *skb, u16 family, | |||
| 2109 | } | 2140 | } |
| 2110 | 2141 | ||
| 2111 | void xfrm_audit_state_add(struct xfrm_state *x, int result, | 2142 | void xfrm_audit_state_add(struct xfrm_state *x, int result, |
| 2112 | kuid_t auid, u32 sessionid, u32 secid) | 2143 | kuid_t auid, unsigned int sessionid, u32 secid) |
| 2113 | { | 2144 | { |
| 2114 | struct audit_buffer *audit_buf; | 2145 | struct audit_buffer *audit_buf; |
| 2115 | 2146 | ||
| @@ -2124,7 +2155,7 @@ void xfrm_audit_state_add(struct xfrm_state *x, int result, | |||
| 2124 | EXPORT_SYMBOL_GPL(xfrm_audit_state_add); | 2155 | EXPORT_SYMBOL_GPL(xfrm_audit_state_add); |
| 2125 | 2156 | ||
| 2126 | void xfrm_audit_state_delete(struct xfrm_state *x, int result, | 2157 | void xfrm_audit_state_delete(struct xfrm_state *x, int result, |
| 2127 | kuid_t auid, u32 sessionid, u32 secid) | 2158 | kuid_t auid, unsigned int sessionid, u32 secid) |
| 2128 | { | 2159 | { |
| 2129 | struct audit_buffer *audit_buf; | 2160 | struct audit_buffer *audit_buf; |
| 2130 | 2161 | ||
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index f964d4c00ffb..1ae3ec7c18b0 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c | |||
| @@ -181,7 +181,9 @@ static int verify_newsa_info(struct xfrm_usersa_info *p, | |||
| 181 | attrs[XFRMA_ALG_AEAD] || | 181 | attrs[XFRMA_ALG_AEAD] || |
| 182 | attrs[XFRMA_ALG_CRYPT] || | 182 | attrs[XFRMA_ALG_CRYPT] || |
| 183 | attrs[XFRMA_ALG_COMP] || | 183 | attrs[XFRMA_ALG_COMP] || |
| 184 | attrs[XFRMA_TFCPAD]) | 184 | attrs[XFRMA_TFCPAD] || |
| 185 | (ntohl(p->id.spi) >= 0x10000)) | ||
| 186 | |||
| 185 | goto out; | 187 | goto out; |
| 186 | break; | 188 | break; |
| 187 | 189 | ||
| @@ -600,7 +602,7 @@ static int xfrm_add_sa(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
| 600 | int err; | 602 | int err; |
| 601 | struct km_event c; | 603 | struct km_event c; |
| 602 | kuid_t loginuid = audit_get_loginuid(current); | 604 | kuid_t loginuid = audit_get_loginuid(current); |
| 603 | u32 sessionid = audit_get_sessionid(current); | 605 | unsigned int sessionid = audit_get_sessionid(current); |
| 604 | u32 sid; | 606 | u32 sid; |
| 605 | 607 | ||
| 606 | err = verify_newsa_info(p, attrs); | 608 | err = verify_newsa_info(p, attrs); |
| @@ -679,7 +681,7 @@ static int xfrm_del_sa(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
| 679 | struct km_event c; | 681 | struct km_event c; |
| 680 | struct xfrm_usersa_id *p = nlmsg_data(nlh); | 682 | struct xfrm_usersa_id *p = nlmsg_data(nlh); |
| 681 | kuid_t loginuid = audit_get_loginuid(current); | 683 | kuid_t loginuid = audit_get_loginuid(current); |
| 682 | u32 sessionid = audit_get_sessionid(current); | 684 | unsigned int sessionid = audit_get_sessionid(current); |
| 683 | u32 sid; | 685 | u32 sid; |
| 684 | 686 | ||
| 685 | x = xfrm_user_state_lookup(net, p, attrs, &err); | 687 | x = xfrm_user_state_lookup(net, p, attrs, &err); |
| @@ -877,7 +879,10 @@ static int dump_one_state(struct xfrm_state *x, int count, void *ptr) | |||
| 877 | static int xfrm_dump_sa_done(struct netlink_callback *cb) | 879 | static int xfrm_dump_sa_done(struct netlink_callback *cb) |
| 878 | { | 880 | { |
| 879 | struct xfrm_state_walk *walk = (struct xfrm_state_walk *) &cb->args[1]; | 881 | struct xfrm_state_walk *walk = (struct xfrm_state_walk *) &cb->args[1]; |
| 880 | xfrm_state_walk_done(walk); | 882 | struct sock *sk = cb->skb->sk; |
| 883 | struct net *net = sock_net(sk); | ||
| 884 | |||
| 885 | xfrm_state_walk_done(walk, net); | ||
| 881 | return 0; | 886 | return 0; |
| 882 | } | 887 | } |
| 883 | 888 | ||
| @@ -1074,29 +1079,6 @@ out_noput: | |||
| 1074 | return err; | 1079 | return err; |
| 1075 | } | 1080 | } |
| 1076 | 1081 | ||
| 1077 | static int verify_userspi_info(struct xfrm_userspi_info *p) | ||
| 1078 | { | ||
| 1079 | switch (p->info.id.proto) { | ||
| 1080 | case IPPROTO_AH: | ||
| 1081 | case IPPROTO_ESP: | ||
| 1082 | break; | ||
| 1083 | |||
| 1084 | case IPPROTO_COMP: | ||
| 1085 | /* IPCOMP spi is 16-bits. */ | ||
| 1086 | if (p->max >= 0x10000) | ||
| 1087 | return -EINVAL; | ||
| 1088 | break; | ||
| 1089 | |||
| 1090 | default: | ||
| 1091 | return -EINVAL; | ||
| 1092 | } | ||
| 1093 | |||
| 1094 | if (p->min > p->max) | ||
| 1095 | return -EINVAL; | ||
| 1096 | |||
| 1097 | return 0; | ||
| 1098 | } | ||
| 1099 | |||
| 1100 | static int xfrm_alloc_userspi(struct sk_buff *skb, struct nlmsghdr *nlh, | 1082 | static int xfrm_alloc_userspi(struct sk_buff *skb, struct nlmsghdr *nlh, |
| 1101 | struct nlattr **attrs) | 1083 | struct nlattr **attrs) |
| 1102 | { | 1084 | { |
| @@ -1111,7 +1093,7 @@ static int xfrm_alloc_userspi(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
| 1111 | struct xfrm_mark m; | 1093 | struct xfrm_mark m; |
| 1112 | 1094 | ||
| 1113 | p = nlmsg_data(nlh); | 1095 | p = nlmsg_data(nlh); |
| 1114 | err = verify_userspi_info(p); | 1096 | err = verify_spi_info(p->info.id.proto, p->min, p->max); |
| 1115 | if (err) | 1097 | if (err) |
| 1116 | goto out_noput; | 1098 | goto out_noput; |
| 1117 | 1099 | ||
| @@ -1189,6 +1171,8 @@ static int verify_policy_type(u8 type) | |||
| 1189 | 1171 | ||
| 1190 | static int verify_newpolicy_info(struct xfrm_userpolicy_info *p) | 1172 | static int verify_newpolicy_info(struct xfrm_userpolicy_info *p) |
| 1191 | { | 1173 | { |
| 1174 | int ret; | ||
| 1175 | |||
| 1192 | switch (p->share) { | 1176 | switch (p->share) { |
| 1193 | case XFRM_SHARE_ANY: | 1177 | case XFRM_SHARE_ANY: |
| 1194 | case XFRM_SHARE_SESSION: | 1178 | case XFRM_SHARE_SESSION: |
| @@ -1224,7 +1208,13 @@ static int verify_newpolicy_info(struct xfrm_userpolicy_info *p) | |||
| 1224 | return -EINVAL; | 1208 | return -EINVAL; |
| 1225 | } | 1209 | } |
| 1226 | 1210 | ||
| 1227 | return verify_policy_dir(p->dir); | 1211 | ret = verify_policy_dir(p->dir); |
| 1212 | if (ret) | ||
| 1213 | return ret; | ||
| 1214 | if (p->index && ((p->index & XFRM_POLICY_MAX) != p->dir)) | ||
| 1215 | return -EINVAL; | ||
| 1216 | |||
| 1217 | return 0; | ||
| 1228 | } | 1218 | } |
| 1229 | 1219 | ||
| 1230 | static int copy_from_user_sec_ctx(struct xfrm_policy *pol, struct nlattr **attrs) | 1220 | static int copy_from_user_sec_ctx(struct xfrm_policy *pol, struct nlattr **attrs) |
| @@ -1405,7 +1395,7 @@ static int xfrm_add_policy(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
| 1405 | int err; | 1395 | int err; |
| 1406 | int excl; | 1396 | int excl; |
| 1407 | kuid_t loginuid = audit_get_loginuid(current); | 1397 | kuid_t loginuid = audit_get_loginuid(current); |
| 1408 | u32 sessionid = audit_get_sessionid(current); | 1398 | unsigned int sessionid = audit_get_sessionid(current); |
| 1409 | u32 sid; | 1399 | u32 sid; |
| 1410 | 1400 | ||
| 1411 | err = verify_newpolicy_info(p); | 1401 | err = verify_newpolicy_info(p); |
| @@ -1547,8 +1537,9 @@ static int dump_one_policy(struct xfrm_policy *xp, int dir, int count, void *ptr | |||
| 1547 | static int xfrm_dump_policy_done(struct netlink_callback *cb) | 1537 | static int xfrm_dump_policy_done(struct netlink_callback *cb) |
| 1548 | { | 1538 | { |
| 1549 | struct xfrm_policy_walk *walk = (struct xfrm_policy_walk *) &cb->args[1]; | 1539 | struct xfrm_policy_walk *walk = (struct xfrm_policy_walk *) &cb->args[1]; |
| 1540 | struct net *net = sock_net(cb->skb->sk); | ||
| 1550 | 1541 | ||
| 1551 | xfrm_policy_walk_done(walk); | 1542 | xfrm_policy_walk_done(walk, net); |
| 1552 | return 0; | 1543 | return 0; |
| 1553 | } | 1544 | } |
| 1554 | 1545 | ||
| @@ -1663,7 +1654,7 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
| 1663 | } | 1654 | } |
| 1664 | } else { | 1655 | } else { |
| 1665 | kuid_t loginuid = audit_get_loginuid(current); | 1656 | kuid_t loginuid = audit_get_loginuid(current); |
| 1666 | u32 sessionid = audit_get_sessionid(current); | 1657 | unsigned int sessionid = audit_get_sessionid(current); |
| 1667 | u32 sid; | 1658 | u32 sid; |
| 1668 | 1659 | ||
| 1669 | security_task_getsecid(current, &sid); | 1660 | security_task_getsecid(current, &sid); |
| @@ -1740,11 +1731,11 @@ static int build_aevent(struct sk_buff *skb, struct xfrm_state *x, const struct | |||
| 1740 | return -EMSGSIZE; | 1731 | return -EMSGSIZE; |
| 1741 | 1732 | ||
| 1742 | id = nlmsg_data(nlh); | 1733 | id = nlmsg_data(nlh); |
| 1743 | memcpy(&id->sa_id.daddr, &x->id.daddr,sizeof(x->id.daddr)); | 1734 | memcpy(&id->sa_id.daddr, &x->id.daddr, sizeof(x->id.daddr)); |
| 1744 | id->sa_id.spi = x->id.spi; | 1735 | id->sa_id.spi = x->id.spi; |
| 1745 | id->sa_id.family = x->props.family; | 1736 | id->sa_id.family = x->props.family; |
| 1746 | id->sa_id.proto = x->id.proto; | 1737 | id->sa_id.proto = x->id.proto; |
| 1747 | memcpy(&id->saddr, &x->props.saddr,sizeof(x->props.saddr)); | 1738 | memcpy(&id->saddr, &x->props.saddr, sizeof(x->props.saddr)); |
| 1748 | id->reqid = x->props.reqid; | 1739 | id->reqid = x->props.reqid; |
| 1749 | id->flags = c->data.aevent; | 1740 | id->flags = c->data.aevent; |
| 1750 | 1741 | ||
| @@ -1833,7 +1824,7 @@ static int xfrm_new_ae(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
| 1833 | struct net *net = sock_net(skb->sk); | 1824 | struct net *net = sock_net(skb->sk); |
| 1834 | struct xfrm_state *x; | 1825 | struct xfrm_state *x; |
| 1835 | struct km_event c; | 1826 | struct km_event c; |
| 1836 | int err = - EINVAL; | 1827 | int err = -EINVAL; |
| 1837 | u32 mark = 0; | 1828 | u32 mark = 0; |
| 1838 | struct xfrm_mark m; | 1829 | struct xfrm_mark m; |
| 1839 | struct xfrm_aevent_id *p = nlmsg_data(nlh); | 1830 | struct xfrm_aevent_id *p = nlmsg_data(nlh); |
| @@ -1959,7 +1950,7 @@ static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
| 1959 | err = 0; | 1950 | err = 0; |
| 1960 | if (up->hard) { | 1951 | if (up->hard) { |
| 1961 | kuid_t loginuid = audit_get_loginuid(current); | 1952 | kuid_t loginuid = audit_get_loginuid(current); |
| 1962 | u32 sessionid = audit_get_sessionid(current); | 1953 | unsigned int sessionid = audit_get_sessionid(current); |
| 1963 | u32 sid; | 1954 | u32 sid; |
| 1964 | 1955 | ||
| 1965 | security_task_getsecid(current, &sid); | 1956 | security_task_getsecid(current, &sid); |
| @@ -2002,7 +1993,7 @@ static int xfrm_add_sa_expire(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
| 2002 | 1993 | ||
| 2003 | if (ue->hard) { | 1994 | if (ue->hard) { |
| 2004 | kuid_t loginuid = audit_get_loginuid(current); | 1995 | kuid_t loginuid = audit_get_loginuid(current); |
| 2005 | u32 sessionid = audit_get_sessionid(current); | 1996 | unsigned int sessionid = audit_get_sessionid(current); |
| 2006 | u32 sid; | 1997 | u32 sid; |
| 2007 | 1998 | ||
| 2008 | security_task_getsecid(current, &sid); | 1999 | security_task_getsecid(current, &sid); |
| @@ -2129,6 +2120,7 @@ static int xfrm_do_migrate(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
| 2129 | u8 type; | 2120 | u8 type; |
| 2130 | int err; | 2121 | int err; |
| 2131 | int n = 0; | 2122 | int n = 0; |
| 2123 | struct net *net = sock_net(skb->sk); | ||
| 2132 | 2124 | ||
| 2133 | if (attrs[XFRMA_MIGRATE] == NULL) | 2125 | if (attrs[XFRMA_MIGRATE] == NULL) |
| 2134 | return -EINVAL; | 2126 | return -EINVAL; |
| @@ -2146,7 +2138,7 @@ static int xfrm_do_migrate(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
| 2146 | if (!n) | 2138 | if (!n) |
| 2147 | return 0; | 2139 | return 0; |
| 2148 | 2140 | ||
| 2149 | xfrm_migrate(&pi->sel, pi->dir, type, m, n, kmp); | 2141 | xfrm_migrate(&pi->sel, pi->dir, type, m, n, kmp, net); |
| 2150 | 2142 | ||
| 2151 | return 0; | 2143 | return 0; |
| 2152 | } | 2144 | } |
| @@ -2394,9 +2386,11 @@ static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
| 2394 | 2386 | ||
| 2395 | static void xfrm_netlink_rcv(struct sk_buff *skb) | 2387 | static void xfrm_netlink_rcv(struct sk_buff *skb) |
| 2396 | { | 2388 | { |
| 2397 | mutex_lock(&xfrm_cfg_mutex); | 2389 | struct net *net = sock_net(skb->sk); |
| 2390 | |||
| 2391 | mutex_lock(&net->xfrm.xfrm_cfg_mutex); | ||
| 2398 | netlink_rcv_skb(skb, &xfrm_user_rcv_msg); | 2392 | netlink_rcv_skb(skb, &xfrm_user_rcv_msg); |
| 2399 | mutex_unlock(&xfrm_cfg_mutex); | 2393 | mutex_unlock(&net->xfrm.xfrm_cfg_mutex); |
| 2400 | } | 2394 | } |
| 2401 | 2395 | ||
| 2402 | static inline size_t xfrm_expire_msgsize(void) | 2396 | static inline size_t xfrm_expire_msgsize(void) |
