diff options
Diffstat (limited to 'net')
107 files changed, 5077 insertions, 2031 deletions
diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index afba51e60310..a292e8050ef2 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c | |||
| @@ -242,6 +242,7 @@ static int register_vlan_device(struct net_device *real_dev, u16 vlan_id) | |||
| 242 | * hope the underlying device can handle it. | 242 | * hope the underlying device can handle it. |
| 243 | */ | 243 | */ |
| 244 | new_dev->mtu = real_dev->mtu; | 244 | new_dev->mtu = real_dev->mtu; |
| 245 | new_dev->priv_flags |= (real_dev->priv_flags & IFF_UNICAST_FLT); | ||
| 245 | 246 | ||
| 246 | vlan_dev_priv(new_dev)->vlan_id = vlan_id; | 247 | vlan_dev_priv(new_dev)->vlan_id = vlan_id; |
| 247 | vlan_dev_priv(new_dev)->real_dev = real_dev; | 248 | vlan_dev_priv(new_dev)->real_dev = real_dev; |
diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c index 365ed74f3946..f1d37cd81815 100644 --- a/net/batman-adv/hard-interface.c +++ b/net/batman-adv/hard-interface.c | |||
| @@ -30,6 +30,7 @@ | |||
| 30 | #include "bridge_loop_avoidance.h" | 30 | #include "bridge_loop_avoidance.h" |
| 31 | 31 | ||
| 32 | #include <linux/if_arp.h> | 32 | #include <linux/if_arp.h> |
| 33 | #include <linux/if_ether.h> | ||
| 33 | 34 | ||
| 34 | void batadv_hardif_free_rcu(struct rcu_head *rcu) | 35 | void batadv_hardif_free_rcu(struct rcu_head *rcu) |
| 35 | { | 36 | { |
| @@ -311,7 +312,7 @@ int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface, | |||
| 311 | { | 312 | { |
| 312 | struct batadv_priv *bat_priv; | 313 | struct batadv_priv *bat_priv; |
| 313 | struct net_device *soft_iface; | 314 | struct net_device *soft_iface; |
| 314 | __be16 ethertype = __constant_htons(BATADV_ETH_P_BATMAN); | 315 | __be16 ethertype = __constant_htons(ETH_P_BATMAN); |
| 315 | int ret; | 316 | int ret; |
| 316 | 317 | ||
| 317 | if (hard_iface->if_status != BATADV_IF_NOT_IN_USE) | 318 | if (hard_iface->if_status != BATADV_IF_NOT_IN_USE) |
diff --git a/net/batman-adv/packet.h b/net/batman-adv/packet.h index 1c5454d33f67..cb6405bf755c 100644 --- a/net/batman-adv/packet.h +++ b/net/batman-adv/packet.h | |||
| @@ -20,8 +20,6 @@ | |||
| 20 | #ifndef _NET_BATMAN_ADV_PACKET_H_ | 20 | #ifndef _NET_BATMAN_ADV_PACKET_H_ |
| 21 | #define _NET_BATMAN_ADV_PACKET_H_ | 21 | #define _NET_BATMAN_ADV_PACKET_H_ |
| 22 | 22 | ||
| 23 | #define BATADV_ETH_P_BATMAN 0x4305 /* unofficial/not registered Ethertype */ | ||
| 24 | |||
| 25 | enum batadv_packettype { | 23 | enum batadv_packettype { |
| 26 | BATADV_IV_OGM = 0x01, | 24 | BATADV_IV_OGM = 0x01, |
| 27 | BATADV_ICMP = 0x02, | 25 | BATADV_ICMP = 0x02, |
diff --git a/net/batman-adv/send.c b/net/batman-adv/send.c index c7f702376535..4425af9dad40 100644 --- a/net/batman-adv/send.c +++ b/net/batman-adv/send.c | |||
| @@ -28,6 +28,8 @@ | |||
| 28 | #include "gateway_common.h" | 28 | #include "gateway_common.h" |
| 29 | #include "originator.h" | 29 | #include "originator.h" |
| 30 | 30 | ||
| 31 | #include <linux/if_ether.h> | ||
| 32 | |||
| 31 | static void batadv_send_outstanding_bcast_packet(struct work_struct *work); | 33 | static void batadv_send_outstanding_bcast_packet(struct work_struct *work); |
| 32 | 34 | ||
| 33 | /* send out an already prepared packet to the given address via the | 35 | /* send out an already prepared packet to the given address via the |
| @@ -60,11 +62,11 @@ int batadv_send_skb_packet(struct sk_buff *skb, | |||
| 60 | ethhdr = (struct ethhdr *)skb_mac_header(skb); | 62 | ethhdr = (struct ethhdr *)skb_mac_header(skb); |
| 61 | memcpy(ethhdr->h_source, hard_iface->net_dev->dev_addr, ETH_ALEN); | 63 | memcpy(ethhdr->h_source, hard_iface->net_dev->dev_addr, ETH_ALEN); |
| 62 | memcpy(ethhdr->h_dest, dst_addr, ETH_ALEN); | 64 | memcpy(ethhdr->h_dest, dst_addr, ETH_ALEN); |
| 63 | ethhdr->h_proto = __constant_htons(BATADV_ETH_P_BATMAN); | 65 | ethhdr->h_proto = __constant_htons(ETH_P_BATMAN); |
| 64 | 66 | ||
| 65 | skb_set_network_header(skb, ETH_HLEN); | 67 | skb_set_network_header(skb, ETH_HLEN); |
| 66 | skb->priority = TC_PRIO_CONTROL; | 68 | skb->priority = TC_PRIO_CONTROL; |
| 67 | skb->protocol = __constant_htons(BATADV_ETH_P_BATMAN); | 69 | skb->protocol = __constant_htons(ETH_P_BATMAN); |
| 68 | 70 | ||
| 69 | skb->dev = hard_iface->net_dev; | 71 | skb->dev = hard_iface->net_dev; |
| 70 | 72 | ||
diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c index 54800c783f96..6b548fde8e04 100644 --- a/net/batman-adv/soft-interface.c +++ b/net/batman-adv/soft-interface.c | |||
| @@ -34,6 +34,7 @@ | |||
| 34 | #include <linux/ethtool.h> | 34 | #include <linux/ethtool.h> |
| 35 | #include <linux/etherdevice.h> | 35 | #include <linux/etherdevice.h> |
| 36 | #include <linux/if_vlan.h> | 36 | #include <linux/if_vlan.h> |
| 37 | #include <linux/if_ether.h> | ||
| 37 | #include "unicast.h" | 38 | #include "unicast.h" |
| 38 | #include "bridge_loop_avoidance.h" | 39 | #include "bridge_loop_avoidance.h" |
| 39 | 40 | ||
| @@ -146,7 +147,7 @@ static int batadv_interface_tx(struct sk_buff *skb, | |||
| 146 | struct batadv_hard_iface *primary_if = NULL; | 147 | struct batadv_hard_iface *primary_if = NULL; |
| 147 | struct batadv_bcast_packet *bcast_packet; | 148 | struct batadv_bcast_packet *bcast_packet; |
| 148 | struct vlan_ethhdr *vhdr; | 149 | struct vlan_ethhdr *vhdr; |
| 149 | __be16 ethertype = __constant_htons(BATADV_ETH_P_BATMAN); | 150 | __be16 ethertype = __constant_htons(ETH_P_BATMAN); |
| 150 | static const uint8_t stp_addr[ETH_ALEN] = {0x01, 0x80, 0xC2, 0x00, | 151 | static const uint8_t stp_addr[ETH_ALEN] = {0x01, 0x80, 0xC2, 0x00, |
| 151 | 0x00, 0x00}; | 152 | 0x00, 0x00}; |
| 152 | static const uint8_t ectp_addr[ETH_ALEN] = {0xCF, 0x00, 0x00, 0x00, | 153 | static const uint8_t ectp_addr[ETH_ALEN] = {0xCF, 0x00, 0x00, 0x00, |
| @@ -172,7 +173,7 @@ static int batadv_interface_tx(struct sk_buff *skb, | |||
| 172 | break; | 173 | break; |
| 173 | 174 | ||
| 174 | /* fall through */ | 175 | /* fall through */ |
| 175 | case BATADV_ETH_P_BATMAN: | 176 | case ETH_P_BATMAN: |
| 176 | goto dropped; | 177 | goto dropped; |
| 177 | } | 178 | } |
| 178 | 179 | ||
| @@ -302,7 +303,7 @@ void batadv_interface_rx(struct net_device *soft_iface, | |||
| 302 | struct vlan_ethhdr *vhdr; | 303 | struct vlan_ethhdr *vhdr; |
| 303 | struct batadv_header *batadv_header = (struct batadv_header *)skb->data; | 304 | struct batadv_header *batadv_header = (struct batadv_header *)skb->data; |
| 304 | short vid __maybe_unused = -1; | 305 | short vid __maybe_unused = -1; |
| 305 | __be16 ethertype = __constant_htons(BATADV_ETH_P_BATMAN); | 306 | __be16 ethertype = __constant_htons(ETH_P_BATMAN); |
| 306 | bool is_bcast; | 307 | bool is_bcast; |
| 307 | 308 | ||
| 308 | is_bcast = (batadv_header->packet_type == BATADV_BCAST); | 309 | is_bcast = (batadv_header->packet_type == BATADV_BCAST); |
| @@ -325,7 +326,7 @@ void batadv_interface_rx(struct net_device *soft_iface, | |||
| 325 | break; | 326 | break; |
| 326 | 327 | ||
| 327 | /* fall through */ | 328 | /* fall through */ |
| 328 | case BATADV_ETH_P_BATMAN: | 329 | case ETH_P_BATMAN: |
| 329 | goto dropped; | 330 | goto dropped; |
| 330 | } | 331 | } |
| 331 | 332 | ||
diff --git a/net/bluetooth/Kconfig b/net/bluetooth/Kconfig index 1c11d0dcd863..d3f3f7b1d32c 100644 --- a/net/bluetooth/Kconfig +++ b/net/bluetooth/Kconfig | |||
| @@ -48,4 +48,3 @@ source "net/bluetooth/cmtp/Kconfig" | |||
| 48 | source "net/bluetooth/hidp/Kconfig" | 48 | source "net/bluetooth/hidp/Kconfig" |
| 49 | 49 | ||
| 50 | source "drivers/bluetooth/Kconfig" | 50 | source "drivers/bluetooth/Kconfig" |
| 51 | |||
diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c index d5136cfb57e2..2f67d5ecc907 100644 --- a/net/bluetooth/a2mp.c +++ b/net/bluetooth/a2mp.c | |||
| @@ -423,7 +423,7 @@ static int a2mp_getampassoc_rsp(struct amp_mgr *mgr, struct sk_buff *skb, | |||
| 423 | 423 | ||
| 424 | BT_DBG("Created hcon %p: loc:%d -> rem:%d", hcon, hdev->id, rsp->id); | 424 | BT_DBG("Created hcon %p: loc:%d -> rem:%d", hcon, hdev->id, rsp->id); |
| 425 | 425 | ||
| 426 | mgr->bredr_chan->ctrl_id = rsp->id; | 426 | mgr->bredr_chan->remote_amp_id = rsp->id; |
| 427 | 427 | ||
| 428 | amp_create_phylink(hdev, mgr, hcon); | 428 | amp_create_phylink(hdev, mgr, hcon); |
| 429 | 429 | ||
| @@ -939,7 +939,7 @@ void a2mp_send_create_phy_link_req(struct hci_dev *hdev, u8 status) | |||
| 939 | goto clean; | 939 | goto clean; |
| 940 | 940 | ||
| 941 | req->local_id = hdev->id; | 941 | req->local_id = hdev->id; |
| 942 | req->remote_id = bredr_chan->ctrl_id; | 942 | req->remote_id = bredr_chan->remote_amp_id; |
| 943 | memcpy(req->amp_assoc, loc_assoc->data, loc_assoc->len); | 943 | memcpy(req->amp_assoc, loc_assoc->data, loc_assoc->len); |
| 944 | 944 | ||
| 945 | a2mp_send(mgr, A2MP_CREATEPHYSLINK_REQ, __next_ident(mgr), len, req); | 945 | a2mp_send(mgr, A2MP_CREATEPHYSLINK_REQ, __next_ident(mgr), len, req); |
diff --git a/net/bluetooth/amp.c b/net/bluetooth/amp.c index 231d7ef53ecb..1b0d92c0643a 100644 --- a/net/bluetooth/amp.c +++ b/net/bluetooth/amp.c | |||
| @@ -372,3 +372,100 @@ void amp_accept_phylink(struct hci_dev *hdev, struct amp_mgr *mgr, | |||
| 372 | 372 | ||
| 373 | hci_send_cmd(hdev, HCI_OP_ACCEPT_PHY_LINK, sizeof(cp), &cp); | 373 | hci_send_cmd(hdev, HCI_OP_ACCEPT_PHY_LINK, sizeof(cp), &cp); |
| 374 | } | 374 | } |
| 375 | |||
| 376 | void amp_physical_cfm(struct hci_conn *bredr_hcon, struct hci_conn *hs_hcon) | ||
| 377 | { | ||
| 378 | struct hci_dev *bredr_hdev = hci_dev_hold(bredr_hcon->hdev); | ||
| 379 | struct amp_mgr *mgr = hs_hcon->amp_mgr; | ||
| 380 | struct l2cap_chan *bredr_chan; | ||
| 381 | |||
| 382 | BT_DBG("bredr_hcon %p hs_hcon %p mgr %p", bredr_hcon, hs_hcon, mgr); | ||
| 383 | |||
| 384 | if (!bredr_hdev || !mgr || !mgr->bredr_chan) | ||
| 385 | return; | ||
| 386 | |||
| 387 | bredr_chan = mgr->bredr_chan; | ||
| 388 | |||
| 389 | l2cap_chan_lock(bredr_chan); | ||
| 390 | |||
| 391 | set_bit(FLAG_EFS_ENABLE, &bredr_chan->flags); | ||
| 392 | bredr_chan->remote_amp_id = hs_hcon->remote_id; | ||
| 393 | bredr_chan->local_amp_id = hs_hcon->hdev->id; | ||
| 394 | bredr_chan->hs_hcon = hs_hcon; | ||
| 395 | bredr_chan->conn->mtu = hs_hcon->hdev->block_mtu; | ||
| 396 | |||
| 397 | __l2cap_physical_cfm(bredr_chan, 0); | ||
| 398 | |||
| 399 | l2cap_chan_unlock(bredr_chan); | ||
| 400 | |||
| 401 | hci_dev_put(bredr_hdev); | ||
| 402 | } | ||
| 403 | |||
| 404 | void amp_create_logical_link(struct l2cap_chan *chan) | ||
| 405 | { | ||
| 406 | struct hci_cp_create_accept_logical_link cp; | ||
| 407 | struct hci_conn *hcon; | ||
| 408 | struct hci_dev *hdev; | ||
| 409 | |||
| 410 | BT_DBG("chan %p", chan); | ||
| 411 | |||
| 412 | if (!chan->hs_hcon) | ||
| 413 | return; | ||
| 414 | |||
| 415 | hdev = hci_dev_hold(chan->hs_hcon->hdev); | ||
| 416 | if (!hdev) | ||
| 417 | return; | ||
| 418 | |||
| 419 | BT_DBG("chan %p dst %pMR", chan, chan->conn->dst); | ||
| 420 | |||
| 421 | hcon = hci_conn_hash_lookup_ba(hdev, AMP_LINK, chan->conn->dst); | ||
| 422 | if (!hcon) | ||
| 423 | goto done; | ||
| 424 | |||
| 425 | cp.phy_handle = hcon->handle; | ||
| 426 | |||
| 427 | cp.tx_flow_spec.id = chan->local_id; | ||
| 428 | cp.tx_flow_spec.stype = chan->local_stype; | ||
| 429 | cp.tx_flow_spec.msdu = cpu_to_le16(chan->local_msdu); | ||
| 430 | cp.tx_flow_spec.sdu_itime = cpu_to_le32(chan->local_sdu_itime); | ||
| 431 | cp.tx_flow_spec.acc_lat = cpu_to_le32(chan->local_acc_lat); | ||
| 432 | cp.tx_flow_spec.flush_to = cpu_to_le32(chan->local_flush_to); | ||
| 433 | |||
| 434 | cp.rx_flow_spec.id = chan->remote_id; | ||
| 435 | cp.rx_flow_spec.stype = chan->remote_stype; | ||
| 436 | cp.rx_flow_spec.msdu = cpu_to_le16(chan->remote_msdu); | ||
| 437 | cp.rx_flow_spec.sdu_itime = cpu_to_le32(chan->remote_sdu_itime); | ||
| 438 | cp.rx_flow_spec.acc_lat = cpu_to_le32(chan->remote_acc_lat); | ||
| 439 | cp.rx_flow_spec.flush_to = cpu_to_le32(chan->remote_flush_to); | ||
| 440 | |||
| 441 | if (hcon->out) | ||
| 442 | hci_send_cmd(hdev, HCI_OP_CREATE_LOGICAL_LINK, sizeof(cp), | ||
| 443 | &cp); | ||
| 444 | else | ||
| 445 | hci_send_cmd(hdev, HCI_OP_ACCEPT_LOGICAL_LINK, sizeof(cp), | ||
| 446 | &cp); | ||
| 447 | |||
| 448 | done: | ||
| 449 | hci_dev_put(hdev); | ||
| 450 | } | ||
| 451 | |||
| 452 | void amp_disconnect_logical_link(struct hci_chan *hchan) | ||
| 453 | { | ||
| 454 | struct hci_conn *hcon = hchan->conn; | ||
| 455 | struct hci_cp_disconn_logical_link cp; | ||
| 456 | |||
| 457 | if (hcon->state != BT_CONNECTED) { | ||
| 458 | BT_DBG("hchan %p not connected", hchan); | ||
| 459 | return; | ||
| 460 | } | ||
| 461 | |||
| 462 | cp.log_handle = cpu_to_le16(hchan->handle); | ||
| 463 | hci_send_cmd(hcon->hdev, HCI_OP_DISCONN_LOGICAL_LINK, sizeof(cp), &cp); | ||
| 464 | } | ||
| 465 | |||
| 466 | void amp_destroy_logical_link(struct hci_chan *hchan, u8 reason) | ||
| 467 | { | ||
| 468 | BT_DBG("hchan %p", hchan); | ||
| 469 | |||
| 470 | hci_chan_del(hchan); | ||
| 471 | } | ||
diff --git a/net/bluetooth/bnep/netdev.c b/net/bluetooth/bnep/netdev.c index 98f86f91d47c..e58c8b32589c 100644 --- a/net/bluetooth/bnep/netdev.c +++ b/net/bluetooth/bnep/netdev.c | |||
| @@ -25,7 +25,6 @@ | |||
| 25 | SOFTWARE IS DISCLAIMED. | 25 | SOFTWARE IS DISCLAIMED. |
| 26 | */ | 26 | */ |
| 27 | 27 | ||
| 28 | #include <linux/export.h> | ||
| 29 | #include <linux/etherdevice.h> | 28 | #include <linux/etherdevice.h> |
| 30 | 29 | ||
| 31 | #include <net/bluetooth/bluetooth.h> | 30 | #include <net/bluetooth/bluetooth.h> |
diff --git a/net/bluetooth/cmtp/capi.c b/net/bluetooth/cmtp/capi.c index 50f0d135eb8f..a4a9d4b6816c 100644 --- a/net/bluetooth/cmtp/capi.c +++ b/net/bluetooth/cmtp/capi.c | |||
| @@ -20,7 +20,7 @@ | |||
| 20 | SOFTWARE IS DISCLAIMED. | 20 | SOFTWARE IS DISCLAIMED. |
| 21 | */ | 21 | */ |
| 22 | 22 | ||
| 23 | #include <linux/module.h> | 23 | #include <linux/export.h> |
| 24 | #include <linux/proc_fs.h> | 24 | #include <linux/proc_fs.h> |
| 25 | #include <linux/seq_file.h> | 25 | #include <linux/seq_file.h> |
| 26 | #include <linux/types.h> | 26 | #include <linux/types.h> |
diff --git a/net/bluetooth/cmtp/sock.c b/net/bluetooth/cmtp/sock.c index aacb802d1ee4..1c57482112b6 100644 --- a/net/bluetooth/cmtp/sock.c +++ b/net/bluetooth/cmtp/sock.c | |||
| @@ -20,7 +20,7 @@ | |||
| 20 | SOFTWARE IS DISCLAIMED. | 20 | SOFTWARE IS DISCLAIMED. |
| 21 | */ | 21 | */ |
| 22 | 22 | ||
| 23 | #include <linux/module.h> | 23 | #include <linux/export.h> |
| 24 | 24 | ||
| 25 | #include <linux/types.h> | 25 | #include <linux/types.h> |
| 26 | #include <linux/capability.h> | 26 | #include <linux/capability.h> |
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index fe646211c61f..25bfce0666eb 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c | |||
| @@ -502,6 +502,9 @@ static struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, | |||
| 502 | { | 502 | { |
| 503 | struct hci_conn *le; | 503 | struct hci_conn *le; |
| 504 | 504 | ||
| 505 | if (test_bit(HCI_LE_PERIPHERAL, &hdev->flags)) | ||
| 506 | return ERR_PTR(-ENOTSUPP); | ||
| 507 | |||
| 505 | le = hci_conn_hash_lookup_ba(hdev, LE_LINK, dst); | 508 | le = hci_conn_hash_lookup_ba(hdev, LE_LINK, dst); |
| 506 | if (!le) { | 509 | if (!le) { |
| 507 | le = hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT); | 510 | le = hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT); |
| @@ -959,6 +962,7 @@ struct hci_chan *hci_chan_create(struct hci_conn *conn) | |||
| 959 | 962 | ||
| 960 | chan->conn = conn; | 963 | chan->conn = conn; |
| 961 | skb_queue_head_init(&chan->data_q); | 964 | skb_queue_head_init(&chan->data_q); |
| 965 | chan->state = BT_CONNECTED; | ||
| 962 | 966 | ||
| 963 | list_add_rcu(&chan->list, &conn->chan_list); | 967 | list_add_rcu(&chan->list, &conn->chan_list); |
| 964 | 968 | ||
| @@ -976,6 +980,8 @@ void hci_chan_del(struct hci_chan *chan) | |||
| 976 | 980 | ||
| 977 | synchronize_rcu(); | 981 | synchronize_rcu(); |
| 978 | 982 | ||
| 983 | hci_conn_put(conn); | ||
| 984 | |||
| 979 | skb_queue_purge(&chan->data_q); | 985 | skb_queue_purge(&chan->data_q); |
| 980 | kfree(chan); | 986 | kfree(chan); |
| 981 | } | 987 | } |
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index f01e5e135b99..7140f83328a2 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c | |||
| @@ -178,48 +178,13 @@ static void hci_reset_req(struct hci_dev *hdev, unsigned long opt) | |||
| 178 | 178 | ||
| 179 | static void bredr_init(struct hci_dev *hdev) | 179 | static void bredr_init(struct hci_dev *hdev) |
| 180 | { | 180 | { |
| 181 | struct hci_cp_delete_stored_link_key cp; | ||
| 182 | __le16 param; | ||
| 183 | __u8 flt_type; | ||
| 184 | |||
| 185 | hdev->flow_ctl_mode = HCI_FLOW_CTL_MODE_PACKET_BASED; | 181 | hdev->flow_ctl_mode = HCI_FLOW_CTL_MODE_PACKET_BASED; |
| 186 | 182 | ||
| 187 | /* Mandatory initialization */ | ||
| 188 | |||
| 189 | /* Read Local Supported Features */ | 183 | /* Read Local Supported Features */ |
| 190 | hci_send_cmd(hdev, HCI_OP_READ_LOCAL_FEATURES, 0, NULL); | 184 | hci_send_cmd(hdev, HCI_OP_READ_LOCAL_FEATURES, 0, NULL); |
| 191 | 185 | ||
| 192 | /* Read Local Version */ | 186 | /* Read Local Version */ |
| 193 | hci_send_cmd(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL); | 187 | hci_send_cmd(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL); |
| 194 | |||
| 195 | /* Read Buffer Size (ACL mtu, max pkt, etc.) */ | ||
| 196 | hci_send_cmd(hdev, HCI_OP_READ_BUFFER_SIZE, 0, NULL); | ||
| 197 | |||
| 198 | /* Read BD Address */ | ||
| 199 | hci_send_cmd(hdev, HCI_OP_READ_BD_ADDR, 0, NULL); | ||
| 200 | |||
| 201 | /* Read Class of Device */ | ||
| 202 | hci_send_cmd(hdev, HCI_OP_READ_CLASS_OF_DEV, 0, NULL); | ||
| 203 | |||
| 204 | /* Read Local Name */ | ||
| 205 | hci_send_cmd(hdev, HCI_OP_READ_LOCAL_NAME, 0, NULL); | ||
| 206 | |||
| 207 | /* Read Voice Setting */ | ||
| 208 | hci_send_cmd(hdev, HCI_OP_READ_VOICE_SETTING, 0, NULL); | ||
| 209 | |||
| 210 | /* Optional initialization */ | ||
| 211 | |||
| 212 | /* Clear Event Filters */ | ||
| 213 | flt_type = HCI_FLT_CLEAR_ALL; | ||
| 214 | hci_send_cmd(hdev, HCI_OP_SET_EVENT_FLT, 1, &flt_type); | ||
| 215 | |||
| 216 | /* Connection accept timeout ~20 secs */ | ||
| 217 | param = __constant_cpu_to_le16(0x7d00); | ||
| 218 | hci_send_cmd(hdev, HCI_OP_WRITE_CA_TIMEOUT, 2, ¶m); | ||
| 219 | |||
| 220 | bacpy(&cp.bdaddr, BDADDR_ANY); | ||
| 221 | cp.delete_all = 1; | ||
| 222 | hci_send_cmd(hdev, HCI_OP_DELETE_STORED_LINK_KEY, sizeof(cp), &cp); | ||
| 223 | } | 188 | } |
| 224 | 189 | ||
| 225 | static void amp_init(struct hci_dev *hdev) | 190 | static void amp_init(struct hci_dev *hdev) |
| @@ -273,14 +238,6 @@ static void hci_init_req(struct hci_dev *hdev, unsigned long opt) | |||
| 273 | } | 238 | } |
| 274 | } | 239 | } |
| 275 | 240 | ||
| 276 | static void hci_le_init_req(struct hci_dev *hdev, unsigned long opt) | ||
| 277 | { | ||
| 278 | BT_DBG("%s", hdev->name); | ||
| 279 | |||
| 280 | /* Read LE buffer size */ | ||
| 281 | hci_send_cmd(hdev, HCI_OP_LE_READ_BUFFER_SIZE, 0, NULL); | ||
| 282 | } | ||
| 283 | |||
| 284 | static void hci_scan_req(struct hci_dev *hdev, unsigned long opt) | 241 | static void hci_scan_req(struct hci_dev *hdev, unsigned long opt) |
| 285 | { | 242 | { |
| 286 | __u8 scan = opt; | 243 | __u8 scan = opt; |
| @@ -477,6 +434,8 @@ bool hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data, | |||
| 477 | 434 | ||
| 478 | BT_DBG("cache %p, %pMR", cache, &data->bdaddr); | 435 | BT_DBG("cache %p, %pMR", cache, &data->bdaddr); |
| 479 | 436 | ||
| 437 | hci_remove_remote_oob_data(hdev, &data->bdaddr); | ||
| 438 | |||
| 480 | if (ssp) | 439 | if (ssp) |
| 481 | *ssp = data->ssp_mode; | 440 | *ssp = data->ssp_mode; |
| 482 | 441 | ||
| @@ -637,6 +596,99 @@ done: | |||
| 637 | return err; | 596 | return err; |
| 638 | } | 597 | } |
| 639 | 598 | ||
| 599 | static u8 create_ad(struct hci_dev *hdev, u8 *ptr) | ||
| 600 | { | ||
| 601 | u8 ad_len = 0, flags = 0; | ||
| 602 | size_t name_len; | ||
| 603 | |||
| 604 | if (test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags)) | ||
| 605 | flags |= LE_AD_GENERAL; | ||
| 606 | |||
| 607 | if (!lmp_bredr_capable(hdev)) | ||
| 608 | flags |= LE_AD_NO_BREDR; | ||
| 609 | |||
| 610 | if (lmp_le_br_capable(hdev)) | ||
| 611 | flags |= LE_AD_SIM_LE_BREDR_CTRL; | ||
| 612 | |||
| 613 | if (lmp_host_le_br_capable(hdev)) | ||
| 614 | flags |= LE_AD_SIM_LE_BREDR_HOST; | ||
| 615 | |||
| 616 | if (flags) { | ||
| 617 | BT_DBG("adv flags 0x%02x", flags); | ||
| 618 | |||
| 619 | ptr[0] = 2; | ||
| 620 | ptr[1] = EIR_FLAGS; | ||
| 621 | ptr[2] = flags; | ||
| 622 | |||
| 623 | ad_len += 3; | ||
| 624 | ptr += 3; | ||
| 625 | } | ||
| 626 | |||
| 627 | if (hdev->adv_tx_power != HCI_TX_POWER_INVALID) { | ||
| 628 | ptr[0] = 2; | ||
| 629 | ptr[1] = EIR_TX_POWER; | ||
| 630 | ptr[2] = (u8) hdev->adv_tx_power; | ||
| 631 | |||
| 632 | ad_len += 3; | ||
| 633 | ptr += 3; | ||
| 634 | } | ||
| 635 | |||
| 636 | name_len = strlen(hdev->dev_name); | ||
| 637 | if (name_len > 0) { | ||
| 638 | size_t max_len = HCI_MAX_AD_LENGTH - ad_len - 2; | ||
| 639 | |||
| 640 | if (name_len > max_len) { | ||
| 641 | name_len = max_len; | ||
| 642 | ptr[1] = EIR_NAME_SHORT; | ||
| 643 | } else | ||
| 644 | ptr[1] = EIR_NAME_COMPLETE; | ||
| 645 | |||
| 646 | ptr[0] = name_len + 1; | ||
| 647 | |||
| 648 | memcpy(ptr + 2, hdev->dev_name, name_len); | ||
| 649 | |||
| 650 | ad_len += (name_len + 2); | ||
| 651 | ptr += (name_len + 2); | ||
| 652 | } | ||
| 653 | |||
| 654 | return ad_len; | ||
| 655 | } | ||
| 656 | |||
| 657 | int hci_update_ad(struct hci_dev *hdev) | ||
| 658 | { | ||
| 659 | struct hci_cp_le_set_adv_data cp; | ||
| 660 | u8 len; | ||
| 661 | int err; | ||
| 662 | |||
| 663 | hci_dev_lock(hdev); | ||
| 664 | |||
| 665 | if (!lmp_le_capable(hdev)) { | ||
| 666 | err = -EINVAL; | ||
| 667 | goto unlock; | ||
| 668 | } | ||
| 669 | |||
| 670 | memset(&cp, 0, sizeof(cp)); | ||
| 671 | |||
| 672 | len = create_ad(hdev, cp.data); | ||
| 673 | |||
| 674 | if (hdev->adv_data_len == len && | ||
| 675 | memcmp(cp.data, hdev->adv_data, len) == 0) { | ||
| 676 | err = 0; | ||
| 677 | goto unlock; | ||
| 678 | } | ||
| 679 | |||
| 680 | memcpy(hdev->adv_data, cp.data, sizeof(cp.data)); | ||
| 681 | hdev->adv_data_len = len; | ||
| 682 | |||
| 683 | cp.length = len; | ||
| 684 | err = hci_send_cmd(hdev, HCI_OP_LE_SET_ADV_DATA, sizeof(cp), &cp); | ||
| 685 | |||
| 686 | unlock: | ||
| 687 | hci_dev_unlock(hdev); | ||
| 688 | |||
| 689 | return err; | ||
| 690 | } | ||
| 691 | |||
| 640 | /* ---- HCI ioctl helpers ---- */ | 692 | /* ---- HCI ioctl helpers ---- */ |
| 641 | 693 | ||
| 642 | int hci_dev_open(__u16 dev) | 694 | int hci_dev_open(__u16 dev) |
| @@ -687,10 +739,6 @@ int hci_dev_open(__u16 dev) | |||
| 687 | 739 | ||
| 688 | ret = __hci_request(hdev, hci_init_req, 0, HCI_INIT_TIMEOUT); | 740 | ret = __hci_request(hdev, hci_init_req, 0, HCI_INIT_TIMEOUT); |
| 689 | 741 | ||
| 690 | if (lmp_host_le_capable(hdev)) | ||
| 691 | ret = __hci_request(hdev, hci_le_init_req, 0, | ||
| 692 | HCI_INIT_TIMEOUT); | ||
| 693 | |||
| 694 | clear_bit(HCI_INIT, &hdev->flags); | 742 | clear_bit(HCI_INIT, &hdev->flags); |
| 695 | } | 743 | } |
| 696 | 744 | ||
| @@ -698,6 +746,7 @@ int hci_dev_open(__u16 dev) | |||
| 698 | hci_dev_hold(hdev); | 746 | hci_dev_hold(hdev); |
| 699 | set_bit(HCI_UP, &hdev->flags); | 747 | set_bit(HCI_UP, &hdev->flags); |
| 700 | hci_notify(hdev, HCI_DEV_UP); | 748 | hci_notify(hdev, HCI_DEV_UP); |
| 749 | hci_update_ad(hdev); | ||
| 701 | if (!test_bit(HCI_SETUP, &hdev->dev_flags) && | 750 | if (!test_bit(HCI_SETUP, &hdev->dev_flags) && |
| 702 | mgmt_valid_hdev(hdev)) { | 751 | mgmt_valid_hdev(hdev)) { |
| 703 | hci_dev_lock(hdev); | 752 | hci_dev_lock(hdev); |
| @@ -1039,10 +1088,17 @@ int hci_get_dev_info(void __user *arg) | |||
| 1039 | di.type = (hdev->bus & 0x0f) | (hdev->dev_type << 4); | 1088 | di.type = (hdev->bus & 0x0f) | (hdev->dev_type << 4); |
| 1040 | di.flags = hdev->flags; | 1089 | di.flags = hdev->flags; |
| 1041 | di.pkt_type = hdev->pkt_type; | 1090 | di.pkt_type = hdev->pkt_type; |
| 1042 | di.acl_mtu = hdev->acl_mtu; | 1091 | if (lmp_bredr_capable(hdev)) { |
| 1043 | di.acl_pkts = hdev->acl_pkts; | 1092 | di.acl_mtu = hdev->acl_mtu; |
| 1044 | di.sco_mtu = hdev->sco_mtu; | 1093 | di.acl_pkts = hdev->acl_pkts; |
| 1045 | di.sco_pkts = hdev->sco_pkts; | 1094 | di.sco_mtu = hdev->sco_mtu; |
| 1095 | di.sco_pkts = hdev->sco_pkts; | ||
| 1096 | } else { | ||
| 1097 | di.acl_mtu = hdev->le_mtu; | ||
| 1098 | di.acl_pkts = hdev->le_pkts; | ||
| 1099 | di.sco_mtu = 0; | ||
| 1100 | di.sco_pkts = 0; | ||
| 1101 | } | ||
| 1046 | di.link_policy = hdev->link_policy; | 1102 | di.link_policy = hdev->link_policy; |
| 1047 | di.link_mode = hdev->link_mode; | 1103 | di.link_mode = hdev->link_mode; |
| 1048 | 1104 | ||
| @@ -1617,6 +1673,9 @@ int hci_le_scan(struct hci_dev *hdev, u8 type, u16 interval, u16 window, | |||
| 1617 | 1673 | ||
| 1618 | BT_DBG("%s", hdev->name); | 1674 | BT_DBG("%s", hdev->name); |
| 1619 | 1675 | ||
| 1676 | if (test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags)) | ||
| 1677 | return -ENOTSUPP; | ||
| 1678 | |||
| 1620 | if (work_busy(&hdev->le_scan)) | 1679 | if (work_busy(&hdev->le_scan)) |
| 1621 | return -EINPROGRESS; | 1680 | return -EINPROGRESS; |
| 1622 | 1681 | ||
| @@ -1643,6 +1702,8 @@ struct hci_dev *hci_alloc_dev(void) | |||
| 1643 | hdev->esco_type = (ESCO_HV1); | 1702 | hdev->esco_type = (ESCO_HV1); |
| 1644 | hdev->link_mode = (HCI_LM_ACCEPT); | 1703 | hdev->link_mode = (HCI_LM_ACCEPT); |
| 1645 | hdev->io_capability = 0x03; /* No Input No Output */ | 1704 | hdev->io_capability = 0x03; /* No Input No Output */ |
| 1705 | hdev->inq_tx_power = HCI_TX_POWER_INVALID; | ||
| 1706 | hdev->adv_tx_power = HCI_TX_POWER_INVALID; | ||
| 1646 | 1707 | ||
| 1647 | hdev->sniff_max_interval = 800; | 1708 | hdev->sniff_max_interval = 800; |
| 1648 | hdev->sniff_min_interval = 80; | 1709 | hdev->sniff_min_interval = 80; |
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 0383635f91fb..9f5c5f244502 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c | |||
| @@ -24,7 +24,6 @@ | |||
| 24 | 24 | ||
| 25 | /* Bluetooth HCI event handling. */ | 25 | /* Bluetooth HCI event handling. */ |
| 26 | 26 | ||
| 27 | #include <linux/export.h> | ||
| 28 | #include <asm/unaligned.h> | 27 | #include <asm/unaligned.h> |
| 29 | 28 | ||
| 30 | #include <net/bluetooth/bluetooth.h> | 29 | #include <net/bluetooth/bluetooth.h> |
| @@ -203,6 +202,11 @@ static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb) | |||
| 203 | BIT(HCI_PERIODIC_INQ)); | 202 | BIT(HCI_PERIODIC_INQ)); |
| 204 | 203 | ||
| 205 | hdev->discovery.state = DISCOVERY_STOPPED; | 204 | hdev->discovery.state = DISCOVERY_STOPPED; |
| 205 | hdev->inq_tx_power = HCI_TX_POWER_INVALID; | ||
| 206 | hdev->adv_tx_power = HCI_TX_POWER_INVALID; | ||
| 207 | |||
| 208 | memset(hdev->adv_data, 0, sizeof(hdev->adv_data)); | ||
| 209 | hdev->adv_data_len = 0; | ||
| 206 | } | 210 | } |
| 207 | 211 | ||
| 208 | static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb) | 212 | static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb) |
| @@ -225,6 +229,9 @@ static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb) | |||
| 225 | 229 | ||
| 226 | hci_dev_unlock(hdev); | 230 | hci_dev_unlock(hdev); |
| 227 | 231 | ||
| 232 | if (!status && !test_bit(HCI_INIT, &hdev->flags)) | ||
| 233 | hci_update_ad(hdev); | ||
| 234 | |||
| 228 | hci_req_complete(hdev, HCI_OP_WRITE_LOCAL_NAME, status); | 235 | hci_req_complete(hdev, HCI_OP_WRITE_LOCAL_NAME, status); |
| 229 | } | 236 | } |
| 230 | 237 | ||
| @@ -440,7 +447,7 @@ static void hci_cc_host_buffer_size(struct hci_dev *hdev, struct sk_buff *skb) | |||
| 440 | static void hci_cc_write_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb) | 447 | static void hci_cc_write_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb) |
| 441 | { | 448 | { |
| 442 | __u8 status = *((__u8 *) skb->data); | 449 | __u8 status = *((__u8 *) skb->data); |
| 443 | void *sent; | 450 | struct hci_cp_write_ssp_mode *sent; |
| 444 | 451 | ||
| 445 | BT_DBG("%s status 0x%2.2x", hdev->name, status); | 452 | BT_DBG("%s status 0x%2.2x", hdev->name, status); |
| 446 | 453 | ||
| @@ -448,10 +455,17 @@ static void hci_cc_write_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb) | |||
| 448 | if (!sent) | 455 | if (!sent) |
| 449 | return; | 456 | return; |
| 450 | 457 | ||
| 458 | if (!status) { | ||
| 459 | if (sent->mode) | ||
| 460 | hdev->host_features[0] |= LMP_HOST_SSP; | ||
| 461 | else | ||
| 462 | hdev->host_features[0] &= ~LMP_HOST_SSP; | ||
| 463 | } | ||
| 464 | |||
| 451 | if (test_bit(HCI_MGMT, &hdev->dev_flags)) | 465 | if (test_bit(HCI_MGMT, &hdev->dev_flags)) |
| 452 | mgmt_ssp_enable_complete(hdev, *((u8 *) sent), status); | 466 | mgmt_ssp_enable_complete(hdev, sent->mode, status); |
| 453 | else if (!status) { | 467 | else if (!status) { |
| 454 | if (*((u8 *) sent)) | 468 | if (sent->mode) |
| 455 | set_bit(HCI_SSP_ENABLED, &hdev->dev_flags); | 469 | set_bit(HCI_SSP_ENABLED, &hdev->dev_flags); |
| 456 | else | 470 | else |
| 457 | clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags); | 471 | clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags); |
| @@ -460,10 +474,10 @@ static void hci_cc_write_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb) | |||
| 460 | 474 | ||
| 461 | static u8 hci_get_inquiry_mode(struct hci_dev *hdev) | 475 | static u8 hci_get_inquiry_mode(struct hci_dev *hdev) |
| 462 | { | 476 | { |
| 463 | if (hdev->features[6] & LMP_EXT_INQ) | 477 | if (lmp_ext_inq_capable(hdev)) |
| 464 | return 2; | 478 | return 2; |
| 465 | 479 | ||
| 466 | if (hdev->features[3] & LMP_RSSI_INQ) | 480 | if (lmp_inq_rssi_capable(hdev)) |
| 467 | return 1; | 481 | return 1; |
| 468 | 482 | ||
| 469 | if (hdev->manufacturer == 11 && hdev->hci_rev == 0x00 && | 483 | if (hdev->manufacturer == 11 && hdev->hci_rev == 0x00 && |
| @@ -507,28 +521,30 @@ static void hci_setup_event_mask(struct hci_dev *hdev) | |||
| 507 | if (hdev->hci_ver < BLUETOOTH_VER_1_2) | 521 | if (hdev->hci_ver < BLUETOOTH_VER_1_2) |
| 508 | return; | 522 | return; |
| 509 | 523 | ||
| 510 | events[4] |= 0x01; /* Flow Specification Complete */ | 524 | if (lmp_bredr_capable(hdev)) { |
| 511 | events[4] |= 0x02; /* Inquiry Result with RSSI */ | 525 | events[4] |= 0x01; /* Flow Specification Complete */ |
| 512 | events[4] |= 0x04; /* Read Remote Extended Features Complete */ | 526 | events[4] |= 0x02; /* Inquiry Result with RSSI */ |
| 513 | events[5] |= 0x08; /* Synchronous Connection Complete */ | 527 | events[4] |= 0x04; /* Read Remote Extended Features Complete */ |
| 514 | events[5] |= 0x10; /* Synchronous Connection Changed */ | 528 | events[5] |= 0x08; /* Synchronous Connection Complete */ |
| 529 | events[5] |= 0x10; /* Synchronous Connection Changed */ | ||
| 530 | } | ||
| 515 | 531 | ||
| 516 | if (hdev->features[3] & LMP_RSSI_INQ) | 532 | if (lmp_inq_rssi_capable(hdev)) |
| 517 | events[4] |= 0x02; /* Inquiry Result with RSSI */ | 533 | events[4] |= 0x02; /* Inquiry Result with RSSI */ |
| 518 | 534 | ||
| 519 | if (lmp_sniffsubr_capable(hdev)) | 535 | if (lmp_sniffsubr_capable(hdev)) |
| 520 | events[5] |= 0x20; /* Sniff Subrating */ | 536 | events[5] |= 0x20; /* Sniff Subrating */ |
| 521 | 537 | ||
| 522 | if (hdev->features[5] & LMP_PAUSE_ENC) | 538 | if (lmp_pause_enc_capable(hdev)) |
| 523 | events[5] |= 0x80; /* Encryption Key Refresh Complete */ | 539 | events[5] |= 0x80; /* Encryption Key Refresh Complete */ |
| 524 | 540 | ||
| 525 | if (hdev->features[6] & LMP_EXT_INQ) | 541 | if (lmp_ext_inq_capable(hdev)) |
| 526 | events[5] |= 0x40; /* Extended Inquiry Result */ | 542 | events[5] |= 0x40; /* Extended Inquiry Result */ |
| 527 | 543 | ||
| 528 | if (lmp_no_flush_capable(hdev)) | 544 | if (lmp_no_flush_capable(hdev)) |
| 529 | events[7] |= 0x01; /* Enhanced Flush Complete */ | 545 | events[7] |= 0x01; /* Enhanced Flush Complete */ |
| 530 | 546 | ||
| 531 | if (hdev->features[7] & LMP_LSTO) | 547 | if (lmp_lsto_capable(hdev)) |
| 532 | events[6] |= 0x80; /* Link Supervision Timeout Changed */ | 548 | events[6] |= 0x80; /* Link Supervision Timeout Changed */ |
| 533 | 549 | ||
| 534 | if (lmp_ssp_capable(hdev)) { | 550 | if (lmp_ssp_capable(hdev)) { |
| @@ -548,6 +564,53 @@ static void hci_setup_event_mask(struct hci_dev *hdev) | |||
| 548 | events[7] |= 0x20; /* LE Meta-Event */ | 564 | events[7] |= 0x20; /* LE Meta-Event */ |
| 549 | 565 | ||
| 550 | hci_send_cmd(hdev, HCI_OP_SET_EVENT_MASK, sizeof(events), events); | 566 | hci_send_cmd(hdev, HCI_OP_SET_EVENT_MASK, sizeof(events), events); |
| 567 | |||
| 568 | if (lmp_le_capable(hdev)) { | ||
| 569 | memset(events, 0, sizeof(events)); | ||
| 570 | events[0] = 0x1f; | ||
| 571 | hci_send_cmd(hdev, HCI_OP_LE_SET_EVENT_MASK, | ||
| 572 | sizeof(events), events); | ||
| 573 | } | ||
| 574 | } | ||
| 575 | |||
| 576 | static void bredr_setup(struct hci_dev *hdev) | ||
| 577 | { | ||
| 578 | struct hci_cp_delete_stored_link_key cp; | ||
| 579 | __le16 param; | ||
| 580 | __u8 flt_type; | ||
| 581 | |||
| 582 | /* Read Buffer Size (ACL mtu, max pkt, etc.) */ | ||
| 583 | hci_send_cmd(hdev, HCI_OP_READ_BUFFER_SIZE, 0, NULL); | ||
| 584 | |||
| 585 | /* Read Class of Device */ | ||
| 586 | hci_send_cmd(hdev, HCI_OP_READ_CLASS_OF_DEV, 0, NULL); | ||
| 587 | |||
| 588 | /* Read Local Name */ | ||
| 589 | hci_send_cmd(hdev, HCI_OP_READ_LOCAL_NAME, 0, NULL); | ||
| 590 | |||
| 591 | /* Read Voice Setting */ | ||
| 592 | hci_send_cmd(hdev, HCI_OP_READ_VOICE_SETTING, 0, NULL); | ||
| 593 | |||
| 594 | /* Clear Event Filters */ | ||
| 595 | flt_type = HCI_FLT_CLEAR_ALL; | ||
| 596 | hci_send_cmd(hdev, HCI_OP_SET_EVENT_FLT, 1, &flt_type); | ||
| 597 | |||
| 598 | /* Connection accept timeout ~20 secs */ | ||
| 599 | param = __constant_cpu_to_le16(0x7d00); | ||
| 600 | hci_send_cmd(hdev, HCI_OP_WRITE_CA_TIMEOUT, 2, ¶m); | ||
| 601 | |||
| 602 | bacpy(&cp.bdaddr, BDADDR_ANY); | ||
| 603 | cp.delete_all = 1; | ||
| 604 | hci_send_cmd(hdev, HCI_OP_DELETE_STORED_LINK_KEY, sizeof(cp), &cp); | ||
| 605 | } | ||
| 606 | |||
| 607 | static void le_setup(struct hci_dev *hdev) | ||
| 608 | { | ||
| 609 | /* Read LE Buffer Size */ | ||
| 610 | hci_send_cmd(hdev, HCI_OP_LE_READ_BUFFER_SIZE, 0, NULL); | ||
| 611 | |||
| 612 | /* Read LE Advertising Channel TX Power */ | ||
| 613 | hci_send_cmd(hdev, HCI_OP_LE_READ_ADV_TX_POWER, 0, NULL); | ||
| 551 | } | 614 | } |
| 552 | 615 | ||
| 553 | static void hci_setup(struct hci_dev *hdev) | 616 | static void hci_setup(struct hci_dev *hdev) |
| @@ -555,6 +618,15 @@ static void hci_setup(struct hci_dev *hdev) | |||
| 555 | if (hdev->dev_type != HCI_BREDR) | 618 | if (hdev->dev_type != HCI_BREDR) |
| 556 | return; | 619 | return; |
| 557 | 620 | ||
| 621 | /* Read BD Address */ | ||
| 622 | hci_send_cmd(hdev, HCI_OP_READ_BD_ADDR, 0, NULL); | ||
| 623 | |||
| 624 | if (lmp_bredr_capable(hdev)) | ||
| 625 | bredr_setup(hdev); | ||
| 626 | |||
| 627 | if (lmp_le_capable(hdev)) | ||
| 628 | le_setup(hdev); | ||
| 629 | |||
| 558 | hci_setup_event_mask(hdev); | 630 | hci_setup_event_mask(hdev); |
| 559 | 631 | ||
| 560 | if (hdev->hci_ver > BLUETOOTH_VER_1_1) | 632 | if (hdev->hci_ver > BLUETOOTH_VER_1_1) |
| @@ -575,13 +647,13 @@ static void hci_setup(struct hci_dev *hdev) | |||
| 575 | } | 647 | } |
| 576 | } | 648 | } |
| 577 | 649 | ||
| 578 | if (hdev->features[3] & LMP_RSSI_INQ) | 650 | if (lmp_inq_rssi_capable(hdev)) |
| 579 | hci_setup_inquiry_mode(hdev); | 651 | hci_setup_inquiry_mode(hdev); |
| 580 | 652 | ||
| 581 | if (hdev->features[7] & LMP_INQ_TX_PWR) | 653 | if (lmp_inq_tx_pwr_capable(hdev)) |
| 582 | hci_send_cmd(hdev, HCI_OP_READ_INQ_RSP_TX_POWER, 0, NULL); | 654 | hci_send_cmd(hdev, HCI_OP_READ_INQ_RSP_TX_POWER, 0, NULL); |
| 583 | 655 | ||
| 584 | if (hdev->features[7] & LMP_EXTFEATURES) { | 656 | if (lmp_ext_feat_capable(hdev)) { |
| 585 | struct hci_cp_read_local_ext_features cp; | 657 | struct hci_cp_read_local_ext_features cp; |
| 586 | 658 | ||
| 587 | cp.page = 0x01; | 659 | cp.page = 0x01; |
| @@ -628,11 +700,11 @@ static void hci_setup_link_policy(struct hci_dev *hdev) | |||
| 628 | 700 | ||
| 629 | if (lmp_rswitch_capable(hdev)) | 701 | if (lmp_rswitch_capable(hdev)) |
| 630 | link_policy |= HCI_LP_RSWITCH; | 702 | link_policy |= HCI_LP_RSWITCH; |
| 631 | if (hdev->features[0] & LMP_HOLD) | 703 | if (lmp_hold_capable(hdev)) |
| 632 | link_policy |= HCI_LP_HOLD; | 704 | link_policy |= HCI_LP_HOLD; |
| 633 | if (lmp_sniff_capable(hdev)) | 705 | if (lmp_sniff_capable(hdev)) |
| 634 | link_policy |= HCI_LP_SNIFF; | 706 | link_policy |= HCI_LP_SNIFF; |
| 635 | if (hdev->features[1] & LMP_PARK) | 707 | if (lmp_park_capable(hdev)) |
| 636 | link_policy |= HCI_LP_PARK; | 708 | link_policy |= HCI_LP_PARK; |
| 637 | 709 | ||
| 638 | cp.policy = cpu_to_le16(link_policy); | 710 | cp.policy = cpu_to_le16(link_policy); |
| @@ -722,10 +794,10 @@ static void hci_set_le_support(struct hci_dev *hdev) | |||
| 722 | 794 | ||
| 723 | if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) { | 795 | if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) { |
| 724 | cp.le = 1; | 796 | cp.le = 1; |
| 725 | cp.simul = !!(hdev->features[6] & LMP_SIMUL_LE_BR); | 797 | cp.simul = !!lmp_le_br_capable(hdev); |
| 726 | } | 798 | } |
| 727 | 799 | ||
| 728 | if (cp.le != !!(hdev->host_features[0] & LMP_HOST_LE)) | 800 | if (cp.le != !!lmp_host_le_capable(hdev)) |
| 729 | hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(cp), | 801 | hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(cp), |
| 730 | &cp); | 802 | &cp); |
| 731 | } | 803 | } |
| @@ -1018,6 +1090,31 @@ static void hci_cc_le_read_buffer_size(struct hci_dev *hdev, | |||
| 1018 | hci_req_complete(hdev, HCI_OP_LE_READ_BUFFER_SIZE, rp->status); | 1090 | hci_req_complete(hdev, HCI_OP_LE_READ_BUFFER_SIZE, rp->status); |
| 1019 | } | 1091 | } |
| 1020 | 1092 | ||
| 1093 | static void hci_cc_le_read_adv_tx_power(struct hci_dev *hdev, | ||
| 1094 | struct sk_buff *skb) | ||
| 1095 | { | ||
| 1096 | struct hci_rp_le_read_adv_tx_power *rp = (void *) skb->data; | ||
| 1097 | |||
| 1098 | BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); | ||
| 1099 | |||
| 1100 | if (!rp->status) { | ||
| 1101 | hdev->adv_tx_power = rp->tx_power; | ||
| 1102 | if (!test_bit(HCI_INIT, &hdev->flags)) | ||
| 1103 | hci_update_ad(hdev); | ||
| 1104 | } | ||
| 1105 | |||
| 1106 | hci_req_complete(hdev, HCI_OP_LE_READ_ADV_TX_POWER, rp->status); | ||
| 1107 | } | ||
| 1108 | |||
| 1109 | static void hci_cc_le_set_event_mask(struct hci_dev *hdev, struct sk_buff *skb) | ||
| 1110 | { | ||
| 1111 | __u8 status = *((__u8 *) skb->data); | ||
| 1112 | |||
| 1113 | BT_DBG("%s status 0x%2.2x", hdev->name, status); | ||
| 1114 | |||
| 1115 | hci_req_complete(hdev, HCI_OP_LE_SET_EVENT_MASK, status); | ||
| 1116 | } | ||
| 1117 | |||
| 1021 | static void hci_cc_user_confirm_reply(struct hci_dev *hdev, struct sk_buff *skb) | 1118 | static void hci_cc_user_confirm_reply(struct hci_dev *hdev, struct sk_buff *skb) |
| 1022 | { | 1119 | { |
| 1023 | struct hci_rp_user_confirm_reply *rp = (void *) skb->data; | 1120 | struct hci_rp_user_confirm_reply *rp = (void *) skb->data; |
| @@ -1093,6 +1190,33 @@ static void hci_cc_read_local_oob_data_reply(struct hci_dev *hdev, | |||
| 1093 | hci_dev_unlock(hdev); | 1190 | hci_dev_unlock(hdev); |
| 1094 | } | 1191 | } |
| 1095 | 1192 | ||
| 1193 | static void hci_cc_le_set_adv_enable(struct hci_dev *hdev, struct sk_buff *skb) | ||
| 1194 | { | ||
| 1195 | __u8 *sent, status = *((__u8 *) skb->data); | ||
| 1196 | |||
| 1197 | BT_DBG("%s status 0x%2.2x", hdev->name, status); | ||
| 1198 | |||
| 1199 | sent = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_ADV_ENABLE); | ||
| 1200 | if (!sent) | ||
| 1201 | return; | ||
| 1202 | |||
| 1203 | hci_dev_lock(hdev); | ||
| 1204 | |||
| 1205 | if (!status) { | ||
| 1206 | if (*sent) | ||
| 1207 | set_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags); | ||
| 1208 | else | ||
| 1209 | clear_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags); | ||
| 1210 | } | ||
| 1211 | |||
| 1212 | hci_dev_unlock(hdev); | ||
| 1213 | |||
| 1214 | if (!test_bit(HCI_INIT, &hdev->flags)) | ||
| 1215 | hci_update_ad(hdev); | ||
| 1216 | |||
| 1217 | hci_req_complete(hdev, HCI_OP_LE_SET_ADV_ENABLE, status); | ||
| 1218 | } | ||
| 1219 | |||
| 1096 | static void hci_cc_le_set_scan_param(struct hci_dev *hdev, struct sk_buff *skb) | 1220 | static void hci_cc_le_set_scan_param(struct hci_dev *hdev, struct sk_buff *skb) |
| 1097 | { | 1221 | { |
| 1098 | __u8 status = *((__u8 *) skb->data); | 1222 | __u8 status = *((__u8 *) skb->data); |
| @@ -1207,6 +1331,11 @@ static void hci_cc_write_le_host_supported(struct hci_dev *hdev, | |||
| 1207 | hdev->host_features[0] |= LMP_HOST_LE; | 1331 | hdev->host_features[0] |= LMP_HOST_LE; |
| 1208 | else | 1332 | else |
| 1209 | hdev->host_features[0] &= ~LMP_HOST_LE; | 1333 | hdev->host_features[0] &= ~LMP_HOST_LE; |
| 1334 | |||
| 1335 | if (sent->simul) | ||
| 1336 | hdev->host_features[0] |= LMP_HOST_LE_BREDR; | ||
| 1337 | else | ||
| 1338 | hdev->host_features[0] &= ~LMP_HOST_LE_BREDR; | ||
| 1210 | } | 1339 | } |
| 1211 | 1340 | ||
| 1212 | if (test_bit(HCI_MGMT, &hdev->dev_flags) && | 1341 | if (test_bit(HCI_MGMT, &hdev->dev_flags) && |
| @@ -1718,14 +1847,23 @@ static void hci_cs_create_phylink(struct hci_dev *hdev, u8 status) | |||
| 1718 | 1847 | ||
| 1719 | BT_DBG("%s status 0x%2.2x", hdev->name, status); | 1848 | BT_DBG("%s status 0x%2.2x", hdev->name, status); |
| 1720 | 1849 | ||
| 1721 | if (status) | ||
| 1722 | return; | ||
| 1723 | |||
| 1724 | cp = hci_sent_cmd_data(hdev, HCI_OP_CREATE_PHY_LINK); | 1850 | cp = hci_sent_cmd_data(hdev, HCI_OP_CREATE_PHY_LINK); |
| 1725 | if (!cp) | 1851 | if (!cp) |
| 1726 | return; | 1852 | return; |
| 1727 | 1853 | ||
| 1728 | amp_write_remote_assoc(hdev, cp->phy_handle); | 1854 | hci_dev_lock(hdev); |
| 1855 | |||
| 1856 | if (status) { | ||
| 1857 | struct hci_conn *hcon; | ||
| 1858 | |||
| 1859 | hcon = hci_conn_hash_lookup_handle(hdev, cp->phy_handle); | ||
| 1860 | if (hcon) | ||
| 1861 | hci_conn_del(hcon); | ||
| 1862 | } else { | ||
| 1863 | amp_write_remote_assoc(hdev, cp->phy_handle); | ||
| 1864 | } | ||
| 1865 | |||
| 1866 | hci_dev_unlock(hdev); | ||
| 1729 | } | 1867 | } |
| 1730 | 1868 | ||
| 1731 | static void hci_cs_accept_phylink(struct hci_dev *hdev, u8 status) | 1869 | static void hci_cs_accept_phylink(struct hci_dev *hdev, u8 status) |
| @@ -1744,6 +1882,11 @@ static void hci_cs_accept_phylink(struct hci_dev *hdev, u8 status) | |||
| 1744 | amp_write_remote_assoc(hdev, cp->phy_handle); | 1882 | amp_write_remote_assoc(hdev, cp->phy_handle); |
| 1745 | } | 1883 | } |
| 1746 | 1884 | ||
| 1885 | static void hci_cs_create_logical_link(struct hci_dev *hdev, u8 status) | ||
| 1886 | { | ||
| 1887 | BT_DBG("%s status 0x%2.2x", hdev->name, status); | ||
| 1888 | } | ||
| 1889 | |||
| 1747 | static void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) | 1890 | static void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) |
| 1748 | { | 1891 | { |
| 1749 | __u8 status = *((__u8 *) skb->data); | 1892 | __u8 status = *((__u8 *) skb->data); |
| @@ -2441,6 +2584,14 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) | |||
| 2441 | hci_cc_le_read_buffer_size(hdev, skb); | 2584 | hci_cc_le_read_buffer_size(hdev, skb); |
| 2442 | break; | 2585 | break; |
| 2443 | 2586 | ||
| 2587 | case HCI_OP_LE_READ_ADV_TX_POWER: | ||
| 2588 | hci_cc_le_read_adv_tx_power(hdev, skb); | ||
| 2589 | break; | ||
| 2590 | |||
| 2591 | case HCI_OP_LE_SET_EVENT_MASK: | ||
| 2592 | hci_cc_le_set_event_mask(hdev, skb); | ||
| 2593 | break; | ||
| 2594 | |||
| 2444 | case HCI_OP_USER_CONFIRM_REPLY: | 2595 | case HCI_OP_USER_CONFIRM_REPLY: |
| 2445 | hci_cc_user_confirm_reply(hdev, skb); | 2596 | hci_cc_user_confirm_reply(hdev, skb); |
| 2446 | break; | 2597 | break; |
| @@ -2461,6 +2612,10 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) | |||
| 2461 | hci_cc_le_set_scan_param(hdev, skb); | 2612 | hci_cc_le_set_scan_param(hdev, skb); |
| 2462 | break; | 2613 | break; |
| 2463 | 2614 | ||
| 2615 | case HCI_OP_LE_SET_ADV_ENABLE: | ||
| 2616 | hci_cc_le_set_adv_enable(hdev, skb); | ||
| 2617 | break; | ||
| 2618 | |||
| 2464 | case HCI_OP_LE_SET_SCAN_ENABLE: | 2619 | case HCI_OP_LE_SET_SCAN_ENABLE: |
| 2465 | hci_cc_le_set_scan_enable(hdev, skb); | 2620 | hci_cc_le_set_scan_enable(hdev, skb); |
| 2466 | break; | 2621 | break; |
| @@ -2570,6 +2725,10 @@ static void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb) | |||
| 2570 | hci_cs_accept_phylink(hdev, ev->status); | 2725 | hci_cs_accept_phylink(hdev, ev->status); |
| 2571 | break; | 2726 | break; |
| 2572 | 2727 | ||
| 2728 | case HCI_OP_CREATE_LOGICAL_LINK: | ||
| 2729 | hci_cs_create_logical_link(hdev, ev->status); | ||
| 2730 | break; | ||
| 2731 | |||
| 2573 | default: | 2732 | default: |
| 2574 | BT_DBG("%s opcode 0x%4.4x", hdev->name, opcode); | 2733 | BT_DBG("%s opcode 0x%4.4x", hdev->name, opcode); |
| 2575 | break; | 2734 | break; |
| @@ -3544,6 +3703,130 @@ unlock: | |||
| 3544 | hci_dev_unlock(hdev); | 3703 | hci_dev_unlock(hdev); |
| 3545 | } | 3704 | } |
| 3546 | 3705 | ||
| 3706 | static void hci_phy_link_complete_evt(struct hci_dev *hdev, | ||
| 3707 | struct sk_buff *skb) | ||
| 3708 | { | ||
| 3709 | struct hci_ev_phy_link_complete *ev = (void *) skb->data; | ||
| 3710 | struct hci_conn *hcon, *bredr_hcon; | ||
| 3711 | |||
| 3712 | BT_DBG("%s handle 0x%2.2x status 0x%2.2x", hdev->name, ev->phy_handle, | ||
| 3713 | ev->status); | ||
| 3714 | |||
| 3715 | hci_dev_lock(hdev); | ||
| 3716 | |||
| 3717 | hcon = hci_conn_hash_lookup_handle(hdev, ev->phy_handle); | ||
| 3718 | if (!hcon) { | ||
| 3719 | hci_dev_unlock(hdev); | ||
| 3720 | return; | ||
| 3721 | } | ||
| 3722 | |||
| 3723 | if (ev->status) { | ||
| 3724 | hci_conn_del(hcon); | ||
| 3725 | hci_dev_unlock(hdev); | ||
| 3726 | return; | ||
| 3727 | } | ||
| 3728 | |||
| 3729 | bredr_hcon = hcon->amp_mgr->l2cap_conn->hcon; | ||
| 3730 | |||
| 3731 | hcon->state = BT_CONNECTED; | ||
| 3732 | bacpy(&hcon->dst, &bredr_hcon->dst); | ||
| 3733 | |||
| 3734 | hci_conn_hold(hcon); | ||
| 3735 | hcon->disc_timeout = HCI_DISCONN_TIMEOUT; | ||
| 3736 | hci_conn_put(hcon); | ||
| 3737 | |||
| 3738 | hci_conn_hold_device(hcon); | ||
| 3739 | hci_conn_add_sysfs(hcon); | ||
| 3740 | |||
| 3741 | amp_physical_cfm(bredr_hcon, hcon); | ||
| 3742 | |||
| 3743 | hci_dev_unlock(hdev); | ||
| 3744 | } | ||
| 3745 | |||
| 3746 | static void hci_loglink_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) | ||
| 3747 | { | ||
| 3748 | struct hci_ev_logical_link_complete *ev = (void *) skb->data; | ||
| 3749 | struct hci_conn *hcon; | ||
| 3750 | struct hci_chan *hchan; | ||
| 3751 | struct amp_mgr *mgr; | ||
| 3752 | |||
| 3753 | BT_DBG("%s log_handle 0x%4.4x phy_handle 0x%2.2x status 0x%2.2x", | ||
| 3754 | hdev->name, le16_to_cpu(ev->handle), ev->phy_handle, | ||
| 3755 | ev->status); | ||
| 3756 | |||
| 3757 | hcon = hci_conn_hash_lookup_handle(hdev, ev->phy_handle); | ||
| 3758 | if (!hcon) | ||
| 3759 | return; | ||
| 3760 | |||
| 3761 | /* Create AMP hchan */ | ||
| 3762 | hchan = hci_chan_create(hcon); | ||
| 3763 | if (!hchan) | ||
| 3764 | return; | ||
| 3765 | |||
| 3766 | hchan->handle = le16_to_cpu(ev->handle); | ||
| 3767 | |||
| 3768 | BT_DBG("hcon %p mgr %p hchan %p", hcon, hcon->amp_mgr, hchan); | ||
| 3769 | |||
| 3770 | mgr = hcon->amp_mgr; | ||
| 3771 | if (mgr && mgr->bredr_chan) { | ||
| 3772 | struct l2cap_chan *bredr_chan = mgr->bredr_chan; | ||
| 3773 | |||
| 3774 | l2cap_chan_lock(bredr_chan); | ||
| 3775 | |||
| 3776 | bredr_chan->conn->mtu = hdev->block_mtu; | ||
| 3777 | l2cap_logical_cfm(bredr_chan, hchan, 0); | ||
| 3778 | hci_conn_hold(hcon); | ||
| 3779 | |||
| 3780 | l2cap_chan_unlock(bredr_chan); | ||
| 3781 | } | ||
| 3782 | } | ||
| 3783 | |||
| 3784 | static void hci_disconn_loglink_complete_evt(struct hci_dev *hdev, | ||
| 3785 | struct sk_buff *skb) | ||
| 3786 | { | ||
| 3787 | struct hci_ev_disconn_logical_link_complete *ev = (void *) skb->data; | ||
| 3788 | struct hci_chan *hchan; | ||
| 3789 | |||
| 3790 | BT_DBG("%s log handle 0x%4.4x status 0x%2.2x", hdev->name, | ||
| 3791 | le16_to_cpu(ev->handle), ev->status); | ||
| 3792 | |||
| 3793 | if (ev->status) | ||
| 3794 | return; | ||
| 3795 | |||
| 3796 | hci_dev_lock(hdev); | ||
| 3797 | |||
| 3798 | hchan = hci_chan_lookup_handle(hdev, le16_to_cpu(ev->handle)); | ||
| 3799 | if (!hchan) | ||
| 3800 | goto unlock; | ||
| 3801 | |||
| 3802 | amp_destroy_logical_link(hchan, ev->reason); | ||
| 3803 | |||
| 3804 | unlock: | ||
| 3805 | hci_dev_unlock(hdev); | ||
| 3806 | } | ||
| 3807 | |||
| 3808 | static void hci_disconn_phylink_complete_evt(struct hci_dev *hdev, | ||
| 3809 | struct sk_buff *skb) | ||
| 3810 | { | ||
| 3811 | struct hci_ev_disconn_phy_link_complete *ev = (void *) skb->data; | ||
| 3812 | struct hci_conn *hcon; | ||
| 3813 | |||
| 3814 | BT_DBG("%s status 0x%2.2x", hdev->name, ev->status); | ||
| 3815 | |||
| 3816 | if (ev->status) | ||
| 3817 | return; | ||
| 3818 | |||
| 3819 | hci_dev_lock(hdev); | ||
| 3820 | |||
| 3821 | hcon = hci_conn_hash_lookup_handle(hdev, ev->phy_handle); | ||
| 3822 | if (hcon) { | ||
| 3823 | hcon->state = BT_CLOSED; | ||
| 3824 | hci_conn_del(hcon); | ||
| 3825 | } | ||
| 3826 | |||
| 3827 | hci_dev_unlock(hdev); | ||
| 3828 | } | ||
| 3829 | |||
| 3547 | static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) | 3830 | static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) |
| 3548 | { | 3831 | { |
| 3549 | struct hci_ev_le_conn_complete *ev = (void *) skb->data; | 3832 | struct hci_ev_le_conn_complete *ev = (void *) skb->data; |
| @@ -3871,6 +4154,22 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb) | |||
| 3871 | hci_remote_oob_data_request_evt(hdev, skb); | 4154 | hci_remote_oob_data_request_evt(hdev, skb); |
| 3872 | break; | 4155 | break; |
| 3873 | 4156 | ||
| 4157 | case HCI_EV_PHY_LINK_COMPLETE: | ||
| 4158 | hci_phy_link_complete_evt(hdev, skb); | ||
| 4159 | break; | ||
| 4160 | |||
| 4161 | case HCI_EV_LOGICAL_LINK_COMPLETE: | ||
| 4162 | hci_loglink_complete_evt(hdev, skb); | ||
| 4163 | break; | ||
| 4164 | |||
| 4165 | case HCI_EV_DISCONN_LOGICAL_LINK_COMPLETE: | ||
| 4166 | hci_disconn_loglink_complete_evt(hdev, skb); | ||
| 4167 | break; | ||
| 4168 | |||
| 4169 | case HCI_EV_DISCONN_PHY_LINK_COMPLETE: | ||
| 4170 | hci_disconn_phylink_complete_evt(hdev, skb); | ||
| 4171 | break; | ||
| 4172 | |||
| 3874 | case HCI_EV_NUM_COMP_BLOCKS: | 4173 | case HCI_EV_NUM_COMP_BLOCKS: |
| 3875 | hci_num_comp_blocks_evt(hdev, skb); | 4174 | hci_num_comp_blocks_evt(hdev, skb); |
| 3876 | break; | 4175 | break; |
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 08efc256c931..b52f66d22437 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c | |||
| @@ -38,6 +38,7 @@ | |||
| 38 | #include <net/bluetooth/l2cap.h> | 38 | #include <net/bluetooth/l2cap.h> |
| 39 | #include <net/bluetooth/smp.h> | 39 | #include <net/bluetooth/smp.h> |
| 40 | #include <net/bluetooth/a2mp.h> | 40 | #include <net/bluetooth/a2mp.h> |
| 41 | #include <net/bluetooth/amp.h> | ||
| 41 | 42 | ||
| 42 | bool disable_ertm; | 43 | bool disable_ertm; |
| 43 | 44 | ||
| @@ -100,6 +101,23 @@ static struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_conn *conn, | |||
| 100 | return c; | 101 | return c; |
| 101 | } | 102 | } |
| 102 | 103 | ||
| 104 | /* Find channel with given DCID. | ||
| 105 | * Returns locked channel. | ||
| 106 | */ | ||
| 107 | static struct l2cap_chan *l2cap_get_chan_by_dcid(struct l2cap_conn *conn, | ||
| 108 | u16 cid) | ||
| 109 | { | ||
| 110 | struct l2cap_chan *c; | ||
| 111 | |||
| 112 | mutex_lock(&conn->chan_lock); | ||
| 113 | c = __l2cap_get_chan_by_dcid(conn, cid); | ||
| 114 | if (c) | ||
| 115 | l2cap_chan_lock(c); | ||
| 116 | mutex_unlock(&conn->chan_lock); | ||
| 117 | |||
| 118 | return c; | ||
| 119 | } | ||
| 120 | |||
| 103 | static struct l2cap_chan *__l2cap_get_chan_by_ident(struct l2cap_conn *conn, | 121 | static struct l2cap_chan *__l2cap_get_chan_by_ident(struct l2cap_conn *conn, |
| 104 | u8 ident) | 122 | u8 ident) |
| 105 | { | 123 | { |
| @@ -112,6 +130,20 @@ static struct l2cap_chan *__l2cap_get_chan_by_ident(struct l2cap_conn *conn, | |||
| 112 | return NULL; | 130 | return NULL; |
| 113 | } | 131 | } |
| 114 | 132 | ||
| 133 | static struct l2cap_chan *l2cap_get_chan_by_ident(struct l2cap_conn *conn, | ||
| 134 | u8 ident) | ||
| 135 | { | ||
| 136 | struct l2cap_chan *c; | ||
| 137 | |||
| 138 | mutex_lock(&conn->chan_lock); | ||
| 139 | c = __l2cap_get_chan_by_ident(conn, ident); | ||
| 140 | if (c) | ||
| 141 | l2cap_chan_lock(c); | ||
| 142 | mutex_unlock(&conn->chan_lock); | ||
| 143 | |||
| 144 | return c; | ||
| 145 | } | ||
| 146 | |||
| 115 | static struct l2cap_chan *__l2cap_global_chan_by_addr(__le16 psm, bdaddr_t *src) | 147 | static struct l2cap_chan *__l2cap_global_chan_by_addr(__le16 psm, bdaddr_t *src) |
| 116 | { | 148 | { |
| 117 | struct l2cap_chan *c; | 149 | struct l2cap_chan *c; |
| @@ -546,6 +578,13 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err) | |||
| 546 | mgr->bredr_chan = NULL; | 578 | mgr->bredr_chan = NULL; |
| 547 | } | 579 | } |
| 548 | 580 | ||
| 581 | if (chan->hs_hchan) { | ||
| 582 | struct hci_chan *hs_hchan = chan->hs_hchan; | ||
| 583 | |||
| 584 | BT_DBG("chan %p disconnect hs_hchan %p", chan, hs_hchan); | ||
| 585 | amp_disconnect_logical_link(hs_hchan); | ||
| 586 | } | ||
| 587 | |||
| 549 | chan->ops->teardown(chan, err); | 588 | chan->ops->teardown(chan, err); |
| 550 | 589 | ||
| 551 | if (test_bit(CONF_NOT_COMPLETE, &chan->conf_state)) | 590 | if (test_bit(CONF_NOT_COMPLETE, &chan->conf_state)) |
| @@ -718,6 +757,12 @@ static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, | |||
| 718 | hci_send_acl(conn->hchan, skb, flags); | 757 | hci_send_acl(conn->hchan, skb, flags); |
| 719 | } | 758 | } |
| 720 | 759 | ||
| 760 | static bool __chan_is_moving(struct l2cap_chan *chan) | ||
| 761 | { | ||
| 762 | return chan->move_state != L2CAP_MOVE_STABLE && | ||
| 763 | chan->move_state != L2CAP_MOVE_WAIT_PREPARE; | ||
| 764 | } | ||
| 765 | |||
| 721 | static void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb) | 766 | static void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb) |
| 722 | { | 767 | { |
| 723 | struct hci_conn *hcon = chan->conn->hcon; | 768 | struct hci_conn *hcon = chan->conn->hcon; |
| @@ -726,6 +771,15 @@ static void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb) | |||
| 726 | BT_DBG("chan %p, skb %p len %d priority %u", chan, skb, skb->len, | 771 | BT_DBG("chan %p, skb %p len %d priority %u", chan, skb, skb->len, |
| 727 | skb->priority); | 772 | skb->priority); |
| 728 | 773 | ||
| 774 | if (chan->hs_hcon && !__chan_is_moving(chan)) { | ||
| 775 | if (chan->hs_hchan) | ||
| 776 | hci_send_acl(chan->hs_hchan, skb, ACL_COMPLETE); | ||
| 777 | else | ||
| 778 | kfree_skb(skb); | ||
| 779 | |||
| 780 | return; | ||
| 781 | } | ||
| 782 | |||
| 729 | if (!test_bit(FLAG_FLUSHABLE, &chan->flags) && | 783 | if (!test_bit(FLAG_FLUSHABLE, &chan->flags) && |
| 730 | lmp_no_flush_capable(hcon->hdev)) | 784 | lmp_no_flush_capable(hcon->hdev)) |
| 731 | flags = ACL_START_NO_FLUSH; | 785 | flags = ACL_START_NO_FLUSH; |
| @@ -901,6 +955,9 @@ static void l2cap_send_sframe(struct l2cap_chan *chan, | |||
| 901 | if (!control->sframe) | 955 | if (!control->sframe) |
| 902 | return; | 956 | return; |
| 903 | 957 | ||
| 958 | if (__chan_is_moving(chan)) | ||
| 959 | return; | ||
| 960 | |||
| 904 | if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state) && | 961 | if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state) && |
| 905 | !control->poll) | 962 | !control->poll) |
| 906 | control->final = 1; | 963 | control->final = 1; |
| @@ -964,6 +1021,12 @@ static bool __amp_capable(struct l2cap_chan *chan) | |||
| 964 | return false; | 1021 | return false; |
| 965 | } | 1022 | } |
| 966 | 1023 | ||
| 1024 | static bool l2cap_check_efs(struct l2cap_chan *chan) | ||
| 1025 | { | ||
| 1026 | /* Check EFS parameters */ | ||
| 1027 | return true; | ||
| 1028 | } | ||
| 1029 | |||
| 967 | void l2cap_send_conn_req(struct l2cap_chan *chan) | 1030 | void l2cap_send_conn_req(struct l2cap_chan *chan) |
| 968 | { | 1031 | { |
| 969 | struct l2cap_conn *conn = chan->conn; | 1032 | struct l2cap_conn *conn = chan->conn; |
| @@ -979,6 +1042,76 @@ void l2cap_send_conn_req(struct l2cap_chan *chan) | |||
| 979 | l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ, sizeof(req), &req); | 1042 | l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ, sizeof(req), &req); |
| 980 | } | 1043 | } |
| 981 | 1044 | ||
| 1045 | static void l2cap_send_create_chan_req(struct l2cap_chan *chan, u8 amp_id) | ||
| 1046 | { | ||
| 1047 | struct l2cap_create_chan_req req; | ||
| 1048 | req.scid = cpu_to_le16(chan->scid); | ||
| 1049 | req.psm = chan->psm; | ||
| 1050 | req.amp_id = amp_id; | ||
| 1051 | |||
| 1052 | chan->ident = l2cap_get_ident(chan->conn); | ||
| 1053 | |||
| 1054 | l2cap_send_cmd(chan->conn, chan->ident, L2CAP_CREATE_CHAN_REQ, | ||
| 1055 | sizeof(req), &req); | ||
| 1056 | } | ||
| 1057 | |||
| 1058 | static void l2cap_move_setup(struct l2cap_chan *chan) | ||
| 1059 | { | ||
| 1060 | struct sk_buff *skb; | ||
| 1061 | |||
| 1062 | BT_DBG("chan %p", chan); | ||
| 1063 | |||
| 1064 | if (chan->mode != L2CAP_MODE_ERTM) | ||
| 1065 | return; | ||
| 1066 | |||
| 1067 | __clear_retrans_timer(chan); | ||
| 1068 | __clear_monitor_timer(chan); | ||
| 1069 | __clear_ack_timer(chan); | ||
| 1070 | |||
| 1071 | chan->retry_count = 0; | ||
| 1072 | skb_queue_walk(&chan->tx_q, skb) { | ||
| 1073 | if (bt_cb(skb)->control.retries) | ||
| 1074 | bt_cb(skb)->control.retries = 1; | ||
| 1075 | else | ||
| 1076 | break; | ||
| 1077 | } | ||
| 1078 | |||
| 1079 | chan->expected_tx_seq = chan->buffer_seq; | ||
| 1080 | |||
| 1081 | clear_bit(CONN_REJ_ACT, &chan->conn_state); | ||
| 1082 | clear_bit(CONN_SREJ_ACT, &chan->conn_state); | ||
| 1083 | l2cap_seq_list_clear(&chan->retrans_list); | ||
| 1084 | l2cap_seq_list_clear(&chan->srej_list); | ||
| 1085 | skb_queue_purge(&chan->srej_q); | ||
| 1086 | |||
| 1087 | chan->tx_state = L2CAP_TX_STATE_XMIT; | ||
| 1088 | chan->rx_state = L2CAP_RX_STATE_MOVE; | ||
| 1089 | |||
| 1090 | set_bit(CONN_REMOTE_BUSY, &chan->conn_state); | ||
| 1091 | } | ||
| 1092 | |||
| 1093 | static void l2cap_move_done(struct l2cap_chan *chan) | ||
| 1094 | { | ||
| 1095 | u8 move_role = chan->move_role; | ||
| 1096 | BT_DBG("chan %p", chan); | ||
| 1097 | |||
| 1098 | chan->move_state = L2CAP_MOVE_STABLE; | ||
| 1099 | chan->move_role = L2CAP_MOVE_ROLE_NONE; | ||
| 1100 | |||
| 1101 | if (chan->mode != L2CAP_MODE_ERTM) | ||
| 1102 | return; | ||
| 1103 | |||
| 1104 | switch (move_role) { | ||
| 1105 | case L2CAP_MOVE_ROLE_INITIATOR: | ||
| 1106 | l2cap_tx(chan, NULL, NULL, L2CAP_EV_EXPLICIT_POLL); | ||
| 1107 | chan->rx_state = L2CAP_RX_STATE_WAIT_F; | ||
| 1108 | break; | ||
| 1109 | case L2CAP_MOVE_ROLE_RESPONDER: | ||
| 1110 | chan->rx_state = L2CAP_RX_STATE_WAIT_P; | ||
| 1111 | break; | ||
| 1112 | } | ||
| 1113 | } | ||
| 1114 | |||
| 982 | static void l2cap_chan_ready(struct l2cap_chan *chan) | 1115 | static void l2cap_chan_ready(struct l2cap_chan *chan) |
| 983 | { | 1116 | { |
| 984 | /* This clears all conf flags, including CONF_NOT_COMPLETE */ | 1117 | /* This clears all conf flags, including CONF_NOT_COMPLETE */ |
| @@ -1695,6 +1828,9 @@ static void l2cap_streaming_send(struct l2cap_chan *chan, | |||
| 1695 | 1828 | ||
| 1696 | BT_DBG("chan %p, skbs %p", chan, skbs); | 1829 | BT_DBG("chan %p, skbs %p", chan, skbs); |
| 1697 | 1830 | ||
| 1831 | if (__chan_is_moving(chan)) | ||
| 1832 | return; | ||
| 1833 | |||
| 1698 | skb_queue_splice_tail_init(skbs, &chan->tx_q); | 1834 | skb_queue_splice_tail_init(skbs, &chan->tx_q); |
| 1699 | 1835 | ||
| 1700 | while (!skb_queue_empty(&chan->tx_q)) { | 1836 | while (!skb_queue_empty(&chan->tx_q)) { |
| @@ -1737,6 +1873,9 @@ static int l2cap_ertm_send(struct l2cap_chan *chan) | |||
| 1737 | if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state)) | 1873 | if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state)) |
| 1738 | return 0; | 1874 | return 0; |
| 1739 | 1875 | ||
| 1876 | if (__chan_is_moving(chan)) | ||
| 1877 | return 0; | ||
| 1878 | |||
| 1740 | while (chan->tx_send_head && | 1879 | while (chan->tx_send_head && |
| 1741 | chan->unacked_frames < chan->remote_tx_win && | 1880 | chan->unacked_frames < chan->remote_tx_win && |
| 1742 | chan->tx_state == L2CAP_TX_STATE_XMIT) { | 1881 | chan->tx_state == L2CAP_TX_STATE_XMIT) { |
| @@ -1802,6 +1941,9 @@ static void l2cap_ertm_resend(struct l2cap_chan *chan) | |||
| 1802 | if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state)) | 1941 | if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state)) |
| 1803 | return; | 1942 | return; |
| 1804 | 1943 | ||
| 1944 | if (__chan_is_moving(chan)) | ||
| 1945 | return; | ||
| 1946 | |||
| 1805 | while (chan->retrans_list.head != L2CAP_SEQ_LIST_CLEAR) { | 1947 | while (chan->retrans_list.head != L2CAP_SEQ_LIST_CLEAR) { |
| 1806 | seq = l2cap_seq_list_pop(&chan->retrans_list); | 1948 | seq = l2cap_seq_list_pop(&chan->retrans_list); |
| 1807 | 1949 | ||
| @@ -2144,7 +2286,9 @@ static int l2cap_segment_sdu(struct l2cap_chan *chan, | |||
| 2144 | /* PDU size is derived from the HCI MTU */ | 2286 | /* PDU size is derived from the HCI MTU */ |
| 2145 | pdu_len = chan->conn->mtu; | 2287 | pdu_len = chan->conn->mtu; |
| 2146 | 2288 | ||
| 2147 | pdu_len = min_t(size_t, pdu_len, L2CAP_BREDR_MAX_PAYLOAD); | 2289 | /* Constrain PDU size for BR/EDR connections */ |
| 2290 | if (!chan->hs_hcon) | ||
| 2291 | pdu_len = min_t(size_t, pdu_len, L2CAP_BREDR_MAX_PAYLOAD); | ||
| 2148 | 2292 | ||
| 2149 | /* Adjust for largest possible L2CAP overhead. */ | 2293 | /* Adjust for largest possible L2CAP overhead. */ |
| 2150 | if (chan->fcs) | 2294 | if (chan->fcs) |
| @@ -2788,6 +2932,11 @@ int l2cap_ertm_init(struct l2cap_chan *chan) | |||
| 2788 | 2932 | ||
| 2789 | skb_queue_head_init(&chan->tx_q); | 2933 | skb_queue_head_init(&chan->tx_q); |
| 2790 | 2934 | ||
| 2935 | chan->local_amp_id = 0; | ||
| 2936 | chan->move_id = 0; | ||
| 2937 | chan->move_state = L2CAP_MOVE_STABLE; | ||
| 2938 | chan->move_role = L2CAP_MOVE_ROLE_NONE; | ||
| 2939 | |||
| 2791 | if (chan->mode != L2CAP_MODE_ERTM) | 2940 | if (chan->mode != L2CAP_MODE_ERTM) |
| 2792 | return 0; | 2941 | return 0; |
| 2793 | 2942 | ||
| @@ -2834,6 +2983,44 @@ static inline bool __l2cap_efs_supported(struct l2cap_chan *chan) | |||
| 2834 | return enable_hs && chan->conn->feat_mask & L2CAP_FEAT_EXT_FLOW; | 2983 | return enable_hs && chan->conn->feat_mask & L2CAP_FEAT_EXT_FLOW; |
| 2835 | } | 2984 | } |
| 2836 | 2985 | ||
| 2986 | static void __l2cap_set_ertm_timeouts(struct l2cap_chan *chan, | ||
| 2987 | struct l2cap_conf_rfc *rfc) | ||
| 2988 | { | ||
| 2989 | if (chan->local_amp_id && chan->hs_hcon) { | ||
| 2990 | u64 ertm_to = chan->hs_hcon->hdev->amp_be_flush_to; | ||
| 2991 | |||
| 2992 | /* Class 1 devices have must have ERTM timeouts | ||
| 2993 | * exceeding the Link Supervision Timeout. The | ||
| 2994 | * default Link Supervision Timeout for AMP | ||
| 2995 | * controllers is 10 seconds. | ||
| 2996 | * | ||
| 2997 | * Class 1 devices use 0xffffffff for their | ||
| 2998 | * best-effort flush timeout, so the clamping logic | ||
| 2999 | * will result in a timeout that meets the above | ||
| 3000 | * requirement. ERTM timeouts are 16-bit values, so | ||
| 3001 | * the maximum timeout is 65.535 seconds. | ||
| 3002 | */ | ||
| 3003 | |||
| 3004 | /* Convert timeout to milliseconds and round */ | ||
| 3005 | ertm_to = DIV_ROUND_UP_ULL(ertm_to, 1000); | ||
| 3006 | |||
| 3007 | /* This is the recommended formula for class 2 devices | ||
| 3008 | * that start ERTM timers when packets are sent to the | ||
| 3009 | * controller. | ||
| 3010 | */ | ||
| 3011 | ertm_to = 3 * ertm_to + 500; | ||
| 3012 | |||
| 3013 | if (ertm_to > 0xffff) | ||
| 3014 | ertm_to = 0xffff; | ||
| 3015 | |||
| 3016 | rfc->retrans_timeout = cpu_to_le16((u16) ertm_to); | ||
| 3017 | rfc->monitor_timeout = rfc->retrans_timeout; | ||
| 3018 | } else { | ||
| 3019 | rfc->retrans_timeout = __constant_cpu_to_le16(L2CAP_DEFAULT_RETRANS_TO); | ||
| 3020 | rfc->monitor_timeout = __constant_cpu_to_le16(L2CAP_DEFAULT_MONITOR_TO); | ||
| 3021 | } | ||
| 3022 | } | ||
| 3023 | |||
| 2837 | static inline void l2cap_txwin_setup(struct l2cap_chan *chan) | 3024 | static inline void l2cap_txwin_setup(struct l2cap_chan *chan) |
| 2838 | { | 3025 | { |
| 2839 | if (chan->tx_win > L2CAP_DEFAULT_TX_WINDOW && | 3026 | if (chan->tx_win > L2CAP_DEFAULT_TX_WINDOW && |
| @@ -2900,8 +3087,8 @@ done: | |||
| 2900 | case L2CAP_MODE_ERTM: | 3087 | case L2CAP_MODE_ERTM: |
| 2901 | rfc.mode = L2CAP_MODE_ERTM; | 3088 | rfc.mode = L2CAP_MODE_ERTM; |
| 2902 | rfc.max_transmit = chan->max_tx; | 3089 | rfc.max_transmit = chan->max_tx; |
| 2903 | rfc.retrans_timeout = 0; | 3090 | |
| 2904 | rfc.monitor_timeout = 0; | 3091 | __l2cap_set_ertm_timeouts(chan, &rfc); |
| 2905 | 3092 | ||
| 2906 | size = min_t(u16, L2CAP_DEFAULT_MAX_PDU_SIZE, chan->conn->mtu - | 3093 | size = min_t(u16, L2CAP_DEFAULT_MAX_PDU_SIZE, chan->conn->mtu - |
| 2907 | L2CAP_EXT_HDR_SIZE - L2CAP_SDULEN_SIZE - | 3094 | L2CAP_EXT_HDR_SIZE - L2CAP_SDULEN_SIZE - |
| @@ -3129,10 +3316,7 @@ done: | |||
| 3129 | rfc.max_pdu_size = cpu_to_le16(size); | 3316 | rfc.max_pdu_size = cpu_to_le16(size); |
| 3130 | chan->remote_mps = size; | 3317 | chan->remote_mps = size; |
| 3131 | 3318 | ||
| 3132 | rfc.retrans_timeout = | 3319 | __l2cap_set_ertm_timeouts(chan, &rfc); |
| 3133 | __constant_cpu_to_le16(L2CAP_DEFAULT_RETRANS_TO); | ||
| 3134 | rfc.monitor_timeout = | ||
| 3135 | __constant_cpu_to_le16(L2CAP_DEFAULT_MONITOR_TO); | ||
| 3136 | 3320 | ||
| 3137 | set_bit(CONF_MODE_DONE, &chan->conf_state); | 3321 | set_bit(CONF_MODE_DONE, &chan->conf_state); |
| 3138 | 3322 | ||
| @@ -3308,12 +3492,21 @@ void __l2cap_connect_rsp_defer(struct l2cap_chan *chan) | |||
| 3308 | struct l2cap_conn_rsp rsp; | 3492 | struct l2cap_conn_rsp rsp; |
| 3309 | struct l2cap_conn *conn = chan->conn; | 3493 | struct l2cap_conn *conn = chan->conn; |
| 3310 | u8 buf[128]; | 3494 | u8 buf[128]; |
| 3495 | u8 rsp_code; | ||
| 3311 | 3496 | ||
| 3312 | rsp.scid = cpu_to_le16(chan->dcid); | 3497 | rsp.scid = cpu_to_le16(chan->dcid); |
| 3313 | rsp.dcid = cpu_to_le16(chan->scid); | 3498 | rsp.dcid = cpu_to_le16(chan->scid); |
| 3314 | rsp.result = __constant_cpu_to_le16(L2CAP_CR_SUCCESS); | 3499 | rsp.result = __constant_cpu_to_le16(L2CAP_CR_SUCCESS); |
| 3315 | rsp.status = __constant_cpu_to_le16(L2CAP_CS_NO_INFO); | 3500 | rsp.status = __constant_cpu_to_le16(L2CAP_CS_NO_INFO); |
| 3316 | l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP, sizeof(rsp), &rsp); | 3501 | |
| 3502 | if (chan->hs_hcon) | ||
| 3503 | rsp_code = L2CAP_CREATE_CHAN_RSP; | ||
| 3504 | else | ||
| 3505 | rsp_code = L2CAP_CONN_RSP; | ||
| 3506 | |||
| 3507 | BT_DBG("chan %p rsp_code %u", chan, rsp_code); | ||
| 3508 | |||
| 3509 | l2cap_send_cmd(conn, chan->ident, rsp_code, sizeof(rsp), &rsp); | ||
| 3317 | 3510 | ||
| 3318 | if (test_and_set_bit(CONF_REQ_SENT, &chan->conf_state)) | 3511 | if (test_and_set_bit(CONF_REQ_SENT, &chan->conf_state)) |
| 3319 | return; | 3512 | return; |
| @@ -3395,8 +3588,9 @@ static inline int l2cap_command_rej(struct l2cap_conn *conn, | |||
| 3395 | return 0; | 3588 | return 0; |
| 3396 | } | 3589 | } |
| 3397 | 3590 | ||
| 3398 | static void l2cap_connect(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, | 3591 | static struct l2cap_chan *l2cap_connect(struct l2cap_conn *conn, |
| 3399 | u8 *data, u8 rsp_code, u8 amp_id) | 3592 | struct l2cap_cmd_hdr *cmd, |
| 3593 | u8 *data, u8 rsp_code, u8 amp_id) | ||
| 3400 | { | 3594 | { |
| 3401 | struct l2cap_conn_req *req = (struct l2cap_conn_req *) data; | 3595 | struct l2cap_conn_req *req = (struct l2cap_conn_req *) data; |
| 3402 | struct l2cap_conn_rsp rsp; | 3596 | struct l2cap_conn_rsp rsp; |
| @@ -3447,6 +3641,7 @@ static void l2cap_connect(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, | |||
| 3447 | bacpy(&bt_sk(sk)->dst, conn->dst); | 3641 | bacpy(&bt_sk(sk)->dst, conn->dst); |
| 3448 | chan->psm = psm; | 3642 | chan->psm = psm; |
| 3449 | chan->dcid = scid; | 3643 | chan->dcid = scid; |
| 3644 | chan->local_amp_id = amp_id; | ||
| 3450 | 3645 | ||
| 3451 | __l2cap_chan_add(conn, chan); | 3646 | __l2cap_chan_add(conn, chan); |
| 3452 | 3647 | ||
| @@ -3464,8 +3659,17 @@ static void l2cap_connect(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, | |||
| 3464 | status = L2CAP_CS_AUTHOR_PEND; | 3659 | status = L2CAP_CS_AUTHOR_PEND; |
| 3465 | chan->ops->defer(chan); | 3660 | chan->ops->defer(chan); |
| 3466 | } else { | 3661 | } else { |
| 3467 | __l2cap_state_change(chan, BT_CONFIG); | 3662 | /* Force pending result for AMP controllers. |
| 3468 | result = L2CAP_CR_SUCCESS; | 3663 | * The connection will succeed after the |
| 3664 | * physical link is up. | ||
| 3665 | */ | ||
| 3666 | if (amp_id) { | ||
| 3667 | __l2cap_state_change(chan, BT_CONNECT2); | ||
| 3668 | result = L2CAP_CR_PEND; | ||
| 3669 | } else { | ||
| 3670 | __l2cap_state_change(chan, BT_CONFIG); | ||
| 3671 | result = L2CAP_CR_SUCCESS; | ||
| 3672 | } | ||
| 3469 | status = L2CAP_CS_NO_INFO; | 3673 | status = L2CAP_CS_NO_INFO; |
| 3470 | } | 3674 | } |
| 3471 | } else { | 3675 | } else { |
| @@ -3511,6 +3715,8 @@ sendresp: | |||
| 3511 | l2cap_build_conf_req(chan, buf), buf); | 3715 | l2cap_build_conf_req(chan, buf), buf); |
| 3512 | chan->num_conf_req++; | 3716 | chan->num_conf_req++; |
| 3513 | } | 3717 | } |
| 3718 | |||
| 3719 | return chan; | ||
| 3514 | } | 3720 | } |
| 3515 | 3721 | ||
| 3516 | static int l2cap_connect_req(struct l2cap_conn *conn, | 3722 | static int l2cap_connect_req(struct l2cap_conn *conn, |
| @@ -3520,7 +3726,7 @@ static int l2cap_connect_req(struct l2cap_conn *conn, | |||
| 3520 | return 0; | 3726 | return 0; |
| 3521 | } | 3727 | } |
| 3522 | 3728 | ||
| 3523 | static inline int l2cap_connect_rsp(struct l2cap_conn *conn, | 3729 | static int l2cap_connect_create_rsp(struct l2cap_conn *conn, |
| 3524 | struct l2cap_cmd_hdr *cmd, u8 *data) | 3730 | struct l2cap_cmd_hdr *cmd, u8 *data) |
| 3525 | { | 3731 | { |
| 3526 | struct l2cap_conn_rsp *rsp = (struct l2cap_conn_rsp *) data; | 3732 | struct l2cap_conn_rsp *rsp = (struct l2cap_conn_rsp *) data; |
| @@ -3675,6 +3881,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, | |||
| 3675 | goto unlock; | 3881 | goto unlock; |
| 3676 | } | 3882 | } |
| 3677 | 3883 | ||
| 3884 | chan->ident = cmd->ident; | ||
| 3678 | l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, len, rsp); | 3885 | l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, len, rsp); |
| 3679 | chan->num_conf_rsp++; | 3886 | chan->num_conf_rsp++; |
| 3680 | 3887 | ||
| @@ -3714,7 +3921,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, | |||
| 3714 | /* check compatibility */ | 3921 | /* check compatibility */ |
| 3715 | 3922 | ||
| 3716 | /* Send rsp for BR/EDR channel */ | 3923 | /* Send rsp for BR/EDR channel */ |
| 3717 | if (!chan->ctrl_id) | 3924 | if (!chan->hs_hcon) |
| 3718 | l2cap_send_efs_conf_rsp(chan, rsp, cmd->ident, flags); | 3925 | l2cap_send_efs_conf_rsp(chan, rsp, cmd->ident, flags); |
| 3719 | else | 3926 | else |
| 3720 | chan->ident = cmd->ident; | 3927 | chan->ident = cmd->ident; |
| @@ -3764,13 +3971,15 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, | |||
| 3764 | goto done; | 3971 | goto done; |
| 3765 | } | 3972 | } |
| 3766 | 3973 | ||
| 3767 | /* check compatibility */ | 3974 | if (!chan->hs_hcon) { |
| 3768 | |||
| 3769 | if (!chan->ctrl_id) | ||
| 3770 | l2cap_send_efs_conf_rsp(chan, buf, cmd->ident, | 3975 | l2cap_send_efs_conf_rsp(chan, buf, cmd->ident, |
| 3771 | 0); | 3976 | 0); |
| 3772 | else | 3977 | } else { |
| 3773 | chan->ident = cmd->ident; | 3978 | if (l2cap_check_efs(chan)) { |
| 3979 | amp_create_logical_link(chan); | ||
| 3980 | chan->ident = cmd->ident; | ||
| 3981 | } | ||
| 3982 | } | ||
| 3774 | } | 3983 | } |
| 3775 | goto done; | 3984 | goto done; |
| 3776 | 3985 | ||
| @@ -4023,12 +4232,14 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn, | |||
| 4023 | return 0; | 4232 | return 0; |
| 4024 | } | 4233 | } |
| 4025 | 4234 | ||
| 4026 | static inline int l2cap_create_channel_req(struct l2cap_conn *conn, | 4235 | static int l2cap_create_channel_req(struct l2cap_conn *conn, |
| 4027 | struct l2cap_cmd_hdr *cmd, | 4236 | struct l2cap_cmd_hdr *cmd, |
| 4028 | u16 cmd_len, void *data) | 4237 | u16 cmd_len, void *data) |
| 4029 | { | 4238 | { |
| 4030 | struct l2cap_create_chan_req *req = data; | 4239 | struct l2cap_create_chan_req *req = data; |
| 4031 | struct l2cap_create_chan_rsp rsp; | 4240 | struct l2cap_create_chan_rsp rsp; |
| 4241 | struct l2cap_chan *chan; | ||
| 4242 | struct hci_dev *hdev; | ||
| 4032 | u16 psm, scid; | 4243 | u16 psm, scid; |
| 4033 | 4244 | ||
| 4034 | if (cmd_len != sizeof(*req)) | 4245 | if (cmd_len != sizeof(*req)) |
| @@ -4042,57 +4253,119 @@ static inline int l2cap_create_channel_req(struct l2cap_conn *conn, | |||
| 4042 | 4253 | ||
| 4043 | BT_DBG("psm 0x%2.2x, scid 0x%4.4x, amp_id %d", psm, scid, req->amp_id); | 4254 | BT_DBG("psm 0x%2.2x, scid 0x%4.4x, amp_id %d", psm, scid, req->amp_id); |
| 4044 | 4255 | ||
| 4045 | /* Placeholder: Always reject */ | 4256 | /* For controller id 0 make BR/EDR connection */ |
| 4257 | if (req->amp_id == HCI_BREDR_ID) { | ||
| 4258 | l2cap_connect(conn, cmd, data, L2CAP_CREATE_CHAN_RSP, | ||
| 4259 | req->amp_id); | ||
| 4260 | return 0; | ||
| 4261 | } | ||
| 4262 | |||
| 4263 | /* Validate AMP controller id */ | ||
| 4264 | hdev = hci_dev_get(req->amp_id); | ||
| 4265 | if (!hdev) | ||
| 4266 | goto error; | ||
| 4267 | |||
| 4268 | if (hdev->dev_type != HCI_AMP || !test_bit(HCI_UP, &hdev->flags)) { | ||
| 4269 | hci_dev_put(hdev); | ||
| 4270 | goto error; | ||
| 4271 | } | ||
| 4272 | |||
| 4273 | chan = l2cap_connect(conn, cmd, data, L2CAP_CREATE_CHAN_RSP, | ||
| 4274 | req->amp_id); | ||
| 4275 | if (chan) { | ||
| 4276 | struct amp_mgr *mgr = conn->hcon->amp_mgr; | ||
| 4277 | struct hci_conn *hs_hcon; | ||
| 4278 | |||
| 4279 | hs_hcon = hci_conn_hash_lookup_ba(hdev, AMP_LINK, conn->dst); | ||
| 4280 | if (!hs_hcon) { | ||
| 4281 | hci_dev_put(hdev); | ||
| 4282 | return -EFAULT; | ||
| 4283 | } | ||
| 4284 | |||
| 4285 | BT_DBG("mgr %p bredr_chan %p hs_hcon %p", mgr, chan, hs_hcon); | ||
| 4286 | |||
| 4287 | mgr->bredr_chan = chan; | ||
| 4288 | chan->hs_hcon = hs_hcon; | ||
| 4289 | chan->fcs = L2CAP_FCS_NONE; | ||
| 4290 | conn->mtu = hdev->block_mtu; | ||
| 4291 | } | ||
| 4292 | |||
| 4293 | hci_dev_put(hdev); | ||
| 4294 | |||
| 4295 | return 0; | ||
| 4296 | |||
| 4297 | error: | ||
| 4046 | rsp.dcid = 0; | 4298 | rsp.dcid = 0; |
| 4047 | rsp.scid = cpu_to_le16(scid); | 4299 | rsp.scid = cpu_to_le16(scid); |
| 4048 | rsp.result = __constant_cpu_to_le16(L2CAP_CR_NO_MEM); | 4300 | rsp.result = __constant_cpu_to_le16(L2CAP_CR_BAD_AMP); |
| 4049 | rsp.status = __constant_cpu_to_le16(L2CAP_CS_NO_INFO); | 4301 | rsp.status = __constant_cpu_to_le16(L2CAP_CS_NO_INFO); |
| 4050 | 4302 | ||
| 4051 | l2cap_send_cmd(conn, cmd->ident, L2CAP_CREATE_CHAN_RSP, | 4303 | l2cap_send_cmd(conn, cmd->ident, L2CAP_CREATE_CHAN_RSP, |
| 4052 | sizeof(rsp), &rsp); | 4304 | sizeof(rsp), &rsp); |
| 4053 | 4305 | ||
| 4054 | return 0; | 4306 | return -EFAULT; |
| 4055 | } | 4307 | } |
| 4056 | 4308 | ||
| 4057 | static inline int l2cap_create_channel_rsp(struct l2cap_conn *conn, | 4309 | static void l2cap_send_move_chan_req(struct l2cap_chan *chan, u8 dest_amp_id) |
| 4058 | struct l2cap_cmd_hdr *cmd, | ||
| 4059 | void *data) | ||
| 4060 | { | 4310 | { |
| 4061 | BT_DBG("conn %p", conn); | 4311 | struct l2cap_move_chan_req req; |
| 4312 | u8 ident; | ||
| 4313 | |||
| 4314 | BT_DBG("chan %p, dest_amp_id %d", chan, dest_amp_id); | ||
| 4315 | |||
| 4316 | ident = l2cap_get_ident(chan->conn); | ||
| 4317 | chan->ident = ident; | ||
| 4062 | 4318 | ||
| 4063 | return l2cap_connect_rsp(conn, cmd, data); | 4319 | req.icid = cpu_to_le16(chan->scid); |
| 4320 | req.dest_amp_id = dest_amp_id; | ||
| 4321 | |||
| 4322 | l2cap_send_cmd(chan->conn, ident, L2CAP_MOVE_CHAN_REQ, sizeof(req), | ||
| 4323 | &req); | ||
| 4324 | |||
| 4325 | __set_chan_timer(chan, L2CAP_MOVE_TIMEOUT); | ||
| 4064 | } | 4326 | } |
| 4065 | 4327 | ||
| 4066 | static void l2cap_send_move_chan_rsp(struct l2cap_conn *conn, u8 ident, | 4328 | static void l2cap_send_move_chan_rsp(struct l2cap_chan *chan, u16 result) |
| 4067 | u16 icid, u16 result) | ||
| 4068 | { | 4329 | { |
| 4069 | struct l2cap_move_chan_rsp rsp; | 4330 | struct l2cap_move_chan_rsp rsp; |
| 4070 | 4331 | ||
| 4071 | BT_DBG("icid 0x%4.4x, result 0x%4.4x", icid, result); | 4332 | BT_DBG("chan %p, result 0x%4.4x", chan, result); |
| 4072 | 4333 | ||
| 4073 | rsp.icid = cpu_to_le16(icid); | 4334 | rsp.icid = cpu_to_le16(chan->dcid); |
| 4074 | rsp.result = cpu_to_le16(result); | 4335 | rsp.result = cpu_to_le16(result); |
| 4075 | 4336 | ||
| 4076 | l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_RSP, sizeof(rsp), &rsp); | 4337 | l2cap_send_cmd(chan->conn, chan->ident, L2CAP_MOVE_CHAN_RSP, |
| 4338 | sizeof(rsp), &rsp); | ||
| 4077 | } | 4339 | } |
| 4078 | 4340 | ||
| 4079 | static void l2cap_send_move_chan_cfm(struct l2cap_conn *conn, | 4341 | static void l2cap_send_move_chan_cfm(struct l2cap_chan *chan, u16 result) |
| 4080 | struct l2cap_chan *chan, | ||
| 4081 | u16 icid, u16 result) | ||
| 4082 | { | 4342 | { |
| 4083 | struct l2cap_move_chan_cfm cfm; | 4343 | struct l2cap_move_chan_cfm cfm; |
| 4084 | u8 ident; | ||
| 4085 | 4344 | ||
| 4086 | BT_DBG("icid 0x%4.4x, result 0x%4.4x", icid, result); | 4345 | BT_DBG("chan %p, result 0x%4.4x", chan, result); |
| 4087 | 4346 | ||
| 4088 | ident = l2cap_get_ident(conn); | 4347 | chan->ident = l2cap_get_ident(chan->conn); |
| 4089 | if (chan) | ||
| 4090 | chan->ident = ident; | ||
| 4091 | 4348 | ||
| 4092 | cfm.icid = cpu_to_le16(icid); | 4349 | cfm.icid = cpu_to_le16(chan->scid); |
| 4093 | cfm.result = cpu_to_le16(result); | 4350 | cfm.result = cpu_to_le16(result); |
| 4094 | 4351 | ||
| 4095 | l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_CFM, sizeof(cfm), &cfm); | 4352 | l2cap_send_cmd(chan->conn, chan->ident, L2CAP_MOVE_CHAN_CFM, |
| 4353 | sizeof(cfm), &cfm); | ||
| 4354 | |||
| 4355 | __set_chan_timer(chan, L2CAP_MOVE_TIMEOUT); | ||
| 4356 | } | ||
| 4357 | |||
| 4358 | static void l2cap_send_move_chan_cfm_icid(struct l2cap_conn *conn, u16 icid) | ||
| 4359 | { | ||
| 4360 | struct l2cap_move_chan_cfm cfm; | ||
| 4361 | |||
| 4362 | BT_DBG("conn %p, icid 0x%4.4x", conn, icid); | ||
| 4363 | |||
| 4364 | cfm.icid = cpu_to_le16(icid); | ||
| 4365 | cfm.result = __constant_cpu_to_le16(L2CAP_MC_UNCONFIRMED); | ||
| 4366 | |||
| 4367 | l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_MOVE_CHAN_CFM, | ||
| 4368 | sizeof(cfm), &cfm); | ||
| 4096 | } | 4369 | } |
| 4097 | 4370 | ||
| 4098 | static void l2cap_send_move_chan_cfm_rsp(struct l2cap_conn *conn, u8 ident, | 4371 | static void l2cap_send_move_chan_cfm_rsp(struct l2cap_conn *conn, u8 ident, |
| @@ -4106,11 +4379,289 @@ static void l2cap_send_move_chan_cfm_rsp(struct l2cap_conn *conn, u8 ident, | |||
| 4106 | l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_CFM_RSP, sizeof(rsp), &rsp); | 4379 | l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_CFM_RSP, sizeof(rsp), &rsp); |
| 4107 | } | 4380 | } |
| 4108 | 4381 | ||
| 4382 | static void __release_logical_link(struct l2cap_chan *chan) | ||
| 4383 | { | ||
| 4384 | chan->hs_hchan = NULL; | ||
| 4385 | chan->hs_hcon = NULL; | ||
| 4386 | |||
| 4387 | /* Placeholder - release the logical link */ | ||
| 4388 | } | ||
| 4389 | |||
| 4390 | static void l2cap_logical_fail(struct l2cap_chan *chan) | ||
| 4391 | { | ||
| 4392 | /* Logical link setup failed */ | ||
| 4393 | if (chan->state != BT_CONNECTED) { | ||
| 4394 | /* Create channel failure, disconnect */ | ||
| 4395 | l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); | ||
| 4396 | return; | ||
| 4397 | } | ||
| 4398 | |||
| 4399 | switch (chan->move_role) { | ||
| 4400 | case L2CAP_MOVE_ROLE_RESPONDER: | ||
| 4401 | l2cap_move_done(chan); | ||
| 4402 | l2cap_send_move_chan_rsp(chan, L2CAP_MR_NOT_SUPP); | ||
| 4403 | break; | ||
| 4404 | case L2CAP_MOVE_ROLE_INITIATOR: | ||
| 4405 | if (chan->move_state == L2CAP_MOVE_WAIT_LOGICAL_COMP || | ||
| 4406 | chan->move_state == L2CAP_MOVE_WAIT_LOGICAL_CFM) { | ||
| 4407 | /* Remote has only sent pending or | ||
| 4408 | * success responses, clean up | ||
| 4409 | */ | ||
| 4410 | l2cap_move_done(chan); | ||
| 4411 | } | ||
| 4412 | |||
| 4413 | /* Other amp move states imply that the move | ||
| 4414 | * has already aborted | ||
| 4415 | */ | ||
| 4416 | l2cap_send_move_chan_cfm(chan, L2CAP_MC_UNCONFIRMED); | ||
| 4417 | break; | ||
| 4418 | } | ||
| 4419 | } | ||
| 4420 | |||
| 4421 | static void l2cap_logical_finish_create(struct l2cap_chan *chan, | ||
| 4422 | struct hci_chan *hchan) | ||
| 4423 | { | ||
| 4424 | struct l2cap_conf_rsp rsp; | ||
| 4425 | |||
| 4426 | chan->hs_hchan = hchan; | ||
| 4427 | chan->hs_hcon->l2cap_data = chan->conn; | ||
| 4428 | |||
| 4429 | l2cap_send_efs_conf_rsp(chan, &rsp, chan->ident, 0); | ||
| 4430 | |||
| 4431 | if (test_bit(CONF_INPUT_DONE, &chan->conf_state)) { | ||
| 4432 | int err; | ||
| 4433 | |||
| 4434 | set_default_fcs(chan); | ||
| 4435 | |||
| 4436 | err = l2cap_ertm_init(chan); | ||
| 4437 | if (err < 0) | ||
| 4438 | l2cap_send_disconn_req(chan->conn, chan, -err); | ||
| 4439 | else | ||
| 4440 | l2cap_chan_ready(chan); | ||
| 4441 | } | ||
| 4442 | } | ||
| 4443 | |||
| 4444 | static void l2cap_logical_finish_move(struct l2cap_chan *chan, | ||
| 4445 | struct hci_chan *hchan) | ||
| 4446 | { | ||
| 4447 | chan->hs_hcon = hchan->conn; | ||
| 4448 | chan->hs_hcon->l2cap_data = chan->conn; | ||
| 4449 | |||
| 4450 | BT_DBG("move_state %d", chan->move_state); | ||
| 4451 | |||
| 4452 | switch (chan->move_state) { | ||
| 4453 | case L2CAP_MOVE_WAIT_LOGICAL_COMP: | ||
| 4454 | /* Move confirm will be sent after a success | ||
| 4455 | * response is received | ||
| 4456 | */ | ||
| 4457 | chan->move_state = L2CAP_MOVE_WAIT_RSP_SUCCESS; | ||
| 4458 | break; | ||
| 4459 | case L2CAP_MOVE_WAIT_LOGICAL_CFM: | ||
| 4460 | if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) { | ||
| 4461 | chan->move_state = L2CAP_MOVE_WAIT_LOCAL_BUSY; | ||
| 4462 | } else if (chan->move_role == L2CAP_MOVE_ROLE_INITIATOR) { | ||
| 4463 | chan->move_state = L2CAP_MOVE_WAIT_CONFIRM_RSP; | ||
| 4464 | l2cap_send_move_chan_cfm(chan, L2CAP_MC_CONFIRMED); | ||
| 4465 | } else if (chan->move_role == L2CAP_MOVE_ROLE_RESPONDER) { | ||
| 4466 | chan->move_state = L2CAP_MOVE_WAIT_CONFIRM; | ||
| 4467 | l2cap_send_move_chan_rsp(chan, L2CAP_MR_SUCCESS); | ||
| 4468 | } | ||
| 4469 | break; | ||
| 4470 | default: | ||
| 4471 | /* Move was not in expected state, free the channel */ | ||
| 4472 | __release_logical_link(chan); | ||
| 4473 | |||
| 4474 | chan->move_state = L2CAP_MOVE_STABLE; | ||
| 4475 | } | ||
| 4476 | } | ||
| 4477 | |||
| 4478 | /* Call with chan locked */ | ||
| 4479 | void l2cap_logical_cfm(struct l2cap_chan *chan, struct hci_chan *hchan, | ||
| 4480 | u8 status) | ||
| 4481 | { | ||
| 4482 | BT_DBG("chan %p, hchan %p, status %d", chan, hchan, status); | ||
| 4483 | |||
| 4484 | if (status) { | ||
| 4485 | l2cap_logical_fail(chan); | ||
| 4486 | __release_logical_link(chan); | ||
| 4487 | return; | ||
| 4488 | } | ||
| 4489 | |||
| 4490 | if (chan->state != BT_CONNECTED) { | ||
| 4491 | /* Ignore logical link if channel is on BR/EDR */ | ||
| 4492 | if (chan->local_amp_id) | ||
| 4493 | l2cap_logical_finish_create(chan, hchan); | ||
| 4494 | } else { | ||
| 4495 | l2cap_logical_finish_move(chan, hchan); | ||
| 4496 | } | ||
| 4497 | } | ||
| 4498 | |||
| 4499 | void l2cap_move_start(struct l2cap_chan *chan) | ||
| 4500 | { | ||
| 4501 | BT_DBG("chan %p", chan); | ||
| 4502 | |||
| 4503 | if (chan->local_amp_id == HCI_BREDR_ID) { | ||
| 4504 | if (chan->chan_policy != BT_CHANNEL_POLICY_AMP_PREFERRED) | ||
| 4505 | return; | ||
| 4506 | chan->move_role = L2CAP_MOVE_ROLE_INITIATOR; | ||
| 4507 | chan->move_state = L2CAP_MOVE_WAIT_PREPARE; | ||
| 4508 | /* Placeholder - start physical link setup */ | ||
| 4509 | } else { | ||
| 4510 | chan->move_role = L2CAP_MOVE_ROLE_INITIATOR; | ||
| 4511 | chan->move_state = L2CAP_MOVE_WAIT_RSP_SUCCESS; | ||
| 4512 | chan->move_id = 0; | ||
| 4513 | l2cap_move_setup(chan); | ||
| 4514 | l2cap_send_move_chan_req(chan, 0); | ||
| 4515 | } | ||
| 4516 | } | ||
| 4517 | |||
| 4518 | static void l2cap_do_create(struct l2cap_chan *chan, int result, | ||
| 4519 | u8 local_amp_id, u8 remote_amp_id) | ||
| 4520 | { | ||
| 4521 | BT_DBG("chan %p state %s %u -> %u", chan, state_to_string(chan->state), | ||
| 4522 | local_amp_id, remote_amp_id); | ||
| 4523 | |||
| 4524 | chan->fcs = L2CAP_FCS_NONE; | ||
| 4525 | |||
| 4526 | /* Outgoing channel on AMP */ | ||
| 4527 | if (chan->state == BT_CONNECT) { | ||
| 4528 | if (result == L2CAP_CR_SUCCESS) { | ||
| 4529 | chan->local_amp_id = local_amp_id; | ||
| 4530 | l2cap_send_create_chan_req(chan, remote_amp_id); | ||
| 4531 | } else { | ||
| 4532 | /* Revert to BR/EDR connect */ | ||
| 4533 | l2cap_send_conn_req(chan); | ||
| 4534 | } | ||
| 4535 | |||
| 4536 | return; | ||
| 4537 | } | ||
| 4538 | |||
| 4539 | /* Incoming channel on AMP */ | ||
| 4540 | if (__l2cap_no_conn_pending(chan)) { | ||
| 4541 | struct l2cap_conn_rsp rsp; | ||
| 4542 | char buf[128]; | ||
| 4543 | rsp.scid = cpu_to_le16(chan->dcid); | ||
| 4544 | rsp.dcid = cpu_to_le16(chan->scid); | ||
| 4545 | |||
| 4546 | if (result == L2CAP_CR_SUCCESS) { | ||
| 4547 | /* Send successful response */ | ||
| 4548 | rsp.result = __constant_cpu_to_le16(L2CAP_CR_SUCCESS); | ||
| 4549 | rsp.status = __constant_cpu_to_le16(L2CAP_CS_NO_INFO); | ||
| 4550 | } else { | ||
| 4551 | /* Send negative response */ | ||
| 4552 | rsp.result = __constant_cpu_to_le16(L2CAP_CR_NO_MEM); | ||
| 4553 | rsp.status = __constant_cpu_to_le16(L2CAP_CS_NO_INFO); | ||
| 4554 | } | ||
| 4555 | |||
| 4556 | l2cap_send_cmd(chan->conn, chan->ident, L2CAP_CREATE_CHAN_RSP, | ||
| 4557 | sizeof(rsp), &rsp); | ||
| 4558 | |||
| 4559 | if (result == L2CAP_CR_SUCCESS) { | ||
| 4560 | __l2cap_state_change(chan, BT_CONFIG); | ||
| 4561 | set_bit(CONF_REQ_SENT, &chan->conf_state); | ||
| 4562 | l2cap_send_cmd(chan->conn, l2cap_get_ident(chan->conn), | ||
| 4563 | L2CAP_CONF_REQ, | ||
| 4564 | l2cap_build_conf_req(chan, buf), buf); | ||
| 4565 | chan->num_conf_req++; | ||
| 4566 | } | ||
| 4567 | } | ||
| 4568 | } | ||
| 4569 | |||
| 4570 | static void l2cap_do_move_initiate(struct l2cap_chan *chan, u8 local_amp_id, | ||
| 4571 | u8 remote_amp_id) | ||
| 4572 | { | ||
| 4573 | l2cap_move_setup(chan); | ||
| 4574 | chan->move_id = local_amp_id; | ||
| 4575 | chan->move_state = L2CAP_MOVE_WAIT_RSP; | ||
| 4576 | |||
| 4577 | l2cap_send_move_chan_req(chan, remote_amp_id); | ||
| 4578 | } | ||
| 4579 | |||
| 4580 | static void l2cap_do_move_respond(struct l2cap_chan *chan, int result) | ||
| 4581 | { | ||
| 4582 | struct hci_chan *hchan = NULL; | ||
| 4583 | |||
| 4584 | /* Placeholder - get hci_chan for logical link */ | ||
| 4585 | |||
| 4586 | if (hchan) { | ||
| 4587 | if (hchan->state == BT_CONNECTED) { | ||
| 4588 | /* Logical link is ready to go */ | ||
| 4589 | chan->hs_hcon = hchan->conn; | ||
| 4590 | chan->hs_hcon->l2cap_data = chan->conn; | ||
| 4591 | chan->move_state = L2CAP_MOVE_WAIT_CONFIRM; | ||
| 4592 | l2cap_send_move_chan_rsp(chan, L2CAP_MR_SUCCESS); | ||
| 4593 | |||
| 4594 | l2cap_logical_cfm(chan, hchan, L2CAP_MR_SUCCESS); | ||
| 4595 | } else { | ||
| 4596 | /* Wait for logical link to be ready */ | ||
| 4597 | chan->move_state = L2CAP_MOVE_WAIT_LOGICAL_CFM; | ||
| 4598 | } | ||
| 4599 | } else { | ||
| 4600 | /* Logical link not available */ | ||
| 4601 | l2cap_send_move_chan_rsp(chan, L2CAP_MR_NOT_ALLOWED); | ||
| 4602 | } | ||
| 4603 | } | ||
| 4604 | |||
| 4605 | static void l2cap_do_move_cancel(struct l2cap_chan *chan, int result) | ||
| 4606 | { | ||
| 4607 | if (chan->move_role == L2CAP_MOVE_ROLE_RESPONDER) { | ||
| 4608 | u8 rsp_result; | ||
| 4609 | if (result == -EINVAL) | ||
| 4610 | rsp_result = L2CAP_MR_BAD_ID; | ||
| 4611 | else | ||
| 4612 | rsp_result = L2CAP_MR_NOT_ALLOWED; | ||
| 4613 | |||
| 4614 | l2cap_send_move_chan_rsp(chan, rsp_result); | ||
| 4615 | } | ||
| 4616 | |||
| 4617 | chan->move_role = L2CAP_MOVE_ROLE_NONE; | ||
| 4618 | chan->move_state = L2CAP_MOVE_STABLE; | ||
| 4619 | |||
| 4620 | /* Restart data transmission */ | ||
| 4621 | l2cap_ertm_send(chan); | ||
| 4622 | } | ||
| 4623 | |||
| 4624 | /* Invoke with locked chan */ | ||
| 4625 | void __l2cap_physical_cfm(struct l2cap_chan *chan, int result) | ||
| 4626 | { | ||
| 4627 | u8 local_amp_id = chan->local_amp_id; | ||
| 4628 | u8 remote_amp_id = chan->remote_amp_id; | ||
| 4629 | |||
| 4630 | BT_DBG("chan %p, result %d, local_amp_id %d, remote_amp_id %d", | ||
| 4631 | chan, result, local_amp_id, remote_amp_id); | ||
| 4632 | |||
| 4633 | if (chan->state == BT_DISCONN || chan->state == BT_CLOSED) { | ||
| 4634 | l2cap_chan_unlock(chan); | ||
| 4635 | return; | ||
| 4636 | } | ||
| 4637 | |||
| 4638 | if (chan->state != BT_CONNECTED) { | ||
| 4639 | l2cap_do_create(chan, result, local_amp_id, remote_amp_id); | ||
| 4640 | } else if (result != L2CAP_MR_SUCCESS) { | ||
| 4641 | l2cap_do_move_cancel(chan, result); | ||
| 4642 | } else { | ||
| 4643 | switch (chan->move_role) { | ||
| 4644 | case L2CAP_MOVE_ROLE_INITIATOR: | ||
| 4645 | l2cap_do_move_initiate(chan, local_amp_id, | ||
| 4646 | remote_amp_id); | ||
| 4647 | break; | ||
| 4648 | case L2CAP_MOVE_ROLE_RESPONDER: | ||
| 4649 | l2cap_do_move_respond(chan, result); | ||
| 4650 | break; | ||
| 4651 | default: | ||
| 4652 | l2cap_do_move_cancel(chan, result); | ||
| 4653 | break; | ||
| 4654 | } | ||
| 4655 | } | ||
| 4656 | } | ||
| 4657 | |||
| 4109 | static inline int l2cap_move_channel_req(struct l2cap_conn *conn, | 4658 | static inline int l2cap_move_channel_req(struct l2cap_conn *conn, |
| 4110 | struct l2cap_cmd_hdr *cmd, | 4659 | struct l2cap_cmd_hdr *cmd, |
| 4111 | u16 cmd_len, void *data) | 4660 | u16 cmd_len, void *data) |
| 4112 | { | 4661 | { |
| 4113 | struct l2cap_move_chan_req *req = data; | 4662 | struct l2cap_move_chan_req *req = data; |
| 4663 | struct l2cap_move_chan_rsp rsp; | ||
| 4664 | struct l2cap_chan *chan; | ||
| 4114 | u16 icid = 0; | 4665 | u16 icid = 0; |
| 4115 | u16 result = L2CAP_MR_NOT_ALLOWED; | 4666 | u16 result = L2CAP_MR_NOT_ALLOWED; |
| 4116 | 4667 | ||
| @@ -4124,15 +4675,206 @@ static inline int l2cap_move_channel_req(struct l2cap_conn *conn, | |||
| 4124 | if (!enable_hs) | 4675 | if (!enable_hs) |
| 4125 | return -EINVAL; | 4676 | return -EINVAL; |
| 4126 | 4677 | ||
| 4127 | /* Placeholder: Always refuse */ | 4678 | chan = l2cap_get_chan_by_dcid(conn, icid); |
| 4128 | l2cap_send_move_chan_rsp(conn, cmd->ident, icid, result); | 4679 | if (!chan) { |
| 4680 | rsp.icid = cpu_to_le16(icid); | ||
| 4681 | rsp.result = __constant_cpu_to_le16(L2CAP_MR_NOT_ALLOWED); | ||
| 4682 | l2cap_send_cmd(conn, cmd->ident, L2CAP_MOVE_CHAN_RSP, | ||
| 4683 | sizeof(rsp), &rsp); | ||
| 4684 | return 0; | ||
| 4685 | } | ||
| 4686 | |||
| 4687 | chan->ident = cmd->ident; | ||
| 4688 | |||
| 4689 | if (chan->scid < L2CAP_CID_DYN_START || | ||
| 4690 | chan->chan_policy == BT_CHANNEL_POLICY_BREDR_ONLY || | ||
| 4691 | (chan->mode != L2CAP_MODE_ERTM && | ||
| 4692 | chan->mode != L2CAP_MODE_STREAMING)) { | ||
| 4693 | result = L2CAP_MR_NOT_ALLOWED; | ||
| 4694 | goto send_move_response; | ||
| 4695 | } | ||
| 4696 | |||
| 4697 | if (chan->local_amp_id == req->dest_amp_id) { | ||
| 4698 | result = L2CAP_MR_SAME_ID; | ||
| 4699 | goto send_move_response; | ||
| 4700 | } | ||
| 4701 | |||
| 4702 | if (req->dest_amp_id) { | ||
| 4703 | struct hci_dev *hdev; | ||
| 4704 | hdev = hci_dev_get(req->dest_amp_id); | ||
| 4705 | if (!hdev || hdev->dev_type != HCI_AMP || | ||
| 4706 | !test_bit(HCI_UP, &hdev->flags)) { | ||
| 4707 | if (hdev) | ||
| 4708 | hci_dev_put(hdev); | ||
| 4709 | |||
| 4710 | result = L2CAP_MR_BAD_ID; | ||
| 4711 | goto send_move_response; | ||
| 4712 | } | ||
| 4713 | hci_dev_put(hdev); | ||
| 4714 | } | ||
| 4715 | |||
| 4716 | /* Detect a move collision. Only send a collision response | ||
| 4717 | * if this side has "lost", otherwise proceed with the move. | ||
| 4718 | * The winner has the larger bd_addr. | ||
| 4719 | */ | ||
| 4720 | if ((__chan_is_moving(chan) || | ||
| 4721 | chan->move_role != L2CAP_MOVE_ROLE_NONE) && | ||
| 4722 | bacmp(conn->src, conn->dst) > 0) { | ||
| 4723 | result = L2CAP_MR_COLLISION; | ||
| 4724 | goto send_move_response; | ||
| 4725 | } | ||
| 4726 | |||
| 4727 | chan->move_role = L2CAP_MOVE_ROLE_RESPONDER; | ||
| 4728 | l2cap_move_setup(chan); | ||
| 4729 | chan->move_id = req->dest_amp_id; | ||
| 4730 | icid = chan->dcid; | ||
| 4731 | |||
| 4732 | if (!req->dest_amp_id) { | ||
| 4733 | /* Moving to BR/EDR */ | ||
| 4734 | if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) { | ||
| 4735 | chan->move_state = L2CAP_MOVE_WAIT_LOCAL_BUSY; | ||
| 4736 | result = L2CAP_MR_PEND; | ||
| 4737 | } else { | ||
| 4738 | chan->move_state = L2CAP_MOVE_WAIT_CONFIRM; | ||
| 4739 | result = L2CAP_MR_SUCCESS; | ||
| 4740 | } | ||
| 4741 | } else { | ||
| 4742 | chan->move_state = L2CAP_MOVE_WAIT_PREPARE; | ||
| 4743 | /* Placeholder - uncomment when amp functions are available */ | ||
| 4744 | /*amp_accept_physical(chan, req->dest_amp_id);*/ | ||
| 4745 | result = L2CAP_MR_PEND; | ||
| 4746 | } | ||
| 4747 | |||
| 4748 | send_move_response: | ||
| 4749 | l2cap_send_move_chan_rsp(chan, result); | ||
| 4750 | |||
| 4751 | l2cap_chan_unlock(chan); | ||
| 4129 | 4752 | ||
| 4130 | return 0; | 4753 | return 0; |
| 4131 | } | 4754 | } |
| 4132 | 4755 | ||
| 4133 | static inline int l2cap_move_channel_rsp(struct l2cap_conn *conn, | 4756 | static void l2cap_move_continue(struct l2cap_conn *conn, u16 icid, u16 result) |
| 4134 | struct l2cap_cmd_hdr *cmd, | 4757 | { |
| 4135 | u16 cmd_len, void *data) | 4758 | struct l2cap_chan *chan; |
| 4759 | struct hci_chan *hchan = NULL; | ||
| 4760 | |||
| 4761 | chan = l2cap_get_chan_by_scid(conn, icid); | ||
| 4762 | if (!chan) { | ||
| 4763 | l2cap_send_move_chan_cfm_icid(conn, icid); | ||
| 4764 | return; | ||
| 4765 | } | ||
| 4766 | |||
| 4767 | __clear_chan_timer(chan); | ||
| 4768 | if (result == L2CAP_MR_PEND) | ||
| 4769 | __set_chan_timer(chan, L2CAP_MOVE_ERTX_TIMEOUT); | ||
| 4770 | |||
| 4771 | switch (chan->move_state) { | ||
| 4772 | case L2CAP_MOVE_WAIT_LOGICAL_COMP: | ||
| 4773 | /* Move confirm will be sent when logical link | ||
| 4774 | * is complete. | ||
| 4775 | */ | ||
| 4776 | chan->move_state = L2CAP_MOVE_WAIT_LOGICAL_CFM; | ||
| 4777 | break; | ||
| 4778 | case L2CAP_MOVE_WAIT_RSP_SUCCESS: | ||
| 4779 | if (result == L2CAP_MR_PEND) { | ||
| 4780 | break; | ||
| 4781 | } else if (test_bit(CONN_LOCAL_BUSY, | ||
| 4782 | &chan->conn_state)) { | ||
| 4783 | chan->move_state = L2CAP_MOVE_WAIT_LOCAL_BUSY; | ||
| 4784 | } else { | ||
| 4785 | /* Logical link is up or moving to BR/EDR, | ||
| 4786 | * proceed with move | ||
| 4787 | */ | ||
| 4788 | chan->move_state = L2CAP_MOVE_WAIT_CONFIRM_RSP; | ||
| 4789 | l2cap_send_move_chan_cfm(chan, L2CAP_MC_CONFIRMED); | ||
| 4790 | } | ||
| 4791 | break; | ||
| 4792 | case L2CAP_MOVE_WAIT_RSP: | ||
| 4793 | /* Moving to AMP */ | ||
| 4794 | if (result == L2CAP_MR_SUCCESS) { | ||
| 4795 | /* Remote is ready, send confirm immediately | ||
| 4796 | * after logical link is ready | ||
| 4797 | */ | ||
| 4798 | chan->move_state = L2CAP_MOVE_WAIT_LOGICAL_CFM; | ||
| 4799 | } else { | ||
| 4800 | /* Both logical link and move success | ||
| 4801 | * are required to confirm | ||
| 4802 | */ | ||
| 4803 | chan->move_state = L2CAP_MOVE_WAIT_LOGICAL_COMP; | ||
| 4804 | } | ||
| 4805 | |||
| 4806 | /* Placeholder - get hci_chan for logical link */ | ||
| 4807 | if (!hchan) { | ||
| 4808 | /* Logical link not available */ | ||
| 4809 | l2cap_send_move_chan_cfm(chan, L2CAP_MC_UNCONFIRMED); | ||
| 4810 | break; | ||
| 4811 | } | ||
| 4812 | |||
| 4813 | /* If the logical link is not yet connected, do not | ||
| 4814 | * send confirmation. | ||
| 4815 | */ | ||
| 4816 | if (hchan->state != BT_CONNECTED) | ||
| 4817 | break; | ||
| 4818 | |||
| 4819 | /* Logical link is already ready to go */ | ||
| 4820 | |||
| 4821 | chan->hs_hcon = hchan->conn; | ||
| 4822 | chan->hs_hcon->l2cap_data = chan->conn; | ||
| 4823 | |||
| 4824 | if (result == L2CAP_MR_SUCCESS) { | ||
| 4825 | /* Can confirm now */ | ||
| 4826 | l2cap_send_move_chan_cfm(chan, L2CAP_MC_CONFIRMED); | ||
| 4827 | } else { | ||
| 4828 | /* Now only need move success | ||
| 4829 | * to confirm | ||
| 4830 | */ | ||
| 4831 | chan->move_state = L2CAP_MOVE_WAIT_RSP_SUCCESS; | ||
| 4832 | } | ||
| 4833 | |||
| 4834 | l2cap_logical_cfm(chan, hchan, L2CAP_MR_SUCCESS); | ||
| 4835 | break; | ||
| 4836 | default: | ||
| 4837 | /* Any other amp move state means the move failed. */ | ||
| 4838 | chan->move_id = chan->local_amp_id; | ||
| 4839 | l2cap_move_done(chan); | ||
| 4840 | l2cap_send_move_chan_cfm(chan, L2CAP_MC_UNCONFIRMED); | ||
| 4841 | } | ||
| 4842 | |||
| 4843 | l2cap_chan_unlock(chan); | ||
| 4844 | } | ||
| 4845 | |||
| 4846 | static void l2cap_move_fail(struct l2cap_conn *conn, u8 ident, u16 icid, | ||
| 4847 | u16 result) | ||
| 4848 | { | ||
| 4849 | struct l2cap_chan *chan; | ||
| 4850 | |||
| 4851 | chan = l2cap_get_chan_by_ident(conn, ident); | ||
| 4852 | if (!chan) { | ||
| 4853 | /* Could not locate channel, icid is best guess */ | ||
| 4854 | l2cap_send_move_chan_cfm_icid(conn, icid); | ||
| 4855 | return; | ||
| 4856 | } | ||
| 4857 | |||
| 4858 | __clear_chan_timer(chan); | ||
| 4859 | |||
| 4860 | if (chan->move_role == L2CAP_MOVE_ROLE_INITIATOR) { | ||
| 4861 | if (result == L2CAP_MR_COLLISION) { | ||
| 4862 | chan->move_role = L2CAP_MOVE_ROLE_RESPONDER; | ||
| 4863 | } else { | ||
| 4864 | /* Cleanup - cancel move */ | ||
| 4865 | chan->move_id = chan->local_amp_id; | ||
| 4866 | l2cap_move_done(chan); | ||
| 4867 | } | ||
| 4868 | } | ||
| 4869 | |||
| 4870 | l2cap_send_move_chan_cfm(chan, L2CAP_MC_UNCONFIRMED); | ||
| 4871 | |||
| 4872 | l2cap_chan_unlock(chan); | ||
| 4873 | } | ||
| 4874 | |||
| 4875 | static int l2cap_move_channel_rsp(struct l2cap_conn *conn, | ||
| 4876 | struct l2cap_cmd_hdr *cmd, | ||
| 4877 | u16 cmd_len, void *data) | ||
| 4136 | { | 4878 | { |
| 4137 | struct l2cap_move_chan_rsp *rsp = data; | 4879 | struct l2cap_move_chan_rsp *rsp = data; |
| 4138 | u16 icid, result; | 4880 | u16 icid, result; |
| @@ -4145,17 +4887,20 @@ static inline int l2cap_move_channel_rsp(struct l2cap_conn *conn, | |||
| 4145 | 4887 | ||
| 4146 | BT_DBG("icid 0x%4.4x, result 0x%4.4x", icid, result); | 4888 | BT_DBG("icid 0x%4.4x, result 0x%4.4x", icid, result); |
| 4147 | 4889 | ||
| 4148 | /* Placeholder: Always unconfirmed */ | 4890 | if (result == L2CAP_MR_SUCCESS || result == L2CAP_MR_PEND) |
| 4149 | l2cap_send_move_chan_cfm(conn, NULL, icid, L2CAP_MC_UNCONFIRMED); | 4891 | l2cap_move_continue(conn, icid, result); |
| 4892 | else | ||
| 4893 | l2cap_move_fail(conn, cmd->ident, icid, result); | ||
| 4150 | 4894 | ||
| 4151 | return 0; | 4895 | return 0; |
| 4152 | } | 4896 | } |
| 4153 | 4897 | ||
| 4154 | static inline int l2cap_move_channel_confirm(struct l2cap_conn *conn, | 4898 | static int l2cap_move_channel_confirm(struct l2cap_conn *conn, |
| 4155 | struct l2cap_cmd_hdr *cmd, | 4899 | struct l2cap_cmd_hdr *cmd, |
| 4156 | u16 cmd_len, void *data) | 4900 | u16 cmd_len, void *data) |
| 4157 | { | 4901 | { |
| 4158 | struct l2cap_move_chan_cfm *cfm = data; | 4902 | struct l2cap_move_chan_cfm *cfm = data; |
| 4903 | struct l2cap_chan *chan; | ||
| 4159 | u16 icid, result; | 4904 | u16 icid, result; |
| 4160 | 4905 | ||
| 4161 | if (cmd_len != sizeof(*cfm)) | 4906 | if (cmd_len != sizeof(*cfm)) |
| @@ -4166,8 +4911,29 @@ static inline int l2cap_move_channel_confirm(struct l2cap_conn *conn, | |||
| 4166 | 4911 | ||
| 4167 | BT_DBG("icid 0x%4.4x, result 0x%4.4x", icid, result); | 4912 | BT_DBG("icid 0x%4.4x, result 0x%4.4x", icid, result); |
| 4168 | 4913 | ||
| 4914 | chan = l2cap_get_chan_by_dcid(conn, icid); | ||
| 4915 | if (!chan) { | ||
| 4916 | /* Spec requires a response even if the icid was not found */ | ||
| 4917 | l2cap_send_move_chan_cfm_rsp(conn, cmd->ident, icid); | ||
| 4918 | return 0; | ||
| 4919 | } | ||
| 4920 | |||
| 4921 | if (chan->move_state == L2CAP_MOVE_WAIT_CONFIRM) { | ||
| 4922 | if (result == L2CAP_MC_CONFIRMED) { | ||
| 4923 | chan->local_amp_id = chan->move_id; | ||
| 4924 | if (!chan->local_amp_id) | ||
| 4925 | __release_logical_link(chan); | ||
| 4926 | } else { | ||
| 4927 | chan->move_id = chan->local_amp_id; | ||
| 4928 | } | ||
| 4929 | |||
| 4930 | l2cap_move_done(chan); | ||
| 4931 | } | ||
| 4932 | |||
| 4169 | l2cap_send_move_chan_cfm_rsp(conn, cmd->ident, icid); | 4933 | l2cap_send_move_chan_cfm_rsp(conn, cmd->ident, icid); |
| 4170 | 4934 | ||
| 4935 | l2cap_chan_unlock(chan); | ||
| 4936 | |||
| 4171 | return 0; | 4937 | return 0; |
| 4172 | } | 4938 | } |
| 4173 | 4939 | ||
| @@ -4176,6 +4942,7 @@ static inline int l2cap_move_channel_confirm_rsp(struct l2cap_conn *conn, | |||
| 4176 | u16 cmd_len, void *data) | 4942 | u16 cmd_len, void *data) |
| 4177 | { | 4943 | { |
| 4178 | struct l2cap_move_chan_cfm_rsp *rsp = data; | 4944 | struct l2cap_move_chan_cfm_rsp *rsp = data; |
| 4945 | struct l2cap_chan *chan; | ||
| 4179 | u16 icid; | 4946 | u16 icid; |
| 4180 | 4947 | ||
| 4181 | if (cmd_len != sizeof(*rsp)) | 4948 | if (cmd_len != sizeof(*rsp)) |
| @@ -4185,6 +4952,23 @@ static inline int l2cap_move_channel_confirm_rsp(struct l2cap_conn *conn, | |||
| 4185 | 4952 | ||
| 4186 | BT_DBG("icid 0x%4.4x", icid); | 4953 | BT_DBG("icid 0x%4.4x", icid); |
| 4187 | 4954 | ||
| 4955 | chan = l2cap_get_chan_by_scid(conn, icid); | ||
| 4956 | if (!chan) | ||
| 4957 | return 0; | ||
| 4958 | |||
| 4959 | __clear_chan_timer(chan); | ||
| 4960 | |||
| 4961 | if (chan->move_state == L2CAP_MOVE_WAIT_CONFIRM_RSP) { | ||
| 4962 | chan->local_amp_id = chan->move_id; | ||
| 4963 | |||
| 4964 | if (!chan->local_amp_id && chan->hs_hchan) | ||
| 4965 | __release_logical_link(chan); | ||
| 4966 | |||
| 4967 | l2cap_move_done(chan); | ||
| 4968 | } | ||
| 4969 | |||
| 4970 | l2cap_chan_unlock(chan); | ||
| 4971 | |||
| 4188 | return 0; | 4972 | return 0; |
| 4189 | } | 4973 | } |
| 4190 | 4974 | ||
| @@ -4269,7 +5053,7 @@ static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn, | |||
| 4269 | 5053 | ||
| 4270 | case L2CAP_CONN_RSP: | 5054 | case L2CAP_CONN_RSP: |
| 4271 | case L2CAP_CREATE_CHAN_RSP: | 5055 | case L2CAP_CREATE_CHAN_RSP: |
| 4272 | err = l2cap_connect_rsp(conn, cmd, data); | 5056 | err = l2cap_connect_create_rsp(conn, cmd, data); |
| 4273 | break; | 5057 | break; |
| 4274 | 5058 | ||
| 4275 | case L2CAP_CONF_REQ: | 5059 | case L2CAP_CONF_REQ: |
| @@ -4556,6 +5340,12 @@ static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb, | |||
| 4556 | return err; | 5340 | return err; |
| 4557 | } | 5341 | } |
| 4558 | 5342 | ||
| 5343 | static int l2cap_resegment(struct l2cap_chan *chan) | ||
| 5344 | { | ||
| 5345 | /* Placeholder */ | ||
| 5346 | return 0; | ||
| 5347 | } | ||
| 5348 | |||
| 4559 | void l2cap_chan_busy(struct l2cap_chan *chan, int busy) | 5349 | void l2cap_chan_busy(struct l2cap_chan *chan, int busy) |
| 4560 | { | 5350 | { |
| 4561 | u8 event; | 5351 | u8 event; |
| @@ -4871,8 +5661,8 @@ static int l2cap_rx_state_recv(struct l2cap_chan *chan, | |||
| 4871 | if (control->final) { | 5661 | if (control->final) { |
| 4872 | clear_bit(CONN_REMOTE_BUSY, &chan->conn_state); | 5662 | clear_bit(CONN_REMOTE_BUSY, &chan->conn_state); |
| 4873 | 5663 | ||
| 4874 | if (!test_and_clear_bit(CONN_REJ_ACT, | 5664 | if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state) && |
| 4875 | &chan->conn_state)) { | 5665 | !__chan_is_moving(chan)) { |
| 4876 | control->final = 0; | 5666 | control->final = 0; |
| 4877 | l2cap_retransmit_all(chan, control); | 5667 | l2cap_retransmit_all(chan, control); |
| 4878 | } | 5668 | } |
| @@ -5061,6 +5851,96 @@ static int l2cap_rx_state_srej_sent(struct l2cap_chan *chan, | |||
| 5061 | return err; | 5851 | return err; |
| 5062 | } | 5852 | } |
| 5063 | 5853 | ||
| 5854 | static int l2cap_finish_move(struct l2cap_chan *chan) | ||
| 5855 | { | ||
| 5856 | BT_DBG("chan %p", chan); | ||
| 5857 | |||
| 5858 | chan->rx_state = L2CAP_RX_STATE_RECV; | ||
| 5859 | |||
| 5860 | if (chan->hs_hcon) | ||
| 5861 | chan->conn->mtu = chan->hs_hcon->hdev->block_mtu; | ||
| 5862 | else | ||
| 5863 | chan->conn->mtu = chan->conn->hcon->hdev->acl_mtu; | ||
| 5864 | |||
| 5865 | return l2cap_resegment(chan); | ||
| 5866 | } | ||
| 5867 | |||
| 5868 | static int l2cap_rx_state_wait_p(struct l2cap_chan *chan, | ||
| 5869 | struct l2cap_ctrl *control, | ||
| 5870 | struct sk_buff *skb, u8 event) | ||
| 5871 | { | ||
| 5872 | int err; | ||
| 5873 | |||
| 5874 | BT_DBG("chan %p, control %p, skb %p, event %d", chan, control, skb, | ||
| 5875 | event); | ||
| 5876 | |||
| 5877 | if (!control->poll) | ||
| 5878 | return -EPROTO; | ||
| 5879 | |||
| 5880 | l2cap_process_reqseq(chan, control->reqseq); | ||
| 5881 | |||
| 5882 | if (!skb_queue_empty(&chan->tx_q)) | ||
| 5883 | chan->tx_send_head = skb_peek(&chan->tx_q); | ||
| 5884 | else | ||
| 5885 | chan->tx_send_head = NULL; | ||
| 5886 | |||
| 5887 | /* Rewind next_tx_seq to the point expected | ||
| 5888 | * by the receiver. | ||
| 5889 | */ | ||
| 5890 | chan->next_tx_seq = control->reqseq; | ||
| 5891 | chan->unacked_frames = 0; | ||
| 5892 | |||
| 5893 | err = l2cap_finish_move(chan); | ||
| 5894 | if (err) | ||
| 5895 | return err; | ||
| 5896 | |||
| 5897 | set_bit(CONN_SEND_FBIT, &chan->conn_state); | ||
| 5898 | l2cap_send_i_or_rr_or_rnr(chan); | ||
| 5899 | |||
| 5900 | if (event == L2CAP_EV_RECV_IFRAME) | ||
| 5901 | return -EPROTO; | ||
| 5902 | |||
| 5903 | return l2cap_rx_state_recv(chan, control, NULL, event); | ||
| 5904 | } | ||
| 5905 | |||
| 5906 | static int l2cap_rx_state_wait_f(struct l2cap_chan *chan, | ||
| 5907 | struct l2cap_ctrl *control, | ||
| 5908 | struct sk_buff *skb, u8 event) | ||
| 5909 | { | ||
| 5910 | int err; | ||
| 5911 | |||
| 5912 | if (!control->final) | ||
| 5913 | return -EPROTO; | ||
| 5914 | |||
| 5915 | clear_bit(CONN_REMOTE_BUSY, &chan->conn_state); | ||
| 5916 | |||
| 5917 | chan->rx_state = L2CAP_RX_STATE_RECV; | ||
| 5918 | l2cap_process_reqseq(chan, control->reqseq); | ||
| 5919 | |||
| 5920 | if (!skb_queue_empty(&chan->tx_q)) | ||
| 5921 | chan->tx_send_head = skb_peek(&chan->tx_q); | ||
| 5922 | else | ||
| 5923 | chan->tx_send_head = NULL; | ||
| 5924 | |||
| 5925 | /* Rewind next_tx_seq to the point expected | ||
| 5926 | * by the receiver. | ||
| 5927 | */ | ||
| 5928 | chan->next_tx_seq = control->reqseq; | ||
| 5929 | chan->unacked_frames = 0; | ||
| 5930 | |||
| 5931 | if (chan->hs_hcon) | ||
| 5932 | chan->conn->mtu = chan->hs_hcon->hdev->block_mtu; | ||
| 5933 | else | ||
| 5934 | chan->conn->mtu = chan->conn->hcon->hdev->acl_mtu; | ||
| 5935 | |||
| 5936 | err = l2cap_resegment(chan); | ||
| 5937 | |||
| 5938 | if (!err) | ||
| 5939 | err = l2cap_rx_state_recv(chan, control, skb, event); | ||
| 5940 | |||
| 5941 | return err; | ||
| 5942 | } | ||
| 5943 | |||
| 5064 | static bool __valid_reqseq(struct l2cap_chan *chan, u16 reqseq) | 5944 | static bool __valid_reqseq(struct l2cap_chan *chan, u16 reqseq) |
| 5065 | { | 5945 | { |
| 5066 | /* Make sure reqseq is for a packet that has been sent but not acked */ | 5946 | /* Make sure reqseq is for a packet that has been sent but not acked */ |
| @@ -5087,6 +5967,12 @@ static int l2cap_rx(struct l2cap_chan *chan, struct l2cap_ctrl *control, | |||
| 5087 | err = l2cap_rx_state_srej_sent(chan, control, skb, | 5967 | err = l2cap_rx_state_srej_sent(chan, control, skb, |
| 5088 | event); | 5968 | event); |
| 5089 | break; | 5969 | break; |
| 5970 | case L2CAP_RX_STATE_WAIT_P: | ||
| 5971 | err = l2cap_rx_state_wait_p(chan, control, skb, event); | ||
| 5972 | break; | ||
| 5973 | case L2CAP_RX_STATE_WAIT_F: | ||
| 5974 | err = l2cap_rx_state_wait_f(chan, control, skb, event); | ||
| 5975 | break; | ||
| 5090 | default: | 5976 | default: |
| 5091 | /* shut it down */ | 5977 | /* shut it down */ |
| 5092 | break; | 5978 | break; |
| @@ -5206,7 +6092,7 @@ static int l2cap_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb) | |||
| 5206 | control->super); | 6092 | control->super); |
| 5207 | 6093 | ||
| 5208 | if (len != 0) { | 6094 | if (len != 0) { |
| 5209 | BT_ERR("%d", len); | 6095 | BT_ERR("Trailing bytes: %d in sframe", len); |
| 5210 | l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); | 6096 | l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); |
| 5211 | goto drop; | 6097 | goto drop; |
| 5212 | } | 6098 | } |
| @@ -5422,9 +6308,9 @@ void l2cap_connect_cfm(struct hci_conn *hcon, u8 status) | |||
| 5422 | conn = l2cap_conn_add(hcon, status); | 6308 | conn = l2cap_conn_add(hcon, status); |
| 5423 | if (conn) | 6309 | if (conn) |
| 5424 | l2cap_conn_ready(conn); | 6310 | l2cap_conn_ready(conn); |
| 5425 | } else | 6311 | } else { |
| 5426 | l2cap_conn_del(hcon, bt_to_errno(status)); | 6312 | l2cap_conn_del(hcon, bt_to_errno(status)); |
| 5427 | 6313 | } | |
| 5428 | } | 6314 | } |
| 5429 | 6315 | ||
| 5430 | int l2cap_disconn_ind(struct hci_conn *hcon) | 6316 | int l2cap_disconn_ind(struct hci_conn *hcon) |
| @@ -5500,7 +6386,7 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) | |||
| 5500 | continue; | 6386 | continue; |
| 5501 | } | 6387 | } |
| 5502 | 6388 | ||
| 5503 | if (test_bit(CONF_CONNECT_PEND, &chan->conf_state)) { | 6389 | if (!__l2cap_no_conn_pending(chan)) { |
| 5504 | l2cap_chan_unlock(chan); | 6390 | l2cap_chan_unlock(chan); |
| 5505 | continue; | 6391 | continue; |
| 5506 | } | 6392 | } |
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 89f1472939ec..1bcfb8422fdc 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c | |||
| @@ -736,6 +736,11 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, | |||
| 736 | } | 736 | } |
| 737 | 737 | ||
| 738 | chan->chan_policy = (u8) opt; | 738 | chan->chan_policy = (u8) opt; |
| 739 | |||
| 740 | if (sk->sk_state == BT_CONNECTED && | ||
| 741 | chan->move_role == L2CAP_MOVE_ROLE_NONE) | ||
| 742 | l2cap_move_start(chan); | ||
| 743 | |||
| 739 | break; | 744 | break; |
| 740 | 745 | ||
| 741 | default: | 746 | default: |
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 158a87bb0c0d..142764aec2af 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c | |||
| @@ -222,7 +222,7 @@ static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status) | |||
| 222 | 222 | ||
| 223 | hdr = (void *) skb_put(skb, sizeof(*hdr)); | 223 | hdr = (void *) skb_put(skb, sizeof(*hdr)); |
| 224 | 224 | ||
| 225 | hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS); | 225 | hdr->opcode = __constant_cpu_to_le16(MGMT_EV_CMD_STATUS); |
| 226 | hdr->index = cpu_to_le16(index); | 226 | hdr->index = cpu_to_le16(index); |
| 227 | hdr->len = cpu_to_le16(sizeof(*ev)); | 227 | hdr->len = cpu_to_le16(sizeof(*ev)); |
| 228 | 228 | ||
| @@ -253,7 +253,7 @@ static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status, | |||
| 253 | 253 | ||
| 254 | hdr = (void *) skb_put(skb, sizeof(*hdr)); | 254 | hdr = (void *) skb_put(skb, sizeof(*hdr)); |
| 255 | 255 | ||
| 256 | hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE); | 256 | hdr->opcode = __constant_cpu_to_le16(MGMT_EV_CMD_COMPLETE); |
| 257 | hdr->index = cpu_to_le16(index); | 257 | hdr->index = cpu_to_le16(index); |
| 258 | hdr->len = cpu_to_le16(sizeof(*ev) + rp_len); | 258 | hdr->len = cpu_to_le16(sizeof(*ev) + rp_len); |
| 259 | 259 | ||
| @@ -377,15 +377,15 @@ static u32 get_supported_settings(struct hci_dev *hdev) | |||
| 377 | u32 settings = 0; | 377 | u32 settings = 0; |
| 378 | 378 | ||
| 379 | settings |= MGMT_SETTING_POWERED; | 379 | settings |= MGMT_SETTING_POWERED; |
| 380 | settings |= MGMT_SETTING_CONNECTABLE; | ||
| 381 | settings |= MGMT_SETTING_FAST_CONNECTABLE; | ||
| 382 | settings |= MGMT_SETTING_DISCOVERABLE; | ||
| 383 | settings |= MGMT_SETTING_PAIRABLE; | 380 | settings |= MGMT_SETTING_PAIRABLE; |
| 384 | 381 | ||
| 385 | if (lmp_ssp_capable(hdev)) | 382 | if (lmp_ssp_capable(hdev)) |
| 386 | settings |= MGMT_SETTING_SSP; | 383 | settings |= MGMT_SETTING_SSP; |
| 387 | 384 | ||
| 388 | if (lmp_bredr_capable(hdev)) { | 385 | if (lmp_bredr_capable(hdev)) { |
| 386 | settings |= MGMT_SETTING_CONNECTABLE; | ||
| 387 | settings |= MGMT_SETTING_FAST_CONNECTABLE; | ||
| 388 | settings |= MGMT_SETTING_DISCOVERABLE; | ||
| 389 | settings |= MGMT_SETTING_BREDR; | 389 | settings |= MGMT_SETTING_BREDR; |
| 390 | settings |= MGMT_SETTING_LINK_SECURITY; | 390 | settings |= MGMT_SETTING_LINK_SECURITY; |
| 391 | } | 391 | } |
| @@ -485,7 +485,7 @@ static void create_eir(struct hci_dev *hdev, u8 *data) | |||
| 485 | ptr += (name_len + 2); | 485 | ptr += (name_len + 2); |
| 486 | } | 486 | } |
| 487 | 487 | ||
| 488 | if (hdev->inq_tx_power) { | 488 | if (hdev->inq_tx_power != HCI_TX_POWER_INVALID) { |
| 489 | ptr[0] = 2; | 489 | ptr[0] = 2; |
| 490 | ptr[1] = EIR_TX_POWER; | 490 | ptr[1] = EIR_TX_POWER; |
| 491 | ptr[2] = (u8) hdev->inq_tx_power; | 491 | ptr[2] = (u8) hdev->inq_tx_power; |
| @@ -566,7 +566,7 @@ static int update_eir(struct hci_dev *hdev) | |||
| 566 | if (!hdev_is_powered(hdev)) | 566 | if (!hdev_is_powered(hdev)) |
| 567 | return 0; | 567 | return 0; |
| 568 | 568 | ||
| 569 | if (!(hdev->features[6] & LMP_EXT_INQ)) | 569 | if (!lmp_ext_inq_capable(hdev)) |
| 570 | return 0; | 570 | return 0; |
| 571 | 571 | ||
| 572 | if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) | 572 | if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) |
| @@ -833,7 +833,7 @@ static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len, | |||
| 833 | if (hdev) | 833 | if (hdev) |
| 834 | hdr->index = cpu_to_le16(hdev->id); | 834 | hdr->index = cpu_to_le16(hdev->id); |
| 835 | else | 835 | else |
| 836 | hdr->index = cpu_to_le16(MGMT_INDEX_NONE); | 836 | hdr->index = __constant_cpu_to_le16(MGMT_INDEX_NONE); |
| 837 | hdr->len = cpu_to_le16(data_len); | 837 | hdr->len = cpu_to_le16(data_len); |
| 838 | 838 | ||
| 839 | if (data) | 839 | if (data) |
| @@ -868,6 +868,10 @@ static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data, | |||
| 868 | 868 | ||
| 869 | BT_DBG("request for %s", hdev->name); | 869 | BT_DBG("request for %s", hdev->name); |
| 870 | 870 | ||
| 871 | if (!lmp_bredr_capable(hdev)) | ||
| 872 | return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE, | ||
| 873 | MGMT_STATUS_NOT_SUPPORTED); | ||
| 874 | |||
| 871 | timeout = __le16_to_cpu(cp->timeout); | 875 | timeout = __le16_to_cpu(cp->timeout); |
| 872 | if (!cp->val && timeout > 0) | 876 | if (!cp->val && timeout > 0) |
| 873 | return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE, | 877 | return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE, |
| @@ -963,6 +967,10 @@ static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data, | |||
| 963 | 967 | ||
| 964 | BT_DBG("request for %s", hdev->name); | 968 | BT_DBG("request for %s", hdev->name); |
| 965 | 969 | ||
| 970 | if (!lmp_bredr_capable(hdev)) | ||
| 971 | return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE, | ||
| 972 | MGMT_STATUS_NOT_SUPPORTED); | ||
| 973 | |||
| 966 | hci_dev_lock(hdev); | 974 | hci_dev_lock(hdev); |
| 967 | 975 | ||
| 968 | if (!hdev_is_powered(hdev)) { | 976 | if (!hdev_is_powered(hdev)) { |
| @@ -1061,6 +1069,10 @@ static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data, | |||
| 1061 | 1069 | ||
| 1062 | BT_DBG("request for %s", hdev->name); | 1070 | BT_DBG("request for %s", hdev->name); |
| 1063 | 1071 | ||
| 1072 | if (!lmp_bredr_capable(hdev)) | ||
| 1073 | return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY, | ||
| 1074 | MGMT_STATUS_NOT_SUPPORTED); | ||
| 1075 | |||
| 1064 | hci_dev_lock(hdev); | 1076 | hci_dev_lock(hdev); |
| 1065 | 1077 | ||
| 1066 | if (!hdev_is_powered(hdev)) { | 1078 | if (!hdev_is_powered(hdev)) { |
| @@ -1214,7 +1226,7 @@ static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) | |||
| 1214 | } | 1226 | } |
| 1215 | 1227 | ||
| 1216 | val = !!cp->val; | 1228 | val = !!cp->val; |
| 1217 | enabled = !!(hdev->host_features[0] & LMP_HOST_LE); | 1229 | enabled = !!lmp_host_le_capable(hdev); |
| 1218 | 1230 | ||
| 1219 | if (!hdev_is_powered(hdev) || val == enabled) { | 1231 | if (!hdev_is_powered(hdev) || val == enabled) { |
| 1220 | bool changed = false; | 1232 | bool changed = false; |
| @@ -1250,7 +1262,7 @@ static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) | |||
| 1250 | 1262 | ||
| 1251 | if (val) { | 1263 | if (val) { |
| 1252 | hci_cp.le = val; | 1264 | hci_cp.le = val; |
| 1253 | hci_cp.simul = !!(hdev->features[6] & LMP_SIMUL_LE_BR); | 1265 | hci_cp.simul = !!lmp_le_br_capable(hdev); |
| 1254 | } | 1266 | } |
| 1255 | 1267 | ||
| 1256 | err = hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp), | 1268 | err = hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp), |
| @@ -2596,6 +2608,10 @@ static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev, | |||
| 2596 | 2608 | ||
| 2597 | BT_DBG("%s", hdev->name); | 2609 | BT_DBG("%s", hdev->name); |
| 2598 | 2610 | ||
| 2611 | if (!lmp_bredr_capable(hdev)) | ||
| 2612 | return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, | ||
| 2613 | MGMT_STATUS_NOT_SUPPORTED); | ||
| 2614 | |||
| 2599 | if (!hdev_is_powered(hdev)) | 2615 | if (!hdev_is_powered(hdev)) |
| 2600 | return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, | 2616 | return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, |
| 2601 | MGMT_STATUS_NOT_POWERED); | 2617 | MGMT_STATUS_NOT_POWERED); |
| @@ -2873,6 +2889,21 @@ static void settings_rsp(struct pending_cmd *cmd, void *data) | |||
| 2873 | mgmt_pending_free(cmd); | 2889 | mgmt_pending_free(cmd); |
| 2874 | } | 2890 | } |
| 2875 | 2891 | ||
| 2892 | static int set_bredr_scan(struct hci_dev *hdev) | ||
| 2893 | { | ||
| 2894 | u8 scan = 0; | ||
| 2895 | |||
| 2896 | if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) | ||
| 2897 | scan |= SCAN_PAGE; | ||
| 2898 | if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) | ||
| 2899 | scan |= SCAN_INQUIRY; | ||
| 2900 | |||
| 2901 | if (!scan) | ||
| 2902 | return 0; | ||
| 2903 | |||
| 2904 | return hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan); | ||
| 2905 | } | ||
| 2906 | |||
| 2876 | int mgmt_powered(struct hci_dev *hdev, u8 powered) | 2907 | int mgmt_powered(struct hci_dev *hdev, u8 powered) |
| 2877 | { | 2908 | { |
| 2878 | struct cmd_lookup match = { NULL, hdev }; | 2909 | struct cmd_lookup match = { NULL, hdev }; |
| @@ -2884,17 +2915,8 @@ int mgmt_powered(struct hci_dev *hdev, u8 powered) | |||
| 2884 | mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match); | 2915 | mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match); |
| 2885 | 2916 | ||
| 2886 | if (powered) { | 2917 | if (powered) { |
| 2887 | u8 scan = 0; | 2918 | if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) && |
| 2888 | 2919 | !lmp_host_ssp_capable(hdev)) { | |
| 2889 | if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) | ||
| 2890 | scan |= SCAN_PAGE; | ||
| 2891 | if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) | ||
| 2892 | scan |= SCAN_INQUIRY; | ||
| 2893 | |||
| 2894 | if (scan) | ||
| 2895 | hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan); | ||
| 2896 | |||
| 2897 | if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) { | ||
| 2898 | u8 ssp = 1; | 2920 | u8 ssp = 1; |
| 2899 | 2921 | ||
| 2900 | hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &ssp); | 2922 | hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &ssp); |
| @@ -2904,15 +2926,24 @@ int mgmt_powered(struct hci_dev *hdev, u8 powered) | |||
| 2904 | struct hci_cp_write_le_host_supported cp; | 2926 | struct hci_cp_write_le_host_supported cp; |
| 2905 | 2927 | ||
| 2906 | cp.le = 1; | 2928 | cp.le = 1; |
| 2907 | cp.simul = !!(hdev->features[6] & LMP_SIMUL_LE_BR); | 2929 | cp.simul = !!lmp_le_br_capable(hdev); |
| 2908 | 2930 | ||
| 2909 | hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, | 2931 | /* Check first if we already have the right |
| 2910 | sizeof(cp), &cp); | 2932 | * host state (host features set) |
| 2933 | */ | ||
| 2934 | if (cp.le != !!lmp_host_le_capable(hdev) || | ||
| 2935 | cp.simul != !!lmp_host_le_br_capable(hdev)) | ||
| 2936 | hci_send_cmd(hdev, | ||
| 2937 | HCI_OP_WRITE_LE_HOST_SUPPORTED, | ||
| 2938 | sizeof(cp), &cp); | ||
| 2911 | } | 2939 | } |
| 2912 | 2940 | ||
| 2913 | update_class(hdev); | 2941 | if (lmp_bredr_capable(hdev)) { |
| 2914 | update_name(hdev, hdev->dev_name); | 2942 | set_bredr_scan(hdev); |
| 2915 | update_eir(hdev); | 2943 | update_class(hdev); |
| 2944 | update_name(hdev, hdev->dev_name); | ||
| 2945 | update_eir(hdev); | ||
| 2946 | } | ||
| 2916 | } else { | 2947 | } else { |
| 2917 | u8 status = MGMT_STATUS_NOT_POWERED; | 2948 | u8 status = MGMT_STATUS_NOT_POWERED; |
| 2918 | mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status); | 2949 | mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status); |
| @@ -3361,7 +3392,7 @@ static int clear_eir(struct hci_dev *hdev) | |||
| 3361 | { | 3392 | { |
| 3362 | struct hci_cp_write_eir cp; | 3393 | struct hci_cp_write_eir cp; |
| 3363 | 3394 | ||
| 3364 | if (!(hdev->features[6] & LMP_EXT_INQ)) | 3395 | if (!lmp_ext_inq_capable(hdev)) |
| 3365 | return 0; | 3396 | return 0; |
| 3366 | 3397 | ||
| 3367 | memset(hdev->eir, 0, sizeof(hdev->eir)); | 3398 | memset(hdev->eir, 0, sizeof(hdev->eir)); |
| @@ -3493,7 +3524,12 @@ send_event: | |||
| 3493 | err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, | 3524 | err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, |
| 3494 | sizeof(ev), cmd ? cmd->sk : NULL); | 3525 | sizeof(ev), cmd ? cmd->sk : NULL); |
| 3495 | 3526 | ||
| 3496 | update_eir(hdev); | 3527 | /* EIR is taken care of separately when powering on the |
| 3528 | * adapter so only update them here if this is a name change | ||
| 3529 | * unrelated to power on. | ||
| 3530 | */ | ||
| 3531 | if (!test_bit(HCI_INIT, &hdev->flags)) | ||
| 3532 | update_eir(hdev); | ||
| 3497 | 3533 | ||
| 3498 | failed: | 3534 | failed: |
| 3499 | if (cmd) | 3535 | if (cmd) |
| @@ -3588,9 +3624,9 @@ int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, | |||
| 3588 | ev->addr.type = link_to_bdaddr(link_type, addr_type); | 3624 | ev->addr.type = link_to_bdaddr(link_type, addr_type); |
| 3589 | ev->rssi = rssi; | 3625 | ev->rssi = rssi; |
| 3590 | if (cfm_name) | 3626 | if (cfm_name) |
| 3591 | ev->flags |= cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME); | 3627 | ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME); |
| 3592 | if (!ssp) | 3628 | if (!ssp) |
| 3593 | ev->flags |= cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING); | 3629 | ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING); |
| 3594 | 3630 | ||
| 3595 | if (eir_len > 0) | 3631 | if (eir_len > 0) |
| 3596 | memcpy(ev->eir, eir, eir_len); | 3632 | memcpy(ev->eir, eir, eir_len); |
diff --git a/net/can/bcm.c b/net/can/bcm.c index 6f747582718e..969b7cdff59d 100644 --- a/net/can/bcm.c +++ b/net/can/bcm.c | |||
| @@ -1084,6 +1084,9 @@ static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg, | |||
| 1084 | op->sk = sk; | 1084 | op->sk = sk; |
| 1085 | op->ifindex = ifindex; | 1085 | op->ifindex = ifindex; |
| 1086 | 1086 | ||
| 1087 | /* ifindex for timeout events w/o previous frame reception */ | ||
| 1088 | op->rx_ifindex = ifindex; | ||
| 1089 | |||
| 1087 | /* initialize uninitialized (kzalloc) structure */ | 1090 | /* initialize uninitialized (kzalloc) structure */ |
| 1088 | hrtimer_init(&op->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); | 1091 | hrtimer_init(&op->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); |
| 1089 | op->timer.function = bcm_rx_timeout_handler; | 1092 | op->timer.function = bcm_rx_timeout_handler; |
diff --git a/net/core/dev.c b/net/core/dev.c index 7304ea8a1f13..2f94df257e5a 100644 --- a/net/core/dev.c +++ b/net/core/dev.c | |||
| @@ -203,6 +203,8 @@ static struct list_head offload_base __read_mostly; | |||
| 203 | DEFINE_RWLOCK(dev_base_lock); | 203 | DEFINE_RWLOCK(dev_base_lock); |
| 204 | EXPORT_SYMBOL(dev_base_lock); | 204 | EXPORT_SYMBOL(dev_base_lock); |
| 205 | 205 | ||
| 206 | DEFINE_SEQLOCK(devnet_rename_seq); | ||
| 207 | |||
| 206 | static inline void dev_base_seq_inc(struct net *net) | 208 | static inline void dev_base_seq_inc(struct net *net) |
| 207 | { | 209 | { |
| 208 | while (++net->dev_base_seq == 0); | 210 | while (++net->dev_base_seq == 0); |
| @@ -1091,22 +1093,31 @@ int dev_change_name(struct net_device *dev, const char *newname) | |||
| 1091 | if (dev->flags & IFF_UP) | 1093 | if (dev->flags & IFF_UP) |
| 1092 | return -EBUSY; | 1094 | return -EBUSY; |
| 1093 | 1095 | ||
| 1094 | if (strncmp(newname, dev->name, IFNAMSIZ) == 0) | 1096 | write_seqlock(&devnet_rename_seq); |
| 1097 | |||
| 1098 | if (strncmp(newname, dev->name, IFNAMSIZ) == 0) { | ||
| 1099 | write_sequnlock(&devnet_rename_seq); | ||
| 1095 | return 0; | 1100 | return 0; |
| 1101 | } | ||
| 1096 | 1102 | ||
| 1097 | memcpy(oldname, dev->name, IFNAMSIZ); | 1103 | memcpy(oldname, dev->name, IFNAMSIZ); |
| 1098 | 1104 | ||
| 1099 | err = dev_get_valid_name(net, dev, newname); | 1105 | err = dev_get_valid_name(net, dev, newname); |
| 1100 | if (err < 0) | 1106 | if (err < 0) { |
| 1107 | write_sequnlock(&devnet_rename_seq); | ||
| 1101 | return err; | 1108 | return err; |
| 1109 | } | ||
| 1102 | 1110 | ||
| 1103 | rollback: | 1111 | rollback: |
| 1104 | ret = device_rename(&dev->dev, dev->name); | 1112 | ret = device_rename(&dev->dev, dev->name); |
| 1105 | if (ret) { | 1113 | if (ret) { |
| 1106 | memcpy(dev->name, oldname, IFNAMSIZ); | 1114 | memcpy(dev->name, oldname, IFNAMSIZ); |
| 1115 | write_sequnlock(&devnet_rename_seq); | ||
| 1107 | return ret; | 1116 | return ret; |
| 1108 | } | 1117 | } |
| 1109 | 1118 | ||
| 1119 | write_sequnlock(&devnet_rename_seq); | ||
| 1120 | |||
| 1110 | write_lock_bh(&dev_base_lock); | 1121 | write_lock_bh(&dev_base_lock); |
| 1111 | hlist_del_rcu(&dev->name_hlist); | 1122 | hlist_del_rcu(&dev->name_hlist); |
| 1112 | write_unlock_bh(&dev_base_lock); | 1123 | write_unlock_bh(&dev_base_lock); |
| @@ -1124,6 +1135,7 @@ rollback: | |||
| 1124 | /* err >= 0 after dev_alloc_name() or stores the first errno */ | 1135 | /* err >= 0 after dev_alloc_name() or stores the first errno */ |
| 1125 | if (err >= 0) { | 1136 | if (err >= 0) { |
| 1126 | err = ret; | 1137 | err = ret; |
| 1138 | write_seqlock(&devnet_rename_seq); | ||
| 1127 | memcpy(dev->name, oldname, IFNAMSIZ); | 1139 | memcpy(dev->name, oldname, IFNAMSIZ); |
| 1128 | goto rollback; | 1140 | goto rollback; |
| 1129 | } else { | 1141 | } else { |
| @@ -3580,7 +3592,7 @@ void napi_gro_flush(struct napi_struct *napi, bool flush_old) | |||
| 3580 | } | 3592 | } |
| 3581 | EXPORT_SYMBOL(napi_gro_flush); | 3593 | EXPORT_SYMBOL(napi_gro_flush); |
| 3582 | 3594 | ||
| 3583 | enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff *skb) | 3595 | static enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff *skb) |
| 3584 | { | 3596 | { |
| 3585 | struct sk_buff **pp = NULL; | 3597 | struct sk_buff **pp = NULL; |
| 3586 | struct packet_offload *ptype; | 3598 | struct packet_offload *ptype; |
| @@ -3671,7 +3683,6 @@ normal: | |||
| 3671 | ret = GRO_NORMAL; | 3683 | ret = GRO_NORMAL; |
| 3672 | goto pull; | 3684 | goto pull; |
| 3673 | } | 3685 | } |
| 3674 | EXPORT_SYMBOL(dev_gro_receive); | ||
| 3675 | 3686 | ||
| 3676 | static inline gro_result_t | 3687 | static inline gro_result_t |
| 3677 | __napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb) | 3688 | __napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb) |
| @@ -3698,7 +3709,7 @@ __napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb) | |||
| 3698 | return dev_gro_receive(napi, skb); | 3709 | return dev_gro_receive(napi, skb); |
| 3699 | } | 3710 | } |
| 3700 | 3711 | ||
| 3701 | gro_result_t napi_skb_finish(gro_result_t ret, struct sk_buff *skb) | 3712 | static gro_result_t napi_skb_finish(gro_result_t ret, struct sk_buff *skb) |
| 3702 | { | 3713 | { |
| 3703 | switch (ret) { | 3714 | switch (ret) { |
| 3704 | case GRO_NORMAL: | 3715 | case GRO_NORMAL: |
| @@ -3724,7 +3735,6 @@ gro_result_t napi_skb_finish(gro_result_t ret, struct sk_buff *skb) | |||
| 3724 | 3735 | ||
| 3725 | return ret; | 3736 | return ret; |
| 3726 | } | 3737 | } |
| 3727 | EXPORT_SYMBOL(napi_skb_finish); | ||
| 3728 | 3738 | ||
| 3729 | static void skb_gro_reset_offset(struct sk_buff *skb) | 3739 | static void skb_gro_reset_offset(struct sk_buff *skb) |
| 3730 | { | 3740 | { |
| @@ -3776,7 +3786,7 @@ struct sk_buff *napi_get_frags(struct napi_struct *napi) | |||
| 3776 | } | 3786 | } |
| 3777 | EXPORT_SYMBOL(napi_get_frags); | 3787 | EXPORT_SYMBOL(napi_get_frags); |
| 3778 | 3788 | ||
| 3779 | gro_result_t napi_frags_finish(struct napi_struct *napi, struct sk_buff *skb, | 3789 | static gro_result_t napi_frags_finish(struct napi_struct *napi, struct sk_buff *skb, |
| 3780 | gro_result_t ret) | 3790 | gro_result_t ret) |
| 3781 | { | 3791 | { |
| 3782 | switch (ret) { | 3792 | switch (ret) { |
| @@ -3801,7 +3811,6 @@ gro_result_t napi_frags_finish(struct napi_struct *napi, struct sk_buff *skb, | |||
| 3801 | 3811 | ||
| 3802 | return ret; | 3812 | return ret; |
| 3803 | } | 3813 | } |
| 3804 | EXPORT_SYMBOL(napi_frags_finish); | ||
| 3805 | 3814 | ||
| 3806 | static struct sk_buff *napi_frags_skb(struct napi_struct *napi) | 3815 | static struct sk_buff *napi_frags_skb(struct napi_struct *napi) |
| 3807 | { | 3816 | { |
| @@ -4148,6 +4157,7 @@ static int dev_ifname(struct net *net, struct ifreq __user *arg) | |||
| 4148 | { | 4157 | { |
| 4149 | struct net_device *dev; | 4158 | struct net_device *dev; |
| 4150 | struct ifreq ifr; | 4159 | struct ifreq ifr; |
| 4160 | unsigned seq; | ||
| 4151 | 4161 | ||
| 4152 | /* | 4162 | /* |
| 4153 | * Fetch the caller's info block. | 4163 | * Fetch the caller's info block. |
| @@ -4156,6 +4166,8 @@ static int dev_ifname(struct net *net, struct ifreq __user *arg) | |||
| 4156 | if (copy_from_user(&ifr, arg, sizeof(struct ifreq))) | 4166 | if (copy_from_user(&ifr, arg, sizeof(struct ifreq))) |
| 4157 | return -EFAULT; | 4167 | return -EFAULT; |
| 4158 | 4168 | ||
| 4169 | retry: | ||
| 4170 | seq = read_seqbegin(&devnet_rename_seq); | ||
| 4159 | rcu_read_lock(); | 4171 | rcu_read_lock(); |
| 4160 | dev = dev_get_by_index_rcu(net, ifr.ifr_ifindex); | 4172 | dev = dev_get_by_index_rcu(net, ifr.ifr_ifindex); |
| 4161 | if (!dev) { | 4173 | if (!dev) { |
| @@ -4165,6 +4177,8 @@ static int dev_ifname(struct net *net, struct ifreq __user *arg) | |||
| 4165 | 4177 | ||
| 4166 | strcpy(ifr.ifr_name, dev->name); | 4178 | strcpy(ifr.ifr_name, dev->name); |
| 4167 | rcu_read_unlock(); | 4179 | rcu_read_unlock(); |
| 4180 | if (read_seqretry(&devnet_rename_seq, seq)) | ||
| 4181 | goto retry; | ||
| 4168 | 4182 | ||
| 4169 | if (copy_to_user(arg, &ifr, sizeof(struct ifreq))) | 4183 | if (copy_to_user(arg, &ifr, sizeof(struct ifreq))) |
| 4170 | return -EFAULT; | 4184 | return -EFAULT; |
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 575a6ee89944..1868625af25e 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c | |||
| @@ -1642,7 +1642,7 @@ int rtnl_configure_link(struct net_device *dev, const struct ifinfomsg *ifm) | |||
| 1642 | } | 1642 | } |
| 1643 | EXPORT_SYMBOL(rtnl_configure_link); | 1643 | EXPORT_SYMBOL(rtnl_configure_link); |
| 1644 | 1644 | ||
| 1645 | struct net_device *rtnl_create_link(struct net *src_net, struct net *net, | 1645 | struct net_device *rtnl_create_link(struct net *net, |
| 1646 | char *ifname, const struct rtnl_link_ops *ops, struct nlattr *tb[]) | 1646 | char *ifname, const struct rtnl_link_ops *ops, struct nlattr *tb[]) |
| 1647 | { | 1647 | { |
| 1648 | int err; | 1648 | int err; |
| @@ -1840,7 +1840,7 @@ replay: | |||
| 1840 | if (IS_ERR(dest_net)) | 1840 | if (IS_ERR(dest_net)) |
| 1841 | return PTR_ERR(dest_net); | 1841 | return PTR_ERR(dest_net); |
| 1842 | 1842 | ||
| 1843 | dev = rtnl_create_link(net, dest_net, ifname, ops, tb); | 1843 | dev = rtnl_create_link(dest_net, ifname, ops, tb); |
| 1844 | if (IS_ERR(dev)) { | 1844 | if (IS_ERR(dev)) { |
| 1845 | err = PTR_ERR(dev); | 1845 | err = PTR_ERR(dev); |
| 1846 | goto out; | 1846 | goto out; |
diff --git a/net/core/sock.c b/net/core/sock.c index d4f7b58b3866..a692ef49c9bb 100644 --- a/net/core/sock.c +++ b/net/core/sock.c | |||
| @@ -505,7 +505,8 @@ struct dst_entry *sk_dst_check(struct sock *sk, u32 cookie) | |||
| 505 | } | 505 | } |
| 506 | EXPORT_SYMBOL(sk_dst_check); | 506 | EXPORT_SYMBOL(sk_dst_check); |
| 507 | 507 | ||
| 508 | static int sock_bindtodevice(struct sock *sk, char __user *optval, int optlen) | 508 | static int sock_setbindtodevice(struct sock *sk, char __user *optval, |
| 509 | int optlen) | ||
| 509 | { | 510 | { |
| 510 | int ret = -ENOPROTOOPT; | 511 | int ret = -ENOPROTOOPT; |
| 511 | #ifdef CONFIG_NETDEVICES | 512 | #ifdef CONFIG_NETDEVICES |
| @@ -562,6 +563,59 @@ out: | |||
| 562 | return ret; | 563 | return ret; |
| 563 | } | 564 | } |
| 564 | 565 | ||
| 566 | static int sock_getbindtodevice(struct sock *sk, char __user *optval, | ||
| 567 | int __user *optlen, int len) | ||
| 568 | { | ||
| 569 | int ret = -ENOPROTOOPT; | ||
| 570 | #ifdef CONFIG_NETDEVICES | ||
| 571 | struct net *net = sock_net(sk); | ||
| 572 | struct net_device *dev; | ||
| 573 | char devname[IFNAMSIZ]; | ||
| 574 | unsigned seq; | ||
| 575 | |||
| 576 | if (sk->sk_bound_dev_if == 0) { | ||
| 577 | len = 0; | ||
| 578 | goto zero; | ||
| 579 | } | ||
| 580 | |||
| 581 | ret = -EINVAL; | ||
| 582 | if (len < IFNAMSIZ) | ||
| 583 | goto out; | ||
| 584 | |||
| 585 | retry: | ||
| 586 | seq = read_seqbegin(&devnet_rename_seq); | ||
| 587 | rcu_read_lock(); | ||
| 588 | dev = dev_get_by_index_rcu(net, sk->sk_bound_dev_if); | ||
| 589 | ret = -ENODEV; | ||
| 590 | if (!dev) { | ||
| 591 | rcu_read_unlock(); | ||
| 592 | goto out; | ||
| 593 | } | ||
| 594 | |||
| 595 | strcpy(devname, dev->name); | ||
| 596 | rcu_read_unlock(); | ||
| 597 | if (read_seqretry(&devnet_rename_seq, seq)) | ||
| 598 | goto retry; | ||
| 599 | |||
| 600 | len = strlen(devname) + 1; | ||
| 601 | |||
| 602 | ret = -EFAULT; | ||
| 603 | if (copy_to_user(optval, devname, len)) | ||
| 604 | goto out; | ||
| 605 | |||
| 606 | zero: | ||
| 607 | ret = -EFAULT; | ||
| 608 | if (put_user(len, optlen)) | ||
| 609 | goto out; | ||
| 610 | |||
| 611 | ret = 0; | ||
| 612 | |||
| 613 | out: | ||
| 614 | #endif | ||
| 615 | |||
| 616 | return ret; | ||
| 617 | } | ||
| 618 | |||
| 565 | static inline void sock_valbool_flag(struct sock *sk, int bit, int valbool) | 619 | static inline void sock_valbool_flag(struct sock *sk, int bit, int valbool) |
| 566 | { | 620 | { |
| 567 | if (valbool) | 621 | if (valbool) |
| @@ -589,7 +643,7 @@ int sock_setsockopt(struct socket *sock, int level, int optname, | |||
| 589 | */ | 643 | */ |
| 590 | 644 | ||
| 591 | if (optname == SO_BINDTODEVICE) | 645 | if (optname == SO_BINDTODEVICE) |
| 592 | return sock_bindtodevice(sk, optval, optlen); | 646 | return sock_setbindtodevice(sk, optval, optlen); |
| 593 | 647 | ||
| 594 | if (optlen < sizeof(int)) | 648 | if (optlen < sizeof(int)) |
| 595 | return -EINVAL; | 649 | return -EINVAL; |
| @@ -1075,15 +1129,17 @@ int sock_getsockopt(struct socket *sock, int level, int optname, | |||
| 1075 | case SO_NOFCS: | 1129 | case SO_NOFCS: |
| 1076 | v.val = sock_flag(sk, SOCK_NOFCS); | 1130 | v.val = sock_flag(sk, SOCK_NOFCS); |
| 1077 | break; | 1131 | break; |
| 1132 | |||
| 1078 | case SO_BINDTODEVICE: | 1133 | case SO_BINDTODEVICE: |
| 1079 | v.val = sk->sk_bound_dev_if; | 1134 | return sock_getbindtodevice(sk, optval, optlen, len); |
| 1080 | break; | 1135 | |
| 1081 | case SO_GET_FILTER: | 1136 | case SO_GET_FILTER: |
| 1082 | len = sk_get_filter(sk, (struct sock_filter __user *)optval, len); | 1137 | len = sk_get_filter(sk, (struct sock_filter __user *)optval, len); |
| 1083 | if (len < 0) | 1138 | if (len < 0) |
| 1084 | return len; | 1139 | return len; |
| 1085 | 1140 | ||
| 1086 | goto lenout; | 1141 | goto lenout; |
| 1142 | |||
| 1087 | default: | 1143 | default: |
| 1088 | return -ENOPROTOOPT; | 1144 | return -ENOPROTOOPT; |
| 1089 | } | 1145 | } |
diff --git a/net/ieee802154/6lowpan.c b/net/ieee802154/6lowpan.c index 6d42c17af96b..f651da60f161 100644 --- a/net/ieee802154/6lowpan.c +++ b/net/ieee802154/6lowpan.c | |||
| @@ -1047,7 +1047,8 @@ static netdev_tx_t lowpan_xmit(struct sk_buff *skb, struct net_device *dev) | |||
| 1047 | goto error; | 1047 | goto error; |
| 1048 | } | 1048 | } |
| 1049 | 1049 | ||
| 1050 | if (skb->len <= IEEE802154_MTU) { | 1050 | /* Send directly if less than the MTU minus the 2 checksum bytes. */ |
| 1051 | if (skb->len <= IEEE802154_MTU - IEEE802154_MFR_SIZE) { | ||
| 1051 | err = dev_queue_xmit(skb); | 1052 | err = dev_queue_xmit(skb); |
| 1052 | goto out; | 1053 | goto out; |
| 1053 | } | 1054 | } |
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index f2eccd531746..17ff9fd7cdda 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c | |||
| @@ -257,7 +257,8 @@ static inline bool icmpv4_xrlim_allow(struct net *net, struct rtable *rt, | |||
| 257 | struct inet_peer *peer = inet_getpeer_v4(net->ipv4.peers, fl4->daddr, 1); | 257 | struct inet_peer *peer = inet_getpeer_v4(net->ipv4.peers, fl4->daddr, 1); |
| 258 | rc = inet_peer_xrlim_allow(peer, | 258 | rc = inet_peer_xrlim_allow(peer, |
| 259 | net->ipv4.sysctl_icmp_ratelimit); | 259 | net->ipv4.sysctl_icmp_ratelimit); |
| 260 | inet_putpeer(peer); | 260 | if (peer) |
| 261 | inet_putpeer(peer); | ||
| 261 | } | 262 | } |
| 262 | out: | 263 | out: |
| 263 | return rc; | 264 | return rc; |
diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c index 7880af970208..fa3ae8148710 100644 --- a/net/ipv4/inet_hashtables.c +++ b/net/ipv4/inet_hashtables.c | |||
| @@ -237,12 +237,14 @@ struct sock *__inet_lookup_established(struct net *net, | |||
| 237 | rcu_read_lock(); | 237 | rcu_read_lock(); |
| 238 | begin: | 238 | begin: |
| 239 | sk_nulls_for_each_rcu(sk, node, &head->chain) { | 239 | sk_nulls_for_each_rcu(sk, node, &head->chain) { |
| 240 | if (INET_MATCH(sk, net, hash, acookie, | 240 | if (sk->sk_hash != hash) |
| 241 | saddr, daddr, ports, dif)) { | 241 | continue; |
| 242 | if (likely(INET_MATCH(sk, net, acookie, | ||
| 243 | saddr, daddr, ports, dif))) { | ||
| 242 | if (unlikely(!atomic_inc_not_zero(&sk->sk_refcnt))) | 244 | if (unlikely(!atomic_inc_not_zero(&sk->sk_refcnt))) |
| 243 | goto begintw; | 245 | goto begintw; |
| 244 | if (unlikely(!INET_MATCH(sk, net, hash, acookie, | 246 | if (unlikely(!INET_MATCH(sk, net, acookie, |
| 245 | saddr, daddr, ports, dif))) { | 247 | saddr, daddr, ports, dif))) { |
| 246 | sock_put(sk); | 248 | sock_put(sk); |
| 247 | goto begin; | 249 | goto begin; |
| 248 | } | 250 | } |
| @@ -260,14 +262,18 @@ begin: | |||
| 260 | begintw: | 262 | begintw: |
| 261 | /* Must check for a TIME_WAIT'er before going to listener hash. */ | 263 | /* Must check for a TIME_WAIT'er before going to listener hash. */ |
| 262 | sk_nulls_for_each_rcu(sk, node, &head->twchain) { | 264 | sk_nulls_for_each_rcu(sk, node, &head->twchain) { |
| 263 | if (INET_TW_MATCH(sk, net, hash, acookie, | 265 | if (sk->sk_hash != hash) |
| 264 | saddr, daddr, ports, dif)) { | 266 | continue; |
| 267 | if (likely(INET_TW_MATCH(sk, net, acookie, | ||
| 268 | saddr, daddr, ports, | ||
| 269 | dif))) { | ||
| 265 | if (unlikely(!atomic_inc_not_zero(&sk->sk_refcnt))) { | 270 | if (unlikely(!atomic_inc_not_zero(&sk->sk_refcnt))) { |
| 266 | sk = NULL; | 271 | sk = NULL; |
| 267 | goto out; | 272 | goto out; |
| 268 | } | 273 | } |
| 269 | if (unlikely(!INET_TW_MATCH(sk, net, hash, acookie, | 274 | if (unlikely(!INET_TW_MATCH(sk, net, acookie, |
| 270 | saddr, daddr, ports, dif))) { | 275 | saddr, daddr, ports, |
| 276 | dif))) { | ||
| 271 | sock_put(sk); | 277 | sock_put(sk); |
| 272 | goto begintw; | 278 | goto begintw; |
| 273 | } | 279 | } |
| @@ -314,10 +320,12 @@ static int __inet_check_established(struct inet_timewait_death_row *death_row, | |||
| 314 | 320 | ||
| 315 | /* Check TIME-WAIT sockets first. */ | 321 | /* Check TIME-WAIT sockets first. */ |
| 316 | sk_nulls_for_each(sk2, node, &head->twchain) { | 322 | sk_nulls_for_each(sk2, node, &head->twchain) { |
| 317 | tw = inet_twsk(sk2); | 323 | if (sk2->sk_hash != hash) |
| 324 | continue; | ||
| 318 | 325 | ||
| 319 | if (INET_TW_MATCH(sk2, net, hash, acookie, | 326 | if (likely(INET_TW_MATCH(sk2, net, acookie, |
| 320 | saddr, daddr, ports, dif)) { | 327 | saddr, daddr, ports, dif))) { |
| 328 | tw = inet_twsk(sk2); | ||
| 321 | if (twsk_unique(sk, sk2, twp)) | 329 | if (twsk_unique(sk, sk2, twp)) |
| 322 | goto unique; | 330 | goto unique; |
| 323 | else | 331 | else |
| @@ -328,8 +336,10 @@ static int __inet_check_established(struct inet_timewait_death_row *death_row, | |||
| 328 | 336 | ||
| 329 | /* And established part... */ | 337 | /* And established part... */ |
| 330 | sk_nulls_for_each(sk2, node, &head->chain) { | 338 | sk_nulls_for_each(sk2, node, &head->chain) { |
| 331 | if (INET_MATCH(sk2, net, hash, acookie, | 339 | if (sk2->sk_hash != hash) |
| 332 | saddr, daddr, ports, dif)) | 340 | continue; |
| 341 | if (likely(INET_MATCH(sk2, net, acookie, | ||
| 342 | saddr, daddr, ports, dif))) | ||
| 333 | goto not_unique; | 343 | goto not_unique; |
| 334 | } | 344 | } |
| 335 | 345 | ||
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index fc09ef936636..58e4160fdcee 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c | |||
| @@ -1323,6 +1323,10 @@ int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsi | |||
| 1323 | if (get_user(v, (u32 __user *)optval)) | 1323 | if (get_user(v, (u32 __user *)optval)) |
| 1324 | return -EFAULT; | 1324 | return -EFAULT; |
| 1325 | 1325 | ||
| 1326 | /* "pimreg%u" should not exceed 16 bytes (IFNAMSIZ) */ | ||
| 1327 | if (v != RT_TABLE_DEFAULT && v >= 1000000000) | ||
| 1328 | return -EINVAL; | ||
| 1329 | |||
| 1326 | rtnl_lock(); | 1330 | rtnl_lock(); |
| 1327 | ret = 0; | 1331 | ret = 0; |
| 1328 | if (sk == rtnl_dereference(mrt->mroute_sk)) { | 1332 | if (sk == rtnl_dereference(mrt->mroute_sk)) { |
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index e6eace1c2bdb..1aca02c9911e 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c | |||
| @@ -3590,8 +3590,7 @@ void __init tcp_init(void) | |||
| 3590 | alloc_large_system_hash("TCP established", | 3590 | alloc_large_system_hash("TCP established", |
| 3591 | sizeof(struct inet_ehash_bucket), | 3591 | sizeof(struct inet_ehash_bucket), |
| 3592 | thash_entries, | 3592 | thash_entries, |
| 3593 | (totalram_pages >= 128 * 1024) ? | 3593 | 17, /* one slot per 128 KB of memory */ |
| 3594 | 13 : 15, | ||
| 3595 | 0, | 3594 | 0, |
| 3596 | NULL, | 3595 | NULL, |
| 3597 | &tcp_hashinfo.ehash_mask, | 3596 | &tcp_hashinfo.ehash_mask, |
| @@ -3607,8 +3606,7 @@ void __init tcp_init(void) | |||
| 3607 | alloc_large_system_hash("TCP bind", | 3606 | alloc_large_system_hash("TCP bind", |
| 3608 | sizeof(struct inet_bind_hashbucket), | 3607 | sizeof(struct inet_bind_hashbucket), |
| 3609 | tcp_hashinfo.ehash_mask + 1, | 3608 | tcp_hashinfo.ehash_mask + 1, |
| 3610 | (totalram_pages >= 128 * 1024) ? | 3609 | 17, /* one slot per 128 KB of memory */ |
| 3611 | 13 : 15, | ||
| 3612 | 0, | 3610 | 0, |
| 3613 | &tcp_hashinfo.bhash_size, | 3611 | &tcp_hashinfo.bhash_size, |
| 3614 | NULL, | 3612 | NULL, |
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index fc0e13ad6337..4b644f656c41 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
| @@ -3150,8 +3150,7 @@ static void addrconf_dad_completed(struct inet6_ifaddr *ifp) | |||
| 3150 | router advertisements, start sending router solicitations. | 3150 | router advertisements, start sending router solicitations. |
| 3151 | */ | 3151 | */ |
| 3152 | 3152 | ||
| 3153 | if (((ifp->idev->cnf.accept_ra == 1 && !ifp->idev->cnf.forwarding) || | 3153 | if (ipv6_accept_ra(ifp->idev) && |
| 3154 | ifp->idev->cnf.accept_ra == 2) && | ||
| 3155 | ifp->idev->cnf.rtr_solicits > 0 && | 3154 | ifp->idev->cnf.rtr_solicits > 0 && |
| 3156 | (dev->flags&IFF_LOOPBACK) == 0 && | 3155 | (dev->flags&IFF_LOOPBACK) == 0 && |
| 3157 | (ipv6_addr_type(&ifp->addr) & IPV6_ADDR_LINKLOCAL)) { | 3156 | (ipv6_addr_type(&ifp->addr) & IPV6_ADDR_LINKLOCAL)) { |
diff --git a/net/ipv6/exthdrs_core.c b/net/ipv6/exthdrs_core.c index e7d756e19d1d..c5e83fae4df4 100644 --- a/net/ipv6/exthdrs_core.c +++ b/net/ipv6/exthdrs_core.c | |||
| @@ -155,3 +155,127 @@ int ipv6_find_tlv(struct sk_buff *skb, int offset, int type) | |||
| 155 | return -1; | 155 | return -1; |
| 156 | } | 156 | } |
| 157 | EXPORT_SYMBOL_GPL(ipv6_find_tlv); | 157 | EXPORT_SYMBOL_GPL(ipv6_find_tlv); |
| 158 | |||
| 159 | /* | ||
| 160 | * find the offset to specified header or the protocol number of last header | ||
| 161 | * if target < 0. "last header" is transport protocol header, ESP, or | ||
| 162 | * "No next header". | ||
| 163 | * | ||
| 164 | * Note that *offset is used as input/output parameter. an if it is not zero, | ||
| 165 | * then it must be a valid offset to an inner IPv6 header. This can be used | ||
| 166 | * to explore inner IPv6 header, eg. ICMPv6 error messages. | ||
| 167 | * | ||
| 168 | * If target header is found, its offset is set in *offset and return protocol | ||
| 169 | * number. Otherwise, return -1. | ||
| 170 | * | ||
| 171 | * If the first fragment doesn't contain the final protocol header or | ||
| 172 | * NEXTHDR_NONE it is considered invalid. | ||
| 173 | * | ||
| 174 | * Note that non-1st fragment is special case that "the protocol number | ||
| 175 | * of last header" is "next header" field in Fragment header. In this case, | ||
| 176 | * *offset is meaningless and fragment offset is stored in *fragoff if fragoff | ||
| 177 | * isn't NULL. | ||
| 178 | * | ||
| 179 | * if flags is not NULL and it's a fragment, then the frag flag | ||
| 180 | * IP6_FH_F_FRAG will be set. If it's an AH header, the | ||
| 181 | * IP6_FH_F_AUTH flag is set and target < 0, then this function will | ||
| 182 | * stop at the AH header. If IP6_FH_F_SKIP_RH flag was passed, then this | ||
| 183 | * function will skip all those routing headers, where segements_left was 0. | ||
| 184 | */ | ||
| 185 | int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset, | ||
| 186 | int target, unsigned short *fragoff, int *flags) | ||
| 187 | { | ||
| 188 | unsigned int start = skb_network_offset(skb) + sizeof(struct ipv6hdr); | ||
| 189 | u8 nexthdr = ipv6_hdr(skb)->nexthdr; | ||
| 190 | unsigned int len; | ||
| 191 | bool found; | ||
| 192 | |||
| 193 | if (fragoff) | ||
| 194 | *fragoff = 0; | ||
| 195 | |||
| 196 | if (*offset) { | ||
| 197 | struct ipv6hdr _ip6, *ip6; | ||
| 198 | |||
| 199 | ip6 = skb_header_pointer(skb, *offset, sizeof(_ip6), &_ip6); | ||
| 200 | if (!ip6 || (ip6->version != 6)) { | ||
| 201 | printk(KERN_ERR "IPv6 header not found\n"); | ||
| 202 | return -EBADMSG; | ||
| 203 | } | ||
| 204 | start = *offset + sizeof(struct ipv6hdr); | ||
| 205 | nexthdr = ip6->nexthdr; | ||
| 206 | } | ||
| 207 | len = skb->len - start; | ||
| 208 | |||
| 209 | do { | ||
| 210 | struct ipv6_opt_hdr _hdr, *hp; | ||
| 211 | unsigned int hdrlen; | ||
| 212 | found = (nexthdr == target); | ||
| 213 | |||
| 214 | if ((!ipv6_ext_hdr(nexthdr)) || nexthdr == NEXTHDR_NONE) { | ||
| 215 | if (target < 0) | ||
| 216 | break; | ||
| 217 | return -ENOENT; | ||
| 218 | } | ||
| 219 | |||
| 220 | hp = skb_header_pointer(skb, start, sizeof(_hdr), &_hdr); | ||
| 221 | if (hp == NULL) | ||
| 222 | return -EBADMSG; | ||
| 223 | |||
| 224 | if (nexthdr == NEXTHDR_ROUTING) { | ||
| 225 | struct ipv6_rt_hdr _rh, *rh; | ||
| 226 | |||
| 227 | rh = skb_header_pointer(skb, start, sizeof(_rh), | ||
| 228 | &_rh); | ||
| 229 | if (rh == NULL) | ||
| 230 | return -EBADMSG; | ||
| 231 | |||
| 232 | if (flags && (*flags & IP6_FH_F_SKIP_RH) && | ||
| 233 | rh->segments_left == 0) | ||
| 234 | found = false; | ||
| 235 | } | ||
| 236 | |||
| 237 | if (nexthdr == NEXTHDR_FRAGMENT) { | ||
| 238 | unsigned short _frag_off; | ||
| 239 | __be16 *fp; | ||
| 240 | |||
| 241 | if (flags) /* Indicate that this is a fragment */ | ||
| 242 | *flags |= IP6_FH_F_FRAG; | ||
| 243 | fp = skb_header_pointer(skb, | ||
| 244 | start+offsetof(struct frag_hdr, | ||
| 245 | frag_off), | ||
| 246 | sizeof(_frag_off), | ||
| 247 | &_frag_off); | ||
| 248 | if (fp == NULL) | ||
| 249 | return -EBADMSG; | ||
| 250 | |||
| 251 | _frag_off = ntohs(*fp) & ~0x7; | ||
| 252 | if (_frag_off) { | ||
| 253 | if (target < 0 && | ||
| 254 | ((!ipv6_ext_hdr(hp->nexthdr)) || | ||
| 255 | hp->nexthdr == NEXTHDR_NONE)) { | ||
| 256 | if (fragoff) | ||
| 257 | *fragoff = _frag_off; | ||
| 258 | return hp->nexthdr; | ||
| 259 | } | ||
| 260 | return -ENOENT; | ||
| 261 | } | ||
| 262 | hdrlen = 8; | ||
| 263 | } else if (nexthdr == NEXTHDR_AUTH) { | ||
| 264 | if (flags && (*flags & IP6_FH_F_AUTH) && (target < 0)) | ||
| 265 | break; | ||
| 266 | hdrlen = (hp->hdrlen + 2) << 2; | ||
| 267 | } else | ||
| 268 | hdrlen = ipv6_optlen(hp); | ||
| 269 | |||
| 270 | if (!found) { | ||
| 271 | nexthdr = hp->nexthdr; | ||
| 272 | len -= hdrlen; | ||
| 273 | start += hdrlen; | ||
| 274 | } | ||
| 275 | } while (!found); | ||
| 276 | |||
| 277 | *offset = start; | ||
| 278 | return nexthdr; | ||
| 279 | } | ||
| 280 | EXPORT_SYMBOL(ipv6_find_hdr); | ||
| 281 | |||
diff --git a/net/ipv6/inet6_hashtables.c b/net/ipv6/inet6_hashtables.c index 73f1a00a96af..dea17fd28e50 100644 --- a/net/ipv6/inet6_hashtables.c +++ b/net/ipv6/inet6_hashtables.c | |||
| @@ -87,11 +87,13 @@ struct sock *__inet6_lookup_established(struct net *net, | |||
| 87 | rcu_read_lock(); | 87 | rcu_read_lock(); |
| 88 | begin: | 88 | begin: |
| 89 | sk_nulls_for_each_rcu(sk, node, &head->chain) { | 89 | sk_nulls_for_each_rcu(sk, node, &head->chain) { |
| 90 | /* For IPV6 do the cheaper port and family tests first. */ | 90 | if (sk->sk_hash != hash) |
| 91 | if (INET6_MATCH(sk, net, hash, saddr, daddr, ports, dif)) { | 91 | continue; |
| 92 | if (likely(INET6_MATCH(sk, net, saddr, daddr, ports, dif))) { | ||
| 92 | if (unlikely(!atomic_inc_not_zero(&sk->sk_refcnt))) | 93 | if (unlikely(!atomic_inc_not_zero(&sk->sk_refcnt))) |
| 93 | goto begintw; | 94 | goto begintw; |
| 94 | if (!INET6_MATCH(sk, net, hash, saddr, daddr, ports, dif)) { | 95 | if (unlikely(!INET6_MATCH(sk, net, saddr, daddr, |
| 96 | ports, dif))) { | ||
| 95 | sock_put(sk); | 97 | sock_put(sk); |
| 96 | goto begin; | 98 | goto begin; |
| 97 | } | 99 | } |
| @@ -104,12 +106,16 @@ begin: | |||
| 104 | begintw: | 106 | begintw: |
| 105 | /* Must check for a TIME_WAIT'er before going to listener hash. */ | 107 | /* Must check for a TIME_WAIT'er before going to listener hash. */ |
| 106 | sk_nulls_for_each_rcu(sk, node, &head->twchain) { | 108 | sk_nulls_for_each_rcu(sk, node, &head->twchain) { |
| 107 | if (INET6_TW_MATCH(sk, net, hash, saddr, daddr, ports, dif)) { | 109 | if (sk->sk_hash != hash) |
| 110 | continue; | ||
| 111 | if (likely(INET6_TW_MATCH(sk, net, saddr, daddr, | ||
| 112 | ports, dif))) { | ||
| 108 | if (unlikely(!atomic_inc_not_zero(&sk->sk_refcnt))) { | 113 | if (unlikely(!atomic_inc_not_zero(&sk->sk_refcnt))) { |
| 109 | sk = NULL; | 114 | sk = NULL; |
| 110 | goto out; | 115 | goto out; |
| 111 | } | 116 | } |
| 112 | if (!INET6_TW_MATCH(sk, net, hash, saddr, daddr, ports, dif)) { | 117 | if (unlikely(!INET6_TW_MATCH(sk, net, saddr, daddr, |
| 118 | ports, dif))) { | ||
| 113 | sock_put(sk); | 119 | sock_put(sk); |
| 114 | goto begintw; | 120 | goto begintw; |
| 115 | } | 121 | } |
| @@ -236,9 +242,12 @@ static int __inet6_check_established(struct inet_timewait_death_row *death_row, | |||
| 236 | 242 | ||
| 237 | /* Check TIME-WAIT sockets first. */ | 243 | /* Check TIME-WAIT sockets first. */ |
| 238 | sk_nulls_for_each(sk2, node, &head->twchain) { | 244 | sk_nulls_for_each(sk2, node, &head->twchain) { |
| 239 | tw = inet_twsk(sk2); | 245 | if (sk2->sk_hash != hash) |
| 246 | continue; | ||
| 240 | 247 | ||
| 241 | if (INET6_TW_MATCH(sk2, net, hash, saddr, daddr, ports, dif)) { | 248 | if (likely(INET6_TW_MATCH(sk2, net, saddr, daddr, |
| 249 | ports, dif))) { | ||
| 250 | tw = inet_twsk(sk2); | ||
| 242 | if (twsk_unique(sk, sk2, twp)) | 251 | if (twsk_unique(sk, sk2, twp)) |
| 243 | goto unique; | 252 | goto unique; |
| 244 | else | 253 | else |
| @@ -249,7 +258,9 @@ static int __inet6_check_established(struct inet_timewait_death_row *death_row, | |||
| 249 | 258 | ||
| 250 | /* And established part... */ | 259 | /* And established part... */ |
| 251 | sk_nulls_for_each(sk2, node, &head->chain) { | 260 | sk_nulls_for_each(sk2, node, &head->chain) { |
| 252 | if (INET6_MATCH(sk2, net, hash, saddr, daddr, ports, dif)) | 261 | if (sk2->sk_hash != hash) |
| 262 | continue; | ||
| 263 | if (likely(INET6_MATCH(sk2, net, saddr, daddr, ports, dif))) | ||
| 253 | goto not_unique; | 264 | goto not_unique; |
| 254 | } | 265 | } |
| 255 | 266 | ||
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index fb828e9fe8e0..a14f28b280f5 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c | |||
| @@ -74,6 +74,10 @@ MODULE_ALIAS_NETDEV("ip6tnl0"); | |||
| 74 | #define HASH_SIZE_SHIFT 5 | 74 | #define HASH_SIZE_SHIFT 5 |
| 75 | #define HASH_SIZE (1 << HASH_SIZE_SHIFT) | 75 | #define HASH_SIZE (1 << HASH_SIZE_SHIFT) |
| 76 | 76 | ||
| 77 | static bool log_ecn_error = true; | ||
| 78 | module_param(log_ecn_error, bool, 0644); | ||
| 79 | MODULE_PARM_DESC(log_ecn_error, "Log packets received with corrupted ECN"); | ||
| 80 | |||
| 77 | static u32 HASH(const struct in6_addr *addr1, const struct in6_addr *addr2) | 81 | static u32 HASH(const struct in6_addr *addr1, const struct in6_addr *addr2) |
| 78 | { | 82 | { |
| 79 | u32 hash = ipv6_addr_hash(addr1) ^ ipv6_addr_hash(addr2); | 83 | u32 hash = ipv6_addr_hash(addr1) ^ ipv6_addr_hash(addr2); |
| @@ -683,28 +687,26 @@ ip6ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
| 683 | return 0; | 687 | return 0; |
| 684 | } | 688 | } |
| 685 | 689 | ||
| 686 | static void ip4ip6_dscp_ecn_decapsulate(const struct ip6_tnl *t, | 690 | static int ip4ip6_dscp_ecn_decapsulate(const struct ip6_tnl *t, |
| 687 | const struct ipv6hdr *ipv6h, | 691 | const struct ipv6hdr *ipv6h, |
| 688 | struct sk_buff *skb) | 692 | struct sk_buff *skb) |
| 689 | { | 693 | { |
| 690 | __u8 dsfield = ipv6_get_dsfield(ipv6h) & ~INET_ECN_MASK; | 694 | __u8 dsfield = ipv6_get_dsfield(ipv6h) & ~INET_ECN_MASK; |
| 691 | 695 | ||
| 692 | if (t->parms.flags & IP6_TNL_F_RCV_DSCP_COPY) | 696 | if (t->parms.flags & IP6_TNL_F_RCV_DSCP_COPY) |
| 693 | ipv4_change_dsfield(ip_hdr(skb), INET_ECN_MASK, dsfield); | 697 | ipv4_change_dsfield(ip_hdr(skb), INET_ECN_MASK, dsfield); |
| 694 | 698 | ||
| 695 | if (INET_ECN_is_ce(dsfield)) | 699 | return IP6_ECN_decapsulate(ipv6h, skb); |
| 696 | IP_ECN_set_ce(ip_hdr(skb)); | ||
| 697 | } | 700 | } |
| 698 | 701 | ||
| 699 | static void ip6ip6_dscp_ecn_decapsulate(const struct ip6_tnl *t, | 702 | static int ip6ip6_dscp_ecn_decapsulate(const struct ip6_tnl *t, |
| 700 | const struct ipv6hdr *ipv6h, | 703 | const struct ipv6hdr *ipv6h, |
| 701 | struct sk_buff *skb) | 704 | struct sk_buff *skb) |
| 702 | { | 705 | { |
| 703 | if (t->parms.flags & IP6_TNL_F_RCV_DSCP_COPY) | 706 | if (t->parms.flags & IP6_TNL_F_RCV_DSCP_COPY) |
| 704 | ipv6_copy_dscp(ipv6_get_dsfield(ipv6h), ipv6_hdr(skb)); | 707 | ipv6_copy_dscp(ipv6_get_dsfield(ipv6h), ipv6_hdr(skb)); |
| 705 | 708 | ||
| 706 | if (INET_ECN_is_ce(ipv6_get_dsfield(ipv6h))) | 709 | return IP6_ECN_decapsulate(ipv6h, skb); |
| 707 | IP6_ECN_set_ce(ipv6_hdr(skb)); | ||
| 708 | } | 710 | } |
| 709 | 711 | ||
| 710 | __u32 ip6_tnl_get_cap(struct ip6_tnl *t, | 712 | __u32 ip6_tnl_get_cap(struct ip6_tnl *t, |
| @@ -768,12 +770,13 @@ EXPORT_SYMBOL_GPL(ip6_tnl_rcv_ctl); | |||
| 768 | 770 | ||
| 769 | static int ip6_tnl_rcv(struct sk_buff *skb, __u16 protocol, | 771 | static int ip6_tnl_rcv(struct sk_buff *skb, __u16 protocol, |
| 770 | __u8 ipproto, | 772 | __u8 ipproto, |
| 771 | void (*dscp_ecn_decapsulate)(const struct ip6_tnl *t, | 773 | int (*dscp_ecn_decapsulate)(const struct ip6_tnl *t, |
| 772 | const struct ipv6hdr *ipv6h, | 774 | const struct ipv6hdr *ipv6h, |
| 773 | struct sk_buff *skb)) | 775 | struct sk_buff *skb)) |
| 774 | { | 776 | { |
| 775 | struct ip6_tnl *t; | 777 | struct ip6_tnl *t; |
| 776 | const struct ipv6hdr *ipv6h = ipv6_hdr(skb); | 778 | const struct ipv6hdr *ipv6h = ipv6_hdr(skb); |
| 779 | int err; | ||
| 777 | 780 | ||
| 778 | rcu_read_lock(); | 781 | rcu_read_lock(); |
| 779 | 782 | ||
| @@ -803,14 +806,26 @@ static int ip6_tnl_rcv(struct sk_buff *skb, __u16 protocol, | |||
| 803 | skb->pkt_type = PACKET_HOST; | 806 | skb->pkt_type = PACKET_HOST; |
| 804 | memset(skb->cb, 0, sizeof(struct inet6_skb_parm)); | 807 | memset(skb->cb, 0, sizeof(struct inet6_skb_parm)); |
| 805 | 808 | ||
| 809 | __skb_tunnel_rx(skb, t->dev); | ||
| 810 | |||
| 811 | err = dscp_ecn_decapsulate(t, ipv6h, skb); | ||
| 812 | if (unlikely(err)) { | ||
| 813 | if (log_ecn_error) | ||
| 814 | net_info_ratelimited("non-ECT from %pI6 with dsfield=%#x\n", | ||
| 815 | &ipv6h->saddr, | ||
| 816 | ipv6_get_dsfield(ipv6h)); | ||
| 817 | if (err > 1) { | ||
| 818 | ++t->dev->stats.rx_frame_errors; | ||
| 819 | ++t->dev->stats.rx_errors; | ||
| 820 | rcu_read_unlock(); | ||
| 821 | goto discard; | ||
| 822 | } | ||
| 823 | } | ||
| 824 | |||
| 806 | tstats = this_cpu_ptr(t->dev->tstats); | 825 | tstats = this_cpu_ptr(t->dev->tstats); |
| 807 | tstats->rx_packets++; | 826 | tstats->rx_packets++; |
| 808 | tstats->rx_bytes += skb->len; | 827 | tstats->rx_bytes += skb->len; |
| 809 | 828 | ||
| 810 | __skb_tunnel_rx(skb, t->dev); | ||
| 811 | |||
| 812 | dscp_ecn_decapsulate(t, ipv6h, skb); | ||
| 813 | |||
| 814 | netif_rx(skb); | 829 | netif_rx(skb); |
| 815 | 830 | ||
| 816 | rcu_read_unlock(); | 831 | rcu_read_unlock(); |
diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index 79bb49061ef6..926ea544f499 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c | |||
| @@ -1646,6 +1646,9 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, uns | |||
| 1646 | case MRT6_ASSERT: | 1646 | case MRT6_ASSERT: |
| 1647 | { | 1647 | { |
| 1648 | int v; | 1648 | int v; |
| 1649 | |||
| 1650 | if (optlen != sizeof(v)) | ||
| 1651 | return -EINVAL; | ||
| 1649 | if (get_user(v, (int __user *)optval)) | 1652 | if (get_user(v, (int __user *)optval)) |
| 1650 | return -EFAULT; | 1653 | return -EFAULT; |
| 1651 | mrt->mroute_do_assert = v; | 1654 | mrt->mroute_do_assert = v; |
| @@ -1656,6 +1659,9 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, uns | |||
| 1656 | case MRT6_PIM: | 1659 | case MRT6_PIM: |
| 1657 | { | 1660 | { |
| 1658 | int v; | 1661 | int v; |
| 1662 | |||
| 1663 | if (optlen != sizeof(v)) | ||
| 1664 | return -EINVAL; | ||
| 1659 | if (get_user(v, (int __user *)optval)) | 1665 | if (get_user(v, (int __user *)optval)) |
| 1660 | return -EFAULT; | 1666 | return -EFAULT; |
| 1661 | v = !!v; | 1667 | v = !!v; |
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index f41853bca428..cf43b6550f5b 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c | |||
| @@ -1032,18 +1032,6 @@ errout: | |||
| 1032 | rtnl_set_sk_err(net, RTNLGRP_ND_USEROPT, err); | 1032 | rtnl_set_sk_err(net, RTNLGRP_ND_USEROPT, err); |
| 1033 | } | 1033 | } |
| 1034 | 1034 | ||
| 1035 | static inline int accept_ra(struct inet6_dev *in6_dev) | ||
| 1036 | { | ||
| 1037 | /* | ||
| 1038 | * If forwarding is enabled, RA are not accepted unless the special | ||
| 1039 | * hybrid mode (accept_ra=2) is enabled. | ||
| 1040 | */ | ||
| 1041 | if (in6_dev->cnf.forwarding && in6_dev->cnf.accept_ra < 2) | ||
| 1042 | return 0; | ||
| 1043 | |||
| 1044 | return in6_dev->cnf.accept_ra; | ||
| 1045 | } | ||
| 1046 | |||
| 1047 | static void ndisc_router_discovery(struct sk_buff *skb) | 1035 | static void ndisc_router_discovery(struct sk_buff *skb) |
| 1048 | { | 1036 | { |
| 1049 | struct ra_msg *ra_msg = (struct ra_msg *)skb_transport_header(skb); | 1037 | struct ra_msg *ra_msg = (struct ra_msg *)skb_transport_header(skb); |
| @@ -1091,7 +1079,7 @@ static void ndisc_router_discovery(struct sk_buff *skb) | |||
| 1091 | return; | 1079 | return; |
| 1092 | } | 1080 | } |
| 1093 | 1081 | ||
| 1094 | if (!accept_ra(in6_dev)) | 1082 | if (!ipv6_accept_ra(in6_dev)) |
| 1095 | goto skip_linkparms; | 1083 | goto skip_linkparms; |
| 1096 | 1084 | ||
| 1097 | #ifdef CONFIG_IPV6_NDISC_NODETYPE | 1085 | #ifdef CONFIG_IPV6_NDISC_NODETYPE |
| @@ -1247,7 +1235,7 @@ skip_linkparms: | |||
| 1247 | NEIGH_UPDATE_F_ISROUTER); | 1235 | NEIGH_UPDATE_F_ISROUTER); |
| 1248 | } | 1236 | } |
| 1249 | 1237 | ||
| 1250 | if (!accept_ra(in6_dev)) | 1238 | if (!ipv6_accept_ra(in6_dev)) |
| 1251 | goto out; | 1239 | goto out; |
| 1252 | 1240 | ||
| 1253 | #ifdef CONFIG_IPV6_ROUTE_INFO | 1241 | #ifdef CONFIG_IPV6_ROUTE_INFO |
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 74cadd0719a5..125a90d6a795 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c | |||
| @@ -2271,112 +2271,9 @@ static void __exit ip6_tables_fini(void) | |||
| 2271 | unregister_pernet_subsys(&ip6_tables_net_ops); | 2271 | unregister_pernet_subsys(&ip6_tables_net_ops); |
| 2272 | } | 2272 | } |
| 2273 | 2273 | ||
| 2274 | /* | ||
| 2275 | * find the offset to specified header or the protocol number of last header | ||
| 2276 | * if target < 0. "last header" is transport protocol header, ESP, or | ||
| 2277 | * "No next header". | ||
| 2278 | * | ||
| 2279 | * Note that *offset is used as input/output parameter. an if it is not zero, | ||
| 2280 | * then it must be a valid offset to an inner IPv6 header. This can be used | ||
| 2281 | * to explore inner IPv6 header, eg. ICMPv6 error messages. | ||
| 2282 | * | ||
| 2283 | * If target header is found, its offset is set in *offset and return protocol | ||
| 2284 | * number. Otherwise, return -1. | ||
| 2285 | * | ||
| 2286 | * If the first fragment doesn't contain the final protocol header or | ||
| 2287 | * NEXTHDR_NONE it is considered invalid. | ||
| 2288 | * | ||
| 2289 | * Note that non-1st fragment is special case that "the protocol number | ||
| 2290 | * of last header" is "next header" field in Fragment header. In this case, | ||
| 2291 | * *offset is meaningless and fragment offset is stored in *fragoff if fragoff | ||
| 2292 | * isn't NULL. | ||
| 2293 | * | ||
| 2294 | * if flags is not NULL and it's a fragment, then the frag flag IP6T_FH_F_FRAG | ||
| 2295 | * will be set. If it's an AH header, the IP6T_FH_F_AUTH flag is set and | ||
| 2296 | * target < 0, then this function will stop at the AH header. | ||
| 2297 | */ | ||
| 2298 | int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset, | ||
| 2299 | int target, unsigned short *fragoff, int *flags) | ||
| 2300 | { | ||
| 2301 | unsigned int start = skb_network_offset(skb) + sizeof(struct ipv6hdr); | ||
| 2302 | u8 nexthdr = ipv6_hdr(skb)->nexthdr; | ||
| 2303 | unsigned int len; | ||
| 2304 | |||
| 2305 | if (fragoff) | ||
| 2306 | *fragoff = 0; | ||
| 2307 | |||
| 2308 | if (*offset) { | ||
| 2309 | struct ipv6hdr _ip6, *ip6; | ||
| 2310 | |||
| 2311 | ip6 = skb_header_pointer(skb, *offset, sizeof(_ip6), &_ip6); | ||
| 2312 | if (!ip6 || (ip6->version != 6)) { | ||
| 2313 | printk(KERN_ERR "IPv6 header not found\n"); | ||
| 2314 | return -EBADMSG; | ||
| 2315 | } | ||
| 2316 | start = *offset + sizeof(struct ipv6hdr); | ||
| 2317 | nexthdr = ip6->nexthdr; | ||
| 2318 | } | ||
| 2319 | len = skb->len - start; | ||
| 2320 | |||
| 2321 | while (nexthdr != target) { | ||
| 2322 | struct ipv6_opt_hdr _hdr, *hp; | ||
| 2323 | unsigned int hdrlen; | ||
| 2324 | |||
| 2325 | if ((!ipv6_ext_hdr(nexthdr)) || nexthdr == NEXTHDR_NONE) { | ||
| 2326 | if (target < 0) | ||
| 2327 | break; | ||
| 2328 | return -ENOENT; | ||
| 2329 | } | ||
| 2330 | |||
| 2331 | hp = skb_header_pointer(skb, start, sizeof(_hdr), &_hdr); | ||
| 2332 | if (hp == NULL) | ||
| 2333 | return -EBADMSG; | ||
| 2334 | if (nexthdr == NEXTHDR_FRAGMENT) { | ||
| 2335 | unsigned short _frag_off; | ||
| 2336 | __be16 *fp; | ||
| 2337 | |||
| 2338 | if (flags) /* Indicate that this is a fragment */ | ||
| 2339 | *flags |= IP6T_FH_F_FRAG; | ||
| 2340 | fp = skb_header_pointer(skb, | ||
| 2341 | start+offsetof(struct frag_hdr, | ||
| 2342 | frag_off), | ||
| 2343 | sizeof(_frag_off), | ||
| 2344 | &_frag_off); | ||
| 2345 | if (fp == NULL) | ||
| 2346 | return -EBADMSG; | ||
| 2347 | |||
| 2348 | _frag_off = ntohs(*fp) & ~0x7; | ||
| 2349 | if (_frag_off) { | ||
| 2350 | if (target < 0 && | ||
| 2351 | ((!ipv6_ext_hdr(hp->nexthdr)) || | ||
| 2352 | hp->nexthdr == NEXTHDR_NONE)) { | ||
| 2353 | if (fragoff) | ||
| 2354 | *fragoff = _frag_off; | ||
| 2355 | return hp->nexthdr; | ||
| 2356 | } | ||
| 2357 | return -ENOENT; | ||
| 2358 | } | ||
| 2359 | hdrlen = 8; | ||
| 2360 | } else if (nexthdr == NEXTHDR_AUTH) { | ||
| 2361 | if (flags && (*flags & IP6T_FH_F_AUTH) && (target < 0)) | ||
| 2362 | break; | ||
| 2363 | hdrlen = (hp->hdrlen + 2) << 2; | ||
| 2364 | } else | ||
| 2365 | hdrlen = ipv6_optlen(hp); | ||
| 2366 | |||
| 2367 | nexthdr = hp->nexthdr; | ||
| 2368 | len -= hdrlen; | ||
| 2369 | start += hdrlen; | ||
| 2370 | } | ||
| 2371 | |||
| 2372 | *offset = start; | ||
| 2373 | return nexthdr; | ||
| 2374 | } | ||
| 2375 | |||
| 2376 | EXPORT_SYMBOL(ip6t_register_table); | 2274 | EXPORT_SYMBOL(ip6t_register_table); |
| 2377 | EXPORT_SYMBOL(ip6t_unregister_table); | 2275 | EXPORT_SYMBOL(ip6t_unregister_table); |
| 2378 | EXPORT_SYMBOL(ip6t_do_table); | 2276 | EXPORT_SYMBOL(ip6t_do_table); |
| 2379 | EXPORT_SYMBOL(ipv6_find_hdr); | ||
| 2380 | 2277 | ||
| 2381 | module_init(ip6_tables_init); | 2278 | module_init(ip6_tables_init); |
| 2382 | module_exit(ip6_tables_fini); | 2279 | module_exit(ip6_tables_fini); |
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 80cb3829831c..cfba99b2c2a4 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c | |||
| @@ -65,6 +65,10 @@ | |||
| 65 | #define HASH_SIZE 16 | 65 | #define HASH_SIZE 16 |
| 66 | #define HASH(addr) (((__force u32)addr^((__force u32)addr>>4))&0xF) | 66 | #define HASH(addr) (((__force u32)addr^((__force u32)addr>>4))&0xF) |
| 67 | 67 | ||
| 68 | static bool log_ecn_error = true; | ||
| 69 | module_param(log_ecn_error, bool, 0644); | ||
| 70 | MODULE_PARM_DESC(log_ecn_error, "Log packets received with corrupted ECN"); | ||
| 71 | |||
| 68 | static int ipip6_tunnel_init(struct net_device *dev); | 72 | static int ipip6_tunnel_init(struct net_device *dev); |
| 69 | static void ipip6_tunnel_setup(struct net_device *dev); | 73 | static void ipip6_tunnel_setup(struct net_device *dev); |
| 70 | static void ipip6_dev_free(struct net_device *dev); | 74 | static void ipip6_dev_free(struct net_device *dev); |
| @@ -106,6 +110,7 @@ static struct rtnl_link_stats64 *ipip6_get_stats64(struct net_device *dev, | |||
| 106 | } | 110 | } |
| 107 | 111 | ||
| 108 | tot->rx_errors = dev->stats.rx_errors; | 112 | tot->rx_errors = dev->stats.rx_errors; |
| 113 | tot->rx_frame_errors = dev->stats.rx_frame_errors; | ||
| 109 | tot->tx_fifo_errors = dev->stats.tx_fifo_errors; | 114 | tot->tx_fifo_errors = dev->stats.tx_fifo_errors; |
| 110 | tot->tx_carrier_errors = dev->stats.tx_carrier_errors; | 115 | tot->tx_carrier_errors = dev->stats.tx_carrier_errors; |
| 111 | tot->tx_dropped = dev->stats.tx_dropped; | 116 | tot->tx_dropped = dev->stats.tx_dropped; |
| @@ -585,16 +590,11 @@ out: | |||
| 585 | return err; | 590 | return err; |
| 586 | } | 591 | } |
| 587 | 592 | ||
| 588 | static inline void ipip6_ecn_decapsulate(const struct iphdr *iph, struct sk_buff *skb) | ||
| 589 | { | ||
| 590 | if (INET_ECN_is_ce(iph->tos)) | ||
| 591 | IP6_ECN_set_ce(ipv6_hdr(skb)); | ||
| 592 | } | ||
| 593 | |||
| 594 | static int ipip6_rcv(struct sk_buff *skb) | 593 | static int ipip6_rcv(struct sk_buff *skb) |
| 595 | { | 594 | { |
| 596 | const struct iphdr *iph; | 595 | const struct iphdr *iph; |
| 597 | struct ip_tunnel *tunnel; | 596 | struct ip_tunnel *tunnel; |
| 597 | int err; | ||
| 598 | 598 | ||
| 599 | if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) | 599 | if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) |
| 600 | goto out; | 600 | goto out; |
| @@ -616,18 +616,27 @@ static int ipip6_rcv(struct sk_buff *skb) | |||
| 616 | if ((tunnel->dev->priv_flags & IFF_ISATAP) && | 616 | if ((tunnel->dev->priv_flags & IFF_ISATAP) && |
| 617 | !isatap_chksrc(skb, iph, tunnel)) { | 617 | !isatap_chksrc(skb, iph, tunnel)) { |
| 618 | tunnel->dev->stats.rx_errors++; | 618 | tunnel->dev->stats.rx_errors++; |
| 619 | kfree_skb(skb); | 619 | goto out; |
| 620 | return 0; | 620 | } |
| 621 | |||
| 622 | __skb_tunnel_rx(skb, tunnel->dev); | ||
| 623 | |||
| 624 | err = IP_ECN_decapsulate(iph, skb); | ||
| 625 | if (unlikely(err)) { | ||
| 626 | if (log_ecn_error) | ||
| 627 | net_info_ratelimited("non-ECT from %pI4 with TOS=%#x\n", | ||
| 628 | &iph->saddr, iph->tos); | ||
| 629 | if (err > 1) { | ||
| 630 | ++tunnel->dev->stats.rx_frame_errors; | ||
| 631 | ++tunnel->dev->stats.rx_errors; | ||
| 632 | goto out; | ||
| 633 | } | ||
| 621 | } | 634 | } |
| 622 | 635 | ||
| 623 | tstats = this_cpu_ptr(tunnel->dev->tstats); | 636 | tstats = this_cpu_ptr(tunnel->dev->tstats); |
| 624 | tstats->rx_packets++; | 637 | tstats->rx_packets++; |
| 625 | tstats->rx_bytes += skb->len; | 638 | tstats->rx_bytes += skb->len; |
| 626 | 639 | ||
| 627 | __skb_tunnel_rx(skb, tunnel->dev); | ||
| 628 | |||
| 629 | ipip6_ecn_decapsulate(iph, skb); | ||
| 630 | |||
| 631 | netif_rx(skb); | 640 | netif_rx(skb); |
| 632 | 641 | ||
| 633 | return 0; | 642 | return 0; |
diff --git a/net/irda/irttp.c b/net/irda/irttp.c index 1002e3396f72..ae43c62f9045 100644 --- a/net/irda/irttp.c +++ b/net/irda/irttp.c | |||
| @@ -441,6 +441,7 @@ struct tsap_cb *irttp_open_tsap(__u8 stsap_sel, int credit, notify_t *notify) | |||
| 441 | lsap = irlmp_open_lsap(stsap_sel, &ttp_notify, 0); | 441 | lsap = irlmp_open_lsap(stsap_sel, &ttp_notify, 0); |
| 442 | if (lsap == NULL) { | 442 | if (lsap == NULL) { |
| 443 | IRDA_DEBUG(0, "%s: unable to allocate LSAP!!\n", __func__); | 443 | IRDA_DEBUG(0, "%s: unable to allocate LSAP!!\n", __func__); |
| 444 | __irttp_close_tsap(self); | ||
| 444 | return NULL; | 445 | return NULL; |
| 445 | } | 446 | } |
| 446 | 447 | ||
diff --git a/net/mac80211/aes_cmac.c b/net/mac80211/aes_cmac.c index 493353534a0f..537488cbf941 100644 --- a/net/mac80211/aes_cmac.c +++ b/net/mac80211/aes_cmac.c | |||
| @@ -10,6 +10,7 @@ | |||
| 10 | #include <linux/kernel.h> | 10 | #include <linux/kernel.h> |
| 11 | #include <linux/types.h> | 11 | #include <linux/types.h> |
| 12 | #include <linux/crypto.h> | 12 | #include <linux/crypto.h> |
| 13 | #include <linux/export.h> | ||
| 13 | #include <linux/err.h> | 14 | #include <linux/err.h> |
| 14 | #include <crypto/aes.h> | 15 | #include <crypto/aes.h> |
| 15 | 16 | ||
diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c index 186d9919b043..808338a1bce5 100644 --- a/net/mac80211/agg-rx.c +++ b/net/mac80211/agg-rx.c | |||
| @@ -118,7 +118,7 @@ void ieee80211_stop_rx_ba_session(struct ieee80211_vif *vif, u16 ba_rx_bitmap, | |||
| 118 | return; | 118 | return; |
| 119 | } | 119 | } |
| 120 | 120 | ||
| 121 | for (i = 0; i < STA_TID_NUM; i++) | 121 | for (i = 0; i < IEEE80211_NUM_TIDS; i++) |
| 122 | if (ba_rx_bitmap & BIT(i)) | 122 | if (ba_rx_bitmap & BIT(i)) |
| 123 | set_bit(i, sta->ampdu_mlme.tid_rx_stop_requested); | 123 | set_bit(i, sta->ampdu_mlme.tid_rx_stop_requested); |
| 124 | 124 | ||
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index 3195a6307f50..4152ed1034b8 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c | |||
| @@ -448,7 +448,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid, | |||
| 448 | if (WARN_ON(!local->ops->ampdu_action)) | 448 | if (WARN_ON(!local->ops->ampdu_action)) |
| 449 | return -EINVAL; | 449 | return -EINVAL; |
| 450 | 450 | ||
| 451 | if ((tid >= STA_TID_NUM) || | 451 | if ((tid >= IEEE80211_NUM_TIDS) || |
| 452 | !(local->hw.flags & IEEE80211_HW_AMPDU_AGGREGATION) || | 452 | !(local->hw.flags & IEEE80211_HW_AMPDU_AGGREGATION) || |
| 453 | (local->hw.flags & IEEE80211_HW_TX_AMPDU_SETUP_IN_HW)) | 453 | (local->hw.flags & IEEE80211_HW_TX_AMPDU_SETUP_IN_HW)) |
| 454 | return -EINVAL; | 454 | return -EINVAL; |
| @@ -605,9 +605,9 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid) | |||
| 605 | 605 | ||
| 606 | trace_api_start_tx_ba_cb(sdata, ra, tid); | 606 | trace_api_start_tx_ba_cb(sdata, ra, tid); |
| 607 | 607 | ||
| 608 | if (tid >= STA_TID_NUM) { | 608 | if (tid >= IEEE80211_NUM_TIDS) { |
| 609 | ht_dbg(sdata, "Bad TID value: tid = %d (>= %d)\n", | 609 | ht_dbg(sdata, "Bad TID value: tid = %d (>= %d)\n", |
| 610 | tid, STA_TID_NUM); | 610 | tid, IEEE80211_NUM_TIDS); |
| 611 | return; | 611 | return; |
| 612 | } | 612 | } |
| 613 | 613 | ||
| @@ -687,7 +687,7 @@ int ieee80211_stop_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid) | |||
| 687 | if (!local->ops->ampdu_action) | 687 | if (!local->ops->ampdu_action) |
| 688 | return -EINVAL; | 688 | return -EINVAL; |
| 689 | 689 | ||
| 690 | if (tid >= STA_TID_NUM) | 690 | if (tid >= IEEE80211_NUM_TIDS) |
| 691 | return -EINVAL; | 691 | return -EINVAL; |
| 692 | 692 | ||
| 693 | spin_lock_bh(&sta->lock); | 693 | spin_lock_bh(&sta->lock); |
| @@ -722,9 +722,9 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid) | |||
| 722 | 722 | ||
| 723 | trace_api_stop_tx_ba_cb(sdata, ra, tid); | 723 | trace_api_stop_tx_ba_cb(sdata, ra, tid); |
| 724 | 724 | ||
| 725 | if (tid >= STA_TID_NUM) { | 725 | if (tid >= IEEE80211_NUM_TIDS) { |
| 726 | ht_dbg(sdata, "Bad TID value: tid = %d (>= %d)\n", | 726 | ht_dbg(sdata, "Bad TID value: tid = %d (>= %d)\n", |
| 727 | tid, STA_TID_NUM); | 727 | tid, IEEE80211_NUM_TIDS); |
| 728 | return; | 728 | return; |
| 729 | } | 729 | } |
| 730 | 730 | ||
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 76690020d605..4965aa6424ec 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
| @@ -370,30 +370,32 @@ static int ieee80211_config_default_mgmt_key(struct wiphy *wiphy, | |||
| 370 | return 0; | 370 | return 0; |
| 371 | } | 371 | } |
| 372 | 372 | ||
| 373 | static void rate_idx_to_bitrate(struct rate_info *rate, struct sta_info *sta, int idx) | ||
| 374 | { | ||
| 375 | enum ieee80211_band band = ieee80211_get_sdata_band(sta->sdata); | ||
| 376 | |||
| 377 | if (!(rate->flags & RATE_INFO_FLAGS_MCS)) { | ||
| 378 | struct ieee80211_supported_band *sband; | ||
| 379 | sband = sta->local->hw.wiphy->bands[band]; | ||
| 380 | rate->legacy = sband->bitrates[idx].bitrate; | ||
| 381 | } else | ||
| 382 | rate->mcs = idx; | ||
| 383 | } | ||
| 384 | |||
| 385 | void sta_set_rate_info_tx(struct sta_info *sta, | 373 | void sta_set_rate_info_tx(struct sta_info *sta, |
| 386 | const struct ieee80211_tx_rate *rate, | 374 | const struct ieee80211_tx_rate *rate, |
| 387 | struct rate_info *rinfo) | 375 | struct rate_info *rinfo) |
| 388 | { | 376 | { |
| 389 | rinfo->flags = 0; | 377 | rinfo->flags = 0; |
| 390 | if (rate->flags & IEEE80211_TX_RC_MCS) | 378 | if (rate->flags & IEEE80211_TX_RC_MCS) { |
| 391 | rinfo->flags |= RATE_INFO_FLAGS_MCS; | 379 | rinfo->flags |= RATE_INFO_FLAGS_MCS; |
| 380 | rinfo->mcs = rate->idx; | ||
| 381 | } else if (rate->flags & IEEE80211_TX_RC_VHT_MCS) { | ||
| 382 | rinfo->flags |= RATE_INFO_FLAGS_VHT_MCS; | ||
| 383 | rinfo->mcs = ieee80211_rate_get_vht_mcs(rate); | ||
| 384 | rinfo->nss = ieee80211_rate_get_vht_nss(rate); | ||
| 385 | } else { | ||
| 386 | struct ieee80211_supported_band *sband; | ||
| 387 | sband = sta->local->hw.wiphy->bands[ | ||
| 388 | ieee80211_get_sdata_band(sta->sdata)]; | ||
| 389 | rinfo->legacy = sband->bitrates[rate->idx].bitrate; | ||
| 390 | } | ||
| 392 | if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) | 391 | if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) |
| 393 | rinfo->flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; | 392 | rinfo->flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; |
| 393 | if (rate->flags & IEEE80211_TX_RC_80_MHZ_WIDTH) | ||
| 394 | rinfo->flags |= RATE_INFO_FLAGS_80_MHZ_WIDTH; | ||
| 395 | if (rate->flags & IEEE80211_TX_RC_160_MHZ_WIDTH) | ||
| 396 | rinfo->flags |= RATE_INFO_FLAGS_160_MHZ_WIDTH; | ||
| 394 | if (rate->flags & IEEE80211_TX_RC_SHORT_GI) | 397 | if (rate->flags & IEEE80211_TX_RC_SHORT_GI) |
| 395 | rinfo->flags |= RATE_INFO_FLAGS_SHORT_GI; | 398 | rinfo->flags |= RATE_INFO_FLAGS_SHORT_GI; |
| 396 | rate_idx_to_bitrate(rinfo, sta, rate->idx); | ||
| 397 | } | 399 | } |
| 398 | 400 | ||
| 399 | static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) | 401 | static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) |
| @@ -444,13 +446,32 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) | |||
| 444 | sta_set_rate_info_tx(sta, &sta->last_tx_rate, &sinfo->txrate); | 446 | sta_set_rate_info_tx(sta, &sta->last_tx_rate, &sinfo->txrate); |
| 445 | 447 | ||
| 446 | sinfo->rxrate.flags = 0; | 448 | sinfo->rxrate.flags = 0; |
| 447 | if (sta->last_rx_rate_flag & RX_FLAG_HT) | 449 | if (sta->last_rx_rate_flag & RX_FLAG_HT) { |
| 448 | sinfo->rxrate.flags |= RATE_INFO_FLAGS_MCS; | 450 | sinfo->rxrate.flags |= RATE_INFO_FLAGS_MCS; |
| 451 | sinfo->rxrate.mcs = sta->last_rx_rate_idx; | ||
| 452 | } else if (sta->last_rx_rate_flag & RX_FLAG_VHT) { | ||
| 453 | sinfo->rxrate.flags |= RATE_INFO_FLAGS_VHT_MCS; | ||
| 454 | sinfo->rxrate.nss = sta->last_rx_rate_vht_nss; | ||
| 455 | sinfo->rxrate.mcs = sta->last_rx_rate_idx; | ||
| 456 | } else { | ||
| 457 | struct ieee80211_supported_band *sband; | ||
| 458 | |||
| 459 | sband = sta->local->hw.wiphy->bands[ | ||
| 460 | ieee80211_get_sdata_band(sta->sdata)]; | ||
| 461 | sinfo->rxrate.legacy = | ||
| 462 | sband->bitrates[sta->last_rx_rate_idx].bitrate; | ||
| 463 | } | ||
| 464 | |||
| 449 | if (sta->last_rx_rate_flag & RX_FLAG_40MHZ) | 465 | if (sta->last_rx_rate_flag & RX_FLAG_40MHZ) |
| 450 | sinfo->rxrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; | 466 | sinfo->rxrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; |
| 451 | if (sta->last_rx_rate_flag & RX_FLAG_SHORT_GI) | 467 | if (sta->last_rx_rate_flag & RX_FLAG_SHORT_GI) |
| 452 | sinfo->rxrate.flags |= RATE_INFO_FLAGS_SHORT_GI; | 468 | sinfo->rxrate.flags |= RATE_INFO_FLAGS_SHORT_GI; |
| 453 | rate_idx_to_bitrate(&sinfo->rxrate, sta, sta->last_rx_rate_idx); | 469 | if (sta->last_rx_rate_flag & RX_FLAG_80MHZ) |
| 470 | sinfo->rxrate.flags |= RATE_INFO_FLAGS_80_MHZ_WIDTH; | ||
| 471 | if (sta->last_rx_rate_flag & RX_FLAG_80P80MHZ) | ||
| 472 | sinfo->rxrate.flags |= RATE_INFO_FLAGS_80P80_MHZ_WIDTH; | ||
| 473 | if (sta->last_rx_rate_flag & RX_FLAG_160MHZ) | ||
| 474 | sinfo->rxrate.flags |= RATE_INFO_FLAGS_160_MHZ_WIDTH; | ||
| 454 | 475 | ||
| 455 | if (ieee80211_vif_is_mesh(&sdata->vif)) { | 476 | if (ieee80211_vif_is_mesh(&sdata->vif)) { |
| 456 | #ifdef CONFIG_MAC80211_MESH | 477 | #ifdef CONFIG_MAC80211_MESH |
| @@ -615,7 +636,7 @@ do_survey: | |||
| 615 | rcu_read_lock(); | 636 | rcu_read_lock(); |
| 616 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | 637 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); |
| 617 | if (chanctx_conf) | 638 | if (chanctx_conf) |
| 618 | channel = chanctx_conf->channel; | 639 | channel = chanctx_conf->def.chan; |
| 619 | else | 640 | else |
| 620 | channel = NULL; | 641 | channel = NULL; |
| 621 | rcu_read_unlock(); | 642 | rcu_read_unlock(); |
| @@ -735,15 +756,13 @@ static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev, | |||
| 735 | } | 756 | } |
| 736 | 757 | ||
| 737 | static int ieee80211_set_monitor_channel(struct wiphy *wiphy, | 758 | static int ieee80211_set_monitor_channel(struct wiphy *wiphy, |
| 738 | struct ieee80211_channel *chan, | 759 | struct cfg80211_chan_def *chandef) |
| 739 | enum nl80211_channel_type channel_type) | ||
| 740 | { | 760 | { |
| 741 | struct ieee80211_local *local = wiphy_priv(wiphy); | 761 | struct ieee80211_local *local = wiphy_priv(wiphy); |
| 742 | struct ieee80211_sub_if_data *sdata; | 762 | struct ieee80211_sub_if_data *sdata; |
| 743 | int ret = 0; | 763 | int ret = 0; |
| 744 | 764 | ||
| 745 | if (local->monitor_channel == chan && | 765 | if (cfg80211_chandef_identical(&local->monitor_chandef, chandef)) |
| 746 | local->monitor_channel_type == channel_type) | ||
| 747 | return 0; | 766 | return 0; |
| 748 | 767 | ||
| 749 | mutex_lock(&local->iflist_mtx); | 768 | mutex_lock(&local->iflist_mtx); |
| @@ -753,20 +772,17 @@ static int ieee80211_set_monitor_channel(struct wiphy *wiphy, | |||
| 753 | lockdep_is_held(&local->iflist_mtx)); | 772 | lockdep_is_held(&local->iflist_mtx)); |
| 754 | if (sdata) { | 773 | if (sdata) { |
| 755 | ieee80211_vif_release_channel(sdata); | 774 | ieee80211_vif_release_channel(sdata); |
| 756 | ret = ieee80211_vif_use_channel( | 775 | ret = ieee80211_vif_use_channel(sdata, chandef, |
| 757 | sdata, chan, channel_type, | ||
| 758 | IEEE80211_CHANCTX_EXCLUSIVE); | 776 | IEEE80211_CHANCTX_EXCLUSIVE); |
| 759 | } | 777 | } |
| 760 | } else if (local->open_count == local->monitors) { | 778 | } else if (local->open_count == local->monitors) { |
| 761 | local->_oper_channel = chan; | 779 | local->_oper_channel = chandef->chan; |
| 762 | local->_oper_channel_type = channel_type; | 780 | local->_oper_channel_type = cfg80211_get_chandef_type(chandef); |
| 763 | ieee80211_hw_config(local, 0); | 781 | ieee80211_hw_config(local, 0); |
| 764 | } | 782 | } |
| 765 | 783 | ||
| 766 | if (ret == 0) { | 784 | if (ret == 0) |
| 767 | local->monitor_channel = chan; | 785 | local->monitor_chandef = *chandef; |
| 768 | local->monitor_channel_type = channel_type; | ||
| 769 | } | ||
| 770 | mutex_unlock(&local->iflist_mtx); | 786 | mutex_unlock(&local->iflist_mtx); |
| 771 | 787 | ||
| 772 | return ret; | 788 | return ret; |
| @@ -888,8 +904,7 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, | |||
| 888 | sdata->smps_mode = IEEE80211_SMPS_OFF; | 904 | sdata->smps_mode = IEEE80211_SMPS_OFF; |
| 889 | sdata->needed_rx_chains = sdata->local->rx_chains; | 905 | sdata->needed_rx_chains = sdata->local->rx_chains; |
| 890 | 906 | ||
| 891 | err = ieee80211_vif_use_channel(sdata, params->channel, | 907 | err = ieee80211_vif_use_channel(sdata, ¶ms->chandef, |
| 892 | params->channel_type, | ||
| 893 | IEEE80211_CHANCTX_SHARED); | 908 | IEEE80211_CHANCTX_SHARED); |
| 894 | if (err) | 909 | if (err) |
| 895 | return err; | 910 | return err; |
| @@ -922,6 +937,15 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, | |||
| 922 | return err; | 937 | return err; |
| 923 | changed |= err; | 938 | changed |= err; |
| 924 | 939 | ||
| 940 | err = drv_start_ap(sdata->local, sdata); | ||
| 941 | if (err) { | ||
| 942 | old = rtnl_dereference(sdata->u.ap.beacon); | ||
| 943 | if (old) | ||
| 944 | kfree_rcu(old, rcu_head); | ||
| 945 | RCU_INIT_POINTER(sdata->u.ap.beacon, NULL); | ||
| 946 | return err; | ||
| 947 | } | ||
| 948 | |||
| 925 | ieee80211_bss_info_change_notify(sdata, changed); | 949 | ieee80211_bss_info_change_notify(sdata, changed); |
| 926 | 950 | ||
| 927 | netif_carrier_on(dev); | 951 | netif_carrier_on(dev); |
| @@ -953,26 +977,38 @@ static int ieee80211_change_beacon(struct wiphy *wiphy, struct net_device *dev, | |||
| 953 | 977 | ||
| 954 | static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) | 978 | static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) |
| 955 | { | 979 | { |
| 956 | struct ieee80211_sub_if_data *sdata, *vlan; | 980 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
| 957 | struct beacon_data *old; | 981 | struct ieee80211_sub_if_data *vlan; |
| 958 | 982 | struct ieee80211_local *local = sdata->local; | |
| 959 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 983 | struct beacon_data *old_beacon; |
| 984 | struct probe_resp *old_probe_resp; | ||
| 960 | 985 | ||
| 961 | old = rtnl_dereference(sdata->u.ap.beacon); | 986 | old_beacon = rtnl_dereference(sdata->u.ap.beacon); |
| 962 | if (!old) | 987 | if (!old_beacon) |
| 963 | return -ENOENT; | 988 | return -ENOENT; |
| 989 | old_probe_resp = rtnl_dereference(sdata->u.ap.probe_resp); | ||
| 964 | 990 | ||
| 991 | /* turn off carrier for this interface and dependent VLANs */ | ||
| 965 | list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) | 992 | list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) |
| 966 | netif_carrier_off(vlan->dev); | 993 | netif_carrier_off(vlan->dev); |
| 967 | netif_carrier_off(dev); | 994 | netif_carrier_off(dev); |
| 968 | 995 | ||
| 996 | /* remove beacon and probe response */ | ||
| 969 | RCU_INIT_POINTER(sdata->u.ap.beacon, NULL); | 997 | RCU_INIT_POINTER(sdata->u.ap.beacon, NULL); |
| 998 | RCU_INIT_POINTER(sdata->u.ap.probe_resp, NULL); | ||
| 999 | kfree_rcu(old_beacon, rcu_head); | ||
| 1000 | if (old_probe_resp) | ||
| 1001 | kfree_rcu(old_probe_resp, rcu_head); | ||
| 970 | 1002 | ||
| 971 | kfree_rcu(old, rcu_head); | 1003 | sta_info_flush(local, sdata); |
| 972 | |||
| 973 | sta_info_flush(sdata->local, sdata); | ||
| 974 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED); | 1004 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED); |
| 975 | 1005 | ||
| 1006 | drv_stop_ap(sdata->local, sdata); | ||
| 1007 | |||
| 1008 | /* free all potentially still buffered bcast frames */ | ||
| 1009 | local->total_ps_buffered -= skb_queue_len(&sdata->u.ap.ps.bc_buf); | ||
| 1010 | skb_queue_purge(&sdata->u.ap.ps.bc_buf); | ||
| 1011 | |||
| 976 | ieee80211_vif_release_channel(sdata); | 1012 | ieee80211_vif_release_channel(sdata); |
| 977 | 1013 | ||
| 978 | return 0; | 1014 | return 0; |
| @@ -1686,8 +1722,7 @@ static int ieee80211_join_mesh(struct wiphy *wiphy, struct net_device *dev, | |||
| 1686 | sdata->smps_mode = IEEE80211_SMPS_OFF; | 1722 | sdata->smps_mode = IEEE80211_SMPS_OFF; |
| 1687 | sdata->needed_rx_chains = sdata->local->rx_chains; | 1723 | sdata->needed_rx_chains = sdata->local->rx_chains; |
| 1688 | 1724 | ||
| 1689 | err = ieee80211_vif_use_channel(sdata, setup->channel, | 1725 | err = ieee80211_vif_use_channel(sdata, &setup->chandef, |
| 1690 | setup->channel_type, | ||
| 1691 | IEEE80211_CHANCTX_SHARED); | 1726 | IEEE80211_CHANCTX_SHARED); |
| 1692 | if (err) | 1727 | if (err) |
| 1693 | return err; | 1728 | return err; |
| @@ -1933,6 +1968,16 @@ static int ieee80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev) | |||
| 1933 | return ieee80211_ibss_leave(IEEE80211_DEV_TO_SUB_IF(dev)); | 1968 | return ieee80211_ibss_leave(IEEE80211_DEV_TO_SUB_IF(dev)); |
| 1934 | } | 1969 | } |
| 1935 | 1970 | ||
| 1971 | static int ieee80211_set_mcast_rate(struct wiphy *wiphy, struct net_device *dev, | ||
| 1972 | int rate[IEEE80211_NUM_BANDS]) | ||
| 1973 | { | ||
| 1974 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
| 1975 | |||
| 1976 | memcpy(sdata->vif.bss_conf.mcast_rate, rate, sizeof(rate)); | ||
| 1977 | |||
| 1978 | return 0; | ||
| 1979 | } | ||
| 1980 | |||
| 1936 | static int ieee80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) | 1981 | static int ieee80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) |
| 1937 | { | 1982 | { |
| 1938 | struct ieee80211_local *local = wiphy_priv(wiphy); | 1983 | struct ieee80211_local *local = wiphy_priv(wiphy); |
| @@ -1959,10 +2004,16 @@ static int ieee80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) | |||
| 1959 | return err; | 2004 | return err; |
| 1960 | } | 2005 | } |
| 1961 | 2006 | ||
| 1962 | if (changed & WIPHY_PARAM_RETRY_SHORT) | 2007 | if (changed & WIPHY_PARAM_RETRY_SHORT) { |
| 2008 | if (wiphy->retry_short > IEEE80211_MAX_TX_RETRY) | ||
| 2009 | return -EINVAL; | ||
| 1963 | local->hw.conf.short_frame_max_tx_count = wiphy->retry_short; | 2010 | local->hw.conf.short_frame_max_tx_count = wiphy->retry_short; |
| 1964 | if (changed & WIPHY_PARAM_RETRY_LONG) | 2011 | } |
| 2012 | if (changed & WIPHY_PARAM_RETRY_LONG) { | ||
| 2013 | if (wiphy->retry_long > IEEE80211_MAX_TX_RETRY) | ||
| 2014 | return -EINVAL; | ||
| 1965 | local->hw.conf.long_frame_max_tx_count = wiphy->retry_long; | 2015 | local->hw.conf.long_frame_max_tx_count = wiphy->retry_long; |
| 2016 | } | ||
| 1966 | if (changed & | 2017 | if (changed & |
| 1967 | (WIPHY_PARAM_RETRY_SHORT | WIPHY_PARAM_RETRY_LONG)) | 2018 | (WIPHY_PARAM_RETRY_SHORT | WIPHY_PARAM_RETRY_LONG)) |
| 1968 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_RETRY_LIMITS); | 2019 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_RETRY_LIMITS); |
| @@ -1971,45 +2022,65 @@ static int ieee80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) | |||
| 1971 | } | 2022 | } |
| 1972 | 2023 | ||
| 1973 | static int ieee80211_set_tx_power(struct wiphy *wiphy, | 2024 | static int ieee80211_set_tx_power(struct wiphy *wiphy, |
| 2025 | struct wireless_dev *wdev, | ||
| 1974 | enum nl80211_tx_power_setting type, int mbm) | 2026 | enum nl80211_tx_power_setting type, int mbm) |
| 1975 | { | 2027 | { |
| 1976 | struct ieee80211_local *local = wiphy_priv(wiphy); | 2028 | struct ieee80211_local *local = wiphy_priv(wiphy); |
| 1977 | struct ieee80211_channel *chan = local->_oper_channel; | 2029 | struct ieee80211_sub_if_data *sdata; |
| 1978 | u32 changes = 0; | ||
| 1979 | 2030 | ||
| 1980 | /* FIXME */ | 2031 | if (wdev) { |
| 1981 | if (local->use_chanctx) | 2032 | sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); |
| 1982 | return -EOPNOTSUPP; | 2033 | |
| 2034 | switch (type) { | ||
| 2035 | case NL80211_TX_POWER_AUTOMATIC: | ||
| 2036 | sdata->user_power_level = IEEE80211_UNSET_POWER_LEVEL; | ||
| 2037 | break; | ||
| 2038 | case NL80211_TX_POWER_LIMITED: | ||
| 2039 | case NL80211_TX_POWER_FIXED: | ||
| 2040 | if (mbm < 0 || (mbm % 100)) | ||
| 2041 | return -EOPNOTSUPP; | ||
| 2042 | sdata->user_power_level = MBM_TO_DBM(mbm); | ||
| 2043 | break; | ||
| 2044 | } | ||
| 2045 | |||
| 2046 | ieee80211_recalc_txpower(sdata); | ||
| 2047 | |||
| 2048 | return 0; | ||
| 2049 | } | ||
| 1983 | 2050 | ||
| 1984 | switch (type) { | 2051 | switch (type) { |
| 1985 | case NL80211_TX_POWER_AUTOMATIC: | 2052 | case NL80211_TX_POWER_AUTOMATIC: |
| 1986 | local->user_power_level = -1; | 2053 | local->user_power_level = IEEE80211_UNSET_POWER_LEVEL; |
| 1987 | break; | 2054 | break; |
| 1988 | case NL80211_TX_POWER_LIMITED: | 2055 | case NL80211_TX_POWER_LIMITED: |
| 1989 | if (mbm < 0 || (mbm % 100)) | ||
| 1990 | return -EOPNOTSUPP; | ||
| 1991 | local->user_power_level = MBM_TO_DBM(mbm); | ||
| 1992 | break; | ||
| 1993 | case NL80211_TX_POWER_FIXED: | 2056 | case NL80211_TX_POWER_FIXED: |
| 1994 | if (mbm < 0 || (mbm % 100)) | 2057 | if (mbm < 0 || (mbm % 100)) |
| 1995 | return -EOPNOTSUPP; | 2058 | return -EOPNOTSUPP; |
| 1996 | /* TODO: move to cfg80211 when it knows the channel */ | ||
| 1997 | if (MBM_TO_DBM(mbm) > chan->max_power) | ||
| 1998 | return -EINVAL; | ||
| 1999 | local->user_power_level = MBM_TO_DBM(mbm); | 2059 | local->user_power_level = MBM_TO_DBM(mbm); |
| 2000 | break; | 2060 | break; |
| 2001 | } | 2061 | } |
| 2002 | 2062 | ||
| 2003 | ieee80211_hw_config(local, changes); | 2063 | mutex_lock(&local->iflist_mtx); |
| 2064 | list_for_each_entry(sdata, &local->interfaces, list) | ||
| 2065 | sdata->user_power_level = local->user_power_level; | ||
| 2066 | list_for_each_entry(sdata, &local->interfaces, list) | ||
| 2067 | ieee80211_recalc_txpower(sdata); | ||
| 2068 | mutex_unlock(&local->iflist_mtx); | ||
| 2004 | 2069 | ||
| 2005 | return 0; | 2070 | return 0; |
| 2006 | } | 2071 | } |
| 2007 | 2072 | ||
| 2008 | static int ieee80211_get_tx_power(struct wiphy *wiphy, int *dbm) | 2073 | static int ieee80211_get_tx_power(struct wiphy *wiphy, |
| 2074 | struct wireless_dev *wdev, | ||
| 2075 | int *dbm) | ||
| 2009 | { | 2076 | { |
| 2010 | struct ieee80211_local *local = wiphy_priv(wiphy); | 2077 | struct ieee80211_local *local = wiphy_priv(wiphy); |
| 2078 | struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); | ||
| 2011 | 2079 | ||
| 2012 | *dbm = local->hw.conf.power_level; | 2080 | if (!local->use_chanctx) |
| 2081 | *dbm = local->hw.conf.power_level; | ||
| 2082 | else | ||
| 2083 | *dbm = sdata->vif.bss_conf.txpower; | ||
| 2013 | 2084 | ||
| 2014 | return 0; | 2085 | return 0; |
| 2015 | } | 2086 | } |
| @@ -2078,7 +2149,7 @@ int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata, | |||
| 2078 | * the new value until we associate. | 2149 | * the new value until we associate. |
| 2079 | */ | 2150 | */ |
| 2080 | if (!sdata->u.mgd.associated || | 2151 | if (!sdata->u.mgd.associated || |
| 2081 | sdata->vif.bss_conf.channel_type == NL80211_CHAN_NO_HT) | 2152 | sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT) |
| 2082 | return 0; | 2153 | return 0; |
| 2083 | 2154 | ||
| 2084 | ap = sdata->u.mgd.associated->bssid; | 2155 | ap = sdata->u.mgd.associated->bssid; |
| @@ -2185,7 +2256,6 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy, | |||
| 2185 | static int ieee80211_start_roc_work(struct ieee80211_local *local, | 2256 | static int ieee80211_start_roc_work(struct ieee80211_local *local, |
| 2186 | struct ieee80211_sub_if_data *sdata, | 2257 | struct ieee80211_sub_if_data *sdata, |
| 2187 | struct ieee80211_channel *channel, | 2258 | struct ieee80211_channel *channel, |
| 2188 | enum nl80211_channel_type channel_type, | ||
| 2189 | unsigned int duration, u64 *cookie, | 2259 | unsigned int duration, u64 *cookie, |
| 2190 | struct sk_buff *txskb) | 2260 | struct sk_buff *txskb) |
| 2191 | { | 2261 | { |
| @@ -2203,7 +2273,6 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local, | |||
| 2203 | return -ENOMEM; | 2273 | return -ENOMEM; |
| 2204 | 2274 | ||
| 2205 | roc->chan = channel; | 2275 | roc->chan = channel; |
| 2206 | roc->chan_type = channel_type; | ||
| 2207 | roc->duration = duration; | 2276 | roc->duration = duration; |
| 2208 | roc->req_duration = duration; | 2277 | roc->req_duration = duration; |
| 2209 | roc->frame = txskb; | 2278 | roc->frame = txskb; |
| @@ -2236,7 +2305,7 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local, | |||
| 2236 | if (!duration) | 2305 | if (!duration) |
| 2237 | duration = 10; | 2306 | duration = 10; |
| 2238 | 2307 | ||
| 2239 | ret = drv_remain_on_channel(local, channel, channel_type, duration); | 2308 | ret = drv_remain_on_channel(local, sdata, channel, duration); |
| 2240 | if (ret) { | 2309 | if (ret) { |
| 2241 | kfree(roc); | 2310 | kfree(roc); |
| 2242 | return ret; | 2311 | return ret; |
| @@ -2247,7 +2316,7 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local, | |||
| 2247 | 2316 | ||
| 2248 | out_check_combine: | 2317 | out_check_combine: |
| 2249 | list_for_each_entry(tmp, &local->roc_list, list) { | 2318 | list_for_each_entry(tmp, &local->roc_list, list) { |
| 2250 | if (tmp->chan != channel || tmp->chan_type != channel_type) | 2319 | if (tmp->chan != channel || tmp->sdata != sdata) |
| 2251 | continue; | 2320 | continue; |
| 2252 | 2321 | ||
| 2253 | /* | 2322 | /* |
| @@ -2341,13 +2410,22 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local, | |||
| 2341 | list_add_tail(&roc->list, &local->roc_list); | 2410 | list_add_tail(&roc->list, &local->roc_list); |
| 2342 | 2411 | ||
| 2343 | /* | 2412 | /* |
| 2344 | * cookie is either the roc (for normal roc) | 2413 | * cookie is either the roc cookie (for normal roc) |
| 2345 | * or the SKB (for mgmt TX) | 2414 | * or the SKB (for mgmt TX) |
| 2346 | */ | 2415 | */ |
| 2347 | if (txskb) | 2416 | if (!txskb) { |
| 2417 | /* local->mtx protects this */ | ||
| 2418 | local->roc_cookie_counter++; | ||
| 2419 | roc->cookie = local->roc_cookie_counter; | ||
| 2420 | /* wow, you wrapped 64 bits ... more likely a bug */ | ||
| 2421 | if (WARN_ON(roc->cookie == 0)) { | ||
| 2422 | roc->cookie = 1; | ||
| 2423 | local->roc_cookie_counter++; | ||
| 2424 | } | ||
| 2425 | *cookie = roc->cookie; | ||
| 2426 | } else { | ||
| 2348 | *cookie = (unsigned long)txskb; | 2427 | *cookie = (unsigned long)txskb; |
| 2349 | else | 2428 | } |
| 2350 | *cookie = (unsigned long)roc; | ||
| 2351 | 2429 | ||
| 2352 | return 0; | 2430 | return 0; |
| 2353 | } | 2431 | } |
| @@ -2355,7 +2433,6 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local, | |||
| 2355 | static int ieee80211_remain_on_channel(struct wiphy *wiphy, | 2433 | static int ieee80211_remain_on_channel(struct wiphy *wiphy, |
| 2356 | struct wireless_dev *wdev, | 2434 | struct wireless_dev *wdev, |
| 2357 | struct ieee80211_channel *chan, | 2435 | struct ieee80211_channel *chan, |
| 2358 | enum nl80211_channel_type channel_type, | ||
| 2359 | unsigned int duration, | 2436 | unsigned int duration, |
| 2360 | u64 *cookie) | 2437 | u64 *cookie) |
| 2361 | { | 2438 | { |
| @@ -2364,7 +2441,7 @@ static int ieee80211_remain_on_channel(struct wiphy *wiphy, | |||
| 2364 | int ret; | 2441 | int ret; |
| 2365 | 2442 | ||
| 2366 | mutex_lock(&local->mtx); | 2443 | mutex_lock(&local->mtx); |
| 2367 | ret = ieee80211_start_roc_work(local, sdata, chan, channel_type, | 2444 | ret = ieee80211_start_roc_work(local, sdata, chan, |
| 2368 | duration, cookie, NULL); | 2445 | duration, cookie, NULL); |
| 2369 | mutex_unlock(&local->mtx); | 2446 | mutex_unlock(&local->mtx); |
| 2370 | 2447 | ||
| @@ -2382,7 +2459,7 @@ static int ieee80211_cancel_roc(struct ieee80211_local *local, | |||
| 2382 | struct ieee80211_roc_work *dep, *tmp2; | 2459 | struct ieee80211_roc_work *dep, *tmp2; |
| 2383 | 2460 | ||
| 2384 | list_for_each_entry_safe(dep, tmp2, &roc->dependents, list) { | 2461 | list_for_each_entry_safe(dep, tmp2, &roc->dependents, list) { |
| 2385 | if (!mgmt_tx && (unsigned long)dep != cookie) | 2462 | if (!mgmt_tx && dep->cookie != cookie) |
| 2386 | continue; | 2463 | continue; |
| 2387 | else if (mgmt_tx && dep->mgmt_tx_cookie != cookie) | 2464 | else if (mgmt_tx && dep->mgmt_tx_cookie != cookie) |
| 2388 | continue; | 2465 | continue; |
| @@ -2394,7 +2471,7 @@ static int ieee80211_cancel_roc(struct ieee80211_local *local, | |||
| 2394 | return 0; | 2471 | return 0; |
| 2395 | } | 2472 | } |
| 2396 | 2473 | ||
| 2397 | if (!mgmt_tx && (unsigned long)roc != cookie) | 2474 | if (!mgmt_tx && roc->cookie != cookie) |
| 2398 | continue; | 2475 | continue; |
| 2399 | else if (mgmt_tx && roc->mgmt_tx_cookie != cookie) | 2476 | else if (mgmt_tx && roc->mgmt_tx_cookie != cookie) |
| 2400 | continue; | 2477 | continue; |
| @@ -2457,10 +2534,8 @@ static int ieee80211_cancel_remain_on_channel(struct wiphy *wiphy, | |||
| 2457 | 2534 | ||
| 2458 | static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, | 2535 | static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, |
| 2459 | struct ieee80211_channel *chan, bool offchan, | 2536 | struct ieee80211_channel *chan, bool offchan, |
| 2460 | enum nl80211_channel_type channel_type, | 2537 | unsigned int wait, const u8 *buf, size_t len, |
| 2461 | bool channel_type_valid, unsigned int wait, | 2538 | bool no_cck, bool dont_wait_for_ack, u64 *cookie) |
| 2462 | const u8 *buf, size_t len, bool no_cck, | ||
| 2463 | bool dont_wait_for_ack, u64 *cookie) | ||
| 2464 | { | 2539 | { |
| 2465 | struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); | 2540 | struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); |
| 2466 | struct ieee80211_local *local = sdata->local; | 2541 | struct ieee80211_local *local = sdata->local; |
| @@ -2529,14 +2604,10 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, | |||
| 2529 | rcu_read_lock(); | 2604 | rcu_read_lock(); |
| 2530 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | 2605 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); |
| 2531 | 2606 | ||
| 2532 | if (chanctx_conf) { | 2607 | if (chanctx_conf) |
| 2533 | need_offchan = chan != chanctx_conf->channel; | 2608 | need_offchan = chan != chanctx_conf->def.chan; |
| 2534 | if (channel_type_valid && | 2609 | else |
| 2535 | channel_type != chanctx_conf->channel_type) | ||
| 2536 | need_offchan = true; | ||
| 2537 | } else { | ||
| 2538 | need_offchan = true; | 2610 | need_offchan = true; |
| 2539 | } | ||
| 2540 | rcu_read_unlock(); | 2611 | rcu_read_unlock(); |
| 2541 | } | 2612 | } |
| 2542 | 2613 | ||
| @@ -2571,7 +2642,7 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, | |||
| 2571 | local->hw.offchannel_tx_hw_queue; | 2642 | local->hw.offchannel_tx_hw_queue; |
| 2572 | 2643 | ||
| 2573 | /* This will handle all kinds of coalescing and immediate TX */ | 2644 | /* This will handle all kinds of coalescing and immediate TX */ |
| 2574 | ret = ieee80211_start_roc_work(local, sdata, chan, channel_type, | 2645 | ret = ieee80211_start_roc_work(local, sdata, chan, |
| 2575 | wait, cookie, skb); | 2646 | wait, cookie, skb); |
| 2576 | if (ret) | 2647 | if (ret) |
| 2577 | kfree_skb(skb); | 2648 | kfree_skb(skb); |
| @@ -3005,7 +3076,7 @@ static int ieee80211_probe_client(struct wiphy *wiphy, struct net_device *dev, | |||
| 3005 | rcu_read_unlock(); | 3076 | rcu_read_unlock(); |
| 3006 | return -EINVAL; | 3077 | return -EINVAL; |
| 3007 | } | 3078 | } |
| 3008 | band = chanctx_conf->channel->band; | 3079 | band = chanctx_conf->def.chan->band; |
| 3009 | sta = sta_info_get(sdata, peer); | 3080 | sta = sta_info_get(sdata, peer); |
| 3010 | if (sta) { | 3081 | if (sta) { |
| 3011 | qos = test_sta_flag(sta, WLAN_STA_WME); | 3082 | qos = test_sta_flag(sta, WLAN_STA_WME); |
| @@ -3062,23 +3133,23 @@ static int ieee80211_probe_client(struct wiphy *wiphy, struct net_device *dev, | |||
| 3062 | return 0; | 3133 | return 0; |
| 3063 | } | 3134 | } |
| 3064 | 3135 | ||
| 3065 | static struct ieee80211_channel * | 3136 | static int ieee80211_cfg_get_channel(struct wiphy *wiphy, |
| 3066 | ieee80211_cfg_get_channel(struct wiphy *wiphy, struct wireless_dev *wdev, | 3137 | struct wireless_dev *wdev, |
| 3067 | enum nl80211_channel_type *type) | 3138 | struct cfg80211_chan_def *chandef) |
| 3068 | { | 3139 | { |
| 3069 | struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); | 3140 | struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); |
| 3070 | struct ieee80211_chanctx_conf *chanctx_conf; | 3141 | struct ieee80211_chanctx_conf *chanctx_conf; |
| 3071 | struct ieee80211_channel *chan = NULL; | 3142 | int ret = -ENODATA; |
| 3072 | 3143 | ||
| 3073 | rcu_read_lock(); | 3144 | rcu_read_lock(); |
| 3074 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | 3145 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); |
| 3075 | if (chanctx_conf) { | 3146 | if (chanctx_conf) { |
| 3076 | *type = chanctx_conf->channel_type; | 3147 | *chandef = chanctx_conf->def; |
| 3077 | chan = chanctx_conf->channel; | 3148 | ret = 0; |
| 3078 | } | 3149 | } |
| 3079 | rcu_read_unlock(); | 3150 | rcu_read_unlock(); |
| 3080 | 3151 | ||
| 3081 | return chan; | 3152 | return ret; |
| 3082 | } | 3153 | } |
| 3083 | 3154 | ||
| 3084 | #ifdef CONFIG_PM | 3155 | #ifdef CONFIG_PM |
| @@ -3133,6 +3204,7 @@ struct cfg80211_ops mac80211_config_ops = { | |||
| 3133 | .disassoc = ieee80211_disassoc, | 3204 | .disassoc = ieee80211_disassoc, |
| 3134 | .join_ibss = ieee80211_join_ibss, | 3205 | .join_ibss = ieee80211_join_ibss, |
| 3135 | .leave_ibss = ieee80211_leave_ibss, | 3206 | .leave_ibss = ieee80211_leave_ibss, |
| 3207 | .set_mcast_rate = ieee80211_set_mcast_rate, | ||
| 3136 | .set_wiphy_params = ieee80211_set_wiphy_params, | 3208 | .set_wiphy_params = ieee80211_set_wiphy_params, |
| 3137 | .set_tx_power = ieee80211_set_tx_power, | 3209 | .set_tx_power = ieee80211_set_tx_power, |
| 3138 | .get_tx_power = ieee80211_get_tx_power, | 3210 | .get_tx_power = ieee80211_get_tx_power, |
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index f84b86028a9c..53f03120db55 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c | |||
| @@ -8,93 +8,47 @@ | |||
| 8 | #include "ieee80211_i.h" | 8 | #include "ieee80211_i.h" |
| 9 | #include "driver-ops.h" | 9 | #include "driver-ops.h" |
| 10 | 10 | ||
| 11 | static bool | 11 | static void ieee80211_change_chandef(struct ieee80211_local *local, |
| 12 | ieee80211_channel_types_are_compatible(enum nl80211_channel_type chantype1, | 12 | struct ieee80211_chanctx *ctx, |
| 13 | enum nl80211_channel_type chantype2, | 13 | const struct cfg80211_chan_def *chandef) |
| 14 | enum nl80211_channel_type *compat) | ||
| 15 | { | 14 | { |
| 16 | /* | 15 | if (cfg80211_chandef_identical(&ctx->conf.def, chandef)) |
| 17 | * start out with chantype1 being the result, | ||
| 18 | * overwriting later if needed | ||
| 19 | */ | ||
| 20 | if (compat) | ||
| 21 | *compat = chantype1; | ||
| 22 | |||
| 23 | switch (chantype1) { | ||
| 24 | case NL80211_CHAN_NO_HT: | ||
| 25 | if (compat) | ||
| 26 | *compat = chantype2; | ||
| 27 | break; | ||
| 28 | case NL80211_CHAN_HT20: | ||
| 29 | /* | ||
| 30 | * allow any change that doesn't go to no-HT | ||
| 31 | * (if it already is no-HT no change is needed) | ||
| 32 | */ | ||
| 33 | if (chantype2 == NL80211_CHAN_NO_HT) | ||
| 34 | break; | ||
| 35 | if (compat) | ||
| 36 | *compat = chantype2; | ||
| 37 | break; | ||
| 38 | case NL80211_CHAN_HT40PLUS: | ||
| 39 | case NL80211_CHAN_HT40MINUS: | ||
| 40 | /* allow smaller bandwidth and same */ | ||
| 41 | if (chantype2 == NL80211_CHAN_NO_HT) | ||
| 42 | break; | ||
| 43 | if (chantype2 == NL80211_CHAN_HT20) | ||
| 44 | break; | ||
| 45 | if (chantype2 == chantype1) | ||
| 46 | break; | ||
| 47 | return false; | ||
| 48 | } | ||
| 49 | |||
| 50 | return true; | ||
| 51 | } | ||
| 52 | |||
| 53 | static void ieee80211_change_chantype(struct ieee80211_local *local, | ||
| 54 | struct ieee80211_chanctx *ctx, | ||
| 55 | enum nl80211_channel_type chantype) | ||
| 56 | { | ||
| 57 | if (chantype == ctx->conf.channel_type) | ||
| 58 | return; | 16 | return; |
| 59 | 17 | ||
| 60 | ctx->conf.channel_type = chantype; | 18 | WARN_ON(!cfg80211_chandef_compatible(&ctx->conf.def, chandef)); |
| 61 | drv_change_chanctx(local, ctx, IEEE80211_CHANCTX_CHANGE_CHANNEL_TYPE); | 19 | |
| 20 | ctx->conf.def = *chandef; | ||
| 21 | drv_change_chanctx(local, ctx, IEEE80211_CHANCTX_CHANGE_WIDTH); | ||
| 62 | 22 | ||
| 63 | if (!local->use_chanctx) { | 23 | if (!local->use_chanctx) { |
| 64 | local->_oper_channel_type = chantype; | 24 | local->_oper_channel_type = cfg80211_get_chandef_type(chandef); |
| 65 | ieee80211_hw_config(local, 0); | 25 | ieee80211_hw_config(local, 0); |
| 66 | } | 26 | } |
| 67 | } | 27 | } |
| 68 | 28 | ||
| 69 | static struct ieee80211_chanctx * | 29 | static struct ieee80211_chanctx * |
| 70 | ieee80211_find_chanctx(struct ieee80211_local *local, | 30 | ieee80211_find_chanctx(struct ieee80211_local *local, |
| 71 | struct ieee80211_channel *channel, | 31 | const struct cfg80211_chan_def *chandef, |
| 72 | enum nl80211_channel_type channel_type, | ||
| 73 | enum ieee80211_chanctx_mode mode) | 32 | enum ieee80211_chanctx_mode mode) |
| 74 | { | 33 | { |
| 75 | struct ieee80211_chanctx *ctx; | 34 | struct ieee80211_chanctx *ctx; |
| 76 | enum nl80211_channel_type compat_type; | ||
| 77 | 35 | ||
| 78 | lockdep_assert_held(&local->chanctx_mtx); | 36 | lockdep_assert_held(&local->chanctx_mtx); |
| 79 | 37 | ||
| 80 | if (mode == IEEE80211_CHANCTX_EXCLUSIVE) | 38 | if (mode == IEEE80211_CHANCTX_EXCLUSIVE) |
| 81 | return NULL; | 39 | return NULL; |
| 82 | if (WARN_ON(!channel)) | ||
| 83 | return NULL; | ||
| 84 | 40 | ||
| 85 | list_for_each_entry(ctx, &local->chanctx_list, list) { | 41 | list_for_each_entry(ctx, &local->chanctx_list, list) { |
| 86 | compat_type = ctx->conf.channel_type; | 42 | const struct cfg80211_chan_def *compat; |
| 87 | 43 | ||
| 88 | if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE) | 44 | if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE) |
| 89 | continue; | 45 | continue; |
| 90 | if (ctx->conf.channel != channel) | 46 | |
| 91 | continue; | 47 | compat = cfg80211_chandef_compatible(&ctx->conf.def, chandef); |
| 92 | if (!ieee80211_channel_types_are_compatible(ctx->conf.channel_type, | 48 | if (!compat) |
| 93 | channel_type, | ||
| 94 | &compat_type)) | ||
| 95 | continue; | 49 | continue; |
| 96 | 50 | ||
| 97 | ieee80211_change_chantype(local, ctx, compat_type); | 51 | ieee80211_change_chandef(local, ctx, compat); |
| 98 | 52 | ||
| 99 | return ctx; | 53 | return ctx; |
| 100 | } | 54 | } |
| @@ -104,8 +58,7 @@ ieee80211_find_chanctx(struct ieee80211_local *local, | |||
| 104 | 58 | ||
| 105 | static struct ieee80211_chanctx * | 59 | static struct ieee80211_chanctx * |
| 106 | ieee80211_new_chanctx(struct ieee80211_local *local, | 60 | ieee80211_new_chanctx(struct ieee80211_local *local, |
| 107 | struct ieee80211_channel *channel, | 61 | const struct cfg80211_chan_def *chandef, |
| 108 | enum nl80211_channel_type channel_type, | ||
| 109 | enum ieee80211_chanctx_mode mode) | 62 | enum ieee80211_chanctx_mode mode) |
| 110 | { | 63 | { |
| 111 | struct ieee80211_chanctx *ctx; | 64 | struct ieee80211_chanctx *ctx; |
| @@ -117,15 +70,15 @@ ieee80211_new_chanctx(struct ieee80211_local *local, | |||
| 117 | if (!ctx) | 70 | if (!ctx) |
| 118 | return ERR_PTR(-ENOMEM); | 71 | return ERR_PTR(-ENOMEM); |
| 119 | 72 | ||
| 120 | ctx->conf.channel = channel; | 73 | ctx->conf.def = *chandef; |
| 121 | ctx->conf.channel_type = channel_type; | ||
| 122 | ctx->conf.rx_chains_static = 1; | 74 | ctx->conf.rx_chains_static = 1; |
| 123 | ctx->conf.rx_chains_dynamic = 1; | 75 | ctx->conf.rx_chains_dynamic = 1; |
| 124 | ctx->mode = mode; | 76 | ctx->mode = mode; |
| 125 | 77 | ||
| 126 | if (!local->use_chanctx) { | 78 | if (!local->use_chanctx) { |
| 127 | local->_oper_channel_type = channel_type; | 79 | local->_oper_channel_type = |
| 128 | local->_oper_channel = channel; | 80 | cfg80211_get_chandef_type(chandef); |
| 81 | local->_oper_channel = chandef->chan; | ||
| 129 | ieee80211_hw_config(local, 0); | 82 | ieee80211_hw_config(local, 0); |
| 130 | } else { | 83 | } else { |
| 131 | err = drv_add_chanctx(local, ctx); | 84 | err = drv_add_chanctx(local, ctx); |
| @@ -173,44 +126,42 @@ static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata, | |||
| 173 | rcu_assign_pointer(sdata->vif.chanctx_conf, &ctx->conf); | 126 | rcu_assign_pointer(sdata->vif.chanctx_conf, &ctx->conf); |
| 174 | ctx->refcount++; | 127 | ctx->refcount++; |
| 175 | 128 | ||
| 129 | ieee80211_recalc_txpower(sdata); | ||
| 130 | |||
| 176 | return 0; | 131 | return 0; |
| 177 | } | 132 | } |
| 178 | 133 | ||
| 179 | static enum nl80211_channel_type | 134 | static void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local, |
| 180 | ieee80211_calc_chantype(struct ieee80211_local *local, | 135 | struct ieee80211_chanctx *ctx) |
| 181 | struct ieee80211_chanctx *ctx) | ||
| 182 | { | 136 | { |
| 183 | struct ieee80211_chanctx_conf *conf = &ctx->conf; | 137 | struct ieee80211_chanctx_conf *conf = &ctx->conf; |
| 184 | struct ieee80211_sub_if_data *sdata; | 138 | struct ieee80211_sub_if_data *sdata; |
| 185 | enum nl80211_channel_type result = NL80211_CHAN_NO_HT; | 139 | const struct cfg80211_chan_def *compat = NULL; |
| 186 | 140 | ||
| 187 | lockdep_assert_held(&local->chanctx_mtx); | 141 | lockdep_assert_held(&local->chanctx_mtx); |
| 188 | 142 | ||
| 189 | rcu_read_lock(); | 143 | rcu_read_lock(); |
| 190 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { | 144 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { |
| 145 | |||
| 191 | if (!ieee80211_sdata_running(sdata)) | 146 | if (!ieee80211_sdata_running(sdata)) |
| 192 | continue; | 147 | continue; |
| 193 | if (rcu_access_pointer(sdata->vif.chanctx_conf) != conf) | 148 | if (rcu_access_pointer(sdata->vif.chanctx_conf) != conf) |
| 194 | continue; | 149 | continue; |
| 195 | 150 | ||
| 196 | WARN_ON_ONCE(!ieee80211_channel_types_are_compatible( | 151 | if (!compat) |
| 197 | sdata->vif.bss_conf.channel_type, | 152 | compat = &sdata->vif.bss_conf.chandef; |
| 198 | result, &result)); | 153 | |
| 154 | compat = cfg80211_chandef_compatible( | ||
| 155 | &sdata->vif.bss_conf.chandef, compat); | ||
| 156 | if (!compat) | ||
| 157 | break; | ||
| 199 | } | 158 | } |
| 200 | rcu_read_unlock(); | 159 | rcu_read_unlock(); |
| 201 | 160 | ||
| 202 | return result; | 161 | if (WARN_ON_ONCE(!compat)) |
| 203 | } | 162 | return; |
| 204 | |||
| 205 | static void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local, | ||
| 206 | struct ieee80211_chanctx *ctx) | ||
| 207 | { | ||
| 208 | enum nl80211_channel_type chantype; | ||
| 209 | |||
| 210 | lockdep_assert_held(&local->chanctx_mtx); | ||
| 211 | 163 | ||
| 212 | chantype = ieee80211_calc_chantype(local, ctx); | 164 | ieee80211_change_chandef(local, ctx, compat); |
| 213 | ieee80211_change_chantype(local, ctx, chantype); | ||
| 214 | } | 165 | } |
| 215 | 166 | ||
| 216 | static void ieee80211_unassign_vif_chanctx(struct ieee80211_sub_if_data *sdata, | 167 | static void ieee80211_unassign_vif_chanctx(struct ieee80211_sub_if_data *sdata, |
| @@ -335,8 +286,7 @@ void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local, | |||
| 335 | } | 286 | } |
| 336 | 287 | ||
| 337 | int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata, | 288 | int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata, |
| 338 | struct ieee80211_channel *channel, | 289 | const struct cfg80211_chan_def *chandef, |
| 339 | enum nl80211_channel_type channel_type, | ||
| 340 | enum ieee80211_chanctx_mode mode) | 290 | enum ieee80211_chanctx_mode mode) |
| 341 | { | 291 | { |
| 342 | struct ieee80211_local *local = sdata->local; | 292 | struct ieee80211_local *local = sdata->local; |
| @@ -348,15 +298,15 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata, | |||
| 348 | mutex_lock(&local->chanctx_mtx); | 298 | mutex_lock(&local->chanctx_mtx); |
| 349 | __ieee80211_vif_release_channel(sdata); | 299 | __ieee80211_vif_release_channel(sdata); |
| 350 | 300 | ||
| 351 | ctx = ieee80211_find_chanctx(local, channel, channel_type, mode); | 301 | ctx = ieee80211_find_chanctx(local, chandef, mode); |
| 352 | if (!ctx) | 302 | if (!ctx) |
| 353 | ctx = ieee80211_new_chanctx(local, channel, channel_type, mode); | 303 | ctx = ieee80211_new_chanctx(local, chandef, mode); |
| 354 | if (IS_ERR(ctx)) { | 304 | if (IS_ERR(ctx)) { |
| 355 | ret = PTR_ERR(ctx); | 305 | ret = PTR_ERR(ctx); |
| 356 | goto out; | 306 | goto out; |
| 357 | } | 307 | } |
| 358 | 308 | ||
| 359 | sdata->vif.bss_conf.channel_type = channel_type; | 309 | sdata->vif.bss_conf.chandef = *chandef; |
| 360 | 310 | ||
| 361 | ret = ieee80211_assign_vif_chanctx(sdata, ctx); | 311 | ret = ieee80211_assign_vif_chanctx(sdata, ctx); |
| 362 | if (ret) { | 312 | if (ret) { |
diff --git a/net/mac80211/debugfs_key.c b/net/mac80211/debugfs_key.c index 090d08ff22c4..2d4235497f1b 100644 --- a/net/mac80211/debugfs_key.c +++ b/net/mac80211/debugfs_key.c | |||
| @@ -116,7 +116,7 @@ static ssize_t key_rx_spec_read(struct file *file, char __user *userbuf, | |||
| 116 | size_t count, loff_t *ppos) | 116 | size_t count, loff_t *ppos) |
| 117 | { | 117 | { |
| 118 | struct ieee80211_key *key = file->private_data; | 118 | struct ieee80211_key *key = file->private_data; |
| 119 | char buf[14*NUM_RX_DATA_QUEUES+1], *p = buf; | 119 | char buf[14*IEEE80211_NUM_TIDS+1], *p = buf; |
| 120 | int i, len; | 120 | int i, len; |
| 121 | const u8 *rpn; | 121 | const u8 *rpn; |
| 122 | 122 | ||
| @@ -126,7 +126,7 @@ static ssize_t key_rx_spec_read(struct file *file, char __user *userbuf, | |||
| 126 | len = scnprintf(buf, sizeof(buf), "\n"); | 126 | len = scnprintf(buf, sizeof(buf), "\n"); |
| 127 | break; | 127 | break; |
| 128 | case WLAN_CIPHER_SUITE_TKIP: | 128 | case WLAN_CIPHER_SUITE_TKIP: |
| 129 | for (i = 0; i < NUM_RX_DATA_QUEUES; i++) | 129 | for (i = 0; i < IEEE80211_NUM_TIDS; i++) |
| 130 | p += scnprintf(p, sizeof(buf)+buf-p, | 130 | p += scnprintf(p, sizeof(buf)+buf-p, |
| 131 | "%08x %04x\n", | 131 | "%08x %04x\n", |
| 132 | key->u.tkip.rx[i].iv32, | 132 | key->u.tkip.rx[i].iv32, |
| @@ -134,7 +134,7 @@ static ssize_t key_rx_spec_read(struct file *file, char __user *userbuf, | |||
| 134 | len = p - buf; | 134 | len = p - buf; |
| 135 | break; | 135 | break; |
| 136 | case WLAN_CIPHER_SUITE_CCMP: | 136 | case WLAN_CIPHER_SUITE_CCMP: |
| 137 | for (i = 0; i < NUM_RX_DATA_QUEUES + 1; i++) { | 137 | for (i = 0; i < IEEE80211_NUM_TIDS + 1; i++) { |
| 138 | rpn = key->u.ccmp.rx_pn[i]; | 138 | rpn = key->u.ccmp.rx_pn[i]; |
| 139 | p += scnprintf(p, sizeof(buf)+buf-p, | 139 | p += scnprintf(p, sizeof(buf)+buf-p, |
| 140 | "%02x%02x%02x%02x%02x%02x\n", | 140 | "%02x%02x%02x%02x%02x%02x\n", |
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index 3393ad5b8ab1..cbde5cc49a40 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c | |||
| @@ -10,6 +10,7 @@ | |||
| 10 | #include <linux/kernel.h> | 10 | #include <linux/kernel.h> |
| 11 | #include <linux/device.h> | 11 | #include <linux/device.h> |
| 12 | #include <linux/if.h> | 12 | #include <linux/if.h> |
| 13 | #include <linux/if_ether.h> | ||
| 13 | #include <linux/interrupt.h> | 14 | #include <linux/interrupt.h> |
| 14 | #include <linux/netdevice.h> | 15 | #include <linux/netdevice.h> |
| 15 | #include <linux/rtnetlink.h> | 16 | #include <linux/rtnetlink.h> |
| @@ -167,7 +168,29 @@ IEEE80211_IF_FILE(rc_rateidx_mcs_mask_5ghz, | |||
| 167 | 168 | ||
| 168 | IEEE80211_IF_FILE(flags, flags, HEX); | 169 | IEEE80211_IF_FILE(flags, flags, HEX); |
| 169 | IEEE80211_IF_FILE(state, state, LHEX); | 170 | IEEE80211_IF_FILE(state, state, LHEX); |
| 170 | IEEE80211_IF_FILE(channel_type, vif.bss_conf.channel_type, DEC); | 171 | IEEE80211_IF_FILE(txpower, vif.bss_conf.txpower, DEC); |
| 172 | IEEE80211_IF_FILE(ap_power_level, ap_power_level, DEC); | ||
| 173 | IEEE80211_IF_FILE(user_power_level, user_power_level, DEC); | ||
| 174 | |||
| 175 | static ssize_t | ||
| 176 | ieee80211_if_fmt_hw_queues(const struct ieee80211_sub_if_data *sdata, | ||
| 177 | char *buf, int buflen) | ||
| 178 | { | ||
| 179 | int len; | ||
| 180 | |||
| 181 | len = scnprintf(buf, buflen, "AC queues: VO:%d VI:%d BE:%d BK:%d\n", | ||
| 182 | sdata->vif.hw_queue[IEEE80211_AC_VO], | ||
| 183 | sdata->vif.hw_queue[IEEE80211_AC_VI], | ||
| 184 | sdata->vif.hw_queue[IEEE80211_AC_BE], | ||
| 185 | sdata->vif.hw_queue[IEEE80211_AC_BK]); | ||
| 186 | |||
| 187 | if (sdata->vif.type == NL80211_IFTYPE_AP) | ||
| 188 | len += scnprintf(buf + len, buflen - len, "cab queue: %d\n", | ||
| 189 | sdata->vif.cab_queue); | ||
| 190 | |||
| 191 | return len; | ||
| 192 | } | ||
| 193 | __IEEE80211_IF_FILE(hw_queues, NULL); | ||
| 171 | 194 | ||
| 172 | /* STA attributes */ | 195 | /* STA attributes */ |
| 173 | IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC); | 196 | IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC); |
| @@ -245,27 +268,6 @@ static ssize_t ieee80211_if_fmt_tkip_mic_test( | |||
| 245 | return -EOPNOTSUPP; | 268 | return -EOPNOTSUPP; |
| 246 | } | 269 | } |
| 247 | 270 | ||
| 248 | static int hwaddr_aton(const char *txt, u8 *addr) | ||
| 249 | { | ||
| 250 | int i; | ||
| 251 | |||
| 252 | for (i = 0; i < ETH_ALEN; i++) { | ||
| 253 | int a, b; | ||
| 254 | |||
| 255 | a = hex_to_bin(*txt++); | ||
| 256 | if (a < 0) | ||
| 257 | return -1; | ||
| 258 | b = hex_to_bin(*txt++); | ||
| 259 | if (b < 0) | ||
| 260 | return -1; | ||
| 261 | *addr++ = (a << 4) | b; | ||
| 262 | if (i < 5 && *txt++ != ':') | ||
| 263 | return -1; | ||
| 264 | } | ||
| 265 | |||
| 266 | return 0; | ||
| 267 | } | ||
| 268 | |||
| 269 | static ssize_t ieee80211_if_parse_tkip_mic_test( | 271 | static ssize_t ieee80211_if_parse_tkip_mic_test( |
| 270 | struct ieee80211_sub_if_data *sdata, const char *buf, int buflen) | 272 | struct ieee80211_sub_if_data *sdata, const char *buf, int buflen) |
| 271 | { | 273 | { |
| @@ -275,13 +277,7 @@ static ssize_t ieee80211_if_parse_tkip_mic_test( | |||
| 275 | struct ieee80211_hdr *hdr; | 277 | struct ieee80211_hdr *hdr; |
| 276 | __le16 fc; | 278 | __le16 fc; |
| 277 | 279 | ||
| 278 | /* | 280 | if (!mac_pton(buf, addr)) |
| 279 | * Assume colon-delimited MAC address with possible white space | ||
| 280 | * following. | ||
| 281 | */ | ||
| 282 | if (buflen < 3 * ETH_ALEN - 1) | ||
| 283 | return -EINVAL; | ||
| 284 | if (hwaddr_aton(buf, addr) < 0) | ||
| 285 | return -EINVAL; | 281 | return -EINVAL; |
| 286 | 282 | ||
| 287 | if (!ieee80211_sdata_running(sdata)) | 283 | if (!ieee80211_sdata_running(sdata)) |
| @@ -307,13 +303,16 @@ static ssize_t ieee80211_if_parse_tkip_mic_test( | |||
| 307 | case NL80211_IFTYPE_STATION: | 303 | case NL80211_IFTYPE_STATION: |
| 308 | fc |= cpu_to_le16(IEEE80211_FCTL_TODS); | 304 | fc |= cpu_to_le16(IEEE80211_FCTL_TODS); |
| 309 | /* BSSID SA DA */ | 305 | /* BSSID SA DA */ |
| 310 | if (sdata->vif.bss_conf.bssid == NULL) { | 306 | mutex_lock(&sdata->u.mgd.mtx); |
| 307 | if (!sdata->u.mgd.associated) { | ||
| 308 | mutex_unlock(&sdata->u.mgd.mtx); | ||
| 311 | dev_kfree_skb(skb); | 309 | dev_kfree_skb(skb); |
| 312 | return -ENOTCONN; | 310 | return -ENOTCONN; |
| 313 | } | 311 | } |
| 314 | memcpy(hdr->addr1, sdata->vif.bss_conf.bssid, ETH_ALEN); | 312 | memcpy(hdr->addr1, sdata->u.mgd.associated->bssid, ETH_ALEN); |
| 315 | memcpy(hdr->addr2, sdata->vif.addr, ETH_ALEN); | 313 | memcpy(hdr->addr2, sdata->vif.addr, ETH_ALEN); |
| 316 | memcpy(hdr->addr3, addr, ETH_ALEN); | 314 | memcpy(hdr->addr3, addr, ETH_ALEN); |
| 315 | mutex_unlock(&sdata->u.mgd.mtx); | ||
| 317 | break; | 316 | break; |
| 318 | default: | 317 | default: |
| 319 | dev_kfree_skb(skb); | 318 | dev_kfree_skb(skb); |
| @@ -443,7 +442,7 @@ static ssize_t ieee80211_if_parse_tsf( | |||
| 443 | } | 442 | } |
| 444 | ret = kstrtoull(buf, 10, &tsf); | 443 | ret = kstrtoull(buf, 10, &tsf); |
| 445 | if (ret < 0) | 444 | if (ret < 0) |
| 446 | return -EINVAL; | 445 | return ret; |
| 447 | if (tsf_is_delta) | 446 | if (tsf_is_delta) |
| 448 | tsf = drv_get_tsf(local, sdata) + tsf_is_delta * tsf; | 447 | tsf = drv_get_tsf(local, sdata) + tsf_is_delta * tsf; |
| 449 | if (local->ops->set_tsf) { | 448 | if (local->ops->set_tsf) { |
| @@ -531,6 +530,7 @@ static void add_common_files(struct ieee80211_sub_if_data *sdata) | |||
| 531 | DEBUGFS_ADD(rc_rateidx_mask_5ghz); | 530 | DEBUGFS_ADD(rc_rateidx_mask_5ghz); |
| 532 | DEBUGFS_ADD(rc_rateidx_mcs_mask_2ghz); | 531 | DEBUGFS_ADD(rc_rateidx_mcs_mask_2ghz); |
| 533 | DEBUGFS_ADD(rc_rateidx_mcs_mask_5ghz); | 532 | DEBUGFS_ADD(rc_rateidx_mcs_mask_5ghz); |
| 533 | DEBUGFS_ADD(hw_queues); | ||
| 534 | } | 534 | } |
| 535 | 535 | ||
| 536 | static void add_sta_files(struct ieee80211_sub_if_data *sdata) | 536 | static void add_sta_files(struct ieee80211_sub_if_data *sdata) |
| @@ -631,7 +631,9 @@ static void add_files(struct ieee80211_sub_if_data *sdata) | |||
| 631 | 631 | ||
| 632 | DEBUGFS_ADD(flags); | 632 | DEBUGFS_ADD(flags); |
| 633 | DEBUGFS_ADD(state); | 633 | DEBUGFS_ADD(state); |
| 634 | DEBUGFS_ADD(channel_type); | 634 | DEBUGFS_ADD(txpower); |
| 635 | DEBUGFS_ADD(user_power_level); | ||
| 636 | DEBUGFS_ADD(ap_power_level); | ||
| 635 | 637 | ||
| 636 | if (sdata->vif.type != NL80211_IFTYPE_MONITOR) | 638 | if (sdata->vif.type != NL80211_IFTYPE_MONITOR) |
| 637 | add_common_files(sdata); | 639 | add_common_files(sdata); |
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index 5ccec2c1e9f6..89281d24b094 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c | |||
| @@ -14,6 +14,7 @@ | |||
| 14 | #include "debugfs.h" | 14 | #include "debugfs.h" |
| 15 | #include "debugfs_sta.h" | 15 | #include "debugfs_sta.h" |
| 16 | #include "sta_info.h" | 16 | #include "sta_info.h" |
| 17 | #include "driver-ops.h" | ||
| 17 | 18 | ||
| 18 | /* sta attributtes */ | 19 | /* sta attributtes */ |
| 19 | 20 | ||
| @@ -131,10 +132,10 @@ STA_OPS(connected_time); | |||
| 131 | static ssize_t sta_last_seq_ctrl_read(struct file *file, char __user *userbuf, | 132 | static ssize_t sta_last_seq_ctrl_read(struct file *file, char __user *userbuf, |
| 132 | size_t count, loff_t *ppos) | 133 | size_t count, loff_t *ppos) |
| 133 | { | 134 | { |
| 134 | char buf[15*NUM_RX_DATA_QUEUES], *p = buf; | 135 | char buf[15*IEEE80211_NUM_TIDS], *p = buf; |
| 135 | int i; | 136 | int i; |
| 136 | struct sta_info *sta = file->private_data; | 137 | struct sta_info *sta = file->private_data; |
| 137 | for (i = 0; i < NUM_RX_DATA_QUEUES; i++) | 138 | for (i = 0; i < IEEE80211_NUM_TIDS; i++) |
| 138 | p += scnprintf(p, sizeof(buf)+buf-p, "%x ", | 139 | p += scnprintf(p, sizeof(buf)+buf-p, "%x ", |
| 139 | le16_to_cpu(sta->last_seq_ctrl[i])); | 140 | le16_to_cpu(sta->last_seq_ctrl[i])); |
| 140 | p += scnprintf(p, sizeof(buf)+buf-p, "\n"); | 141 | p += scnprintf(p, sizeof(buf)+buf-p, "\n"); |
| @@ -145,7 +146,7 @@ STA_OPS(last_seq_ctrl); | |||
| 145 | static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf, | 146 | static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf, |
| 146 | size_t count, loff_t *ppos) | 147 | size_t count, loff_t *ppos) |
| 147 | { | 148 | { |
| 148 | char buf[71 + STA_TID_NUM * 40], *p = buf; | 149 | char buf[71 + IEEE80211_NUM_TIDS * 40], *p = buf; |
| 149 | int i; | 150 | int i; |
| 150 | struct sta_info *sta = file->private_data; | 151 | struct sta_info *sta = file->private_data; |
| 151 | struct tid_ampdu_rx *tid_rx; | 152 | struct tid_ampdu_rx *tid_rx; |
| @@ -158,7 +159,7 @@ static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf, | |||
| 158 | p += scnprintf(p, sizeof(buf) + buf - p, | 159 | p += scnprintf(p, sizeof(buf) + buf - p, |
| 159 | "TID\t\tRX active\tDTKN\tSSN\t\tTX\tDTKN\tpending\n"); | 160 | "TID\t\tRX active\tDTKN\tSSN\t\tTX\tDTKN\tpending\n"); |
| 160 | 161 | ||
| 161 | for (i = 0; i < STA_TID_NUM; i++) { | 162 | for (i = 0; i < IEEE80211_NUM_TIDS; i++) { |
| 162 | tid_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[i]); | 163 | tid_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[i]); |
| 163 | tid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[i]); | 164 | tid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[i]); |
| 164 | 165 | ||
| @@ -220,7 +221,7 @@ static ssize_t sta_agg_status_write(struct file *file, const char __user *userbu | |||
| 220 | 221 | ||
| 221 | tid = simple_strtoul(buf, NULL, 0); | 222 | tid = simple_strtoul(buf, NULL, 0); |
| 222 | 223 | ||
| 223 | if (tid >= STA_TID_NUM) | 224 | if (tid >= IEEE80211_NUM_TIDS) |
| 224 | return -EINVAL; | 225 | return -EINVAL; |
| 225 | 226 | ||
| 226 | if (tx) { | 227 | if (tx) { |
| @@ -334,6 +335,8 @@ STA_OPS(ht_capa); | |||
| 334 | 335 | ||
| 335 | void ieee80211_sta_debugfs_add(struct sta_info *sta) | 336 | void ieee80211_sta_debugfs_add(struct sta_info *sta) |
| 336 | { | 337 | { |
| 338 | struct ieee80211_local *local = sta->local; | ||
| 339 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
| 337 | struct dentry *stations_dir = sta->sdata->debugfs.subdir_stations; | 340 | struct dentry *stations_dir = sta->sdata->debugfs.subdir_stations; |
| 338 | u8 mac[3*ETH_ALEN]; | 341 | u8 mac[3*ETH_ALEN]; |
| 339 | 342 | ||
| @@ -379,10 +382,16 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta) | |||
| 379 | DEBUGFS_ADD_COUNTER(tx_retry_failed, tx_retry_failed); | 382 | DEBUGFS_ADD_COUNTER(tx_retry_failed, tx_retry_failed); |
| 380 | DEBUGFS_ADD_COUNTER(tx_retry_count, tx_retry_count); | 383 | DEBUGFS_ADD_COUNTER(tx_retry_count, tx_retry_count); |
| 381 | DEBUGFS_ADD_COUNTER(wep_weak_iv_count, wep_weak_iv_count); | 384 | DEBUGFS_ADD_COUNTER(wep_weak_iv_count, wep_weak_iv_count); |
| 385 | |||
| 386 | drv_sta_add_debugfs(local, sdata, &sta->sta, sta->debugfs.dir); | ||
| 382 | } | 387 | } |
| 383 | 388 | ||
| 384 | void ieee80211_sta_debugfs_remove(struct sta_info *sta) | 389 | void ieee80211_sta_debugfs_remove(struct sta_info *sta) |
| 385 | { | 390 | { |
| 391 | struct ieee80211_local *local = sta->local; | ||
| 392 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
| 393 | |||
| 394 | drv_sta_remove_debugfs(local, sdata, &sta->sta, sta->debugfs.dir); | ||
| 386 | debugfs_remove_recursive(sta->debugfs.dir); | 395 | debugfs_remove_recursive(sta->debugfs.dir); |
| 387 | sta->debugfs.dir = NULL; | 396 | sta->debugfs.dir = NULL; |
| 388 | } | 397 | } |
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 77407b31e1ff..c6560cc7a9d6 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h | |||
| @@ -490,6 +490,38 @@ static inline void drv_sta_remove(struct ieee80211_local *local, | |||
| 490 | trace_drv_return_void(local); | 490 | trace_drv_return_void(local); |
| 491 | } | 491 | } |
| 492 | 492 | ||
| 493 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
| 494 | static inline void drv_sta_add_debugfs(struct ieee80211_local *local, | ||
| 495 | struct ieee80211_sub_if_data *sdata, | ||
| 496 | struct ieee80211_sta *sta, | ||
| 497 | struct dentry *dir) | ||
| 498 | { | ||
| 499 | might_sleep(); | ||
| 500 | |||
| 501 | sdata = get_bss_sdata(sdata); | ||
| 502 | check_sdata_in_driver(sdata); | ||
| 503 | |||
| 504 | if (local->ops->sta_add_debugfs) | ||
| 505 | local->ops->sta_add_debugfs(&local->hw, &sdata->vif, | ||
| 506 | sta, dir); | ||
| 507 | } | ||
| 508 | |||
| 509 | static inline void drv_sta_remove_debugfs(struct ieee80211_local *local, | ||
| 510 | struct ieee80211_sub_if_data *sdata, | ||
| 511 | struct ieee80211_sta *sta, | ||
| 512 | struct dentry *dir) | ||
| 513 | { | ||
| 514 | might_sleep(); | ||
| 515 | |||
| 516 | sdata = get_bss_sdata(sdata); | ||
| 517 | check_sdata_in_driver(sdata); | ||
| 518 | |||
| 519 | if (local->ops->sta_remove_debugfs) | ||
| 520 | local->ops->sta_remove_debugfs(&local->hw, &sdata->vif, | ||
| 521 | sta, dir); | ||
| 522 | } | ||
| 523 | #endif | ||
| 524 | |||
| 493 | static inline __must_check | 525 | static inline __must_check |
| 494 | int drv_sta_state(struct ieee80211_local *local, | 526 | int drv_sta_state(struct ieee80211_local *local, |
| 495 | struct ieee80211_sub_if_data *sdata, | 527 | struct ieee80211_sub_if_data *sdata, |
| @@ -704,17 +736,17 @@ static inline int drv_get_antenna(struct ieee80211_local *local, | |||
| 704 | } | 736 | } |
| 705 | 737 | ||
| 706 | static inline int drv_remain_on_channel(struct ieee80211_local *local, | 738 | static inline int drv_remain_on_channel(struct ieee80211_local *local, |
| 739 | struct ieee80211_sub_if_data *sdata, | ||
| 707 | struct ieee80211_channel *chan, | 740 | struct ieee80211_channel *chan, |
| 708 | enum nl80211_channel_type chantype, | ||
| 709 | unsigned int duration) | 741 | unsigned int duration) |
| 710 | { | 742 | { |
| 711 | int ret; | 743 | int ret; |
| 712 | 744 | ||
| 713 | might_sleep(); | 745 | might_sleep(); |
| 714 | 746 | ||
| 715 | trace_drv_remain_on_channel(local, chan, chantype, duration); | 747 | trace_drv_remain_on_channel(local, sdata, chan, duration); |
| 716 | ret = local->ops->remain_on_channel(&local->hw, chan, chantype, | 748 | ret = local->ops->remain_on_channel(&local->hw, &sdata->vif, |
| 717 | duration); | 749 | chan, duration); |
| 718 | trace_drv_return_int(local, ret); | 750 | trace_drv_return_int(local, ret); |
| 719 | 751 | ||
| 720 | return ret; | 752 | return ret; |
| @@ -936,4 +968,39 @@ static inline void drv_unassign_vif_chanctx(struct ieee80211_local *local, | |||
| 936 | trace_drv_return_void(local); | 968 | trace_drv_return_void(local); |
| 937 | } | 969 | } |
| 938 | 970 | ||
| 971 | static inline int drv_start_ap(struct ieee80211_local *local, | ||
| 972 | struct ieee80211_sub_if_data *sdata) | ||
| 973 | { | ||
| 974 | int ret = 0; | ||
| 975 | |||
| 976 | check_sdata_in_driver(sdata); | ||
| 977 | |||
| 978 | trace_drv_start_ap(local, sdata, &sdata->vif.bss_conf); | ||
| 979 | if (local->ops->start_ap) | ||
| 980 | ret = local->ops->start_ap(&local->hw, &sdata->vif); | ||
| 981 | trace_drv_return_int(local, ret); | ||
| 982 | return ret; | ||
| 983 | } | ||
| 984 | |||
| 985 | static inline void drv_stop_ap(struct ieee80211_local *local, | ||
| 986 | struct ieee80211_sub_if_data *sdata) | ||
| 987 | { | ||
| 988 | check_sdata_in_driver(sdata); | ||
| 989 | |||
| 990 | trace_drv_stop_ap(local, sdata); | ||
| 991 | if (local->ops->stop_ap) | ||
| 992 | local->ops->stop_ap(&local->hw, &sdata->vif); | ||
| 993 | trace_drv_return_void(local); | ||
| 994 | } | ||
| 995 | |||
| 996 | static inline void drv_restart_complete(struct ieee80211_local *local) | ||
| 997 | { | ||
| 998 | might_sleep(); | ||
| 999 | |||
| 1000 | trace_drv_restart_complete(local); | ||
| 1001 | if (local->ops->restart_complete) | ||
| 1002 | local->ops->restart_complete(&local->hw); | ||
| 1003 | trace_drv_return_void(local); | ||
| 1004 | } | ||
| 1005 | |||
| 939 | #endif /* __MAC80211_DRIVER_OPS */ | 1006 | #endif /* __MAC80211_DRIVER_OPS */ |
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index 4b4538d63925..a71d891794a4 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c | |||
| @@ -185,7 +185,7 @@ void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta, bool tx) | |||
| 185 | 185 | ||
| 186 | cancel_work_sync(&sta->ampdu_mlme.work); | 186 | cancel_work_sync(&sta->ampdu_mlme.work); |
| 187 | 187 | ||
| 188 | for (i = 0; i < STA_TID_NUM; i++) { | 188 | for (i = 0; i < IEEE80211_NUM_TIDS; i++) { |
| 189 | __ieee80211_stop_tx_ba_session(sta, i, WLAN_BACK_INITIATOR, tx); | 189 | __ieee80211_stop_tx_ba_session(sta, i, WLAN_BACK_INITIATOR, tx); |
| 190 | __ieee80211_stop_rx_ba_session(sta, i, WLAN_BACK_RECIPIENT, | 190 | __ieee80211_stop_rx_ba_session(sta, i, WLAN_BACK_RECIPIENT, |
| 191 | WLAN_REASON_QSTA_LEAVE_QBSS, tx); | 191 | WLAN_REASON_QSTA_LEAVE_QBSS, tx); |
| @@ -209,7 +209,7 @@ void ieee80211_ba_session_work(struct work_struct *work) | |||
| 209 | return; | 209 | return; |
| 210 | 210 | ||
| 211 | mutex_lock(&sta->ampdu_mlme.mtx); | 211 | mutex_lock(&sta->ampdu_mlme.mtx); |
| 212 | for (tid = 0; tid < STA_TID_NUM; tid++) { | 212 | for (tid = 0; tid < IEEE80211_NUM_TIDS; tid++) { |
| 213 | if (test_and_clear_bit(tid, sta->ampdu_mlme.tid_rx_timer_expired)) | 213 | if (test_and_clear_bit(tid, sta->ampdu_mlme.tid_rx_timer_expired)) |
| 214 | ___ieee80211_stop_rx_ba_session( | 214 | ___ieee80211_stop_rx_ba_session( |
| 215 | sta, tid, WLAN_BACK_RECIPIENT, | 215 | sta, tid, WLAN_BACK_RECIPIENT, |
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 67774b053535..fa862b24a7e0 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c | |||
| @@ -51,7 +51,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
| 51 | struct cfg80211_bss *bss; | 51 | struct cfg80211_bss *bss; |
| 52 | u32 bss_change; | 52 | u32 bss_change; |
| 53 | u8 supp_rates[IEEE80211_MAX_SUPP_RATES]; | 53 | u8 supp_rates[IEEE80211_MAX_SUPP_RATES]; |
| 54 | enum nl80211_channel_type channel_type; | 54 | struct cfg80211_chan_def chandef; |
| 55 | 55 | ||
| 56 | lockdep_assert_held(&ifibss->mtx); | 56 | lockdep_assert_held(&ifibss->mtx); |
| 57 | 57 | ||
| @@ -79,12 +79,14 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
| 79 | 79 | ||
| 80 | sdata->drop_unencrypted = capability & WLAN_CAPABILITY_PRIVACY ? 1 : 0; | 80 | sdata->drop_unencrypted = capability & WLAN_CAPABILITY_PRIVACY ? 1 : 0; |
| 81 | 81 | ||
| 82 | channel_type = ifibss->channel_type; | 82 | cfg80211_chandef_create(&chandef, chan, ifibss->channel_type); |
| 83 | if (!cfg80211_can_beacon_sec_chan(local->hw.wiphy, chan, channel_type)) | 83 | if (!cfg80211_reg_can_beacon(local->hw.wiphy, &chandef)) { |
| 84 | channel_type = NL80211_CHAN_HT20; | 84 | chandef.width = NL80211_CHAN_WIDTH_20; |
| 85 | chandef.center_freq1 = chan->center_freq; | ||
| 86 | } | ||
| 85 | 87 | ||
| 86 | ieee80211_vif_release_channel(sdata); | 88 | ieee80211_vif_release_channel(sdata); |
| 87 | if (ieee80211_vif_use_channel(sdata, chan, channel_type, | 89 | if (ieee80211_vif_use_channel(sdata, &chandef, |
| 88 | ifibss->fixed_channel ? | 90 | ifibss->fixed_channel ? |
| 89 | IEEE80211_CHANCTX_SHARED : | 91 | IEEE80211_CHANCTX_SHARED : |
| 90 | IEEE80211_CHANCTX_EXCLUSIVE)) { | 92 | IEEE80211_CHANCTX_EXCLUSIVE)) { |
| @@ -158,7 +160,8 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
| 158 | ifibss->ie, ifibss->ie_len); | 160 | ifibss->ie, ifibss->ie_len); |
| 159 | 161 | ||
| 160 | /* add HT capability and information IEs */ | 162 | /* add HT capability and information IEs */ |
| 161 | if (channel_type && sband->ht_cap.ht_supported) { | 163 | if (chandef.width != NL80211_CHAN_WIDTH_20_NOHT && |
| 164 | sband->ht_cap.ht_supported) { | ||
| 162 | pos = skb_put(skb, 4 + | 165 | pos = skb_put(skb, 4 + |
| 163 | sizeof(struct ieee80211_ht_cap) + | 166 | sizeof(struct ieee80211_ht_cap) + |
| 164 | sizeof(struct ieee80211_ht_operation)); | 167 | sizeof(struct ieee80211_ht_operation)); |
| @@ -170,7 +173,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
| 170 | * keep them at 0 | 173 | * keep them at 0 |
| 171 | */ | 174 | */ |
| 172 | pos = ieee80211_ie_build_ht_oper(pos, &sband->ht_cap, | 175 | pos = ieee80211_ie_build_ht_oper(pos, &sband->ht_cap, |
| 173 | chan, channel_type, 0); | 176 | &chandef, 0); |
| 174 | } | 177 | } |
| 175 | 178 | ||
| 176 | if (local->hw.queues >= IEEE80211_NUM_ACS) { | 179 | if (local->hw.queues >= IEEE80211_NUM_ACS) { |
| @@ -326,7 +329,7 @@ ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, | |||
| 326 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | 329 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); |
| 327 | if (WARN_ON_ONCE(!chanctx_conf)) | 330 | if (WARN_ON_ONCE(!chanctx_conf)) |
| 328 | return NULL; | 331 | return NULL; |
| 329 | band = chanctx_conf->channel->band; | 332 | band = chanctx_conf->def.chan->band; |
| 330 | rcu_read_unlock(); | 333 | rcu_read_unlock(); |
| 331 | 334 | ||
| 332 | sta = sta_info_alloc(sdata, addr, GFP_KERNEL); | 335 | sta = sta_info_alloc(sdata, addr, GFP_KERNEL); |
| @@ -374,11 +377,13 @@ static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata, | |||
| 374 | auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg); | 377 | auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg); |
| 375 | auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction); | 378 | auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction); |
| 376 | 379 | ||
| 377 | if (auth_alg != WLAN_AUTH_OPEN || auth_transaction != 1) | ||
| 378 | return; | ||
| 379 | ibss_dbg(sdata, | 380 | ibss_dbg(sdata, |
| 380 | "RX Auth SA=%pM DA=%pM BSSID=%pM (auth_transaction=%d)\n", | 381 | "RX Auth SA=%pM DA=%pM BSSID=%pM (auth_transaction=%d)\n", |
| 381 | mgmt->sa, mgmt->da, mgmt->bssid, auth_transaction); | 382 | mgmt->sa, mgmt->da, mgmt->bssid, auth_transaction); |
| 383 | |||
| 384 | if (auth_alg != WLAN_AUTH_OPEN || auth_transaction != 1) | ||
| 385 | return; | ||
| 386 | |||
| 382 | sta_info_destroy_addr(sdata, mgmt->sa); | 387 | sta_info_destroy_addr(sdata, mgmt->sa); |
| 383 | sta = ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, 0, false); | 388 | sta = ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, 0, false); |
| 384 | rcu_read_unlock(); | 389 | rcu_read_unlock(); |
| @@ -473,9 +478,11 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
| 473 | sdata->u.ibss.channel_type != NL80211_CHAN_NO_HT) { | 478 | sdata->u.ibss.channel_type != NL80211_CHAN_NO_HT) { |
| 474 | /* we both use HT */ | 479 | /* we both use HT */ |
| 475 | struct ieee80211_sta_ht_cap sta_ht_cap_new; | 480 | struct ieee80211_sta_ht_cap sta_ht_cap_new; |
| 476 | enum nl80211_channel_type channel_type = | 481 | struct cfg80211_chan_def chandef; |
| 477 | ieee80211_ht_oper_to_channel_type( | 482 | |
| 478 | elems->ht_operation); | 483 | ieee80211_ht_oper_to_chandef(channel, |
| 484 | elems->ht_operation, | ||
| 485 | &chandef); | ||
| 479 | 486 | ||
| 480 | ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, | 487 | ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, |
| 481 | elems->ht_cap_elem, | 488 | elems->ht_cap_elem, |
| @@ -485,9 +492,9 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
| 485 | * fall back to HT20 if we don't use or use | 492 | * fall back to HT20 if we don't use or use |
| 486 | * the other extension channel | 493 | * the other extension channel |
| 487 | */ | 494 | */ |
| 488 | if (!(channel_type == NL80211_CHAN_HT40MINUS || | 495 | if (chandef.width != NL80211_CHAN_WIDTH_40 || |
| 489 | channel_type == NL80211_CHAN_HT40PLUS) || | 496 | cfg80211_get_chandef_type(&chandef) != |
| 490 | channel_type != sdata->u.ibss.channel_type) | 497 | sdata->u.ibss.channel_type) |
| 491 | sta_ht_cap_new.cap &= | 498 | sta_ht_cap_new.cap &= |
| 492 | ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; | 499 | ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; |
| 493 | 500 | ||
| @@ -543,30 +550,11 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
| 543 | if (ether_addr_equal(cbss->bssid, sdata->u.ibss.bssid)) | 550 | if (ether_addr_equal(cbss->bssid, sdata->u.ibss.bssid)) |
| 544 | goto put_bss; | 551 | goto put_bss; |
| 545 | 552 | ||
| 546 | if (rx_status->flag & RX_FLAG_MACTIME_MPDU) { | 553 | if (ieee80211_have_rx_timestamp(rx_status)) { |
| 547 | /* | 554 | /* time when timestamp field was received */ |
| 548 | * For correct IBSS merging we need mactime; since mactime is | 555 | rx_timestamp = |
| 549 | * defined as the time the first data symbol of the frame hits | 556 | ieee80211_calculate_rx_timestamp(local, rx_status, |
| 550 | * the PHY, and the timestamp of the beacon is defined as "the | 557 | len + FCS_LEN, 24); |
| 551 | * time that the data symbol containing the first bit of the | ||
| 552 | * timestamp is transmitted to the PHY plus the transmitting | ||
| 553 | * STA's delays through its local PHY from the MAC-PHY | ||
| 554 | * interface to its interface with the WM" (802.11 11.1.2) | ||
| 555 | * - equals the time this bit arrives at the receiver - we have | ||
| 556 | * to take into account the offset between the two. | ||
| 557 | * | ||
| 558 | * E.g. at 1 MBit that means mactime is 192 usec earlier | ||
| 559 | * (=24 bytes * 8 usecs/byte) than the beacon timestamp. | ||
| 560 | */ | ||
| 561 | int rate; | ||
| 562 | |||
| 563 | if (rx_status->flag & RX_FLAG_HT) | ||
| 564 | rate = 65; /* TODO: HT rates */ | ||
| 565 | else | ||
| 566 | rate = local->hw.wiphy->bands[band]-> | ||
| 567 | bitrates[rx_status->rate_idx].bitrate; | ||
| 568 | |||
| 569 | rx_timestamp = rx_status->mactime + (24 * 8 * 10 / rate); | ||
| 570 | } else { | 558 | } else { |
| 571 | /* | 559 | /* |
| 572 | * second best option: get current TSF | 560 | * second best option: get current TSF |
| @@ -630,7 +618,7 @@ void ieee80211_ibss_rx_no_sta(struct ieee80211_sub_if_data *sdata, | |||
| 630 | rcu_read_unlock(); | 618 | rcu_read_unlock(); |
| 631 | return; | 619 | return; |
| 632 | } | 620 | } |
| 633 | band = chanctx_conf->channel->band; | 621 | band = chanctx_conf->def.chan->band; |
| 634 | rcu_read_unlock(); | 622 | rcu_read_unlock(); |
| 635 | 623 | ||
| 636 | sta = sta_info_alloc(sdata, addr, GFP_ATOMIC); | 624 | sta = sta_info_alloc(sdata, addr, GFP_ATOMIC); |
| @@ -1095,8 +1083,9 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, | |||
| 1095 | 1083 | ||
| 1096 | sdata->vif.bss_conf.beacon_int = params->beacon_interval; | 1084 | sdata->vif.bss_conf.beacon_int = params->beacon_interval; |
| 1097 | 1085 | ||
| 1098 | sdata->u.ibss.channel = params->channel; | 1086 | sdata->u.ibss.channel = params->chandef.chan; |
| 1099 | sdata->u.ibss.channel_type = params->channel_type; | 1087 | sdata->u.ibss.channel_type = |
| 1088 | cfg80211_get_chandef_type(¶ms->chandef); | ||
| 1100 | sdata->u.ibss.fixed_channel = params->channel_fixed; | 1089 | sdata->u.ibss.fixed_channel = params->channel_fixed; |
| 1101 | 1090 | ||
| 1102 | if (params->ie) { | 1091 | if (params->ie) { |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 32e47853f329..5c0d5a6946c1 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
| @@ -56,6 +56,9 @@ struct ieee80211_local; | |||
| 56 | #define TU_TO_JIFFIES(x) (usecs_to_jiffies((x) * 1024)) | 56 | #define TU_TO_JIFFIES(x) (usecs_to_jiffies((x) * 1024)) |
| 57 | #define TU_TO_EXP_TIME(x) (jiffies + TU_TO_JIFFIES(x)) | 57 | #define TU_TO_EXP_TIME(x) (jiffies + TU_TO_JIFFIES(x)) |
| 58 | 58 | ||
| 59 | /* power level hasn't been configured (or set to automatic) */ | ||
| 60 | #define IEEE80211_UNSET_POWER_LEVEL INT_MIN | ||
| 61 | |||
| 59 | /* | 62 | /* |
| 60 | * Some APs experience problems when working with U-APSD. Decrease the | 63 | * Some APs experience problems when working with U-APSD. Decrease the |
| 61 | * probability of that happening by using legacy mode for all ACs but VO. | 64 | * probability of that happening by using legacy mode for all ACs but VO. |
| @@ -345,7 +348,6 @@ struct ieee80211_roc_work { | |||
| 345 | struct ieee80211_sub_if_data *sdata; | 348 | struct ieee80211_sub_if_data *sdata; |
| 346 | 349 | ||
| 347 | struct ieee80211_channel *chan; | 350 | struct ieee80211_channel *chan; |
| 348 | enum nl80211_channel_type chan_type; | ||
| 349 | 351 | ||
| 350 | bool started, abort, hw_begun, notified; | 352 | bool started, abort, hw_begun, notified; |
| 351 | 353 | ||
| @@ -353,7 +355,7 @@ struct ieee80211_roc_work { | |||
| 353 | 355 | ||
| 354 | u32 duration, req_duration; | 356 | u32 duration, req_duration; |
| 355 | struct sk_buff *frame; | 357 | struct sk_buff *frame; |
| 356 | u64 mgmt_tx_cookie; | 358 | u64 cookie, mgmt_tx_cookie; |
| 357 | }; | 359 | }; |
| 358 | 360 | ||
| 359 | /* flags used in struct ieee80211_if_managed.flags */ | 361 | /* flags used in struct ieee80211_if_managed.flags */ |
| @@ -361,7 +363,7 @@ enum ieee80211_sta_flags { | |||
| 361 | IEEE80211_STA_BEACON_POLL = BIT(0), | 363 | IEEE80211_STA_BEACON_POLL = BIT(0), |
| 362 | IEEE80211_STA_CONNECTION_POLL = BIT(1), | 364 | IEEE80211_STA_CONNECTION_POLL = BIT(1), |
| 363 | IEEE80211_STA_CONTROL_PORT = BIT(2), | 365 | IEEE80211_STA_CONTROL_PORT = BIT(2), |
| 364 | IEEE80211_STA_DISABLE_11N = BIT(4), | 366 | IEEE80211_STA_DISABLE_HT = BIT(4), |
| 365 | IEEE80211_STA_CSA_RECEIVED = BIT(5), | 367 | IEEE80211_STA_CSA_RECEIVED = BIT(5), |
| 366 | IEEE80211_STA_MFP_ENABLED = BIT(6), | 368 | IEEE80211_STA_MFP_ENABLED = BIT(6), |
| 367 | IEEE80211_STA_UAPSD_ENABLED = BIT(7), | 369 | IEEE80211_STA_UAPSD_ENABLED = BIT(7), |
| @@ -470,6 +472,8 @@ struct ieee80211_if_managed { | |||
| 470 | 472 | ||
| 471 | u8 use_4addr; | 473 | u8 use_4addr; |
| 472 | 474 | ||
| 475 | u8 p2p_noa_index; | ||
| 476 | |||
| 473 | /* Signal strength from the last Beacon frame in the current BSS. */ | 477 | /* Signal strength from the last Beacon frame in the current BSS. */ |
| 474 | int last_beacon_signal; | 478 | int last_beacon_signal; |
| 475 | 479 | ||
| @@ -743,6 +747,9 @@ struct ieee80211_sub_if_data { | |||
| 743 | u8 needed_rx_chains; | 747 | u8 needed_rx_chains; |
| 744 | enum ieee80211_smps_mode smps_mode; | 748 | enum ieee80211_smps_mode smps_mode; |
| 745 | 749 | ||
| 750 | int user_power_level; /* in dBm */ | ||
| 751 | int ap_power_level; /* in dBm */ | ||
| 752 | |||
| 746 | /* | 753 | /* |
| 747 | * AP this belongs to: self in AP mode and | 754 | * AP this belongs to: self in AP mode and |
| 748 | * corresponding AP in VLAN mode, NULL for | 755 | * corresponding AP in VLAN mode, NULL for |
| @@ -792,7 +799,7 @@ ieee80211_get_sdata_band(struct ieee80211_sub_if_data *sdata) | |||
| 792 | rcu_read_lock(); | 799 | rcu_read_lock(); |
| 793 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | 800 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); |
| 794 | if (!WARN_ON(!chanctx_conf)) | 801 | if (!WARN_ON(!chanctx_conf)) |
| 795 | band = chanctx_conf->channel->band; | 802 | band = chanctx_conf->def.chan->band; |
| 796 | rcu_read_unlock(); | 803 | rcu_read_unlock(); |
| 797 | 804 | ||
| 798 | return band; | 805 | return band; |
| @@ -1040,7 +1047,6 @@ struct ieee80211_local { | |||
| 1040 | 1047 | ||
| 1041 | /* Temporary remain-on-channel for off-channel operations */ | 1048 | /* Temporary remain-on-channel for off-channel operations */ |
| 1042 | struct ieee80211_channel *tmp_channel; | 1049 | struct ieee80211_channel *tmp_channel; |
| 1043 | enum nl80211_channel_type tmp_channel_type; | ||
| 1044 | 1050 | ||
| 1045 | /* channel contexts */ | 1051 | /* channel contexts */ |
| 1046 | struct list_head chanctx_list; | 1052 | struct list_head chanctx_list; |
| @@ -1117,8 +1123,7 @@ struct ieee80211_local { | |||
| 1117 | int dynamic_ps_user_timeout; | 1123 | int dynamic_ps_user_timeout; |
| 1118 | bool disable_dynamic_ps; | 1124 | bool disable_dynamic_ps; |
| 1119 | 1125 | ||
| 1120 | int user_power_level; /* in dBm */ | 1126 | int user_power_level; /* in dBm, for all interfaces */ |
| 1121 | int ap_power_level; /* in dBm */ | ||
| 1122 | 1127 | ||
| 1123 | enum ieee80211_smps_mode smps_mode; | 1128 | enum ieee80211_smps_mode smps_mode; |
| 1124 | 1129 | ||
| @@ -1137,6 +1142,7 @@ struct ieee80211_local { | |||
| 1137 | struct list_head roc_list; | 1142 | struct list_head roc_list; |
| 1138 | struct work_struct hw_roc_start, hw_roc_done; | 1143 | struct work_struct hw_roc_start, hw_roc_done; |
| 1139 | unsigned long hw_roc_start_time; | 1144 | unsigned long hw_roc_start_time; |
| 1145 | u64 roc_cookie_counter; | ||
| 1140 | 1146 | ||
| 1141 | struct idr ack_status_frames; | 1147 | struct idr ack_status_frames; |
| 1142 | spinlock_t ack_status_lock; | 1148 | spinlock_t ack_status_lock; |
| @@ -1150,8 +1156,7 @@ struct ieee80211_local { | |||
| 1150 | 1156 | ||
| 1151 | /* virtual monitor interface */ | 1157 | /* virtual monitor interface */ |
| 1152 | struct ieee80211_sub_if_data __rcu *monitor_sdata; | 1158 | struct ieee80211_sub_if_data __rcu *monitor_sdata; |
| 1153 | struct ieee80211_channel *monitor_channel; | 1159 | struct cfg80211_chan_def monitor_chandef; |
| 1154 | enum nl80211_channel_type monitor_channel_type; | ||
| 1155 | }; | 1160 | }; |
| 1156 | 1161 | ||
| 1157 | static inline struct ieee80211_sub_if_data * | 1162 | static inline struct ieee80211_sub_if_data * |
| @@ -1251,7 +1256,18 @@ static inline int ieee80211_bssid_match(const u8 *raddr, const u8 *addr) | |||
| 1251 | is_broadcast_ether_addr(raddr); | 1256 | is_broadcast_ether_addr(raddr); |
| 1252 | } | 1257 | } |
| 1253 | 1258 | ||
| 1259 | static inline bool | ||
| 1260 | ieee80211_have_rx_timestamp(struct ieee80211_rx_status *status) | ||
| 1261 | { | ||
| 1262 | WARN_ON_ONCE(status->flag & RX_FLAG_MACTIME_START && | ||
| 1263 | status->flag & RX_FLAG_MACTIME_END); | ||
| 1264 | return status->flag & (RX_FLAG_MACTIME_START | RX_FLAG_MACTIME_END); | ||
| 1265 | } | ||
| 1254 | 1266 | ||
| 1267 | u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local, | ||
| 1268 | struct ieee80211_rx_status *status, | ||
| 1269 | unsigned int mpdu_len, | ||
| 1270 | unsigned int mpdu_offset); | ||
| 1255 | int ieee80211_hw_config(struct ieee80211_local *local, u32 changed); | 1271 | int ieee80211_hw_config(struct ieee80211_local *local, u32 changed); |
| 1256 | void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx); | 1272 | void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx); |
| 1257 | void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, | 1273 | void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, |
| @@ -1365,6 +1381,9 @@ void ieee80211_adjust_monitor_flags(struct ieee80211_sub_if_data *sdata, | |||
| 1365 | int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up); | 1381 | int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up); |
| 1366 | void ieee80211_sdata_stop(struct ieee80211_sub_if_data *sdata); | 1382 | void ieee80211_sdata_stop(struct ieee80211_sub_if_data *sdata); |
| 1367 | 1383 | ||
| 1384 | bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata); | ||
| 1385 | void ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata); | ||
| 1386 | |||
| 1368 | static inline bool ieee80211_sdata_running(struct ieee80211_sub_if_data *sdata) | 1387 | static inline bool ieee80211_sdata_running(struct ieee80211_sub_if_data *sdata) |
| 1369 | { | 1388 | { |
| 1370 | return test_bit(SDATA_STATE_RUNNING, &sdata->state); | 1389 | return test_bit(SDATA_STATE_RUNNING, &sdata->state); |
| @@ -1496,7 +1515,7 @@ static inline void ieee80211_tx_skb_tid(struct ieee80211_sub_if_data *sdata, | |||
| 1496 | } | 1515 | } |
| 1497 | 1516 | ||
| 1498 | __ieee80211_tx_skb_tid_band(sdata, skb, tid, | 1517 | __ieee80211_tx_skb_tid_band(sdata, skb, tid, |
| 1499 | chanctx_conf->channel->band); | 1518 | chanctx_conf->def.chan->band); |
| 1500 | rcu_read_unlock(); | 1519 | rcu_read_unlock(); |
| 1501 | } | 1520 | } |
| 1502 | 1521 | ||
| @@ -1585,8 +1604,7 @@ size_t ieee80211_ie_split_vendor(const u8 *ies, size_t ielen, size_t offset); | |||
| 1585 | u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, | 1604 | u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, |
| 1586 | u16 cap); | 1605 | u16 cap); |
| 1587 | u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, | 1606 | u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, |
| 1588 | struct ieee80211_channel *channel, | 1607 | const struct cfg80211_chan_def *chandef, |
| 1589 | enum nl80211_channel_type channel_type, | ||
| 1590 | u16 prot_mode); | 1608 | u16 prot_mode); |
| 1591 | u8 *ieee80211_ie_build_vht_cap(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap, | 1609 | u8 *ieee80211_ie_build_vht_cap(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap, |
| 1592 | u32 cap); | 1610 | u32 cap); |
| @@ -1598,13 +1616,13 @@ int ieee80211_add_ext_srates_ie(struct ieee80211_sub_if_data *sdata, | |||
| 1598 | enum ieee80211_band band); | 1616 | enum ieee80211_band band); |
| 1599 | 1617 | ||
| 1600 | /* channel management */ | 1618 | /* channel management */ |
| 1601 | enum nl80211_channel_type | 1619 | void ieee80211_ht_oper_to_chandef(struct ieee80211_channel *control_chan, |
| 1602 | ieee80211_ht_oper_to_channel_type(struct ieee80211_ht_operation *ht_oper); | 1620 | struct ieee80211_ht_operation *ht_oper, |
| 1621 | struct cfg80211_chan_def *chandef); | ||
| 1603 | 1622 | ||
| 1604 | int __must_check | 1623 | int __must_check |
| 1605 | ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata, | 1624 | ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata, |
| 1606 | struct ieee80211_channel *channel, | 1625 | const struct cfg80211_chan_def *chandef, |
| 1607 | enum nl80211_channel_type channel_type, | ||
| 1608 | enum ieee80211_chanctx_mode mode); | 1626 | enum ieee80211_chanctx_mode mode); |
| 1609 | void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata); | 1627 | void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata); |
| 1610 | 1628 | ||
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index bc3e3e1db093..5331662489f7 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
| @@ -42,6 +42,41 @@ | |||
| 42 | * by either the RTNL, the iflist_mtx or RCU. | 42 | * by either the RTNL, the iflist_mtx or RCU. |
| 43 | */ | 43 | */ |
| 44 | 44 | ||
| 45 | bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata) | ||
| 46 | { | ||
| 47 | struct ieee80211_chanctx_conf *chanctx_conf; | ||
| 48 | int power; | ||
| 49 | |||
| 50 | rcu_read_lock(); | ||
| 51 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | ||
| 52 | if (!chanctx_conf) { | ||
| 53 | rcu_read_unlock(); | ||
| 54 | return false; | ||
| 55 | } | ||
| 56 | |||
| 57 | power = chanctx_conf->def.chan->max_power; | ||
| 58 | rcu_read_unlock(); | ||
| 59 | |||
| 60 | if (sdata->user_power_level != IEEE80211_UNSET_POWER_LEVEL) | ||
| 61 | power = min(power, sdata->user_power_level); | ||
| 62 | |||
| 63 | if (sdata->ap_power_level != IEEE80211_UNSET_POWER_LEVEL) | ||
| 64 | power = min(power, sdata->ap_power_level); | ||
| 65 | |||
| 66 | if (power != sdata->vif.bss_conf.txpower) { | ||
| 67 | sdata->vif.bss_conf.txpower = power; | ||
| 68 | ieee80211_hw_config(sdata->local, 0); | ||
| 69 | return true; | ||
| 70 | } | ||
| 71 | |||
| 72 | return false; | ||
| 73 | } | ||
| 74 | |||
| 75 | void ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata) | ||
| 76 | { | ||
| 77 | if (__ieee80211_recalc_txpower(sdata)) | ||
| 78 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_TXPOWER); | ||
| 79 | } | ||
| 45 | 80 | ||
| 46 | static u32 ieee80211_idle_off(struct ieee80211_local *local, | 81 | static u32 ieee80211_idle_off(struct ieee80211_local *local, |
| 47 | const char *reason) | 82 | const char *reason) |
| @@ -380,8 +415,7 @@ static int ieee80211_add_virtual_monitor(struct ieee80211_local *local) | |||
| 380 | goto out_unlock; | 415 | goto out_unlock; |
| 381 | } | 416 | } |
| 382 | 417 | ||
| 383 | ret = ieee80211_vif_use_channel(sdata, local->monitor_channel, | 418 | ret = ieee80211_vif_use_channel(sdata, &local->monitor_chandef, |
| 384 | local->monitor_channel_type, | ||
| 385 | IEEE80211_CHANCTX_EXCLUSIVE); | 419 | IEEE80211_CHANCTX_EXCLUSIVE); |
| 386 | if (ret) { | 420 | if (ret) { |
| 387 | drv_remove_interface(local, sdata); | 421 | drv_remove_interface(local, sdata); |
| @@ -744,31 +778,12 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
| 744 | /* APs need special treatment */ | 778 | /* APs need special treatment */ |
| 745 | if (sdata->vif.type == NL80211_IFTYPE_AP) { | 779 | if (sdata->vif.type == NL80211_IFTYPE_AP) { |
| 746 | struct ieee80211_sub_if_data *vlan, *tmpsdata; | 780 | struct ieee80211_sub_if_data *vlan, *tmpsdata; |
| 747 | struct beacon_data *old_beacon = | ||
| 748 | rtnl_dereference(sdata->u.ap.beacon); | ||
| 749 | struct probe_resp *old_probe_resp = | ||
| 750 | rtnl_dereference(sdata->u.ap.probe_resp); | ||
| 751 | |||
| 752 | /* sdata_running will return false, so this will disable */ | ||
| 753 | ieee80211_bss_info_change_notify(sdata, | ||
| 754 | BSS_CHANGED_BEACON_ENABLED); | ||
| 755 | |||
| 756 | /* remove beacon and probe response */ | ||
| 757 | RCU_INIT_POINTER(sdata->u.ap.beacon, NULL); | ||
| 758 | RCU_INIT_POINTER(sdata->u.ap.probe_resp, NULL); | ||
| 759 | synchronize_rcu(); | ||
| 760 | kfree(old_beacon); | ||
| 761 | kfree(old_probe_resp); | ||
| 762 | 781 | ||
| 763 | /* down all dependent devices, that is VLANs */ | 782 | /* down all dependent devices, that is VLANs */ |
| 764 | list_for_each_entry_safe(vlan, tmpsdata, &sdata->u.ap.vlans, | 783 | list_for_each_entry_safe(vlan, tmpsdata, &sdata->u.ap.vlans, |
| 765 | u.vlan.list) | 784 | u.vlan.list) |
| 766 | dev_close(vlan->dev); | 785 | dev_close(vlan->dev); |
| 767 | WARN_ON(!list_empty(&sdata->u.ap.vlans)); | 786 | WARN_ON(!list_empty(&sdata->u.ap.vlans)); |
| 768 | |||
| 769 | /* free all potentially still buffered bcast frames */ | ||
| 770 | local->total_ps_buffered -= skb_queue_len(&sdata->u.ap.ps.bc_buf); | ||
| 771 | skb_queue_purge(&sdata->u.ap.ps.bc_buf); | ||
| 772 | } else if (sdata->vif.type == NL80211_IFTYPE_STATION) { | 787 | } else if (sdata->vif.type == NL80211_IFTYPE_STATION) { |
| 773 | ieee80211_mgd_stop(sdata); | 788 | ieee80211_mgd_stop(sdata); |
| 774 | } | 789 | } |
| @@ -1529,6 +1544,9 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, | |||
| 1529 | 1544 | ||
| 1530 | ieee80211_set_default_queues(sdata); | 1545 | ieee80211_set_default_queues(sdata); |
| 1531 | 1546 | ||
| 1547 | sdata->ap_power_level = IEEE80211_UNSET_POWER_LEVEL; | ||
| 1548 | sdata->user_power_level = local->user_power_level; | ||
| 1549 | |||
| 1532 | /* setup type-dependent data */ | 1550 | /* setup type-dependent data */ |
| 1533 | ieee80211_setup_sdata(sdata, type); | 1551 | ieee80211_setup_sdata(sdata, type); |
| 1534 | 1552 | ||
diff --git a/net/mac80211/key.c b/net/mac80211/key.c index d27e61aaa71b..619c5d697999 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c | |||
| @@ -339,7 +339,7 @@ struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len, | |||
| 339 | key->conf.iv_len = TKIP_IV_LEN; | 339 | key->conf.iv_len = TKIP_IV_LEN; |
| 340 | key->conf.icv_len = TKIP_ICV_LEN; | 340 | key->conf.icv_len = TKIP_ICV_LEN; |
| 341 | if (seq) { | 341 | if (seq) { |
| 342 | for (i = 0; i < NUM_RX_DATA_QUEUES; i++) { | 342 | for (i = 0; i < IEEE80211_NUM_TIDS; i++) { |
| 343 | key->u.tkip.rx[i].iv32 = | 343 | key->u.tkip.rx[i].iv32 = |
| 344 | get_unaligned_le32(&seq[2]); | 344 | get_unaligned_le32(&seq[2]); |
| 345 | key->u.tkip.rx[i].iv16 = | 345 | key->u.tkip.rx[i].iv16 = |
| @@ -352,7 +352,7 @@ struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len, | |||
| 352 | key->conf.iv_len = CCMP_HDR_LEN; | 352 | key->conf.iv_len = CCMP_HDR_LEN; |
| 353 | key->conf.icv_len = CCMP_MIC_LEN; | 353 | key->conf.icv_len = CCMP_MIC_LEN; |
| 354 | if (seq) { | 354 | if (seq) { |
| 355 | for (i = 0; i < NUM_RX_DATA_QUEUES + 1; i++) | 355 | for (i = 0; i < IEEE80211_NUM_TIDS + 1; i++) |
| 356 | for (j = 0; j < CCMP_PN_LEN; j++) | 356 | for (j = 0; j < CCMP_PN_LEN; j++) |
| 357 | key->u.ccmp.rx_pn[i][j] = | 357 | key->u.ccmp.rx_pn[i][j] = |
| 358 | seq[CCMP_PN_LEN - j - 1]; | 358 | seq[CCMP_PN_LEN - j - 1]; |
| @@ -372,8 +372,9 @@ struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len, | |||
| 372 | key->conf.iv_len = 0; | 372 | key->conf.iv_len = 0; |
| 373 | key->conf.icv_len = sizeof(struct ieee80211_mmie); | 373 | key->conf.icv_len = sizeof(struct ieee80211_mmie); |
| 374 | if (seq) | 374 | if (seq) |
| 375 | for (j = 0; j < 6; j++) | 375 | for (j = 0; j < CMAC_PN_LEN; j++) |
| 376 | key->u.aes_cmac.rx_pn[j] = seq[6 - j - 1]; | 376 | key->u.aes_cmac.rx_pn[j] = |
| 377 | seq[CMAC_PN_LEN - j - 1]; | ||
| 377 | /* | 378 | /* |
| 378 | * Initialize AES key state here as an optimization so that | 379 | * Initialize AES key state here as an optimization so that |
| 379 | * it does not need to be initialized for every packet. | 380 | * it does not need to be initialized for every packet. |
| @@ -654,16 +655,16 @@ void ieee80211_get_key_rx_seq(struct ieee80211_key_conf *keyconf, | |||
| 654 | 655 | ||
| 655 | switch (key->conf.cipher) { | 656 | switch (key->conf.cipher) { |
| 656 | case WLAN_CIPHER_SUITE_TKIP: | 657 | case WLAN_CIPHER_SUITE_TKIP: |
| 657 | if (WARN_ON(tid < 0 || tid >= NUM_RX_DATA_QUEUES)) | 658 | if (WARN_ON(tid < 0 || tid >= IEEE80211_NUM_TIDS)) |
| 658 | return; | 659 | return; |
| 659 | seq->tkip.iv32 = key->u.tkip.rx[tid].iv32; | 660 | seq->tkip.iv32 = key->u.tkip.rx[tid].iv32; |
| 660 | seq->tkip.iv16 = key->u.tkip.rx[tid].iv16; | 661 | seq->tkip.iv16 = key->u.tkip.rx[tid].iv16; |
| 661 | break; | 662 | break; |
| 662 | case WLAN_CIPHER_SUITE_CCMP: | 663 | case WLAN_CIPHER_SUITE_CCMP: |
| 663 | if (WARN_ON(tid < -1 || tid >= NUM_RX_DATA_QUEUES)) | 664 | if (WARN_ON(tid < -1 || tid >= IEEE80211_NUM_TIDS)) |
| 664 | return; | 665 | return; |
| 665 | if (tid < 0) | 666 | if (tid < 0) |
| 666 | pn = key->u.ccmp.rx_pn[NUM_RX_DATA_QUEUES]; | 667 | pn = key->u.ccmp.rx_pn[IEEE80211_NUM_TIDS]; |
| 667 | else | 668 | else |
| 668 | pn = key->u.ccmp.rx_pn[tid]; | 669 | pn = key->u.ccmp.rx_pn[tid]; |
| 669 | memcpy(seq->ccmp.pn, pn, CCMP_PN_LEN); | 670 | memcpy(seq->ccmp.pn, pn, CCMP_PN_LEN); |
diff --git a/net/mac80211/key.h b/net/mac80211/key.h index 7d4e31f037d7..7cff0d3a519c 100644 --- a/net/mac80211/key.h +++ b/net/mac80211/key.h | |||
| @@ -30,8 +30,6 @@ | |||
| 30 | #define TKIP_ICV_LEN 4 | 30 | #define TKIP_ICV_LEN 4 |
| 31 | #define CMAC_PN_LEN 6 | 31 | #define CMAC_PN_LEN 6 |
| 32 | 32 | ||
| 33 | #define NUM_RX_DATA_QUEUES 16 | ||
| 34 | |||
| 35 | struct ieee80211_local; | 33 | struct ieee80211_local; |
| 36 | struct ieee80211_sub_if_data; | 34 | struct ieee80211_sub_if_data; |
| 37 | struct sta_info; | 35 | struct sta_info; |
| @@ -82,17 +80,17 @@ struct ieee80211_key { | |||
| 82 | struct tkip_ctx tx; | 80 | struct tkip_ctx tx; |
| 83 | 81 | ||
| 84 | /* last received RSC */ | 82 | /* last received RSC */ |
| 85 | struct tkip_ctx rx[NUM_RX_DATA_QUEUES]; | 83 | struct tkip_ctx rx[IEEE80211_NUM_TIDS]; |
| 86 | } tkip; | 84 | } tkip; |
| 87 | struct { | 85 | struct { |
| 88 | atomic64_t tx_pn; | 86 | atomic64_t tx_pn; |
| 89 | /* | 87 | /* |
| 90 | * Last received packet number. The first | 88 | * Last received packet number. The first |
| 91 | * NUM_RX_DATA_QUEUES counters are used with Data | 89 | * IEEE80211_NUM_TIDS counters are used with Data |
| 92 | * frames and the last counter is used with Robust | 90 | * frames and the last counter is used with Robust |
| 93 | * Management frames. | 91 | * Management frames. |
| 94 | */ | 92 | */ |
| 95 | u8 rx_pn[NUM_RX_DATA_QUEUES + 1][CCMP_PN_LEN]; | 93 | u8 rx_pn[IEEE80211_NUM_TIDS + 1][CCMP_PN_LEN]; |
| 96 | struct crypto_cipher *tfm; | 94 | struct crypto_cipher *tfm; |
| 97 | u32 replays; /* dot11RSNAStatsCCMPReplays */ | 95 | u32 replays; /* dot11RSNAStatsCCMPReplays */ |
| 98 | } ccmp; | 96 | } ccmp; |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index d6e43b08d629..f5e4c1f24bf2 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
| @@ -95,11 +95,13 @@ static void ieee80211_reconfig_filter(struct work_struct *work) | |||
| 95 | 95 | ||
| 96 | static u32 ieee80211_hw_conf_chan(struct ieee80211_local *local) | 96 | static u32 ieee80211_hw_conf_chan(struct ieee80211_local *local) |
| 97 | { | 97 | { |
| 98 | struct ieee80211_sub_if_data *sdata; | ||
| 98 | struct ieee80211_channel *chan; | 99 | struct ieee80211_channel *chan; |
| 99 | u32 changed = 0; | 100 | u32 changed = 0; |
| 100 | int power; | 101 | int power; |
| 101 | enum nl80211_channel_type channel_type; | 102 | enum nl80211_channel_type channel_type; |
| 102 | u32 offchannel_flag; | 103 | u32 offchannel_flag; |
| 104 | bool scanning = false; | ||
| 103 | 105 | ||
| 104 | offchannel_flag = local->hw.conf.flags & IEEE80211_CONF_OFFCHANNEL; | 106 | offchannel_flag = local->hw.conf.flags & IEEE80211_CONF_OFFCHANNEL; |
| 105 | if (local->scan_channel) { | 107 | if (local->scan_channel) { |
| @@ -113,7 +115,7 @@ static u32 ieee80211_hw_conf_chan(struct ieee80211_local *local) | |||
| 113 | channel_type = NL80211_CHAN_NO_HT; | 115 | channel_type = NL80211_CHAN_NO_HT; |
| 114 | } else if (local->tmp_channel) { | 116 | } else if (local->tmp_channel) { |
| 115 | chan = local->tmp_channel; | 117 | chan = local->tmp_channel; |
| 116 | channel_type = local->tmp_channel_type; | 118 | channel_type = NL80211_CHAN_NO_HT; |
| 117 | } else { | 119 | } else { |
| 118 | chan = local->_oper_channel; | 120 | chan = local->_oper_channel; |
| 119 | channel_type = local->_oper_channel_type; | 121 | channel_type = local->_oper_channel_type; |
| @@ -146,16 +148,18 @@ static u32 ieee80211_hw_conf_chan(struct ieee80211_local *local) | |||
| 146 | changed |= IEEE80211_CONF_CHANGE_SMPS; | 148 | changed |= IEEE80211_CONF_CHANGE_SMPS; |
| 147 | } | 149 | } |
| 148 | 150 | ||
| 149 | if (test_bit(SCAN_SW_SCANNING, &local->scanning) || | 151 | scanning = test_bit(SCAN_SW_SCANNING, &local->scanning) || |
| 150 | test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning) || | 152 | test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning) || |
| 151 | test_bit(SCAN_HW_SCANNING, &local->scanning) || | 153 | test_bit(SCAN_HW_SCANNING, &local->scanning); |
| 152 | !local->ap_power_level) | 154 | power = chan->max_power; |
| 153 | power = chan->max_power; | ||
| 154 | else | ||
| 155 | power = min(chan->max_power, local->ap_power_level); | ||
| 156 | 155 | ||
| 157 | if (local->user_power_level >= 0) | 156 | rcu_read_lock(); |
| 158 | power = min(power, local->user_power_level); | 157 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { |
| 158 | if (!rcu_access_pointer(sdata->vif.chanctx_conf)) | ||
| 159 | continue; | ||
| 160 | power = min(power, sdata->vif.bss_conf.txpower); | ||
| 161 | } | ||
| 162 | rcu_read_unlock(); | ||
| 159 | 163 | ||
| 160 | if (local->hw.conf.power_level != power) { | 164 | if (local->hw.conf.power_level != power) { |
| 161 | changed |= IEEE80211_CONF_CHANGE_POWER; | 165 | changed |= IEEE80211_CONF_CHANGE_POWER; |
| @@ -600,7 +604,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
| 600 | 604 | ||
| 601 | wiphy->features |= NL80211_FEATURE_SK_TX_STATUS | | 605 | wiphy->features |= NL80211_FEATURE_SK_TX_STATUS | |
| 602 | NL80211_FEATURE_SAE | | 606 | NL80211_FEATURE_SAE | |
| 603 | NL80211_FEATURE_HT_IBSS; | 607 | NL80211_FEATURE_HT_IBSS | |
| 608 | NL80211_FEATURE_VIF_TXPOWER; | ||
| 604 | 609 | ||
| 605 | if (!ops->hw_scan) | 610 | if (!ops->hw_scan) |
| 606 | wiphy->features |= NL80211_FEATURE_LOW_PRIORITY_SCAN | | 611 | wiphy->features |= NL80211_FEATURE_LOW_PRIORITY_SCAN | |
| @@ -633,7 +638,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
| 633 | local->hw.radiotap_mcs_details = IEEE80211_RADIOTAP_MCS_HAVE_MCS | | 638 | local->hw.radiotap_mcs_details = IEEE80211_RADIOTAP_MCS_HAVE_MCS | |
| 634 | IEEE80211_RADIOTAP_MCS_HAVE_GI | | 639 | IEEE80211_RADIOTAP_MCS_HAVE_GI | |
| 635 | IEEE80211_RADIOTAP_MCS_HAVE_BW; | 640 | IEEE80211_RADIOTAP_MCS_HAVE_BW; |
| 636 | local->user_power_level = -1; | 641 | local->user_power_level = IEEE80211_UNSET_POWER_LEVEL; |
| 637 | wiphy->ht_capa_mod_mask = &mac80211_ht_capa_mod_mask; | 642 | wiphy->ht_capa_mod_mask = &mac80211_ht_capa_mod_mask; |
| 638 | 643 | ||
| 639 | INIT_LIST_HEAD(&local->interfaces); | 644 | INIT_LIST_HEAD(&local->interfaces); |
| @@ -793,10 +798,9 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
| 793 | local->_oper_channel = &sband->channels[0]; | 798 | local->_oper_channel = &sband->channels[0]; |
| 794 | local->hw.conf.channel_type = NL80211_CHAN_NO_HT; | 799 | local->hw.conf.channel_type = NL80211_CHAN_NO_HT; |
| 795 | } | 800 | } |
| 796 | if (!local->monitor_channel) { | 801 | cfg80211_chandef_create(&local->monitor_chandef, |
| 797 | local->monitor_channel = &sband->channels[0]; | 802 | &sband->channels[0], |
| 798 | local->monitor_channel_type = NL80211_CHAN_NO_HT; | 803 | NL80211_CHAN_NO_HT); |
| 799 | } | ||
| 800 | channels += sband->n_channels; | 804 | channels += sband->n_channels; |
| 801 | 805 | ||
| 802 | if (max_bitrates < sband->n_bitrates) | 806 | if (max_bitrates < sband->n_bitrates) |
| @@ -879,10 +883,22 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
| 879 | if (supp_ht) | 883 | if (supp_ht) |
| 880 | local->scan_ies_len += 2 + sizeof(struct ieee80211_ht_cap); | 884 | local->scan_ies_len += 2 + sizeof(struct ieee80211_ht_cap); |
| 881 | 885 | ||
| 882 | if (supp_vht) | 886 | if (supp_vht) { |
| 883 | local->scan_ies_len += | 887 | local->scan_ies_len += |
| 884 | 2 + sizeof(struct ieee80211_vht_cap); | 888 | 2 + sizeof(struct ieee80211_vht_cap); |
| 885 | 889 | ||
| 890 | /* | ||
| 891 | * (for now at least), drivers wanting to use VHT must | ||
| 892 | * support channel contexts, as they contain all the | ||
| 893 | * necessary VHT information and the global hw config | ||
| 894 | * doesn't (yet) | ||
| 895 | */ | ||
| 896 | if (WARN_ON(!local->use_chanctx)) { | ||
| 897 | result = -EINVAL; | ||
| 898 | goto fail_wiphy_register; | ||
| 899 | } | ||
| 900 | } | ||
| 901 | |||
| 886 | if (!local->ops->hw_scan) { | 902 | if (!local->ops->hw_scan) { |
| 887 | /* For hw_scan, driver needs to set these up. */ | 903 | /* For hw_scan, driver needs to set these up. */ |
| 888 | local->hw.wiphy->max_scan_ssids = 4; | 904 | local->hw.wiphy->max_scan_ssids = 4; |
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index a350cab4b339..1bf03f9ff3ba 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c | |||
| @@ -76,7 +76,7 @@ bool mesh_matches_local(struct ieee80211_sub_if_data *sdata, | |||
| 76 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | 76 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
| 77 | struct ieee80211_local *local = sdata->local; | 77 | struct ieee80211_local *local = sdata->local; |
| 78 | u32 basic_rates = 0; | 78 | u32 basic_rates = 0; |
| 79 | enum nl80211_channel_type sta_channel_type = NL80211_CHAN_NO_HT; | 79 | struct cfg80211_chan_def sta_chan_def; |
| 80 | 80 | ||
| 81 | /* | 81 | /* |
| 82 | * As support for each feature is added, check for matching | 82 | * As support for each feature is added, check for matching |
| @@ -103,17 +103,11 @@ bool mesh_matches_local(struct ieee80211_sub_if_data *sdata, | |||
| 103 | if (sdata->vif.bss_conf.basic_rates != basic_rates) | 103 | if (sdata->vif.bss_conf.basic_rates != basic_rates) |
| 104 | goto mismatch; | 104 | goto mismatch; |
| 105 | 105 | ||
| 106 | if (ie->ht_operation) | 106 | ieee80211_ht_oper_to_chandef(sdata->vif.bss_conf.chandef.chan, |
| 107 | sta_channel_type = | 107 | ie->ht_operation, &sta_chan_def); |
| 108 | ieee80211_ht_oper_to_channel_type(ie->ht_operation); | 108 | |
| 109 | 109 | if (!cfg80211_chandef_compatible(&sdata->vif.bss_conf.chandef, | |
| 110 | /* Disallow HT40+/- mismatch */ | 110 | &sta_chan_def)) |
| 111 | if (ie->ht_operation && | ||
| 112 | (sdata->vif.bss_conf.channel_type == NL80211_CHAN_HT40MINUS || | ||
| 113 | sdata->vif.bss_conf.channel_type == NL80211_CHAN_HT40PLUS) && | ||
| 114 | (sta_channel_type == NL80211_CHAN_HT40MINUS || | ||
| 115 | sta_channel_type == NL80211_CHAN_HT40PLUS) && | ||
| 116 | sdata->vif.bss_conf.channel_type != sta_channel_type) | ||
| 117 | goto mismatch; | 111 | goto mismatch; |
| 118 | 112 | ||
| 119 | return true; | 113 | return true; |
| @@ -129,7 +123,7 @@ mismatch: | |||
| 129 | bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie) | 123 | bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie) |
| 130 | { | 124 | { |
| 131 | return (ie->mesh_config->meshconf_cap & | 125 | return (ie->mesh_config->meshconf_cap & |
| 132 | MESHCONF_CAPAB_ACCEPT_PLINKS) != 0; | 126 | IEEE80211_MESHCONF_CAPAB_ACCEPT_PLINKS) != 0; |
| 133 | } | 127 | } |
| 134 | 128 | ||
| 135 | /** | 129 | /** |
| @@ -269,11 +263,11 @@ mesh_add_meshconf_ie(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata) | |||
| 269 | neighbors = (neighbors > 15) ? 15 : neighbors; | 263 | neighbors = (neighbors > 15) ? 15 : neighbors; |
| 270 | *pos++ = neighbors << 1; | 264 | *pos++ = neighbors << 1; |
| 271 | /* Mesh capability */ | 265 | /* Mesh capability */ |
| 272 | *pos = MESHCONF_CAPAB_FORWARDING; | 266 | *pos = IEEE80211_MESHCONF_CAPAB_FORWARDING; |
| 273 | *pos |= ifmsh->accepting_plinks ? | 267 | *pos |= ifmsh->accepting_plinks ? |
| 274 | MESHCONF_CAPAB_ACCEPT_PLINKS : 0x00; | 268 | IEEE80211_MESHCONF_CAPAB_ACCEPT_PLINKS : 0x00; |
| 275 | *pos++ |= ifmsh->adjusting_tbtt ? | 269 | *pos++ |= ifmsh->adjusting_tbtt ? |
| 276 | MESHCONF_CAPAB_TBTT_ADJUSTING : 0x00; | 270 | IEEE80211_MESHCONF_CAPAB_TBTT_ADJUSTING : 0x00; |
| 277 | *pos++ = 0x00; | 271 | *pos++ = 0x00; |
| 278 | 272 | ||
| 279 | return 0; | 273 | return 0; |
| @@ -368,7 +362,7 @@ int mesh_add_ds_params_ie(struct sk_buff *skb, | |||
| 368 | rcu_read_unlock(); | 362 | rcu_read_unlock(); |
| 369 | return -EINVAL; | 363 | return -EINVAL; |
| 370 | } | 364 | } |
| 371 | chan = chanctx_conf->channel; | 365 | chan = chanctx_conf->def.chan; |
| 372 | rcu_read_unlock(); | 366 | rcu_read_unlock(); |
| 373 | 367 | ||
| 374 | sband = local->hw.wiphy->bands[chan->band]; | 368 | sband = local->hw.wiphy->bands[chan->band]; |
| @@ -392,7 +386,7 @@ int mesh_add_ht_cap_ie(struct sk_buff *skb, | |||
| 392 | 386 | ||
| 393 | sband = local->hw.wiphy->bands[band]; | 387 | sband = local->hw.wiphy->bands[band]; |
| 394 | if (!sband->ht_cap.ht_supported || | 388 | if (!sband->ht_cap.ht_supported || |
| 395 | sdata->vif.bss_conf.channel_type == NL80211_CHAN_NO_HT) | 389 | sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT) |
| 396 | return 0; | 390 | return 0; |
| 397 | 391 | ||
| 398 | if (skb_tailroom(skb) < 2 + sizeof(struct ieee80211_ht_cap)) | 392 | if (skb_tailroom(skb) < 2 + sizeof(struct ieee80211_ht_cap)) |
| @@ -411,7 +405,7 @@ int mesh_add_ht_oper_ie(struct sk_buff *skb, | |||
| 411 | struct ieee80211_chanctx_conf *chanctx_conf; | 405 | struct ieee80211_chanctx_conf *chanctx_conf; |
| 412 | struct ieee80211_channel *channel; | 406 | struct ieee80211_channel *channel; |
| 413 | enum nl80211_channel_type channel_type = | 407 | enum nl80211_channel_type channel_type = |
| 414 | sdata->vif.bss_conf.channel_type; | 408 | cfg80211_get_chandef_type(&sdata->vif.bss_conf.chandef); |
| 415 | struct ieee80211_supported_band *sband; | 409 | struct ieee80211_supported_band *sband; |
| 416 | struct ieee80211_sta_ht_cap *ht_cap; | 410 | struct ieee80211_sta_ht_cap *ht_cap; |
| 417 | u8 *pos; | 411 | u8 *pos; |
| @@ -422,7 +416,7 @@ int mesh_add_ht_oper_ie(struct sk_buff *skb, | |||
| 422 | rcu_read_unlock(); | 416 | rcu_read_unlock(); |
| 423 | return -EINVAL; | 417 | return -EINVAL; |
| 424 | } | 418 | } |
| 425 | channel = chanctx_conf->channel; | 419 | channel = chanctx_conf->def.chan; |
| 426 | rcu_read_unlock(); | 420 | rcu_read_unlock(); |
| 427 | 421 | ||
| 428 | sband = local->hw.wiphy->bands[channel->band]; | 422 | sband = local->hw.wiphy->bands[channel->band]; |
| @@ -435,7 +429,7 @@ int mesh_add_ht_oper_ie(struct sk_buff *skb, | |||
| 435 | return -ENOMEM; | 429 | return -ENOMEM; |
| 436 | 430 | ||
| 437 | pos = skb_put(skb, 2 + sizeof(struct ieee80211_ht_operation)); | 431 | pos = skb_put(skb, 2 + sizeof(struct ieee80211_ht_operation)); |
| 438 | ieee80211_ie_build_ht_oper(pos, ht_cap, channel, channel_type, | 432 | ieee80211_ie_build_ht_oper(pos, ht_cap, &sdata->vif.bss_conf.chandef, |
| 439 | sdata->vif.bss_conf.ht_operation_mode); | 433 | sdata->vif.bss_conf.ht_operation_mode); |
| 440 | 434 | ||
| 441 | return 0; | 435 | return 0; |
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index 9285f3f67e66..7c9215fb2ac8 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h | |||
| @@ -19,20 +19,6 @@ | |||
| 19 | /* Data structures */ | 19 | /* Data structures */ |
| 20 | 20 | ||
| 21 | /** | 21 | /** |
| 22 | * enum mesh_config_capab_flags - mesh config IE capability flags | ||
| 23 | * | ||
| 24 | * @MESHCONF_CAPAB_ACCEPT_PLINKS: STA is willing to establish | ||
| 25 | * additional mesh peerings with other mesh STAs | ||
| 26 | * @MESHCONF_CAPAB_FORWARDING: the STA forwards MSDUs | ||
| 27 | * @MESHCONF_CAPAB_TBTT_ADJUSTING: TBTT adjustment procedure is ongoing | ||
| 28 | */ | ||
| 29 | enum mesh_config_capab_flags { | ||
| 30 | MESHCONF_CAPAB_ACCEPT_PLINKS = BIT(0), | ||
| 31 | MESHCONF_CAPAB_FORWARDING = BIT(3), | ||
| 32 | MESHCONF_CAPAB_TBTT_ADJUSTING = BIT(5), | ||
| 33 | }; | ||
| 34 | |||
| 35 | /** | ||
| 36 | * enum mesh_path_flags - mac80211 mesh path flags | 22 | * enum mesh_path_flags - mac80211 mesh path flags |
| 37 | * | 23 | * |
| 38 | * | 24 | * |
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 234fe755968b..ca52dfdd5375 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 | #define dot11MeshMaxRetries(s) (s->u.mesh.mshcfg.dot11MeshMaxRetries) | ||
| 23 | #define dot11MeshRetryTimeout(s) (s->u.mesh.mshcfg.dot11MeshRetryTimeout) | ||
| 24 | #define dot11MeshConfirmTimeout(s) (s->u.mesh.mshcfg.dot11MeshConfirmTimeout) | ||
| 25 | #define dot11MeshHoldingTimeout(s) (s->u.mesh.mshcfg.dot11MeshHoldingTimeout) | ||
| 26 | #define dot11MeshMaxPeerLinks(s) (s->u.mesh.mshcfg.dot11MeshMaxPeerLinks) | ||
| 27 | |||
| 28 | /* We only need a valid sta if user configured a minimum rssi_threshold. */ | 22 | /* We only need a valid sta if user configured a minimum rssi_threshold. */ |
| 29 | #define rssi_threshold_check(sta, sdata) \ | 23 | #define rssi_threshold_check(sta, sdata) \ |
| 30 | (sdata->u.mesh.mshcfg.rssi_threshold == 0 ||\ | 24 | (sdata->u.mesh.mshcfg.rssi_threshold == 0 ||\ |
| @@ -117,7 +111,7 @@ static u32 mesh_set_ht_prot_mode(struct ieee80211_sub_if_data *sdata) | |||
| 117 | u16 ht_opmode; | 111 | u16 ht_opmode; |
| 118 | bool non_ht_sta = false, ht20_sta = false; | 112 | bool non_ht_sta = false, ht20_sta = false; |
| 119 | 113 | ||
| 120 | if (sdata->vif.bss_conf.channel_type == NL80211_CHAN_NO_HT) | 114 | if (sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT) |
| 121 | return 0; | 115 | return 0; |
| 122 | 116 | ||
| 123 | rcu_read_lock(); | 117 | rcu_read_lock(); |
| @@ -126,14 +120,14 @@ static u32 mesh_set_ht_prot_mode(struct ieee80211_sub_if_data *sdata) | |||
| 126 | sta->plink_state != NL80211_PLINK_ESTAB) | 120 | sta->plink_state != NL80211_PLINK_ESTAB) |
| 127 | continue; | 121 | continue; |
| 128 | 122 | ||
| 129 | switch (sta->ch_type) { | 123 | switch (sta->ch_width) { |
| 130 | case NL80211_CHAN_NO_HT: | 124 | case NL80211_CHAN_WIDTH_20_NOHT: |
| 131 | mpl_dbg(sdata, | 125 | mpl_dbg(sdata, |
| 132 | "mesh_plink %pM: nonHT sta (%pM) is present\n", | 126 | "mesh_plink %pM: nonHT sta (%pM) is present\n", |
| 133 | sdata->vif.addr, sta->sta.addr); | 127 | sdata->vif.addr, sta->sta.addr); |
| 134 | non_ht_sta = true; | 128 | non_ht_sta = true; |
| 135 | goto out; | 129 | goto out; |
| 136 | case NL80211_CHAN_HT20: | 130 | case NL80211_CHAN_WIDTH_20: |
| 137 | mpl_dbg(sdata, | 131 | mpl_dbg(sdata, |
| 138 | "mesh_plink %pM: HT20 sta (%pM) is present\n", | 132 | "mesh_plink %pM: HT20 sta (%pM) is present\n", |
| 139 | sdata->vif.addr, sta->sta.addr); | 133 | sdata->vif.addr, sta->sta.addr); |
| @@ -148,7 +142,7 @@ out: | |||
| 148 | if (non_ht_sta) | 142 | if (non_ht_sta) |
| 149 | ht_opmode = IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED; | 143 | ht_opmode = IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED; |
| 150 | else if (ht20_sta && | 144 | else if (ht20_sta && |
| 151 | sdata->vif.bss_conf.channel_type > NL80211_CHAN_HT20) | 145 | sdata->vif.bss_conf.chandef.width > NL80211_CHAN_WIDTH_20) |
| 152 | ht_opmode = IEEE80211_HT_OP_MODE_PROTECTION_20MHZ; | 146 | ht_opmode = IEEE80211_HT_OP_MODE_PROTECTION_20MHZ; |
| 153 | else | 147 | else |
| 154 | ht_opmode = IEEE80211_HT_OP_MODE_PROTECTION_NONE; | 148 | ht_opmode = IEEE80211_HT_OP_MODE_PROTECTION_NONE; |
| @@ -378,7 +372,7 @@ static struct sta_info *mesh_peer_init(struct ieee80211_sub_if_data *sdata, | |||
| 378 | 372 | ||
| 379 | sta->sta.supp_rates[band] = rates; | 373 | sta->sta.supp_rates[band] = rates; |
| 380 | if (elems->ht_cap_elem && | 374 | if (elems->ht_cap_elem && |
| 381 | sdata->vif.bss_conf.channel_type != NL80211_CHAN_NO_HT) | 375 | sdata->vif.bss_conf.chandef.width != NL80211_CHAN_WIDTH_20_NOHT) |
| 382 | ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, | 376 | ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, |
| 383 | elems->ht_cap_elem, | 377 | elems->ht_cap_elem, |
| 384 | &sta->sta.ht_cap); | 378 | &sta->sta.ht_cap); |
| @@ -386,12 +380,15 @@ static struct sta_info *mesh_peer_init(struct ieee80211_sub_if_data *sdata, | |||
| 386 | memset(&sta->sta.ht_cap, 0, sizeof(sta->sta.ht_cap)); | 380 | memset(&sta->sta.ht_cap, 0, sizeof(sta->sta.ht_cap)); |
| 387 | 381 | ||
| 388 | if (elems->ht_operation) { | 382 | if (elems->ht_operation) { |
| 383 | struct cfg80211_chan_def chandef; | ||
| 384 | |||
| 389 | if (!(elems->ht_operation->ht_param & | 385 | if (!(elems->ht_operation->ht_param & |
| 390 | IEEE80211_HT_PARAM_CHAN_WIDTH_ANY)) | 386 | IEEE80211_HT_PARAM_CHAN_WIDTH_ANY)) |
| 391 | sta->sta.ht_cap.cap &= | 387 | sta->sta.ht_cap.cap &= |
| 392 | ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; | 388 | ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; |
| 393 | sta->ch_type = | 389 | ieee80211_ht_oper_to_chandef(sdata->vif.bss_conf.chandef.chan, |
| 394 | ieee80211_ht_oper_to_channel_type(elems->ht_operation); | 390 | elems->ht_operation, &chandef); |
| 391 | sta->ch_width = chandef.width; | ||
| 395 | } | 392 | } |
| 396 | 393 | ||
| 397 | rate_control_rate_init(sta); | 394 | rate_control_rate_init(sta); |
| @@ -430,6 +427,7 @@ static void mesh_plink_timer(unsigned long data) | |||
| 430 | struct sta_info *sta; | 427 | struct sta_info *sta; |
| 431 | __le16 llid, plid, reason; | 428 | __le16 llid, plid, reason; |
| 432 | struct ieee80211_sub_if_data *sdata; | 429 | struct ieee80211_sub_if_data *sdata; |
| 430 | struct mesh_config *mshcfg; | ||
| 433 | 431 | ||
| 434 | /* | 432 | /* |
| 435 | * This STA is valid because sta_info_destroy() will | 433 | * This STA is valid because sta_info_destroy() will |
| @@ -456,12 +454,13 @@ static void mesh_plink_timer(unsigned long data) | |||
| 456 | llid = sta->llid; | 454 | llid = sta->llid; |
| 457 | plid = sta->plid; | 455 | plid = sta->plid; |
| 458 | sdata = sta->sdata; | 456 | sdata = sta->sdata; |
| 457 | mshcfg = &sdata->u.mesh.mshcfg; | ||
| 459 | 458 | ||
| 460 | switch (sta->plink_state) { | 459 | switch (sta->plink_state) { |
| 461 | case NL80211_PLINK_OPN_RCVD: | 460 | case NL80211_PLINK_OPN_RCVD: |
| 462 | case NL80211_PLINK_OPN_SNT: | 461 | case NL80211_PLINK_OPN_SNT: |
| 463 | /* retry timer */ | 462 | /* retry timer */ |
| 464 | if (sta->plink_retries < dot11MeshMaxRetries(sdata)) { | 463 | if (sta->plink_retries < mshcfg->dot11MeshMaxRetries) { |
| 465 | u32 rand; | 464 | u32 rand; |
| 466 | mpl_dbg(sta->sdata, | 465 | mpl_dbg(sta->sdata, |
| 467 | "Mesh plink for %pM (retry, timeout): %d %d\n", | 466 | "Mesh plink for %pM (retry, timeout): %d %d\n", |
| @@ -484,7 +483,7 @@ static void mesh_plink_timer(unsigned long data) | |||
| 484 | if (!reason) | 483 | if (!reason) |
| 485 | reason = cpu_to_le16(WLAN_REASON_MESH_CONFIRM_TIMEOUT); | 484 | reason = cpu_to_le16(WLAN_REASON_MESH_CONFIRM_TIMEOUT); |
| 486 | sta->plink_state = NL80211_PLINK_HOLDING; | 485 | sta->plink_state = NL80211_PLINK_HOLDING; |
| 487 | mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata)); | 486 | mod_plink_timer(sta, mshcfg->dot11MeshHoldingTimeout); |
| 488 | spin_unlock_bh(&sta->lock); | 487 | spin_unlock_bh(&sta->lock); |
| 489 | mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE, | 488 | mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE, |
| 490 | sta->sta.addr, llid, plid, reason); | 489 | sta->sta.addr, llid, plid, reason); |
| @@ -543,7 +542,7 @@ int mesh_plink_open(struct sta_info *sta) | |||
| 543 | return -EBUSY; | 542 | return -EBUSY; |
| 544 | } | 543 | } |
| 545 | sta->plink_state = NL80211_PLINK_OPN_SNT; | 544 | sta->plink_state = NL80211_PLINK_OPN_SNT; |
| 546 | mesh_plink_timer_set(sta, dot11MeshRetryTimeout(sdata)); | 545 | mesh_plink_timer_set(sta, sdata->u.mesh.mshcfg.dot11MeshRetryTimeout); |
| 547 | spin_unlock_bh(&sta->lock); | 546 | spin_unlock_bh(&sta->lock); |
| 548 | mpl_dbg(sdata, | 547 | mpl_dbg(sdata, |
| 549 | "Mesh plink: starting establishment with %pM\n", | 548 | "Mesh plink: starting establishment with %pM\n", |
| @@ -570,6 +569,7 @@ void mesh_plink_block(struct sta_info *sta) | |||
| 570 | void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgmt *mgmt, | 569 | void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgmt *mgmt, |
| 571 | size_t len, struct ieee80211_rx_status *rx_status) | 570 | size_t len, struct ieee80211_rx_status *rx_status) |
| 572 | { | 571 | { |
| 572 | struct mesh_config *mshcfg = &sdata->u.mesh.mshcfg; | ||
| 573 | struct ieee802_11_elems elems; | 573 | struct ieee802_11_elems elems; |
| 574 | struct sta_info *sta; | 574 | struct sta_info *sta; |
| 575 | enum plink_event event; | 575 | enum plink_event event; |
| @@ -777,7 +777,8 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
| 777 | sta->plid = plid; | 777 | sta->plid = plid; |
| 778 | get_random_bytes(&llid, 2); | 778 | get_random_bytes(&llid, 2); |
| 779 | sta->llid = llid; | 779 | sta->llid = llid; |
| 780 | mesh_plink_timer_set(sta, dot11MeshRetryTimeout(sdata)); | 780 | mesh_plink_timer_set(sta, |
| 781 | mshcfg->dot11MeshRetryTimeout); | ||
| 781 | spin_unlock_bh(&sta->lock); | 782 | spin_unlock_bh(&sta->lock); |
| 782 | mesh_plink_frame_tx(sdata, | 783 | mesh_plink_frame_tx(sdata, |
| 783 | WLAN_SP_MESH_PEERING_OPEN, | 784 | WLAN_SP_MESH_PEERING_OPEN, |
| @@ -803,7 +804,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
| 803 | sta->reason = reason; | 804 | sta->reason = reason; |
| 804 | sta->plink_state = NL80211_PLINK_HOLDING; | 805 | sta->plink_state = NL80211_PLINK_HOLDING; |
| 805 | if (!mod_plink_timer(sta, | 806 | if (!mod_plink_timer(sta, |
| 806 | dot11MeshHoldingTimeout(sdata))) | 807 | mshcfg->dot11MeshHoldingTimeout)) |
| 807 | sta->ignore_plink_timer = true; | 808 | sta->ignore_plink_timer = true; |
| 808 | 809 | ||
| 809 | llid = sta->llid; | 810 | llid = sta->llid; |
| @@ -825,7 +826,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
| 825 | case CNF_ACPT: | 826 | case CNF_ACPT: |
| 826 | sta->plink_state = NL80211_PLINK_CNF_RCVD; | 827 | sta->plink_state = NL80211_PLINK_CNF_RCVD; |
| 827 | if (!mod_plink_timer(sta, | 828 | if (!mod_plink_timer(sta, |
| 828 | dot11MeshConfirmTimeout(sdata))) | 829 | mshcfg->dot11MeshConfirmTimeout)) |
| 829 | sta->ignore_plink_timer = true; | 830 | sta->ignore_plink_timer = true; |
| 830 | 831 | ||
| 831 | spin_unlock_bh(&sta->lock); | 832 | spin_unlock_bh(&sta->lock); |
| @@ -847,7 +848,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
| 847 | sta->reason = reason; | 848 | sta->reason = reason; |
| 848 | sta->plink_state = NL80211_PLINK_HOLDING; | 849 | sta->plink_state = NL80211_PLINK_HOLDING; |
| 849 | if (!mod_plink_timer(sta, | 850 | if (!mod_plink_timer(sta, |
| 850 | dot11MeshHoldingTimeout(sdata))) | 851 | mshcfg->dot11MeshHoldingTimeout)) |
| 851 | sta->ignore_plink_timer = true; | 852 | sta->ignore_plink_timer = true; |
| 852 | 853 | ||
| 853 | llid = sta->llid; | 854 | llid = sta->llid; |
| @@ -888,7 +889,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
| 888 | sta->reason = reason; | 889 | sta->reason = reason; |
| 889 | sta->plink_state = NL80211_PLINK_HOLDING; | 890 | sta->plink_state = NL80211_PLINK_HOLDING; |
| 890 | if (!mod_plink_timer(sta, | 891 | if (!mod_plink_timer(sta, |
| 891 | dot11MeshHoldingTimeout(sdata))) | 892 | mshcfg->dot11MeshHoldingTimeout)) |
| 892 | sta->ignore_plink_timer = true; | 893 | sta->ignore_plink_timer = true; |
| 893 | 894 | ||
| 894 | llid = sta->llid; | 895 | llid = sta->llid; |
| @@ -923,7 +924,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
| 923 | changed |= __mesh_plink_deactivate(sta); | 924 | changed |= __mesh_plink_deactivate(sta); |
| 924 | sta->plink_state = NL80211_PLINK_HOLDING; | 925 | sta->plink_state = NL80211_PLINK_HOLDING; |
| 925 | llid = sta->llid; | 926 | llid = sta->llid; |
| 926 | mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata)); | 927 | mod_plink_timer(sta, mshcfg->dot11MeshHoldingTimeout); |
| 927 | spin_unlock_bh(&sta->lock); | 928 | spin_unlock_bh(&sta->lock); |
| 928 | changed |= mesh_set_ht_prot_mode(sdata); | 929 | changed |= mesh_set_ht_prot_mode(sdata); |
| 929 | mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE, | 930 | mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE, |
diff --git a/net/mac80211/mesh_sync.c b/net/mac80211/mesh_sync.c index 407c8705e10d..0f40086cce18 100644 --- a/net/mac80211/mesh_sync.c +++ b/net/mac80211/mesh_sync.c | |||
| @@ -43,7 +43,7 @@ struct sync_method { | |||
| 43 | static bool mesh_peer_tbtt_adjusting(struct ieee802_11_elems *ie) | 43 | static bool mesh_peer_tbtt_adjusting(struct ieee802_11_elems *ie) |
| 44 | { | 44 | { |
| 45 | return (ie->mesh_config->meshconf_cap & | 45 | return (ie->mesh_config->meshconf_cap & |
| 46 | MESHCONF_CAPAB_TBTT_ADJUSTING) != 0; | 46 | IEEE80211_MESHCONF_CAPAB_TBTT_ADJUSTING) != 0; |
| 47 | } | 47 | } |
| 48 | 48 | ||
| 49 | void mesh_sync_adjust_tbtt(struct ieee80211_sub_if_data *sdata) | 49 | void mesh_sync_adjust_tbtt(struct ieee80211_sub_if_data *sdata) |
| @@ -116,43 +116,13 @@ static void mesh_sync_offset_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, | |||
| 116 | goto no_sync; | 116 | goto no_sync; |
| 117 | } | 117 | } |
| 118 | 118 | ||
| 119 | if (rx_status->flag & RX_FLAG_MACTIME_MPDU && rx_status->mactime) { | 119 | if (ieee80211_have_rx_timestamp(rx_status)) |
| 120 | /* | 120 | /* time when timestamp field was received */ |
| 121 | * The mactime is defined as the time the first data symbol | 121 | t_r = ieee80211_calculate_rx_timestamp(local, rx_status, |
| 122 | * of the frame hits the PHY, and the timestamp of the beacon | 122 | 24 + 12 + |
| 123 | * is defined as "the time that the data symbol containing the | 123 | elems->total_len + |
| 124 | * first bit of the timestamp is transmitted to the PHY plus | 124 | FCS_LEN, |
| 125 | * the transmitting STA's delays through its local PHY from the | 125 | 24); |
| 126 | * MAC-PHY interface to its interface with the WM" (802.11 | ||
| 127 | * 11.1.2) | ||
| 128 | * | ||
| 129 | * T_r, in 13.13.2.2.2, is just defined as "the frame reception | ||
| 130 | * time" but we unless we interpret that time to be the same | ||
| 131 | * time of the beacon timestamp, the offset calculation will be | ||
| 132 | * off. Below we adjust t_r to be "the time at which the first | ||
| 133 | * symbol of the timestamp element in the beacon is received". | ||
| 134 | * This correction depends on the rate. | ||
| 135 | * | ||
| 136 | * Based on similar code in ibss.c | ||
| 137 | */ | ||
| 138 | int rate; | ||
| 139 | |||
| 140 | if (rx_status->flag & RX_FLAG_HT) { | ||
| 141 | /* TODO: | ||
| 142 | * In principle there could be HT-beacons (Dual Beacon | ||
| 143 | * HT Operation options), but for now ignore them and | ||
| 144 | * just use the primary (i.e. non-HT) beacons for | ||
| 145 | * synchronization. | ||
| 146 | * */ | ||
| 147 | goto no_sync; | ||
| 148 | } else | ||
| 149 | rate = local->hw.wiphy->bands[rx_status->band]-> | ||
| 150 | bitrates[rx_status->rate_idx].bitrate; | ||
| 151 | |||
| 152 | /* 24 bytes of header * 8 bits/byte * | ||
| 153 | * 10*(100 Kbps)/Mbps / rate (100 Kbps)*/ | ||
| 154 | t_r = rx_status->mactime + (24 * 8 * 10 / rate); | ||
| 155 | } | ||
| 156 | 126 | ||
| 157 | /* Timing offset calculation (see 13.13.2.2.2) */ | 127 | /* Timing offset calculation (see 13.13.2.2.2) */ |
| 158 | t_t = le64_to_cpu(mgmt->u.beacon.timestamp); | 128 | t_t = le64_to_cpu(mgmt->u.beacon.timestamp); |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 1d1fdf0791f0..d2a4f78b4b0f 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
| @@ -191,17 +191,19 @@ static u32 ieee80211_config_ht_tx(struct ieee80211_sub_if_data *sdata, | |||
| 191 | rcu_read_unlock(); | 191 | rcu_read_unlock(); |
| 192 | return 0; | 192 | return 0; |
| 193 | } | 193 | } |
| 194 | chan = chanctx_conf->channel; | 194 | chan = chanctx_conf->def.chan; |
| 195 | rcu_read_unlock(); | 195 | rcu_read_unlock(); |
| 196 | sband = local->hw.wiphy->bands[chan->band]; | 196 | sband = local->hw.wiphy->bands[chan->band]; |
| 197 | 197 | ||
| 198 | switch (sdata->vif.bss_conf.channel_type) { | 198 | switch (sdata->vif.bss_conf.chandef.width) { |
| 199 | case NL80211_CHAN_HT40PLUS: | 199 | case NL80211_CHAN_WIDTH_40: |
| 200 | if (chan->flags & IEEE80211_CHAN_NO_HT40PLUS) | 200 | if (sdata->vif.bss_conf.chandef.chan->center_freq > |
| 201 | sdata->vif.bss_conf.chandef.center_freq1 && | ||
| 202 | chan->flags & IEEE80211_CHAN_NO_HT40PLUS) | ||
| 201 | disable_40 = true; | 203 | disable_40 = true; |
| 202 | break; | 204 | if (sdata->vif.bss_conf.chandef.chan->center_freq < |
| 203 | case NL80211_CHAN_HT40MINUS: | 205 | sdata->vif.bss_conf.chandef.center_freq1 && |
| 204 | if (chan->flags & IEEE80211_CHAN_NO_HT40MINUS) | 206 | chan->flags & IEEE80211_CHAN_NO_HT40MINUS) |
| 205 | disable_40 = true; | 207 | disable_40 = true; |
| 206 | break; | 208 | break; |
| 207 | default: | 209 | default: |
| @@ -381,7 +383,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) | |||
| 381 | rcu_read_unlock(); | 383 | rcu_read_unlock(); |
| 382 | return; | 384 | return; |
| 383 | } | 385 | } |
| 384 | chan = chanctx_conf->channel; | 386 | chan = chanctx_conf->def.chan; |
| 385 | rcu_read_unlock(); | 387 | rcu_read_unlock(); |
| 386 | sband = local->hw.wiphy->bands[chan->band]; | 388 | sband = local->hw.wiphy->bands[chan->band]; |
| 387 | 389 | ||
| @@ -541,7 +543,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) | |||
| 541 | offset = noffset; | 543 | offset = noffset; |
| 542 | } | 544 | } |
| 543 | 545 | ||
| 544 | if (!(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) | 546 | if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) |
| 545 | ieee80211_add_ht_ie(sdata, skb, assoc_data->ap_ht_param, | 547 | ieee80211_add_ht_ie(sdata, skb, assoc_data->ap_ht_param, |
| 546 | sband, chan, sdata->smps_mode); | 548 | sband, chan, sdata->smps_mode); |
| 547 | 549 | ||
| @@ -820,10 +822,10 @@ void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
| 820 | cbss->beacon_interval)); | 822 | cbss->beacon_interval)); |
| 821 | } | 823 | } |
| 822 | 824 | ||
| 823 | static void ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata, | 825 | static u32 ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata, |
| 824 | struct ieee80211_channel *channel, | 826 | struct ieee80211_channel *channel, |
| 825 | const u8 *country_ie, u8 country_ie_len, | 827 | const u8 *country_ie, u8 country_ie_len, |
| 826 | const u8 *pwr_constr_elem) | 828 | const u8 *pwr_constr_elem) |
| 827 | { | 829 | { |
| 828 | struct ieee80211_country_ie_triplet *triplet; | 830 | struct ieee80211_country_ie_triplet *triplet; |
| 829 | int chan = ieee80211_frequency_to_channel(channel->center_freq); | 831 | int chan = ieee80211_frequency_to_channel(channel->center_freq); |
| @@ -832,7 +834,7 @@ static void ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata, | |||
| 832 | 834 | ||
| 833 | /* Invalid IE */ | 835 | /* Invalid IE */ |
| 834 | if (country_ie_len % 2 || country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN) | 836 | if (country_ie_len % 2 || country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN) |
| 835 | return; | 837 | return 0; |
| 836 | 838 | ||
| 837 | triplet = (void *)(country_ie + 3); | 839 | triplet = (void *)(country_ie + 3); |
| 838 | country_ie_len -= 3; | 840 | country_ie_len -= 3; |
| @@ -873,19 +875,21 @@ static void ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata, | |||
| 873 | } | 875 | } |
| 874 | 876 | ||
| 875 | if (!have_chan_pwr) | 877 | if (!have_chan_pwr) |
| 876 | return; | 878 | return 0; |
| 877 | 879 | ||
| 878 | new_ap_level = max_t(int, 0, chan_pwr - *pwr_constr_elem); | 880 | new_ap_level = max_t(int, 0, chan_pwr - *pwr_constr_elem); |
| 879 | 881 | ||
| 880 | if (sdata->local->ap_power_level == new_ap_level) | 882 | if (sdata->ap_power_level == new_ap_level) |
| 881 | return; | 883 | return 0; |
| 882 | 884 | ||
| 883 | sdata_info(sdata, | 885 | sdata_info(sdata, |
| 884 | "Limiting TX power to %d (%d - %d) dBm as advertised by %pM\n", | 886 | "Limiting TX power to %d (%d - %d) dBm as advertised by %pM\n", |
| 885 | new_ap_level, chan_pwr, *pwr_constr_elem, | 887 | new_ap_level, chan_pwr, *pwr_constr_elem, |
| 886 | sdata->u.mgd.bssid); | 888 | sdata->u.mgd.bssid); |
| 887 | sdata->local->ap_power_level = new_ap_level; | 889 | sdata->ap_power_level = new_ap_level; |
| 888 | ieee80211_hw_config(sdata->local, 0); | 890 | if (__ieee80211_recalc_txpower(sdata)) |
| 891 | return BSS_CHANGED_TXPOWER; | ||
| 892 | return 0; | ||
| 889 | } | 893 | } |
| 890 | 894 | ||
| 891 | void ieee80211_enable_dyn_ps(struct ieee80211_vif *vif) | 895 | void ieee80211_enable_dyn_ps(struct ieee80211_vif *vif) |
| @@ -1363,6 +1367,22 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, | |||
| 1363 | 1367 | ||
| 1364 | sdata->u.mgd.flags |= IEEE80211_STA_RESET_SIGNAL_AVE; | 1368 | sdata->u.mgd.flags |= IEEE80211_STA_RESET_SIGNAL_AVE; |
| 1365 | 1369 | ||
| 1370 | if (sdata->vif.p2p) { | ||
| 1371 | u8 noa[2]; | ||
| 1372 | int ret; | ||
| 1373 | |||
| 1374 | ret = cfg80211_get_p2p_attr(cbss->information_elements, | ||
| 1375 | cbss->len_information_elements, | ||
| 1376 | IEEE80211_P2P_ATTR_ABSENCE_NOTICE, | ||
| 1377 | noa, sizeof(noa)); | ||
| 1378 | if (ret >= 2) { | ||
| 1379 | bss_conf->p2p_oppps = noa[1] & 0x80; | ||
| 1380 | bss_conf->p2p_ctwindow = noa[1] & 0x7f; | ||
| 1381 | bss_info_changed |= BSS_CHANGED_P2P_PS; | ||
| 1382 | sdata->u.mgd.p2p_noa_index = noa[0]; | ||
| 1383 | } | ||
| 1384 | } | ||
| 1385 | |||
| 1366 | /* just to be sure */ | 1386 | /* just to be sure */ |
| 1367 | ieee80211_stop_poll(sdata); | 1387 | ieee80211_stop_poll(sdata); |
| 1368 | 1388 | ||
| @@ -1485,11 +1505,14 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
| 1485 | changed |= BSS_CHANGED_ASSOC; | 1505 | changed |= BSS_CHANGED_ASSOC; |
| 1486 | sdata->vif.bss_conf.assoc = false; | 1506 | sdata->vif.bss_conf.assoc = false; |
| 1487 | 1507 | ||
| 1508 | sdata->vif.bss_conf.p2p_ctwindow = 0; | ||
| 1509 | sdata->vif.bss_conf.p2p_oppps = false; | ||
| 1510 | |||
| 1488 | /* on the next assoc, re-program HT parameters */ | 1511 | /* on the next assoc, re-program HT parameters */ |
| 1489 | memset(&ifmgd->ht_capa, 0, sizeof(ifmgd->ht_capa)); | 1512 | memset(&ifmgd->ht_capa, 0, sizeof(ifmgd->ht_capa)); |
| 1490 | memset(&ifmgd->ht_capa_mask, 0, sizeof(ifmgd->ht_capa_mask)); | 1513 | memset(&ifmgd->ht_capa_mask, 0, sizeof(ifmgd->ht_capa_mask)); |
| 1491 | 1514 | ||
| 1492 | local->ap_power_level = 0; | 1515 | sdata->ap_power_level = IEEE80211_UNSET_POWER_LEVEL; |
| 1493 | 1516 | ||
| 1494 | del_timer_sync(&local->dynamic_ps_timer); | 1517 | del_timer_sync(&local->dynamic_ps_timer); |
| 1495 | cancel_work_sync(&local->dynamic_ps_enable_work); | 1518 | cancel_work_sync(&local->dynamic_ps_enable_work); |
| @@ -1507,8 +1530,6 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
| 1507 | changed |= BSS_CHANGED_BSSID | BSS_CHANGED_HT; | 1530 | changed |= BSS_CHANGED_BSSID | BSS_CHANGED_HT; |
| 1508 | ieee80211_bss_info_change_notify(sdata, changed); | 1531 | ieee80211_bss_info_change_notify(sdata, changed); |
| 1509 | 1532 | ||
| 1510 | ieee80211_vif_release_channel(sdata); | ||
| 1511 | |||
| 1512 | /* disassociated - set to defaults now */ | 1533 | /* disassociated - set to defaults now */ |
| 1513 | ieee80211_set_wmm_default(sdata, false); | 1534 | ieee80211_set_wmm_default(sdata, false); |
| 1514 | 1535 | ||
| @@ -1518,6 +1539,9 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
| 1518 | del_timer_sync(&sdata->u.mgd.chswitch_timer); | 1539 | del_timer_sync(&sdata->u.mgd.chswitch_timer); |
| 1519 | 1540 | ||
| 1520 | sdata->u.mgd.timers_running = 0; | 1541 | sdata->u.mgd.timers_running = 0; |
| 1542 | |||
| 1543 | ifmgd->flags = 0; | ||
| 1544 | ieee80211_vif_release_channel(sdata); | ||
| 1521 | } | 1545 | } |
| 1522 | 1546 | ||
| 1523 | void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, | 1547 | void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, |
| @@ -1843,6 +1867,7 @@ static void ieee80211_destroy_auth_data(struct ieee80211_sub_if_data *sdata, | |||
| 1843 | 1867 | ||
| 1844 | memset(sdata->u.mgd.bssid, 0, ETH_ALEN); | 1868 | memset(sdata->u.mgd.bssid, 0, ETH_ALEN); |
| 1845 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID); | 1869 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID); |
| 1870 | sdata->u.mgd.flags = 0; | ||
| 1846 | ieee80211_vif_release_channel(sdata); | 1871 | ieee80211_vif_release_channel(sdata); |
| 1847 | } | 1872 | } |
| 1848 | 1873 | ||
| @@ -2085,6 +2110,7 @@ static void ieee80211_destroy_assoc_data(struct ieee80211_sub_if_data *sdata, | |||
| 2085 | 2110 | ||
| 2086 | memset(sdata->u.mgd.bssid, 0, ETH_ALEN); | 2111 | memset(sdata->u.mgd.bssid, 0, ETH_ALEN); |
| 2087 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID); | 2112 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID); |
| 2113 | sdata->u.mgd.flags = 0; | ||
| 2088 | ieee80211_vif_release_channel(sdata); | 2114 | ieee80211_vif_release_channel(sdata); |
| 2089 | } | 2115 | } |
| 2090 | 2116 | ||
| @@ -2149,7 +2175,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, | |||
| 2149 | 2175 | ||
| 2150 | sband = local->hw.wiphy->bands[ieee80211_get_sdata_band(sdata)]; | 2176 | sband = local->hw.wiphy->bands[ieee80211_get_sdata_band(sdata)]; |
| 2151 | 2177 | ||
| 2152 | if (elems.ht_cap_elem && !(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) | 2178 | if (elems.ht_cap_elem && !(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) |
| 2153 | ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, | 2179 | ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, |
| 2154 | elems.ht_cap_elem, &sta->sta.ht_cap); | 2180 | elems.ht_cap_elem, &sta->sta.ht_cap); |
| 2155 | 2181 | ||
| @@ -2201,7 +2227,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, | |||
| 2201 | changed |= BSS_CHANGED_QOS; | 2227 | changed |= BSS_CHANGED_QOS; |
| 2202 | 2228 | ||
| 2203 | if (elems.ht_operation && elems.wmm_param && | 2229 | if (elems.ht_operation && elems.wmm_param && |
| 2204 | !(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) | 2230 | !(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) |
| 2205 | changed |= ieee80211_config_ht_tx(sdata, elems.ht_operation, | 2231 | changed |= ieee80211_config_ht_tx(sdata, elems.ht_operation, |
| 2206 | cbss->bssid, false); | 2232 | cbss->bssid, false); |
| 2207 | 2233 | ||
| @@ -2452,11 +2478,11 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
| 2452 | return; | 2478 | return; |
| 2453 | } | 2479 | } |
| 2454 | 2480 | ||
| 2455 | if (rx_status->freq != chanctx_conf->channel->center_freq) { | 2481 | if (rx_status->freq != chanctx_conf->def.chan->center_freq) { |
| 2456 | rcu_read_unlock(); | 2482 | rcu_read_unlock(); |
| 2457 | return; | 2483 | return; |
| 2458 | } | 2484 | } |
| 2459 | chan = chanctx_conf->channel; | 2485 | chan = chanctx_conf->def.chan; |
| 2460 | rcu_read_unlock(); | 2486 | rcu_read_unlock(); |
| 2461 | 2487 | ||
| 2462 | if (ifmgd->assoc_data && !ifmgd->assoc_data->have_beacon && | 2488 | if (ifmgd->assoc_data && !ifmgd->assoc_data->have_beacon && |
| @@ -2592,6 +2618,27 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
| 2592 | } | 2618 | } |
| 2593 | } | 2619 | } |
| 2594 | 2620 | ||
| 2621 | if (sdata->vif.p2p) { | ||
| 2622 | u8 noa[2]; | ||
| 2623 | int ret; | ||
| 2624 | |||
| 2625 | ret = cfg80211_get_p2p_attr(mgmt->u.beacon.variable, | ||
| 2626 | len - baselen, | ||
| 2627 | IEEE80211_P2P_ATTR_ABSENCE_NOTICE, | ||
| 2628 | noa, sizeof(noa)); | ||
| 2629 | if (ret >= 2 && sdata->u.mgd.p2p_noa_index != noa[0]) { | ||
| 2630 | bss_conf->p2p_oppps = noa[1] & 0x80; | ||
| 2631 | bss_conf->p2p_ctwindow = noa[1] & 0x7f; | ||
| 2632 | changed |= BSS_CHANGED_P2P_PS; | ||
| 2633 | sdata->u.mgd.p2p_noa_index = noa[0]; | ||
| 2634 | /* | ||
| 2635 | * make sure we update all information, the CRC | ||
| 2636 | * mechanism doesn't look at P2P attributes. | ||
| 2637 | */ | ||
| 2638 | ifmgd->beacon_crc_valid = false; | ||
| 2639 | } | ||
| 2640 | } | ||
| 2641 | |||
| 2595 | if (ncrc == ifmgd->beacon_crc && ifmgd->beacon_crc_valid) | 2642 | if (ncrc == ifmgd->beacon_crc && ifmgd->beacon_crc_valid) |
| 2596 | return; | 2643 | return; |
| 2597 | ifmgd->beacon_crc = ncrc; | 2644 | ifmgd->beacon_crc = ncrc; |
| @@ -2616,17 +2663,17 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
| 2616 | 2663 | ||
| 2617 | 2664 | ||
| 2618 | if (elems.ht_cap_elem && elems.ht_operation && elems.wmm_param && | 2665 | if (elems.ht_cap_elem && elems.ht_operation && elems.wmm_param && |
| 2619 | !(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) | 2666 | !(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) |
| 2620 | changed |= ieee80211_config_ht_tx(sdata, elems.ht_operation, | 2667 | changed |= ieee80211_config_ht_tx(sdata, elems.ht_operation, |
| 2621 | bssid, true); | 2668 | bssid, true); |
| 2622 | 2669 | ||
| 2623 | if (elems.country_elem && elems.pwr_constr_elem && | 2670 | if (elems.country_elem && elems.pwr_constr_elem && |
| 2624 | mgmt->u.probe_resp.capab_info & | 2671 | mgmt->u.probe_resp.capab_info & |
| 2625 | cpu_to_le16(WLAN_CAPABILITY_SPECTRUM_MGMT)) | 2672 | cpu_to_le16(WLAN_CAPABILITY_SPECTRUM_MGMT)) |
| 2626 | ieee80211_handle_pwr_constr(sdata, chan, | 2673 | changed |= ieee80211_handle_pwr_constr(sdata, chan, |
| 2627 | elems.country_elem, | 2674 | elems.country_elem, |
| 2628 | elems.country_elem_len, | 2675 | elems.country_elem_len, |
| 2629 | elems.pwr_constr_elem); | 2676 | elems.pwr_constr_elem); |
| 2630 | 2677 | ||
| 2631 | ieee80211_bss_info_change_notify(sdata, changed); | 2678 | ieee80211_bss_info_change_notify(sdata, changed); |
| 2632 | } | 2679 | } |
| @@ -3146,6 +3193,7 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, | |||
| 3146 | const u8 *ht_oper_ie; | 3193 | const u8 *ht_oper_ie; |
| 3147 | const struct ieee80211_ht_operation *ht_oper = NULL; | 3194 | const struct ieee80211_ht_operation *ht_oper = NULL; |
| 3148 | struct ieee80211_supported_band *sband; | 3195 | struct ieee80211_supported_band *sband; |
| 3196 | struct cfg80211_chan_def chandef; | ||
| 3149 | 3197 | ||
| 3150 | sband = local->hw.wiphy->bands[cbss->channel->band]; | 3198 | sband = local->hw.wiphy->bands[cbss->channel->band]; |
| 3151 | 3199 | ||
| @@ -3177,12 +3225,10 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, | |||
| 3177 | ht_cfreq, ht_oper->primary_chan, | 3225 | ht_cfreq, ht_oper->primary_chan, |
| 3178 | cbss->channel->band); | 3226 | cbss->channel->band); |
| 3179 | ht_oper = NULL; | 3227 | ht_oper = NULL; |
| 3180 | } else { | ||
| 3181 | channel_type = NL80211_CHAN_HT20; | ||
| 3182 | } | 3228 | } |
| 3183 | } | 3229 | } |
| 3184 | 3230 | ||
| 3185 | if (ht_oper && sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) { | 3231 | if (ht_oper) { |
| 3186 | /* | 3232 | /* |
| 3187 | * cfg80211 already verified that the channel itself can | 3233 | * cfg80211 already verified that the channel itself can |
| 3188 | * be used, but it didn't check that we can do the right | 3234 | * be used, but it didn't check that we can do the right |
| @@ -3195,19 +3241,26 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, | |||
| 3195 | 3241 | ||
| 3196 | channel_type = NL80211_CHAN_HT20; | 3242 | channel_type = NL80211_CHAN_HT20; |
| 3197 | 3243 | ||
| 3198 | switch (ht_oper->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { | 3244 | if (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) { |
| 3199 | case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: | 3245 | switch (ht_oper->ht_param & |
| 3200 | if (cbss->channel->flags & IEEE80211_CHAN_NO_HT40PLUS) | 3246 | IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { |
| 3201 | ifmgd->flags |= IEEE80211_STA_DISABLE_40MHZ; | 3247 | case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: |
| 3202 | else | 3248 | if (cbss->channel->flags & |
| 3203 | channel_type = NL80211_CHAN_HT40PLUS; | 3249 | IEEE80211_CHAN_NO_HT40PLUS) |
| 3204 | break; | 3250 | ifmgd->flags |= |
| 3205 | case IEEE80211_HT_PARAM_CHA_SEC_BELOW: | 3251 | IEEE80211_STA_DISABLE_40MHZ; |
| 3206 | if (cbss->channel->flags & IEEE80211_CHAN_NO_HT40MINUS) | 3252 | else |
| 3207 | ifmgd->flags |= IEEE80211_STA_DISABLE_40MHZ; | 3253 | channel_type = NL80211_CHAN_HT40PLUS; |
| 3208 | else | 3254 | break; |
| 3209 | channel_type = NL80211_CHAN_HT40MINUS; | 3255 | case IEEE80211_HT_PARAM_CHA_SEC_BELOW: |
| 3210 | break; | 3256 | if (cbss->channel->flags & |
| 3257 | IEEE80211_CHAN_NO_HT40MINUS) | ||
| 3258 | ifmgd->flags |= | ||
| 3259 | IEEE80211_STA_DISABLE_40MHZ; | ||
| 3260 | else | ||
| 3261 | channel_type = NL80211_CHAN_HT40MINUS; | ||
| 3262 | break; | ||
| 3263 | } | ||
| 3211 | } | 3264 | } |
| 3212 | 3265 | ||
| 3213 | ht_cap_ie = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, | 3266 | ht_cap_ie = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, |
| @@ -3220,13 +3273,15 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, | |||
| 3220 | sdata->needed_rx_chains = min(chains, local->rx_chains); | 3273 | sdata->needed_rx_chains = min(chains, local->rx_chains); |
| 3221 | } else { | 3274 | } else { |
| 3222 | sdata->needed_rx_chains = 1; | 3275 | sdata->needed_rx_chains = 1; |
| 3276 | sdata->u.mgd.flags |= IEEE80211_STA_DISABLE_HT; | ||
| 3223 | } | 3277 | } |
| 3224 | 3278 | ||
| 3225 | /* will change later if needed */ | 3279 | /* will change later if needed */ |
| 3226 | sdata->smps_mode = IEEE80211_SMPS_OFF; | 3280 | sdata->smps_mode = IEEE80211_SMPS_OFF; |
| 3227 | 3281 | ||
| 3228 | ieee80211_vif_release_channel(sdata); | 3282 | ieee80211_vif_release_channel(sdata); |
| 3229 | return ieee80211_vif_use_channel(sdata, cbss->channel, channel_type, | 3283 | cfg80211_chandef_create(&chandef, cbss->channel, channel_type); |
| 3284 | return ieee80211_vif_use_channel(sdata, &chandef, | ||
| 3230 | IEEE80211_CHANCTX_SHARED); | 3285 | IEEE80211_CHANCTX_SHARED); |
| 3231 | } | 3286 | } |
| 3232 | 3287 | ||
| @@ -3488,13 +3543,6 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
| 3488 | 3543 | ||
| 3489 | /* prepare assoc data */ | 3544 | /* prepare assoc data */ |
| 3490 | 3545 | ||
| 3491 | /* | ||
| 3492 | * keep only the 40 MHz disable bit set as it might have | ||
| 3493 | * been set during authentication already, all other bits | ||
| 3494 | * should be reset for a new connection | ||
| 3495 | */ | ||
| 3496 | ifmgd->flags &= IEEE80211_STA_DISABLE_40MHZ; | ||
| 3497 | |||
| 3498 | ifmgd->beacon_crc_valid = false; | 3546 | ifmgd->beacon_crc_valid = false; |
| 3499 | 3547 | ||
| 3500 | /* | 3548 | /* |
| @@ -3508,7 +3556,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
| 3508 | if (req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP40 || | 3556 | if (req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP40 || |
| 3509 | req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_TKIP || | 3557 | req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_TKIP || |
| 3510 | req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP104) { | 3558 | req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP104) { |
| 3511 | ifmgd->flags |= IEEE80211_STA_DISABLE_11N; | 3559 | ifmgd->flags |= IEEE80211_STA_DISABLE_HT; |
| 3512 | ifmgd->flags |= IEEE80211_STA_DISABLE_VHT; | 3560 | ifmgd->flags |= IEEE80211_STA_DISABLE_VHT; |
| 3513 | netdev_info(sdata->dev, | 3561 | netdev_info(sdata->dev, |
| 3514 | "disabling HT/VHT due to WEP/TKIP use\n"); | 3562 | "disabling HT/VHT due to WEP/TKIP use\n"); |
| @@ -3516,7 +3564,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
| 3516 | } | 3564 | } |
| 3517 | 3565 | ||
| 3518 | if (req->flags & ASSOC_REQ_DISABLE_HT) { | 3566 | if (req->flags & ASSOC_REQ_DISABLE_HT) { |
| 3519 | ifmgd->flags |= IEEE80211_STA_DISABLE_11N; | 3567 | ifmgd->flags |= IEEE80211_STA_DISABLE_HT; |
| 3520 | ifmgd->flags |= IEEE80211_STA_DISABLE_VHT; | 3568 | ifmgd->flags |= IEEE80211_STA_DISABLE_VHT; |
| 3521 | } | 3569 | } |
| 3522 | 3570 | ||
| @@ -3524,7 +3572,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
| 3524 | sband = local->hw.wiphy->bands[req->bss->channel->band]; | 3572 | sband = local->hw.wiphy->bands[req->bss->channel->band]; |
| 3525 | if (!sband->ht_cap.ht_supported || | 3573 | if (!sband->ht_cap.ht_supported || |
| 3526 | local->hw.queues < IEEE80211_NUM_ACS || !bss->wmm_used) { | 3574 | local->hw.queues < IEEE80211_NUM_ACS || !bss->wmm_used) { |
| 3527 | ifmgd->flags |= IEEE80211_STA_DISABLE_11N; | 3575 | ifmgd->flags |= IEEE80211_STA_DISABLE_HT; |
| 3528 | if (!bss->wmm_used) | 3576 | if (!bss->wmm_used) |
| 3529 | netdev_info(sdata->dev, | 3577 | netdev_info(sdata->dev, |
| 3530 | "disabling HT as WMM/QoS is not supported by the AP\n"); | 3578 | "disabling HT as WMM/QoS is not supported by the AP\n"); |
| @@ -3569,7 +3617,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
| 3569 | assoc_data->ap_ht_param = | 3617 | assoc_data->ap_ht_param = |
| 3570 | ((struct ieee80211_ht_operation *)(ht_ie + 2))->ht_param; | 3618 | ((struct ieee80211_ht_operation *)(ht_ie + 2))->ht_param; |
| 3571 | else | 3619 | else |
| 3572 | ifmgd->flags |= IEEE80211_STA_DISABLE_11N; | 3620 | ifmgd->flags |= IEEE80211_STA_DISABLE_HT; |
| 3573 | 3621 | ||
| 3574 | if (bss->wmm_used && bss->uapsd_supported && | 3622 | if (bss->wmm_used && bss->uapsd_supported && |
| 3575 | (sdata->local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD)) { | 3623 | (sdata->local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD)) { |
| @@ -3660,40 +3708,44 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, | |||
| 3660 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 3708 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
| 3661 | u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN]; | 3709 | u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN]; |
| 3662 | bool tx = !req->local_state_change; | 3710 | bool tx = !req->local_state_change; |
| 3711 | bool sent_frame = false; | ||
| 3663 | 3712 | ||
| 3664 | mutex_lock(&ifmgd->mtx); | 3713 | mutex_lock(&ifmgd->mtx); |
| 3665 | 3714 | ||
| 3666 | if (ifmgd->auth_data) { | ||
| 3667 | ieee80211_destroy_auth_data(sdata, false); | ||
| 3668 | mutex_unlock(&ifmgd->mtx); | ||
| 3669 | return 0; | ||
| 3670 | } | ||
| 3671 | |||
| 3672 | sdata_info(sdata, | 3715 | sdata_info(sdata, |
| 3673 | "deauthenticating from %pM by local choice (reason=%d)\n", | 3716 | "deauthenticating from %pM by local choice (reason=%d)\n", |
| 3674 | req->bssid, req->reason_code); | 3717 | req->bssid, req->reason_code); |
| 3675 | 3718 | ||
| 3676 | if (ifmgd->associated && | 3719 | if (ifmgd->auth_data) { |
| 3677 | ether_addr_equal(ifmgd->associated->bssid, req->bssid)) { | ||
| 3678 | ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, | ||
| 3679 | req->reason_code, tx, frame_buf); | ||
| 3680 | } else { | ||
| 3681 | drv_mgd_prepare_tx(sdata->local, sdata); | 3720 | drv_mgd_prepare_tx(sdata->local, sdata); |
| 3682 | ieee80211_send_deauth_disassoc(sdata, req->bssid, | 3721 | ieee80211_send_deauth_disassoc(sdata, req->bssid, |
| 3683 | IEEE80211_STYPE_DEAUTH, | 3722 | IEEE80211_STYPE_DEAUTH, |
| 3684 | req->reason_code, tx, | 3723 | req->reason_code, tx, |
| 3685 | frame_buf); | 3724 | frame_buf); |
| 3725 | ieee80211_destroy_auth_data(sdata, false); | ||
| 3726 | mutex_unlock(&ifmgd->mtx); | ||
| 3727 | |||
| 3728 | sent_frame = tx; | ||
| 3729 | goto out; | ||
| 3686 | } | 3730 | } |
| 3687 | 3731 | ||
| 3732 | if (ifmgd->associated && | ||
| 3733 | ether_addr_equal(ifmgd->associated->bssid, req->bssid)) { | ||
| 3734 | ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, | ||
| 3735 | req->reason_code, tx, frame_buf); | ||
| 3736 | sent_frame = tx; | ||
| 3737 | } | ||
| 3688 | mutex_unlock(&ifmgd->mtx); | 3738 | mutex_unlock(&ifmgd->mtx); |
| 3689 | 3739 | ||
| 3690 | __cfg80211_send_deauth(sdata->dev, frame_buf, | 3740 | out: |
| 3691 | IEEE80211_DEAUTH_FRAME_LEN); | ||
| 3692 | |||
| 3693 | mutex_lock(&sdata->local->mtx); | 3741 | mutex_lock(&sdata->local->mtx); |
| 3694 | ieee80211_recalc_idle(sdata->local); | 3742 | ieee80211_recalc_idle(sdata->local); |
| 3695 | mutex_unlock(&sdata->local->mtx); | 3743 | mutex_unlock(&sdata->local->mtx); |
| 3696 | 3744 | ||
| 3745 | if (sent_frame) | ||
| 3746 | __cfg80211_send_deauth(sdata->dev, frame_buf, | ||
| 3747 | IEEE80211_DEAUTH_FRAME_LEN); | ||
| 3748 | |||
| 3697 | return 0; | 3749 | return 0; |
| 3698 | } | 3750 | } |
| 3699 | 3751 | ||
diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c index c349f3aaf59e..5abddfe3e101 100644 --- a/net/mac80211/offchannel.c +++ b/net/mac80211/offchannel.c | |||
| @@ -204,9 +204,9 @@ void ieee80211_handle_roc_started(struct ieee80211_roc_work *roc) | |||
| 204 | roc->frame = NULL; | 204 | roc->frame = NULL; |
| 205 | } | 205 | } |
| 206 | } else { | 206 | } else { |
| 207 | cfg80211_ready_on_channel(&roc->sdata->wdev, (unsigned long)roc, | 207 | cfg80211_ready_on_channel(&roc->sdata->wdev, roc->cookie, |
| 208 | roc->chan, roc->chan_type, | 208 | roc->chan, roc->req_duration, |
| 209 | roc->req_duration, GFP_KERNEL); | 209 | GFP_KERNEL); |
| 210 | } | 210 | } |
| 211 | 211 | ||
| 212 | roc->notified = true; | 212 | roc->notified = true; |
| @@ -283,8 +283,7 @@ void ieee80211_start_next_roc(struct ieee80211_local *local) | |||
| 283 | if (!duration) | 283 | if (!duration) |
| 284 | duration = 10; | 284 | duration = 10; |
| 285 | 285 | ||
| 286 | ret = drv_remain_on_channel(local, roc->chan, | 286 | ret = drv_remain_on_channel(local, roc->sdata, roc->chan, |
| 287 | roc->chan_type, | ||
| 288 | duration); | 287 | duration); |
| 289 | 288 | ||
| 290 | roc->started = true; | 289 | roc->started = true; |
| @@ -320,8 +319,7 @@ void ieee80211_roc_notify_destroy(struct ieee80211_roc_work *roc) | |||
| 320 | 319 | ||
| 321 | if (!roc->mgmt_tx_cookie) | 320 | if (!roc->mgmt_tx_cookie) |
| 322 | cfg80211_remain_on_channel_expired(&roc->sdata->wdev, | 321 | cfg80211_remain_on_channel_expired(&roc->sdata->wdev, |
| 323 | (unsigned long)roc, | 322 | roc->cookie, roc->chan, |
| 324 | roc->chan, roc->chan_type, | ||
| 325 | GFP_KERNEL); | 323 | GFP_KERNEL); |
| 326 | 324 | ||
| 327 | list_for_each_entry_safe(dep, tmp, &roc->dependents, list) | 325 | list_for_each_entry_safe(dep, tmp, &roc->dependents, list) |
| @@ -360,7 +358,6 @@ void ieee80211_sw_roc_work(struct work_struct *work) | |||
| 360 | ieee80211_recalc_idle(local); | 358 | ieee80211_recalc_idle(local); |
| 361 | 359 | ||
| 362 | local->tmp_channel = roc->chan; | 360 | local->tmp_channel = roc->chan; |
| 363 | local->tmp_channel_type = roc->chan_type; | ||
| 364 | ieee80211_hw_config(local, 0); | 361 | ieee80211_hw_config(local, 0); |
| 365 | 362 | ||
| 366 | /* tell userspace or send frame */ | 363 | /* tell userspace or send frame */ |
diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index 9f404ac901ab..79a48f37d409 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c | |||
| @@ -33,6 +33,7 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) | |||
| 33 | struct ieee80211_local *local = hw_to_local(hw); | 33 | struct ieee80211_local *local = hw_to_local(hw); |
| 34 | struct ieee80211_sub_if_data *sdata; | 34 | struct ieee80211_sub_if_data *sdata; |
| 35 | struct sta_info *sta; | 35 | struct sta_info *sta; |
| 36 | struct ieee80211_chanctx *ctx; | ||
| 36 | 37 | ||
| 37 | if (!local->open_count) | 38 | if (!local->open_count) |
| 38 | goto suspend; | 39 | goto suspend; |
| @@ -135,14 +136,55 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) | |||
| 135 | ieee80211_bss_info_change_notify(sdata, | 136 | ieee80211_bss_info_change_notify(sdata, |
| 136 | BSS_CHANGED_BEACON_ENABLED); | 137 | BSS_CHANGED_BEACON_ENABLED); |
| 137 | 138 | ||
| 138 | /* the interface is leaving the channel and is removed */ | 139 | if (sdata->vif.type == NL80211_IFTYPE_AP && |
| 139 | ieee80211_vif_release_channel(sdata); | 140 | rcu_access_pointer(sdata->u.ap.beacon)) |
| 141 | drv_stop_ap(local, sdata); | ||
| 142 | |||
| 143 | if (local->use_chanctx) { | ||
| 144 | struct ieee80211_chanctx_conf *conf; | ||
| 145 | |||
| 146 | mutex_lock(&local->chanctx_mtx); | ||
| 147 | conf = rcu_dereference_protected( | ||
| 148 | sdata->vif.chanctx_conf, | ||
| 149 | lockdep_is_held(&local->chanctx_mtx)); | ||
| 150 | if (conf) { | ||
| 151 | ctx = container_of(conf, | ||
| 152 | struct ieee80211_chanctx, | ||
| 153 | conf); | ||
| 154 | drv_unassign_vif_chanctx(local, sdata, ctx); | ||
| 155 | } | ||
| 156 | |||
| 157 | mutex_unlock(&local->chanctx_mtx); | ||
| 158 | } | ||
| 140 | drv_remove_interface(local, sdata); | 159 | drv_remove_interface(local, sdata); |
| 141 | } | 160 | } |
| 142 | 161 | ||
| 143 | sdata = rtnl_dereference(local->monitor_sdata); | 162 | sdata = rtnl_dereference(local->monitor_sdata); |
| 144 | if (sdata) | 163 | if (sdata) { |
| 164 | if (local->use_chanctx) { | ||
| 165 | struct ieee80211_chanctx_conf *conf; | ||
| 166 | |||
| 167 | mutex_lock(&local->chanctx_mtx); | ||
| 168 | conf = rcu_dereference_protected( | ||
| 169 | sdata->vif.chanctx_conf, | ||
| 170 | lockdep_is_held(&local->chanctx_mtx)); | ||
| 171 | if (conf) { | ||
| 172 | ctx = container_of(conf, | ||
| 173 | struct ieee80211_chanctx, | ||
| 174 | conf); | ||
| 175 | drv_unassign_vif_chanctx(local, sdata, ctx); | ||
| 176 | } | ||
| 177 | |||
| 178 | mutex_unlock(&local->chanctx_mtx); | ||
| 179 | } | ||
| 180 | |||
| 145 | drv_remove_interface(local, sdata); | 181 | drv_remove_interface(local, sdata); |
| 182 | } | ||
| 183 | |||
| 184 | mutex_lock(&local->chanctx_mtx); | ||
| 185 | list_for_each_entry(ctx, &local->chanctx_list, list) | ||
| 186 | drv_remove_chanctx(local, ctx); | ||
| 187 | mutex_unlock(&local->chanctx_mtx); | ||
| 146 | 188 | ||
| 147 | /* stop hardware - this must stop RX */ | 189 | /* stop hardware - this must stop RX */ |
| 148 | if (local->open_count) | 190 | if (local->open_count) |
diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c index 3313c117b322..dd88381c53b7 100644 --- a/net/mac80211/rate.c +++ b/net/mac80211/rate.c | |||
| @@ -391,7 +391,7 @@ static void rate_idx_match_mask(struct ieee80211_tx_rate *rate, | |||
| 391 | return; | 391 | return; |
| 392 | 392 | ||
| 393 | /* if HT BSS, and we handle a data frame, also try HT rates */ | 393 | /* if HT BSS, and we handle a data frame, also try HT rates */ |
| 394 | if (txrc->bss_conf->channel_type == NL80211_CHAN_NO_HT) | 394 | if (txrc->bss_conf->chandef.width == NL80211_CHAN_WIDTH_20_NOHT) |
| 395 | return; | 395 | return; |
| 396 | 396 | ||
| 397 | fc = hdr->frame_control; | 397 | fc = hdr->frame_control; |
| @@ -408,8 +408,7 @@ static void rate_idx_match_mask(struct ieee80211_tx_rate *rate, | |||
| 408 | 408 | ||
| 409 | alt_rate.flags |= IEEE80211_TX_RC_MCS; | 409 | alt_rate.flags |= IEEE80211_TX_RC_MCS; |
| 410 | 410 | ||
| 411 | if ((txrc->bss_conf->channel_type == NL80211_CHAN_HT40MINUS) || | 411 | if (txrc->bss_conf->chandef.width == NL80211_CHAN_WIDTH_40) |
| 412 | (txrc->bss_conf->channel_type == NL80211_CHAN_HT40PLUS)) | ||
| 413 | alt_rate.flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; | 412 | alt_rate.flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; |
| 414 | 413 | ||
| 415 | if (rate_idx_match_mcs_mask(&alt_rate, mcs_mask)) { | 414 | if (rate_idx_match_mcs_mask(&alt_rate, mcs_mask)) { |
diff --git a/net/mac80211/rate.h b/net/mac80211/rate.h index ec198ef6aa8a..301386dabf88 100644 --- a/net/mac80211/rate.h +++ b/net/mac80211/rate.h | |||
| @@ -65,7 +65,7 @@ static inline void rate_control_rate_init(struct sta_info *sta) | |||
| 65 | return; | 65 | return; |
| 66 | } | 66 | } |
| 67 | 67 | ||
| 68 | sband = local->hw.wiphy->bands[chanctx_conf->channel->band]; | 68 | sband = local->hw.wiphy->bands[chanctx_conf->def.chan->band]; |
| 69 | rcu_read_unlock(); | 69 | rcu_read_unlock(); |
| 70 | 70 | ||
| 71 | ref->ops->rate_init(ref->priv, sband, ista, priv_sta); | 71 | ref->ops->rate_init(ref->priv, sband, ista, priv_sta); |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 8c1f1527d671..825f33cf7bbc 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
| @@ -40,6 +40,8 @@ | |||
| 40 | static struct sk_buff *remove_monitor_info(struct ieee80211_local *local, | 40 | static struct sk_buff *remove_monitor_info(struct ieee80211_local *local, |
| 41 | struct sk_buff *skb) | 41 | struct sk_buff *skb) |
| 42 | { | 42 | { |
| 43 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); | ||
| 44 | |||
| 43 | if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) { | 45 | if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) { |
| 44 | if (likely(skb->len > FCS_LEN)) | 46 | if (likely(skb->len > FCS_LEN)) |
| 45 | __pskb_trim(skb, skb->len - FCS_LEN); | 47 | __pskb_trim(skb, skb->len - FCS_LEN); |
| @@ -51,20 +53,25 @@ static struct sk_buff *remove_monitor_info(struct ieee80211_local *local, | |||
| 51 | } | 53 | } |
| 52 | } | 54 | } |
| 53 | 55 | ||
| 56 | if (status->vendor_radiotap_len) | ||
| 57 | __pskb_pull(skb, status->vendor_radiotap_len); | ||
| 58 | |||
| 54 | return skb; | 59 | return skb; |
| 55 | } | 60 | } |
| 56 | 61 | ||
| 57 | static inline int should_drop_frame(struct sk_buff *skb, | 62 | static inline int should_drop_frame(struct sk_buff *skb, int present_fcs_len) |
| 58 | int present_fcs_len) | ||
| 59 | { | 63 | { |
| 60 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); | 64 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); |
| 61 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | 65 | struct ieee80211_hdr *hdr; |
| 66 | |||
| 67 | hdr = (void *)(skb->data + status->vendor_radiotap_len); | ||
| 62 | 68 | ||
| 63 | if (status->flag & (RX_FLAG_FAILED_FCS_CRC | | 69 | if (status->flag & (RX_FLAG_FAILED_FCS_CRC | |
| 64 | RX_FLAG_FAILED_PLCP_CRC | | 70 | RX_FLAG_FAILED_PLCP_CRC | |
| 65 | RX_FLAG_AMPDU_IS_ZEROLEN)) | 71 | RX_FLAG_AMPDU_IS_ZEROLEN)) |
| 66 | return 1; | 72 | return 1; |
| 67 | if (unlikely(skb->len < 16 + present_fcs_len)) | 73 | if (unlikely(skb->len < 16 + present_fcs_len + |
| 74 | status->vendor_radiotap_len)) | ||
| 68 | return 1; | 75 | return 1; |
| 69 | if (ieee80211_is_ctl(hdr->frame_control) && | 76 | if (ieee80211_is_ctl(hdr->frame_control) && |
| 70 | !ieee80211_is_pspoll(hdr->frame_control) && | 77 | !ieee80211_is_pspoll(hdr->frame_control) && |
| @@ -74,32 +81,48 @@ static inline int should_drop_frame(struct sk_buff *skb, | |||
| 74 | } | 81 | } |
| 75 | 82 | ||
| 76 | static int | 83 | static int |
| 77 | ieee80211_rx_radiotap_len(struct ieee80211_local *local, | 84 | ieee80211_rx_radiotap_space(struct ieee80211_local *local, |
| 78 | struct ieee80211_rx_status *status) | 85 | struct ieee80211_rx_status *status) |
| 79 | { | 86 | { |
| 80 | int len; | 87 | int len; |
| 81 | 88 | ||
| 82 | /* always present fields */ | 89 | /* always present fields */ |
| 83 | len = sizeof(struct ieee80211_radiotap_header) + 9; | 90 | len = sizeof(struct ieee80211_radiotap_header) + 9; |
| 84 | 91 | ||
| 85 | if (status->flag & RX_FLAG_MACTIME_MPDU) | 92 | /* allocate extra bitmap */ |
| 93 | if (status->vendor_radiotap_len) | ||
| 94 | len += 4; | ||
| 95 | |||
| 96 | if (ieee80211_have_rx_timestamp(status)) { | ||
| 97 | len = ALIGN(len, 8); | ||
| 86 | len += 8; | 98 | len += 8; |
| 99 | } | ||
| 87 | if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) | 100 | if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) |
| 88 | len += 1; | 101 | len += 1; |
| 89 | 102 | ||
| 90 | if (len & 1) /* padding for RX_FLAGS if necessary */ | 103 | /* padding for RX_FLAGS if necessary */ |
| 91 | len++; | 104 | len = ALIGN(len, 2); |
| 92 | 105 | ||
| 93 | if (status->flag & RX_FLAG_HT) /* HT info */ | 106 | if (status->flag & RX_FLAG_HT) /* HT info */ |
| 94 | len += 3; | 107 | len += 3; |
| 95 | 108 | ||
| 96 | if (status->flag & RX_FLAG_AMPDU_DETAILS) { | 109 | if (status->flag & RX_FLAG_AMPDU_DETAILS) { |
| 97 | /* padding */ | 110 | len = ALIGN(len, 4); |
| 98 | while (len & 3) | ||
| 99 | len++; | ||
| 100 | len += 8; | 111 | len += 8; |
| 101 | } | 112 | } |
| 102 | 113 | ||
| 114 | if (status->vendor_radiotap_len) { | ||
| 115 | if (WARN_ON_ONCE(status->vendor_radiotap_align == 0)) | ||
| 116 | status->vendor_radiotap_align = 1; | ||
| 117 | /* align standard part of vendor namespace */ | ||
| 118 | len = ALIGN(len, 2); | ||
| 119 | /* allocate standard part of vendor namespace */ | ||
| 120 | len += 6; | ||
| 121 | /* align vendor-defined part */ | ||
| 122 | len = ALIGN(len, status->vendor_radiotap_align); | ||
| 123 | /* vendor-defined part is already in skb */ | ||
| 124 | } | ||
| 125 | |||
| 103 | return len; | 126 | return len; |
| 104 | } | 127 | } |
| 105 | 128 | ||
| @@ -118,6 +141,11 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, | |||
| 118 | struct ieee80211_radiotap_header *rthdr; | 141 | struct ieee80211_radiotap_header *rthdr; |
| 119 | unsigned char *pos; | 142 | unsigned char *pos; |
| 120 | u16 rx_flags = 0; | 143 | u16 rx_flags = 0; |
| 144 | int mpdulen; | ||
| 145 | |||
| 146 | mpdulen = skb->len; | ||
| 147 | if (!(has_fcs && (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS))) | ||
| 148 | mpdulen += FCS_LEN; | ||
| 121 | 149 | ||
| 122 | rthdr = (struct ieee80211_radiotap_header *)skb_push(skb, rtap_len); | 150 | rthdr = (struct ieee80211_radiotap_header *)skb_push(skb, rtap_len); |
| 123 | memset(rthdr, 0, rtap_len); | 151 | memset(rthdr, 0, rtap_len); |
| @@ -128,17 +156,30 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, | |||
| 128 | (1 << IEEE80211_RADIOTAP_CHANNEL) | | 156 | (1 << IEEE80211_RADIOTAP_CHANNEL) | |
| 129 | (1 << IEEE80211_RADIOTAP_ANTENNA) | | 157 | (1 << IEEE80211_RADIOTAP_ANTENNA) | |
| 130 | (1 << IEEE80211_RADIOTAP_RX_FLAGS)); | 158 | (1 << IEEE80211_RADIOTAP_RX_FLAGS)); |
| 131 | rthdr->it_len = cpu_to_le16(rtap_len); | 159 | rthdr->it_len = cpu_to_le16(rtap_len + status->vendor_radiotap_len); |
| 132 | 160 | ||
| 133 | pos = (unsigned char *)(rthdr+1); | 161 | pos = (unsigned char *)(rthdr + 1); |
| 162 | |||
| 163 | if (status->vendor_radiotap_len) { | ||
| 164 | rthdr->it_present |= | ||
| 165 | cpu_to_le32(BIT(IEEE80211_RADIOTAP_VENDOR_NAMESPACE)) | | ||
| 166 | cpu_to_le32(BIT(IEEE80211_RADIOTAP_EXT)); | ||
| 167 | put_unaligned_le32(status->vendor_radiotap_bitmap, pos); | ||
| 168 | pos += 4; | ||
| 169 | } | ||
| 134 | 170 | ||
| 135 | /* the order of the following fields is important */ | 171 | /* the order of the following fields is important */ |
| 136 | 172 | ||
| 137 | /* IEEE80211_RADIOTAP_TSFT */ | 173 | /* IEEE80211_RADIOTAP_TSFT */ |
| 138 | if (status->flag & RX_FLAG_MACTIME_MPDU) { | 174 | if (ieee80211_have_rx_timestamp(status)) { |
| 139 | put_unaligned_le64(status->mactime, pos); | 175 | /* padding */ |
| 140 | rthdr->it_present |= | 176 | while ((pos - (u8 *)rthdr) & 7) |
| 141 | cpu_to_le32(1 << IEEE80211_RADIOTAP_TSFT); | 177 | *pos++ = 0; |
| 178 | put_unaligned_le64( | ||
| 179 | ieee80211_calculate_rx_timestamp(local, status, | ||
| 180 | mpdulen, 0), | ||
| 181 | pos); | ||
| 182 | rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_TSFT); | ||
| 142 | pos += 8; | 183 | pos += 8; |
| 143 | } | 184 | } |
| 144 | 185 | ||
| @@ -152,7 +193,7 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, | |||
| 152 | pos++; | 193 | pos++; |
| 153 | 194 | ||
| 154 | /* IEEE80211_RADIOTAP_RATE */ | 195 | /* IEEE80211_RADIOTAP_RATE */ |
| 155 | if (!rate || status->flag & RX_FLAG_HT) { | 196 | if (!rate || status->flag & (RX_FLAG_HT | RX_FLAG_VHT)) { |
| 156 | /* | 197 | /* |
| 157 | * Without rate information don't add it. If we have, | 198 | * Without rate information don't add it. If we have, |
| 158 | * MCS information is a separate field in radiotap, | 199 | * MCS information is a separate field in radiotap, |
| @@ -172,7 +213,7 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, | |||
| 172 | if (status->band == IEEE80211_BAND_5GHZ) | 213 | if (status->band == IEEE80211_BAND_5GHZ) |
| 173 | put_unaligned_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ, | 214 | put_unaligned_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ, |
| 174 | pos); | 215 | pos); |
| 175 | else if (status->flag & RX_FLAG_HT) | 216 | else if (status->flag & (RX_FLAG_HT | RX_FLAG_VHT)) |
| 176 | put_unaligned_le16(IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ, | 217 | put_unaligned_le16(IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ, |
| 177 | pos); | 218 | pos); |
| 178 | else if (rate && rate->flags & IEEE80211_RATE_ERP_G) | 219 | else if (rate && rate->flags & IEEE80211_RATE_ERP_G) |
| @@ -205,7 +246,7 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, | |||
| 205 | /* IEEE80211_RADIOTAP_RX_FLAGS */ | 246 | /* IEEE80211_RADIOTAP_RX_FLAGS */ |
| 206 | /* ensure 2 byte alignment for the 2 byte field as required */ | 247 | /* ensure 2 byte alignment for the 2 byte field as required */ |
| 207 | if ((pos - (u8 *)rthdr) & 1) | 248 | if ((pos - (u8 *)rthdr) & 1) |
| 208 | pos++; | 249 | *pos++ = 0; |
| 209 | if (status->flag & RX_FLAG_FAILED_PLCP_CRC) | 250 | if (status->flag & RX_FLAG_FAILED_PLCP_CRC) |
| 210 | rx_flags |= IEEE80211_RADIOTAP_F_RX_BADPLCP; | 251 | rx_flags |= IEEE80211_RADIOTAP_F_RX_BADPLCP; |
| 211 | put_unaligned_le16(rx_flags, pos); | 252 | put_unaligned_le16(rx_flags, pos); |
| @@ -255,6 +296,21 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, | |||
| 255 | *pos++ = 0; | 296 | *pos++ = 0; |
| 256 | *pos++ = 0; | 297 | *pos++ = 0; |
| 257 | } | 298 | } |
| 299 | |||
| 300 | if (status->vendor_radiotap_len) { | ||
| 301 | /* ensure 2 byte alignment for the vendor field as required */ | ||
| 302 | if ((pos - (u8 *)rthdr) & 1) | ||
| 303 | *pos++ = 0; | ||
| 304 | *pos++ = status->vendor_radiotap_oui[0]; | ||
| 305 | *pos++ = status->vendor_radiotap_oui[1]; | ||
| 306 | *pos++ = status->vendor_radiotap_oui[2]; | ||
| 307 | *pos++ = status->vendor_radiotap_subns; | ||
| 308 | put_unaligned_le16(status->vendor_radiotap_len, pos); | ||
| 309 | pos += 2; | ||
| 310 | /* align the actual payload as requested */ | ||
| 311 | while ((pos - (u8 *)rthdr) & (status->vendor_radiotap_align - 1)) | ||
| 312 | *pos++ = 0; | ||
| 313 | } | ||
| 258 | } | 314 | } |
| 259 | 315 | ||
| 260 | /* | 316 | /* |
| @@ -283,13 +339,13 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, | |||
| 283 | */ | 339 | */ |
| 284 | 340 | ||
| 285 | /* room for the radiotap header based on driver features */ | 341 | /* room for the radiotap header based on driver features */ |
| 286 | needed_headroom = ieee80211_rx_radiotap_len(local, status); | 342 | needed_headroom = ieee80211_rx_radiotap_space(local, status); |
| 287 | 343 | ||
| 288 | if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) | 344 | if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) |
| 289 | present_fcs_len = FCS_LEN; | 345 | present_fcs_len = FCS_LEN; |
| 290 | 346 | ||
| 291 | /* make sure hdr->frame_control is on the linear part */ | 347 | /* ensure hdr->frame_control and vendor radiotap data are in skb head */ |
| 292 | if (!pskb_may_pull(origskb, 2)) { | 348 | if (!pskb_may_pull(origskb, 2 + status->vendor_radiotap_len)) { |
| 293 | dev_kfree_skb(origskb); | 349 | dev_kfree_skb(origskb); |
| 294 | return NULL; | 350 | return NULL; |
| 295 | } | 351 | } |
| @@ -374,7 +430,6 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, | |||
| 374 | return origskb; | 430 | return origskb; |
| 375 | } | 431 | } |
| 376 | 432 | ||
| 377 | |||
| 378 | static void ieee80211_parse_qos(struct ieee80211_rx_data *rx) | 433 | static void ieee80211_parse_qos(struct ieee80211_rx_data *rx) |
| 379 | { | 434 | { |
| 380 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; | 435 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; |
| @@ -403,10 +458,10 @@ static void ieee80211_parse_qos(struct ieee80211_rx_data *rx) | |||
| 403 | * | 458 | * |
| 404 | * We also use that counter for non-QoS STAs. | 459 | * We also use that counter for non-QoS STAs. |
| 405 | */ | 460 | */ |
| 406 | seqno_idx = NUM_RX_DATA_QUEUES; | 461 | seqno_idx = IEEE80211_NUM_TIDS; |
| 407 | security_idx = 0; | 462 | security_idx = 0; |
| 408 | if (ieee80211_is_mgmt(hdr->frame_control)) | 463 | if (ieee80211_is_mgmt(hdr->frame_control)) |
| 409 | security_idx = NUM_RX_DATA_QUEUES; | 464 | security_idx = IEEE80211_NUM_TIDS; |
| 410 | tid = 0; | 465 | tid = 0; |
| 411 | } | 466 | } |
| 412 | 467 | ||
| @@ -481,8 +536,7 @@ static int ieee80211_get_mmie_keyidx(struct sk_buff *skb) | |||
| 481 | struct ieee80211_mgmt *hdr = (struct ieee80211_mgmt *) skb->data; | 536 | struct ieee80211_mgmt *hdr = (struct ieee80211_mgmt *) skb->data; |
| 482 | struct ieee80211_mmie *mmie; | 537 | struct ieee80211_mmie *mmie; |
| 483 | 538 | ||
| 484 | if (skb->len < 24 + sizeof(*mmie) || | 539 | if (skb->len < 24 + sizeof(*mmie) || !is_multicast_ether_addr(hdr->da)) |
| 485 | !is_multicast_ether_addr(hdr->da)) | ||
| 486 | return -1; | 540 | return -1; |
| 487 | 541 | ||
| 488 | if (!ieee80211_is_robust_mgmt_frame((struct ieee80211_hdr *) hdr)) | 542 | if (!ieee80211_is_robust_mgmt_frame((struct ieee80211_hdr *) hdr)) |
| @@ -497,9 +551,7 @@ static int ieee80211_get_mmie_keyidx(struct sk_buff *skb) | |||
| 497 | return le16_to_cpu(mmie->key_id); | 551 | return le16_to_cpu(mmie->key_id); |
| 498 | } | 552 | } |
| 499 | 553 | ||
| 500 | 554 | static ieee80211_rx_result ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) | |
| 501 | static ieee80211_rx_result | ||
| 502 | ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) | ||
| 503 | { | 555 | { |
| 504 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; | 556 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; |
| 505 | char *dev_addr = rx->sdata->vif.addr; | 557 | char *dev_addr = rx->sdata->vif.addr; |
| @@ -507,7 +559,7 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) | |||
| 507 | if (ieee80211_is_data(hdr->frame_control)) { | 559 | if (ieee80211_is_data(hdr->frame_control)) { |
| 508 | if (is_multicast_ether_addr(hdr->addr1)) { | 560 | if (is_multicast_ether_addr(hdr->addr1)) { |
| 509 | if (ieee80211_has_tods(hdr->frame_control) || | 561 | if (ieee80211_has_tods(hdr->frame_control) || |
| 510 | !ieee80211_has_fromds(hdr->frame_control)) | 562 | !ieee80211_has_fromds(hdr->frame_control)) |
| 511 | return RX_DROP_MONITOR; | 563 | return RX_DROP_MONITOR; |
| 512 | if (ether_addr_equal(hdr->addr3, dev_addr)) | 564 | if (ether_addr_equal(hdr->addr3, dev_addr)) |
| 513 | return RX_DROP_MONITOR; | 565 | return RX_DROP_MONITOR; |
| @@ -539,7 +591,7 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) | |||
| 539 | mgmt = (struct ieee80211_mgmt *)hdr; | 591 | mgmt = (struct ieee80211_mgmt *)hdr; |
| 540 | category = mgmt->u.action.category; | 592 | category = mgmt->u.action.category; |
| 541 | if (category != WLAN_CATEGORY_MESH_ACTION && | 593 | if (category != WLAN_CATEGORY_MESH_ACTION && |
| 542 | category != WLAN_CATEGORY_SELF_PROTECTED) | 594 | category != WLAN_CATEGORY_SELF_PROTECTED) |
| 543 | return RX_DROP_MONITOR; | 595 | return RX_DROP_MONITOR; |
| 544 | return RX_CONTINUE; | 596 | return RX_CONTINUE; |
| 545 | } | 597 | } |
| @@ -551,7 +603,6 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) | |||
| 551 | return RX_CONTINUE; | 603 | return RX_CONTINUE; |
| 552 | 604 | ||
| 553 | return RX_DROP_MONITOR; | 605 | return RX_DROP_MONITOR; |
| 554 | |||
| 555 | } | 606 | } |
| 556 | 607 | ||
| 557 | return RX_CONTINUE; | 608 | return RX_CONTINUE; |
| @@ -575,7 +626,6 @@ static inline u16 seq_sub(u16 sq1, u16 sq2) | |||
| 575 | return (sq1 - sq2) & SEQ_MASK; | 626 | return (sq1 - sq2) & SEQ_MASK; |
| 576 | } | 627 | } |
| 577 | 628 | ||
| 578 | |||
| 579 | static void ieee80211_release_reorder_frame(struct ieee80211_sub_if_data *sdata, | 629 | static void ieee80211_release_reorder_frame(struct ieee80211_sub_if_data *sdata, |
| 580 | struct tid_ampdu_rx *tid_agg_rx, | 630 | struct tid_ampdu_rx *tid_agg_rx, |
| 581 | int index) | 631 | int index) |
| @@ -1291,17 +1341,22 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) | |||
| 1291 | 1341 | ||
| 1292 | /* | 1342 | /* |
| 1293 | * Update last_rx only for IBSS packets which are for the current | 1343 | * Update last_rx only for IBSS packets which are for the current |
| 1294 | * BSSID to avoid keeping the current IBSS network alive in cases | 1344 | * BSSID and for station already AUTHORIZED to avoid keeping the |
| 1295 | * where other STAs start using different BSSID. | 1345 | * current IBSS network alive in cases where other STAs start |
| 1346 | * using different BSSID. This will also give the station another | ||
| 1347 | * chance to restart the authentication/authorization in case | ||
| 1348 | * something went wrong the first time. | ||
| 1296 | */ | 1349 | */ |
| 1297 | if (rx->sdata->vif.type == NL80211_IFTYPE_ADHOC) { | 1350 | if (rx->sdata->vif.type == NL80211_IFTYPE_ADHOC) { |
| 1298 | u8 *bssid = ieee80211_get_bssid(hdr, rx->skb->len, | 1351 | u8 *bssid = ieee80211_get_bssid(hdr, rx->skb->len, |
| 1299 | NL80211_IFTYPE_ADHOC); | 1352 | NL80211_IFTYPE_ADHOC); |
| 1300 | if (ether_addr_equal(bssid, rx->sdata->u.ibss.bssid)) { | 1353 | if (ether_addr_equal(bssid, rx->sdata->u.ibss.bssid) && |
| 1354 | test_sta_flag(sta, WLAN_STA_AUTHORIZED)) { | ||
| 1301 | sta->last_rx = jiffies; | 1355 | sta->last_rx = jiffies; |
| 1302 | if (ieee80211_is_data(hdr->frame_control)) { | 1356 | if (ieee80211_is_data(hdr->frame_control)) { |
| 1303 | sta->last_rx_rate_idx = status->rate_idx; | 1357 | sta->last_rx_rate_idx = status->rate_idx; |
| 1304 | sta->last_rx_rate_flag = status->flag; | 1358 | sta->last_rx_rate_flag = status->flag; |
| 1359 | sta->last_rx_rate_vht_nss = status->vht_nss; | ||
| 1305 | } | 1360 | } |
| 1306 | } | 1361 | } |
| 1307 | } else if (!is_multicast_ether_addr(hdr->addr1)) { | 1362 | } else if (!is_multicast_ether_addr(hdr->addr1)) { |
| @@ -1313,6 +1368,7 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) | |||
| 1313 | if (ieee80211_is_data(hdr->frame_control)) { | 1368 | if (ieee80211_is_data(hdr->frame_control)) { |
| 1314 | sta->last_rx_rate_idx = status->rate_idx; | 1369 | sta->last_rx_rate_idx = status->rate_idx; |
| 1315 | sta->last_rx_rate_flag = status->flag; | 1370 | sta->last_rx_rate_flag = status->flag; |
| 1371 | sta->last_rx_rate_vht_nss = status->vht_nss; | ||
| 1316 | } | 1372 | } |
| 1317 | } | 1373 | } |
| 1318 | 1374 | ||
| @@ -1585,18 +1641,15 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) | |||
| 1585 | return RX_CONTINUE; | 1641 | return RX_CONTINUE; |
| 1586 | } | 1642 | } |
| 1587 | 1643 | ||
| 1588 | static int | 1644 | static int ieee80211_802_1x_port_control(struct ieee80211_rx_data *rx) |
| 1589 | ieee80211_802_1x_port_control(struct ieee80211_rx_data *rx) | ||
| 1590 | { | 1645 | { |
| 1591 | if (unlikely(!rx->sta || | 1646 | if (unlikely(!rx->sta || !test_sta_flag(rx->sta, WLAN_STA_AUTHORIZED))) |
| 1592 | !test_sta_flag(rx->sta, WLAN_STA_AUTHORIZED))) | ||
| 1593 | return -EACCES; | 1647 | return -EACCES; |
| 1594 | 1648 | ||
| 1595 | return 0; | 1649 | return 0; |
| 1596 | } | 1650 | } |
| 1597 | 1651 | ||
| 1598 | static int | 1652 | static int ieee80211_drop_unencrypted(struct ieee80211_rx_data *rx, __le16 fc) |
| 1599 | ieee80211_drop_unencrypted(struct ieee80211_rx_data *rx, __le16 fc) | ||
| 1600 | { | 1653 | { |
| 1601 | struct sk_buff *skb = rx->skb; | 1654 | struct sk_buff *skb = rx->skb; |
| 1602 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); | 1655 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); |
| @@ -1618,8 +1671,7 @@ ieee80211_drop_unencrypted(struct ieee80211_rx_data *rx, __le16 fc) | |||
| 1618 | return 0; | 1671 | return 0; |
| 1619 | } | 1672 | } |
| 1620 | 1673 | ||
| 1621 | static int | 1674 | static int ieee80211_drop_unencrypted_mgmt(struct ieee80211_rx_data *rx) |
| 1622 | ieee80211_drop_unencrypted_mgmt(struct ieee80211_rx_data *rx) | ||
| 1623 | { | 1675 | { |
| 1624 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; | 1676 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; |
| 1625 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); | 1677 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); |
| @@ -2003,7 +2055,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) | |||
| 2003 | } else { | 2055 | } else { |
| 2004 | /* unable to resolve next hop */ | 2056 | /* unable to resolve next hop */ |
| 2005 | mesh_path_error_tx(ifmsh->mshcfg.element_ttl, fwd_hdr->addr3, | 2057 | mesh_path_error_tx(ifmsh->mshcfg.element_ttl, fwd_hdr->addr3, |
| 2006 | 0, reason, fwd_hdr->addr2, sdata); | 2058 | 0, reason, fwd_hdr->addr2, sdata); |
| 2007 | IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_no_route); | 2059 | IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_no_route); |
| 2008 | kfree_skb(fwd_skb); | 2060 | kfree_skb(fwd_skb); |
| 2009 | return RX_DROP_MONITOR; | 2061 | return RX_DROP_MONITOR; |
| @@ -2212,7 +2264,7 @@ ieee80211_rx_h_mgmt_check(struct ieee80211_rx_data *rx) | |||
| 2212 | 2264 | ||
| 2213 | cfg80211_report_obss_beacon(rx->local->hw.wiphy, | 2265 | cfg80211_report_obss_beacon(rx->local->hw.wiphy, |
| 2214 | rx->skb->data, rx->skb->len, | 2266 | rx->skb->data, rx->skb->len, |
| 2215 | status->freq, sig, GFP_ATOMIC); | 2267 | status->freq, sig); |
| 2216 | rx->flags |= IEEE80211_RX_BEACON_REPORTED; | 2268 | rx->flags |= IEEE80211_RX_BEACON_REPORTED; |
| 2217 | } | 2269 | } |
| 2218 | 2270 | ||
| @@ -2412,7 +2464,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) | |||
| 2412 | if (!ieee80211_vif_is_mesh(&sdata->vif)) | 2464 | if (!ieee80211_vif_is_mesh(&sdata->vif)) |
| 2413 | break; | 2465 | break; |
| 2414 | if (mesh_action_is_path_sel(mgmt) && | 2466 | if (mesh_action_is_path_sel(mgmt) && |
| 2415 | (!mesh_path_sel_is_hwmp(sdata))) | 2467 | !mesh_path_sel_is_hwmp(sdata)) |
| 2416 | break; | 2468 | break; |
| 2417 | goto queue; | 2469 | goto queue; |
| 2418 | } | 2470 | } |
| @@ -2468,7 +2520,6 @@ ieee80211_rx_h_userspace_mgmt(struct ieee80211_rx_data *rx) | |||
| 2468 | return RX_QUEUED; | 2520 | return RX_QUEUED; |
| 2469 | } | 2521 | } |
| 2470 | 2522 | ||
| 2471 | |||
| 2472 | return RX_CONTINUE; | 2523 | return RX_CONTINUE; |
| 2473 | } | 2524 | } |
| 2474 | 2525 | ||
| @@ -2598,7 +2649,7 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx, | |||
| 2598 | goto out_free_skb; | 2649 | goto out_free_skb; |
| 2599 | 2650 | ||
| 2600 | /* room for the radiotap header based on driver features */ | 2651 | /* room for the radiotap header based on driver features */ |
| 2601 | needed_headroom = ieee80211_rx_radiotap_len(local, status); | 2652 | needed_headroom = ieee80211_rx_radiotap_space(local, status); |
| 2602 | 2653 | ||
| 2603 | if (skb_headroom(skb) < needed_headroom && | 2654 | if (skb_headroom(skb) < needed_headroom && |
| 2604 | pskb_expand_head(skb, needed_headroom, 0, GFP_ATOMIC)) | 2655 | pskb_expand_head(skb, needed_headroom, 0, GFP_ATOMIC)) |
| @@ -2661,7 +2712,8 @@ static void ieee80211_rx_handlers_result(struct ieee80211_rx_data *rx, | |||
| 2661 | status = IEEE80211_SKB_RXCB((rx->skb)); | 2712 | status = IEEE80211_SKB_RXCB((rx->skb)); |
| 2662 | 2713 | ||
| 2663 | sband = rx->local->hw.wiphy->bands[status->band]; | 2714 | sband = rx->local->hw.wiphy->bands[status->band]; |
| 2664 | if (!(status->flag & RX_FLAG_HT)) | 2715 | if (!(status->flag & RX_FLAG_HT) && |
| 2716 | !(status->flag & RX_FLAG_VHT)) | ||
| 2665 | rate = &sband->bitrates[status->rate_idx]; | 2717 | rate = &sband->bitrates[status->rate_idx]; |
| 2666 | 2718 | ||
| 2667 | ieee80211_rx_cooked_monitor(rx, rate); | 2719 | ieee80211_rx_cooked_monitor(rx, rate); |
| @@ -2828,8 +2880,8 @@ static int prepare_for_handlers(struct ieee80211_rx_data *rx, | |||
| 2828 | status->rx_flags &= ~IEEE80211_RX_RA_MATCH; | 2880 | status->rx_flags &= ~IEEE80211_RX_RA_MATCH; |
| 2829 | } else if (!rx->sta) { | 2881 | } else if (!rx->sta) { |
| 2830 | int rate_idx; | 2882 | int rate_idx; |
| 2831 | if (status->flag & RX_FLAG_HT) | 2883 | if (status->flag & (RX_FLAG_HT | RX_FLAG_VHT)) |
| 2832 | rate_idx = 0; /* TODO: HT rates */ | 2884 | rate_idx = 0; /* TODO: HT/VHT rates */ |
| 2833 | else | 2885 | else |
| 2834 | rate_idx = status->rate_idx; | 2886 | rate_idx = status->rate_idx; |
| 2835 | ieee80211_ibss_rx_no_sta(sdata, bssid, hdr->addr2, | 2887 | ieee80211_ibss_rx_no_sta(sdata, bssid, hdr->addr2, |
| @@ -3105,6 +3157,13 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
| 3105 | status->rate_idx, | 3157 | status->rate_idx, |
| 3106 | status->rate_idx)) | 3158 | status->rate_idx)) |
| 3107 | goto drop; | 3159 | goto drop; |
| 3160 | } else if (status->flag & RX_FLAG_VHT) { | ||
| 3161 | if (WARN_ONCE(status->rate_idx > 9 || | ||
| 3162 | !status->vht_nss || | ||
| 3163 | status->vht_nss > 8, | ||
| 3164 | "Rate marked as a VHT rate but data is invalid: MCS: %d, NSS: %d\n", | ||
| 3165 | status->rate_idx, status->vht_nss)) | ||
| 3166 | goto drop; | ||
| 3108 | } else { | 3167 | } else { |
| 3109 | if (WARN_ON(status->rate_idx >= sband->n_bitrates)) | 3168 | if (WARN_ON(status->rate_idx >= sband->n_bitrates)) |
| 3110 | goto drop; | 3169 | goto drop; |
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 8e9bb168b73b..f3340279aba3 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c | |||
| @@ -174,7 +174,6 @@ void ieee80211_scan_rx(struct ieee80211_local *local, struct sk_buff *skb) | |||
| 174 | u8 *elements; | 174 | u8 *elements; |
| 175 | struct ieee80211_channel *channel; | 175 | struct ieee80211_channel *channel; |
| 176 | size_t baselen; | 176 | size_t baselen; |
| 177 | int freq; | ||
| 178 | bool beacon; | 177 | bool beacon; |
| 179 | struct ieee802_11_elems elems; | 178 | struct ieee802_11_elems elems; |
| 180 | 179 | ||
| @@ -209,13 +208,7 @@ void ieee80211_scan_rx(struct ieee80211_local *local, struct sk_buff *skb) | |||
| 209 | 208 | ||
| 210 | ieee802_11_parse_elems(elements, skb->len - baselen, &elems); | 209 | ieee802_11_parse_elems(elements, skb->len - baselen, &elems); |
| 211 | 210 | ||
| 212 | if (elems.ds_params && elems.ds_params_len == 1) | 211 | channel = ieee80211_get_channel(local->hw.wiphy, rx_status->freq); |
| 213 | freq = ieee80211_channel_to_frequency(elems.ds_params[0], | ||
| 214 | rx_status->band); | ||
| 215 | else | ||
| 216 | freq = rx_status->freq; | ||
| 217 | |||
| 218 | channel = ieee80211_get_channel(local->hw.wiphy, freq); | ||
| 219 | 212 | ||
| 220 | if (!channel || channel->flags & IEEE80211_CHAN_DISABLED) | 213 | if (!channel || channel->flags & IEEE80211_CHAN_DISABLED) |
| 221 | return; | 214 | return; |
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index e9d57689c05f..f3e502502fee 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
| @@ -142,7 +142,7 @@ static void free_sta_work(struct work_struct *wk) | |||
| 142 | * drivers have to handle aggregation stop being requested, followed | 142 | * drivers have to handle aggregation stop being requested, followed |
| 143 | * directly by station destruction. | 143 | * directly by station destruction. |
| 144 | */ | 144 | */ |
| 145 | for (i = 0; i < STA_TID_NUM; i++) { | 145 | for (i = 0; i < IEEE80211_NUM_TIDS; i++) { |
| 146 | tid_tx = rcu_dereference_raw(sta->ampdu_mlme.tid_tx[i]); | 146 | tid_tx = rcu_dereference_raw(sta->ampdu_mlme.tid_tx[i]); |
| 147 | if (!tid_tx) | 147 | if (!tid_tx) |
| 148 | continue; | 148 | continue; |
| @@ -330,7 +330,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | |||
| 330 | return NULL; | 330 | return NULL; |
| 331 | } | 331 | } |
| 332 | 332 | ||
| 333 | for (i = 0; i < STA_TID_NUM; i++) { | 333 | for (i = 0; i < IEEE80211_NUM_TIDS; i++) { |
| 334 | /* | 334 | /* |
| 335 | * timer_to_tid must be initialized with identity mapping | 335 | * timer_to_tid must be initialized with identity mapping |
| 336 | * to enable session_timer's data differentiation. See | 336 | * to enable session_timer's data differentiation. See |
| @@ -343,7 +343,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | |||
| 343 | skb_queue_head_init(&sta->tx_filtered[i]); | 343 | skb_queue_head_init(&sta->tx_filtered[i]); |
| 344 | } | 344 | } |
| 345 | 345 | ||
| 346 | for (i = 0; i < NUM_RX_DATA_QUEUES; i++) | 346 | for (i = 0; i < IEEE80211_NUM_TIDS; i++) |
| 347 | sta->last_seq_ctrl[i] = cpu_to_le16(USHRT_MAX); | 347 | sta->last_seq_ctrl[i] = cpu_to_le16(USHRT_MAX); |
| 348 | 348 | ||
| 349 | sta_dbg(sdata, "Allocated STA %pM\n", sta->sta.addr); | 349 | sta_dbg(sdata, "Allocated STA %pM\n", sta->sta.addr); |
| @@ -986,7 +986,7 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta) | |||
| 986 | 986 | ||
| 987 | clear_sta_flag(sta, WLAN_STA_SP); | 987 | clear_sta_flag(sta, WLAN_STA_SP); |
| 988 | 988 | ||
| 989 | BUILD_BUG_ON(BITS_TO_LONGS(STA_TID_NUM) > 1); | 989 | BUILD_BUG_ON(BITS_TO_LONGS(IEEE80211_NUM_TIDS) > 1); |
| 990 | sta->driver_buffered_tids = 0; | 990 | sta->driver_buffered_tids = 0; |
| 991 | 991 | ||
| 992 | if (!(local->hw.flags & IEEE80211_HW_AP_LINK_PS)) | 992 | if (!(local->hw.flags & IEEE80211_HW_AP_LINK_PS)) |
| @@ -1092,7 +1092,7 @@ static void ieee80211_send_null_response(struct ieee80211_sub_if_data *sdata, | |||
| 1092 | return; | 1092 | return; |
| 1093 | } | 1093 | } |
| 1094 | 1094 | ||
| 1095 | ieee80211_xmit(sdata, skb, chanctx_conf->channel->band); | 1095 | ieee80211_xmit(sdata, skb, chanctx_conf->def.chan->band); |
| 1096 | rcu_read_unlock(); | 1096 | rcu_read_unlock(); |
| 1097 | } | 1097 | } |
| 1098 | 1098 | ||
| @@ -1374,7 +1374,7 @@ void ieee80211_sta_set_buffered(struct ieee80211_sta *pubsta, | |||
| 1374 | { | 1374 | { |
| 1375 | struct sta_info *sta = container_of(pubsta, struct sta_info, sta); | 1375 | struct sta_info *sta = container_of(pubsta, struct sta_info, sta); |
| 1376 | 1376 | ||
| 1377 | if (WARN_ON(tid >= STA_TID_NUM)) | 1377 | if (WARN_ON(tid >= IEEE80211_NUM_TIDS)) |
| 1378 | return; | 1378 | return; |
| 1379 | 1379 | ||
| 1380 | if (buffered) | 1380 | if (buffered) |
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index c88f161f8118..6835cea4e402 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h | |||
| @@ -80,7 +80,6 @@ enum ieee80211_sta_info_flags { | |||
| 80 | WLAN_STA_TOFFSET_KNOWN, | 80 | WLAN_STA_TOFFSET_KNOWN, |
| 81 | }; | 81 | }; |
| 82 | 82 | ||
| 83 | #define STA_TID_NUM 16 | ||
| 84 | #define ADDBA_RESP_INTERVAL HZ | 83 | #define ADDBA_RESP_INTERVAL HZ |
| 85 | #define HT_AGG_MAX_RETRIES 15 | 84 | #define HT_AGG_MAX_RETRIES 15 |
| 86 | #define HT_AGG_BURST_RETRIES 3 | 85 | #define HT_AGG_BURST_RETRIES 3 |
| @@ -197,15 +196,15 @@ struct tid_ampdu_rx { | |||
| 197 | struct sta_ampdu_mlme { | 196 | struct sta_ampdu_mlme { |
| 198 | struct mutex mtx; | 197 | struct mutex mtx; |
| 199 | /* rx */ | 198 | /* rx */ |
| 200 | struct tid_ampdu_rx __rcu *tid_rx[STA_TID_NUM]; | 199 | struct tid_ampdu_rx __rcu *tid_rx[IEEE80211_NUM_TIDS]; |
| 201 | unsigned long tid_rx_timer_expired[BITS_TO_LONGS(STA_TID_NUM)]; | 200 | unsigned long tid_rx_timer_expired[BITS_TO_LONGS(IEEE80211_NUM_TIDS)]; |
| 202 | unsigned long tid_rx_stop_requested[BITS_TO_LONGS(STA_TID_NUM)]; | 201 | unsigned long tid_rx_stop_requested[BITS_TO_LONGS(IEEE80211_NUM_TIDS)]; |
| 203 | /* tx */ | 202 | /* tx */ |
| 204 | struct work_struct work; | 203 | struct work_struct work; |
| 205 | struct tid_ampdu_tx __rcu *tid_tx[STA_TID_NUM]; | 204 | struct tid_ampdu_tx __rcu *tid_tx[IEEE80211_NUM_TIDS]; |
| 206 | struct tid_ampdu_tx *tid_start_tx[STA_TID_NUM]; | 205 | struct tid_ampdu_tx *tid_start_tx[IEEE80211_NUM_TIDS]; |
| 207 | unsigned long last_addba_req_time[STA_TID_NUM]; | 206 | unsigned long last_addba_req_time[IEEE80211_NUM_TIDS]; |
| 208 | u8 addba_req_num[STA_TID_NUM]; | 207 | u8 addba_req_num[IEEE80211_NUM_TIDS]; |
| 209 | u8 dialog_token_allocator; | 208 | u8 dialog_token_allocator; |
| 210 | }; | 209 | }; |
| 211 | 210 | ||
| @@ -228,6 +227,7 @@ struct sta_ampdu_mlme { | |||
| 228 | * "the" transmit rate | 227 | * "the" transmit rate |
| 229 | * @last_rx_rate_idx: rx status rate index of the last data packet | 228 | * @last_rx_rate_idx: rx status rate index of the last data packet |
| 230 | * @last_rx_rate_flag: rx status flag of the last data packet | 229 | * @last_rx_rate_flag: rx status flag of the last data packet |
| 230 | * @last_rx_rate_vht_nss: rx status nss of last data packet | ||
| 231 | * @lock: used for locking all fields that require locking, see comments | 231 | * @lock: used for locking all fields that require locking, see comments |
| 232 | * in the header file. | 232 | * in the header file. |
| 233 | * @drv_unblock_wk: used for driver PS unblocking | 233 | * @drv_unblock_wk: used for driver PS unblocking |
| @@ -273,7 +273,7 @@ struct sta_ampdu_mlme { | |||
| 273 | * @t_offset: timing offset relative to this host | 273 | * @t_offset: timing offset relative to this host |
| 274 | * @t_offset_setpoint: reference timing offset of this sta to be used when | 274 | * @t_offset_setpoint: reference timing offset of this sta to be used when |
| 275 | * calculating clockdrift | 275 | * calculating clockdrift |
| 276 | * @ch_type: peer's channel type | 276 | * @ch_width: peer's channel width |
| 277 | * @debugfs: debug filesystem info | 277 | * @debugfs: debug filesystem info |
| 278 | * @dead: set to true when sta is unlinked | 278 | * @dead: set to true when sta is unlinked |
| 279 | * @uploaded: set to true when sta is uploaded to the driver | 279 | * @uploaded: set to true when sta is uploaded to the driver |
| @@ -330,7 +330,7 @@ struct sta_info { | |||
| 330 | int last_signal; | 330 | int last_signal; |
| 331 | struct ewma avg_signal; | 331 | struct ewma avg_signal; |
| 332 | /* Plus 1 for non-QoS frames */ | 332 | /* Plus 1 for non-QoS frames */ |
| 333 | __le16 last_seq_ctrl[NUM_RX_DATA_QUEUES + 1]; | 333 | __le16 last_seq_ctrl[IEEE80211_NUM_TIDS + 1]; |
| 334 | 334 | ||
| 335 | /* Updated from TX status path only, no locking requirements */ | 335 | /* Updated from TX status path only, no locking requirements */ |
| 336 | unsigned long tx_filtered_count; | 336 | unsigned long tx_filtered_count; |
| @@ -344,14 +344,15 @@ struct sta_info { | |||
| 344 | unsigned long tx_fragments; | 344 | unsigned long tx_fragments; |
| 345 | struct ieee80211_tx_rate last_tx_rate; | 345 | struct ieee80211_tx_rate last_tx_rate; |
| 346 | int last_rx_rate_idx; | 346 | int last_rx_rate_idx; |
| 347 | int last_rx_rate_flag; | 347 | u32 last_rx_rate_flag; |
| 348 | u8 last_rx_rate_vht_nss; | ||
| 348 | u16 tid_seq[IEEE80211_QOS_CTL_TID_MASK + 1]; | 349 | u16 tid_seq[IEEE80211_QOS_CTL_TID_MASK + 1]; |
| 349 | 350 | ||
| 350 | /* | 351 | /* |
| 351 | * Aggregation information, locked with lock. | 352 | * Aggregation information, locked with lock. |
| 352 | */ | 353 | */ |
| 353 | struct sta_ampdu_mlme ampdu_mlme; | 354 | struct sta_ampdu_mlme ampdu_mlme; |
| 354 | u8 timer_to_tid[STA_TID_NUM]; | 355 | u8 timer_to_tid[IEEE80211_NUM_TIDS]; |
| 355 | 356 | ||
| 356 | #ifdef CONFIG_MAC80211_MESH | 357 | #ifdef CONFIG_MAC80211_MESH |
| 357 | /* | 358 | /* |
| @@ -369,7 +370,7 @@ struct sta_info { | |||
| 369 | struct timer_list plink_timer; | 370 | struct timer_list plink_timer; |
| 370 | s64 t_offset; | 371 | s64 t_offset; |
| 371 | s64 t_offset_setpoint; | 372 | s64 t_offset_setpoint; |
| 372 | enum nl80211_channel_type ch_type; | 373 | enum nl80211_chan_width ch_width; |
| 373 | #endif | 374 | #endif |
| 374 | 375 | ||
| 375 | #ifdef CONFIG_MAC80211_DEBUGFS | 376 | #ifdef CONFIG_MAC80211_DEBUGFS |
diff --git a/net/mac80211/status.c b/net/mac80211/status.c index 248247877eb6..ab63237107c8 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c | |||
| @@ -325,6 +325,75 @@ static void ieee80211_add_tx_radiotap_header(struct ieee80211_supported_band | |||
| 325 | 325 | ||
| 326 | } | 326 | } |
| 327 | 327 | ||
| 328 | static void ieee80211_report_used_skb(struct ieee80211_local *local, | ||
| 329 | struct sk_buff *skb, bool dropped) | ||
| 330 | { | ||
| 331 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||
| 332 | struct ieee80211_hdr *hdr = (void *)skb->data; | ||
| 333 | bool acked = info->flags & IEEE80211_TX_STAT_ACK; | ||
| 334 | |||
| 335 | if (dropped) | ||
| 336 | acked = false; | ||
| 337 | |||
| 338 | if (info->flags & IEEE80211_TX_INTFL_NL80211_FRAME_TX) { | ||
| 339 | struct ieee80211_sub_if_data *sdata = NULL; | ||
| 340 | struct ieee80211_sub_if_data *iter_sdata; | ||
| 341 | u64 cookie = (unsigned long)skb; | ||
| 342 | |||
| 343 | rcu_read_lock(); | ||
| 344 | |||
| 345 | if (skb->dev) { | ||
| 346 | list_for_each_entry_rcu(iter_sdata, &local->interfaces, | ||
| 347 | list) { | ||
| 348 | if (!iter_sdata->dev) | ||
| 349 | continue; | ||
| 350 | |||
| 351 | if (skb->dev == iter_sdata->dev) { | ||
| 352 | sdata = iter_sdata; | ||
| 353 | break; | ||
| 354 | } | ||
| 355 | } | ||
| 356 | } else { | ||
| 357 | sdata = rcu_dereference(local->p2p_sdata); | ||
| 358 | } | ||
| 359 | |||
| 360 | if (!sdata) | ||
| 361 | skb->dev = NULL; | ||
| 362 | else if (ieee80211_is_nullfunc(hdr->frame_control) || | ||
| 363 | ieee80211_is_qos_nullfunc(hdr->frame_control)) { | ||
| 364 | cfg80211_probe_status(sdata->dev, hdr->addr1, | ||
| 365 | cookie, acked, GFP_ATOMIC); | ||
| 366 | } else { | ||
| 367 | cfg80211_mgmt_tx_status(&sdata->wdev, cookie, skb->data, | ||
| 368 | skb->len, acked, GFP_ATOMIC); | ||
| 369 | } | ||
| 370 | |||
| 371 | rcu_read_unlock(); | ||
| 372 | } | ||
| 373 | |||
| 374 | if (unlikely(info->ack_frame_id)) { | ||
| 375 | struct sk_buff *ack_skb; | ||
| 376 | unsigned long flags; | ||
| 377 | |||
| 378 | spin_lock_irqsave(&local->ack_status_lock, flags); | ||
| 379 | ack_skb = idr_find(&local->ack_status_frames, | ||
| 380 | info->ack_frame_id); | ||
| 381 | if (ack_skb) | ||
| 382 | idr_remove(&local->ack_status_frames, | ||
| 383 | info->ack_frame_id); | ||
| 384 | spin_unlock_irqrestore(&local->ack_status_lock, flags); | ||
| 385 | |||
| 386 | if (ack_skb) { | ||
| 387 | if (!dropped) { | ||
| 388 | /* consumes ack_skb */ | ||
| 389 | skb_complete_wifi_ack(ack_skb, acked); | ||
| 390 | } else { | ||
| 391 | dev_kfree_skb_any(ack_skb); | ||
| 392 | } | ||
| 393 | } | ||
| 394 | } | ||
| 395 | } | ||
| 396 | |||
| 328 | /* | 397 | /* |
| 329 | * Use a static threshold for now, best value to be determined | 398 | * Use a static threshold for now, best value to be determined |
| 330 | * by testing ... | 399 | * by testing ... |
| @@ -516,62 +585,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
| 516 | msecs_to_jiffies(10)); | 585 | msecs_to_jiffies(10)); |
| 517 | } | 586 | } |
| 518 | 587 | ||
| 519 | if (info->flags & IEEE80211_TX_INTFL_NL80211_FRAME_TX) { | 588 | ieee80211_report_used_skb(local, skb, false); |
| 520 | u64 cookie = (unsigned long)skb; | ||
| 521 | bool found = false; | ||
| 522 | |||
| 523 | acked = info->flags & IEEE80211_TX_STAT_ACK; | ||
| 524 | |||
| 525 | rcu_read_lock(); | ||
| 526 | |||
| 527 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { | ||
| 528 | if (!sdata->dev) | ||
| 529 | continue; | ||
| 530 | |||
| 531 | if (skb->dev != sdata->dev) | ||
| 532 | continue; | ||
| 533 | |||
| 534 | found = true; | ||
| 535 | break; | ||
| 536 | } | ||
| 537 | |||
| 538 | if (!skb->dev) { | ||
| 539 | sdata = rcu_dereference(local->p2p_sdata); | ||
| 540 | if (sdata) | ||
| 541 | found = true; | ||
| 542 | } | ||
| 543 | |||
| 544 | if (!found) | ||
| 545 | skb->dev = NULL; | ||
| 546 | else if (ieee80211_is_nullfunc(hdr->frame_control) || | ||
| 547 | ieee80211_is_qos_nullfunc(hdr->frame_control)) { | ||
| 548 | cfg80211_probe_status(sdata->dev, hdr->addr1, | ||
| 549 | cookie, acked, GFP_ATOMIC); | ||
| 550 | } else { | ||
| 551 | cfg80211_mgmt_tx_status(&sdata->wdev, cookie, skb->data, | ||
| 552 | skb->len, acked, GFP_ATOMIC); | ||
| 553 | } | ||
| 554 | |||
| 555 | rcu_read_unlock(); | ||
| 556 | } | ||
| 557 | |||
| 558 | if (unlikely(info->ack_frame_id)) { | ||
| 559 | struct sk_buff *ack_skb; | ||
| 560 | unsigned long flags; | ||
| 561 | |||
| 562 | spin_lock_irqsave(&local->ack_status_lock, flags); | ||
| 563 | ack_skb = idr_find(&local->ack_status_frames, | ||
| 564 | info->ack_frame_id); | ||
| 565 | if (ack_skb) | ||
| 566 | idr_remove(&local->ack_status_frames, | ||
| 567 | info->ack_frame_id); | ||
| 568 | spin_unlock_irqrestore(&local->ack_status_lock, flags); | ||
| 569 | |||
| 570 | /* consumes ack_skb */ | ||
| 571 | if (ack_skb) | ||
| 572 | skb_complete_wifi_ack(ack_skb, | ||
| 573 | info->flags & IEEE80211_TX_STAT_ACK); | ||
| 574 | } | ||
| 575 | 589 | ||
| 576 | /* this was a transmitted frame, but now we want to reuse it */ | 590 | /* this was a transmitted frame, but now we want to reuse it */ |
| 577 | skb_orphan(skb); | 591 | skb_orphan(skb); |
| @@ -647,25 +661,8 @@ EXPORT_SYMBOL(ieee80211_report_low_ack); | |||
| 647 | void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb) | 661 | void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb) |
| 648 | { | 662 | { |
| 649 | struct ieee80211_local *local = hw_to_local(hw); | 663 | struct ieee80211_local *local = hw_to_local(hw); |
| 650 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||
| 651 | |||
| 652 | if (unlikely(info->ack_frame_id)) { | ||
| 653 | struct sk_buff *ack_skb; | ||
| 654 | unsigned long flags; | ||
| 655 | |||
| 656 | spin_lock_irqsave(&local->ack_status_lock, flags); | ||
| 657 | ack_skb = idr_find(&local->ack_status_frames, | ||
| 658 | info->ack_frame_id); | ||
| 659 | if (ack_skb) | ||
| 660 | idr_remove(&local->ack_status_frames, | ||
| 661 | info->ack_frame_id); | ||
| 662 | spin_unlock_irqrestore(&local->ack_status_lock, flags); | ||
| 663 | |||
| 664 | /* consumes ack_skb */ | ||
| 665 | if (ack_skb) | ||
| 666 | dev_kfree_skb_any(ack_skb); | ||
| 667 | } | ||
| 668 | 664 | ||
| 665 | ieee80211_report_used_skb(local, skb, true); | ||
| 669 | dev_kfree_skb_any(skb); | 666 | dev_kfree_skb_any(skb); |
| 670 | } | 667 | } |
| 671 | EXPORT_SYMBOL(ieee80211_free_txskb); | 668 | EXPORT_SYMBOL(ieee80211_free_txskb); |
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index 0638541b625f..a8270b441a6f 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h | |||
| @@ -28,16 +28,21 @@ | |||
| 28 | #define VIF_PR_FMT " vif:%s(%d%s)" | 28 | #define VIF_PR_FMT " vif:%s(%d%s)" |
| 29 | #define VIF_PR_ARG __get_str(vif_name), __entry->vif_type, __entry->p2p ? "/p2p" : "" | 29 | #define VIF_PR_ARG __get_str(vif_name), __entry->vif_type, __entry->p2p ? "/p2p" : "" |
| 30 | 30 | ||
| 31 | #define CHANCTX_ENTRY __field(int, freq) \ | 31 | #define CHANCTX_ENTRY __field(u32, control_freq) \ |
| 32 | __field(int, chantype) \ | 32 | __field(u32, chan_width) \ |
| 33 | __field(u32, center_freq1) \ | ||
| 34 | __field(u32, center_freq2) \ | ||
| 33 | __field(u8, rx_chains_static) \ | 35 | __field(u8, rx_chains_static) \ |
| 34 | __field(u8, rx_chains_dynamic) | 36 | __field(u8, rx_chains_dynamic) |
| 35 | #define CHANCTX_ASSIGN __entry->freq = ctx->conf.channel->center_freq; \ | 37 | #define CHANCTX_ASSIGN __entry->control_freq = ctx->conf.def.chan->center_freq;\ |
| 36 | __entry->chantype = ctx->conf.channel_type; \ | 38 | __entry->chan_width = ctx->conf.def.width; \ |
| 39 | __entry->center_freq1 = ctx->conf.def.center_freq1; \ | ||
| 40 | __entry->center_freq2 = ctx->conf.def.center_freq2; \ | ||
| 37 | __entry->rx_chains_static = ctx->conf.rx_chains_static; \ | 41 | __entry->rx_chains_static = ctx->conf.rx_chains_static; \ |
| 38 | __entry->rx_chains_dynamic = ctx->conf.rx_chains_dynamic | 42 | __entry->rx_chains_dynamic = ctx->conf.rx_chains_dynamic |
| 39 | #define CHANCTX_PR_FMT " freq:%d MHz chantype:%d chains:%d/%d" | 43 | #define CHANCTX_PR_FMT " control:%d MHz width:%d center: %d/%d MHz chains:%d/%d" |
| 40 | #define CHANCTX_PR_ARG __entry->freq, __entry->chantype, \ | 44 | #define CHANCTX_PR_ARG __entry->control_freq, __entry->chan_width, \ |
| 45 | __entry->center_freq1, __entry->center_freq2, \ | ||
| 41 | __entry->rx_chains_static, __entry->rx_chains_dynamic | 46 | __entry->rx_chains_static, __entry->rx_chains_dynamic |
| 42 | 47 | ||
| 43 | 48 | ||
| @@ -334,7 +339,8 @@ TRACE_EVENT(drv_bss_info_changed, | |||
| 334 | __field(u16, ht_operation_mode) | 339 | __field(u16, ht_operation_mode) |
| 335 | __field(s32, cqm_rssi_thold); | 340 | __field(s32, cqm_rssi_thold); |
| 336 | __field(s32, cqm_rssi_hyst); | 341 | __field(s32, cqm_rssi_hyst); |
| 337 | __field(u32, channel_type); | 342 | __field(u32, channel_width); |
| 343 | __field(u32, channel_cfreq1); | ||
| 338 | __dynamic_array(u32, arp_addr_list, info->arp_addr_cnt); | 344 | __dynamic_array(u32, arp_addr_list, info->arp_addr_cnt); |
| 339 | __field(bool, arp_filter_enabled); | 345 | __field(bool, arp_filter_enabled); |
| 340 | __field(bool, qos); | 346 | __field(bool, qos); |
| @@ -342,6 +348,9 @@ TRACE_EVENT(drv_bss_info_changed, | |||
| 342 | __field(bool, ps); | 348 | __field(bool, ps); |
| 343 | __dynamic_array(u8, ssid, info->ssid_len); | 349 | __dynamic_array(u8, ssid, info->ssid_len); |
| 344 | __field(bool, hidden_ssid); | 350 | __field(bool, hidden_ssid); |
| 351 | __field(int, txpower) | ||
| 352 | __field(u8, p2p_ctwindow) | ||
| 353 | __field(bool, p2p_oppps) | ||
| 345 | ), | 354 | ), |
| 346 | 355 | ||
| 347 | TP_fast_assign( | 356 | TP_fast_assign( |
| @@ -367,7 +376,8 @@ TRACE_EVENT(drv_bss_info_changed, | |||
| 367 | __entry->ht_operation_mode = info->ht_operation_mode; | 376 | __entry->ht_operation_mode = info->ht_operation_mode; |
| 368 | __entry->cqm_rssi_thold = info->cqm_rssi_thold; | 377 | __entry->cqm_rssi_thold = info->cqm_rssi_thold; |
| 369 | __entry->cqm_rssi_hyst = info->cqm_rssi_hyst; | 378 | __entry->cqm_rssi_hyst = info->cqm_rssi_hyst; |
| 370 | __entry->channel_type = info->channel_type; | 379 | __entry->channel_width = info->chandef.width; |
| 380 | __entry->channel_cfreq1 = info->chandef.center_freq1; | ||
| 371 | memcpy(__get_dynamic_array(arp_addr_list), info->arp_addr_list, | 381 | memcpy(__get_dynamic_array(arp_addr_list), info->arp_addr_list, |
| 372 | sizeof(u32) * info->arp_addr_cnt); | 382 | sizeof(u32) * info->arp_addr_cnt); |
| 373 | __entry->arp_filter_enabled = info->arp_filter_enabled; | 383 | __entry->arp_filter_enabled = info->arp_filter_enabled; |
| @@ -376,6 +386,9 @@ TRACE_EVENT(drv_bss_info_changed, | |||
| 376 | __entry->ps = info->ps; | 386 | __entry->ps = info->ps; |
| 377 | memcpy(__get_dynamic_array(ssid), info->ssid, info->ssid_len); | 387 | memcpy(__get_dynamic_array(ssid), info->ssid, info->ssid_len); |
| 378 | __entry->hidden_ssid = info->hidden_ssid; | 388 | __entry->hidden_ssid = info->hidden_ssid; |
| 389 | __entry->txpower = info->txpower; | ||
| 390 | __entry->p2p_ctwindow = info->p2p_ctwindow; | ||
| 391 | __entry->p2p_oppps = info->p2p_oppps; | ||
| 379 | ), | 392 | ), |
| 380 | 393 | ||
| 381 | TP_printk( | 394 | TP_printk( |
| @@ -1013,28 +1026,31 @@ TRACE_EVENT(drv_get_antenna, | |||
| 1013 | ); | 1026 | ); |
| 1014 | 1027 | ||
| 1015 | TRACE_EVENT(drv_remain_on_channel, | 1028 | TRACE_EVENT(drv_remain_on_channel, |
| 1016 | TP_PROTO(struct ieee80211_local *local, struct ieee80211_channel *chan, | 1029 | TP_PROTO(struct ieee80211_local *local, |
| 1017 | enum nl80211_channel_type chantype, unsigned int duration), | 1030 | struct ieee80211_sub_if_data *sdata, |
| 1031 | struct ieee80211_channel *chan, | ||
| 1032 | unsigned int duration), | ||
| 1018 | 1033 | ||
| 1019 | TP_ARGS(local, chan, chantype, duration), | 1034 | TP_ARGS(local, sdata, chan, duration), |
| 1020 | 1035 | ||
| 1021 | TP_STRUCT__entry( | 1036 | TP_STRUCT__entry( |
| 1022 | LOCAL_ENTRY | 1037 | LOCAL_ENTRY |
| 1038 | VIF_ENTRY | ||
| 1023 | __field(int, center_freq) | 1039 | __field(int, center_freq) |
| 1024 | __field(int, channel_type) | ||
| 1025 | __field(unsigned int, duration) | 1040 | __field(unsigned int, duration) |
| 1026 | ), | 1041 | ), |
| 1027 | 1042 | ||
| 1028 | TP_fast_assign( | 1043 | TP_fast_assign( |
| 1029 | LOCAL_ASSIGN; | 1044 | LOCAL_ASSIGN; |
| 1045 | VIF_ASSIGN; | ||
| 1030 | __entry->center_freq = chan->center_freq; | 1046 | __entry->center_freq = chan->center_freq; |
| 1031 | __entry->channel_type = chantype; | ||
| 1032 | __entry->duration = duration; | 1047 | __entry->duration = duration; |
| 1033 | ), | 1048 | ), |
| 1034 | 1049 | ||
| 1035 | TP_printk( | 1050 | TP_printk( |
| 1036 | LOCAL_PR_FMT " freq:%dMHz duration:%dms", | 1051 | LOCAL_PR_FMT VIF_PR_FMT " freq:%dMHz duration:%dms", |
| 1037 | LOCAL_PR_ARG, __entry->center_freq, __entry->duration | 1052 | LOCAL_PR_ARG, VIF_PR_ARG, |
| 1053 | __entry->center_freq, __entry->duration | ||
| 1038 | ) | 1054 | ) |
| 1039 | ); | 1055 | ); |
| 1040 | 1056 | ||
| @@ -1043,34 +1059,6 @@ DEFINE_EVENT(local_only_evt, drv_cancel_remain_on_channel, | |||
| 1043 | TP_ARGS(local) | 1059 | TP_ARGS(local) |
| 1044 | ); | 1060 | ); |
| 1045 | 1061 | ||
| 1046 | TRACE_EVENT(drv_offchannel_tx, | ||
| 1047 | TP_PROTO(struct ieee80211_local *local, struct sk_buff *skb, | ||
| 1048 | struct ieee80211_channel *chan, | ||
| 1049 | enum nl80211_channel_type channel_type, | ||
| 1050 | unsigned int wait), | ||
| 1051 | |||
| 1052 | TP_ARGS(local, skb, chan, channel_type, wait), | ||
| 1053 | |||
| 1054 | TP_STRUCT__entry( | ||
| 1055 | LOCAL_ENTRY | ||
| 1056 | __field(int, center_freq) | ||
| 1057 | __field(int, channel_type) | ||
| 1058 | __field(unsigned int, wait) | ||
| 1059 | ), | ||
| 1060 | |||
| 1061 | TP_fast_assign( | ||
| 1062 | LOCAL_ASSIGN; | ||
| 1063 | __entry->center_freq = chan->center_freq; | ||
| 1064 | __entry->channel_type = channel_type; | ||
| 1065 | __entry->wait = wait; | ||
| 1066 | ), | ||
| 1067 | |||
| 1068 | TP_printk( | ||
| 1069 | LOCAL_PR_FMT " freq:%dMHz, wait:%dms", | ||
| 1070 | LOCAL_PR_ARG, __entry->center_freq, __entry->wait | ||
| 1071 | ) | ||
| 1072 | ); | ||
| 1073 | |||
| 1074 | TRACE_EVENT(drv_set_ringparam, | 1062 | TRACE_EVENT(drv_set_ringparam, |
| 1075 | TP_PROTO(struct ieee80211_local *local, u32 tx, u32 rx), | 1063 | TP_PROTO(struct ieee80211_local *local, u32 tx, u32 rx), |
| 1076 | 1064 | ||
| @@ -1396,6 +1384,48 @@ DEFINE_EVENT(local_sdata_chanctx, drv_unassign_vif_chanctx, | |||
| 1396 | TP_ARGS(local, sdata, ctx) | 1384 | TP_ARGS(local, sdata, ctx) |
| 1397 | ); | 1385 | ); |
| 1398 | 1386 | ||
| 1387 | TRACE_EVENT(drv_start_ap, | ||
| 1388 | TP_PROTO(struct ieee80211_local *local, | ||
| 1389 | struct ieee80211_sub_if_data *sdata, | ||
| 1390 | struct ieee80211_bss_conf *info), | ||
| 1391 | |||
| 1392 | TP_ARGS(local, sdata, info), | ||
| 1393 | |||
| 1394 | TP_STRUCT__entry( | ||
| 1395 | LOCAL_ENTRY | ||
| 1396 | VIF_ENTRY | ||
| 1397 | __field(u8, dtimper) | ||
| 1398 | __field(u16, bcnint) | ||
| 1399 | __dynamic_array(u8, ssid, info->ssid_len); | ||
| 1400 | __field(bool, hidden_ssid); | ||
| 1401 | ), | ||
| 1402 | |||
| 1403 | TP_fast_assign( | ||
| 1404 | LOCAL_ASSIGN; | ||
| 1405 | VIF_ASSIGN; | ||
| 1406 | __entry->dtimper = info->dtim_period; | ||
| 1407 | __entry->bcnint = info->beacon_int; | ||
| 1408 | memcpy(__get_dynamic_array(ssid), info->ssid, info->ssid_len); | ||
| 1409 | __entry->hidden_ssid = info->hidden_ssid; | ||
| 1410 | ), | ||
| 1411 | |||
| 1412 | TP_printk( | ||
| 1413 | LOCAL_PR_FMT VIF_PR_FMT, | ||
| 1414 | LOCAL_PR_ARG, VIF_PR_ARG | ||
| 1415 | ) | ||
| 1416 | ); | ||
| 1417 | |||
| 1418 | DEFINE_EVENT(local_sdata_evt, drv_stop_ap, | ||
| 1419 | TP_PROTO(struct ieee80211_local *local, | ||
| 1420 | struct ieee80211_sub_if_data *sdata), | ||
| 1421 | TP_ARGS(local, sdata) | ||
| 1422 | ); | ||
| 1423 | |||
| 1424 | DEFINE_EVENT(local_only_evt, drv_restart_complete, | ||
| 1425 | TP_PROTO(struct ieee80211_local *local), | ||
| 1426 | TP_ARGS(local) | ||
| 1427 | ); | ||
| 1428 | |||
| 1399 | /* | 1429 | /* |
| 1400 | * Tracing for API calls that drivers call. | 1430 | * Tracing for API calls that drivers call. |
| 1401 | */ | 1431 | */ |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 6f1981816dc5..d287a4f2c01b 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
| @@ -1676,7 +1676,7 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb, | |||
| 1676 | if (!chanctx_conf) | 1676 | if (!chanctx_conf) |
| 1677 | goto fail_rcu; | 1677 | goto fail_rcu; |
| 1678 | 1678 | ||
| 1679 | chan = chanctx_conf->channel; | 1679 | chan = chanctx_conf->def.chan; |
| 1680 | 1680 | ||
| 1681 | /* | 1681 | /* |
| 1682 | * Frame injection is not allowed if beaconing is not allowed | 1682 | * Frame injection is not allowed if beaconing is not allowed |
| @@ -1779,7 +1779,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
| 1779 | chanctx_conf = rcu_dereference(ap_sdata->vif.chanctx_conf); | 1779 | chanctx_conf = rcu_dereference(ap_sdata->vif.chanctx_conf); |
| 1780 | if (!chanctx_conf) | 1780 | if (!chanctx_conf) |
| 1781 | goto fail_rcu; | 1781 | goto fail_rcu; |
| 1782 | band = chanctx_conf->channel->band; | 1782 | band = chanctx_conf->def.chan->band; |
| 1783 | if (sta) | 1783 | if (sta) |
| 1784 | break; | 1784 | break; |
| 1785 | /* fall through */ | 1785 | /* fall through */ |
| @@ -1794,7 +1794,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
| 1794 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | 1794 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); |
| 1795 | if (!chanctx_conf) | 1795 | if (!chanctx_conf) |
| 1796 | goto fail_rcu; | 1796 | goto fail_rcu; |
| 1797 | band = chanctx_conf->channel->band; | 1797 | band = chanctx_conf->def.chan->band; |
| 1798 | break; | 1798 | break; |
| 1799 | case NL80211_IFTYPE_WDS: | 1799 | case NL80211_IFTYPE_WDS: |
| 1800 | fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS); | 1800 | fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS); |
| @@ -1871,7 +1871,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
| 1871 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | 1871 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); |
| 1872 | if (!chanctx_conf) | 1872 | if (!chanctx_conf) |
| 1873 | goto fail_rcu; | 1873 | goto fail_rcu; |
| 1874 | band = chanctx_conf->channel->band; | 1874 | band = chanctx_conf->def.chan->band; |
| 1875 | break; | 1875 | break; |
| 1876 | #endif | 1876 | #endif |
| 1877 | case NL80211_IFTYPE_STATION: | 1877 | case NL80211_IFTYPE_STATION: |
| @@ -1930,7 +1930,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
| 1930 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | 1930 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); |
| 1931 | if (!chanctx_conf) | 1931 | if (!chanctx_conf) |
| 1932 | goto fail_rcu; | 1932 | goto fail_rcu; |
| 1933 | band = chanctx_conf->channel->band; | 1933 | band = chanctx_conf->def.chan->band; |
| 1934 | break; | 1934 | break; |
| 1935 | case NL80211_IFTYPE_ADHOC: | 1935 | case NL80211_IFTYPE_ADHOC: |
| 1936 | /* DA SA BSSID */ | 1936 | /* DA SA BSSID */ |
| @@ -1941,7 +1941,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
| 1941 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | 1941 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); |
| 1942 | if (!chanctx_conf) | 1942 | if (!chanctx_conf) |
| 1943 | goto fail_rcu; | 1943 | goto fail_rcu; |
| 1944 | band = chanctx_conf->channel->band; | 1944 | band = chanctx_conf->def.chan->band; |
| 1945 | break; | 1945 | break; |
| 1946 | default: | 1946 | default: |
| 1947 | goto fail_rcu; | 1947 | goto fail_rcu; |
| @@ -2089,6 +2089,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
| 2089 | head_need = max_t(int, 0, head_need); | 2089 | head_need = max_t(int, 0, head_need); |
| 2090 | if (ieee80211_skb_resize(sdata, skb, head_need, true)) { | 2090 | if (ieee80211_skb_resize(sdata, skb, head_need, true)) { |
| 2091 | ieee80211_free_txskb(&local->hw, skb); | 2091 | ieee80211_free_txskb(&local->hw, skb); |
| 2092 | skb = NULL; | ||
| 2092 | goto fail_rcu; | 2093 | goto fail_rcu; |
| 2093 | } | 2094 | } |
| 2094 | } | 2095 | } |
| @@ -2193,7 +2194,7 @@ static bool ieee80211_tx_pending_skb(struct ieee80211_local *local, | |||
| 2193 | return true; | 2194 | return true; |
| 2194 | } | 2195 | } |
| 2195 | result = ieee80211_tx(sdata, skb, true, | 2196 | result = ieee80211_tx(sdata, skb, true, |
| 2196 | chanctx_conf->channel->band); | 2197 | chanctx_conf->def.chan->band); |
| 2197 | } else { | 2198 | } else { |
| 2198 | struct sk_buff_head skbs; | 2199 | struct sk_buff_head skbs; |
| 2199 | 2200 | ||
| @@ -2457,7 +2458,7 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, | |||
| 2457 | *pos++ = WLAN_EID_SSID; | 2458 | *pos++ = WLAN_EID_SSID; |
| 2458 | *pos++ = 0x0; | 2459 | *pos++ = 0x0; |
| 2459 | 2460 | ||
| 2460 | band = chanctx_conf->channel->band; | 2461 | band = chanctx_conf->def.chan->band; |
| 2461 | 2462 | ||
| 2462 | if (ieee80211_add_srates_ie(sdata, skb, true, band) || | 2463 | if (ieee80211_add_srates_ie(sdata, skb, true, band) || |
| 2463 | mesh_add_ds_params_ie(skb, sdata) || | 2464 | mesh_add_ds_params_ie(skb, sdata) || |
| @@ -2476,7 +2477,7 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, | |||
| 2476 | goto out; | 2477 | goto out; |
| 2477 | } | 2478 | } |
| 2478 | 2479 | ||
| 2479 | band = chanctx_conf->channel->band; | 2480 | band = chanctx_conf->def.chan->band; |
| 2480 | 2481 | ||
| 2481 | info = IEEE80211_SKB_CB(skb); | 2482 | info = IEEE80211_SKB_CB(skb); |
| 2482 | 2483 | ||
| @@ -2756,7 +2757,7 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, | |||
| 2756 | info = IEEE80211_SKB_CB(skb); | 2757 | info = IEEE80211_SKB_CB(skb); |
| 2757 | 2758 | ||
| 2758 | tx.flags |= IEEE80211_TX_PS_BUFFERED; | 2759 | tx.flags |= IEEE80211_TX_PS_BUFFERED; |
| 2759 | info->band = chanctx_conf->channel->band; | 2760 | info->band = chanctx_conf->def.chan->band; |
| 2760 | 2761 | ||
| 2761 | if (invoke_tx_handlers(&tx)) | 2762 | if (invoke_tx_handlers(&tx)) |
| 2762 | skb = NULL; | 2763 | skb = NULL; |
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index acbb8c9bae2a..08132ff98155 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
| @@ -512,7 +512,7 @@ void ieee80211_wake_queues(struct ieee80211_hw *hw) | |||
| 512 | EXPORT_SYMBOL(ieee80211_wake_queues); | 512 | EXPORT_SYMBOL(ieee80211_wake_queues); |
| 513 | 513 | ||
| 514 | void ieee80211_iterate_active_interfaces( | 514 | void ieee80211_iterate_active_interfaces( |
| 515 | struct ieee80211_hw *hw, | 515 | struct ieee80211_hw *hw, u32 iter_flags, |
| 516 | void (*iterator)(void *data, u8 *mac, | 516 | void (*iterator)(void *data, u8 *mac, |
| 517 | struct ieee80211_vif *vif), | 517 | struct ieee80211_vif *vif), |
| 518 | void *data) | 518 | void *data) |
| @@ -530,6 +530,9 @@ void ieee80211_iterate_active_interfaces( | |||
| 530 | default: | 530 | default: |
| 531 | break; | 531 | break; |
| 532 | } | 532 | } |
| 533 | if (!(iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL) && | ||
| 534 | !(sdata->flags & IEEE80211_SDATA_IN_DRIVER)) | ||
| 535 | continue; | ||
| 533 | if (ieee80211_sdata_running(sdata)) | 536 | if (ieee80211_sdata_running(sdata)) |
| 534 | iterator(data, sdata->vif.addr, | 537 | iterator(data, sdata->vif.addr, |
| 535 | &sdata->vif); | 538 | &sdata->vif); |
| @@ -537,7 +540,9 @@ void ieee80211_iterate_active_interfaces( | |||
| 537 | 540 | ||
| 538 | sdata = rcu_dereference_protected(local->monitor_sdata, | 541 | sdata = rcu_dereference_protected(local->monitor_sdata, |
| 539 | lockdep_is_held(&local->iflist_mtx)); | 542 | lockdep_is_held(&local->iflist_mtx)); |
| 540 | if (sdata) | 543 | if (sdata && |
| 544 | (iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL || | ||
| 545 | sdata->flags & IEEE80211_SDATA_IN_DRIVER)) | ||
| 541 | iterator(data, sdata->vif.addr, &sdata->vif); | 546 | iterator(data, sdata->vif.addr, &sdata->vif); |
| 542 | 547 | ||
| 543 | mutex_unlock(&local->iflist_mtx); | 548 | mutex_unlock(&local->iflist_mtx); |
| @@ -545,7 +550,7 @@ void ieee80211_iterate_active_interfaces( | |||
| 545 | EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces); | 550 | EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces); |
| 546 | 551 | ||
| 547 | void ieee80211_iterate_active_interfaces_atomic( | 552 | void ieee80211_iterate_active_interfaces_atomic( |
| 548 | struct ieee80211_hw *hw, | 553 | struct ieee80211_hw *hw, u32 iter_flags, |
| 549 | void (*iterator)(void *data, u8 *mac, | 554 | void (*iterator)(void *data, u8 *mac, |
| 550 | struct ieee80211_vif *vif), | 555 | struct ieee80211_vif *vif), |
| 551 | void *data) | 556 | void *data) |
| @@ -563,13 +568,18 @@ void ieee80211_iterate_active_interfaces_atomic( | |||
| 563 | default: | 568 | default: |
| 564 | break; | 569 | break; |
| 565 | } | 570 | } |
| 571 | if (!(iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL) && | ||
| 572 | !(sdata->flags & IEEE80211_SDATA_IN_DRIVER)) | ||
| 573 | continue; | ||
| 566 | if (ieee80211_sdata_running(sdata)) | 574 | if (ieee80211_sdata_running(sdata)) |
| 567 | iterator(data, sdata->vif.addr, | 575 | iterator(data, sdata->vif.addr, |
| 568 | &sdata->vif); | 576 | &sdata->vif); |
| 569 | } | 577 | } |
| 570 | 578 | ||
| 571 | sdata = rcu_dereference(local->monitor_sdata); | 579 | sdata = rcu_dereference(local->monitor_sdata); |
| 572 | if (sdata) | 580 | if (sdata && |
| 581 | (iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL || | ||
| 582 | sdata->flags & IEEE80211_SDATA_IN_DRIVER)) | ||
| 573 | iterator(data, sdata->vif.addr, &sdata->vif); | 583 | iterator(data, sdata->vif.addr, &sdata->vif); |
| 574 | 584 | ||
| 575 | rcu_read_unlock(); | 585 | rcu_read_unlock(); |
| @@ -888,7 +898,7 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata, | |||
| 888 | rcu_read_lock(); | 898 | rcu_read_lock(); |
| 889 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | 899 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); |
| 890 | use_11b = (chanctx_conf && | 900 | use_11b = (chanctx_conf && |
| 891 | chanctx_conf->channel->band == IEEE80211_BAND_2GHZ) && | 901 | chanctx_conf->def.chan->band == IEEE80211_BAND_2GHZ) && |
| 892 | !(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE); | 902 | !(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE); |
| 893 | rcu_read_unlock(); | 903 | rcu_read_unlock(); |
| 894 | 904 | ||
| @@ -981,7 +991,7 @@ void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata, | |||
| 981 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | 991 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); |
| 982 | 992 | ||
| 983 | if (chanctx_conf && | 993 | if (chanctx_conf && |
| 984 | chanctx_conf->channel->band == IEEE80211_BAND_2GHZ && | 994 | chanctx_conf->def.chan->band == IEEE80211_BAND_2GHZ && |
| 985 | have_higher_than_11mbit) | 995 | have_higher_than_11mbit) |
| 986 | sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE; | 996 | sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE; |
| 987 | else | 997 | else |
| @@ -1407,10 +1417,44 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
| 1407 | } | 1417 | } |
| 1408 | 1418 | ||
| 1409 | /* add channel contexts */ | 1419 | /* add channel contexts */ |
| 1410 | mutex_lock(&local->chanctx_mtx); | 1420 | if (local->use_chanctx) { |
| 1411 | list_for_each_entry(ctx, &local->chanctx_list, list) | 1421 | mutex_lock(&local->chanctx_mtx); |
| 1412 | WARN_ON(drv_add_chanctx(local, ctx)); | 1422 | list_for_each_entry(ctx, &local->chanctx_list, list) |
| 1413 | mutex_unlock(&local->chanctx_mtx); | 1423 | WARN_ON(drv_add_chanctx(local, ctx)); |
| 1424 | mutex_unlock(&local->chanctx_mtx); | ||
| 1425 | } | ||
| 1426 | |||
| 1427 | list_for_each_entry(sdata, &local->interfaces, list) { | ||
| 1428 | struct ieee80211_chanctx_conf *ctx_conf; | ||
| 1429 | |||
| 1430 | if (!ieee80211_sdata_running(sdata)) | ||
| 1431 | continue; | ||
| 1432 | |||
| 1433 | mutex_lock(&local->chanctx_mtx); | ||
| 1434 | ctx_conf = rcu_dereference_protected(sdata->vif.chanctx_conf, | ||
| 1435 | lockdep_is_held(&local->chanctx_mtx)); | ||
| 1436 | if (ctx_conf) { | ||
| 1437 | ctx = container_of(ctx_conf, struct ieee80211_chanctx, | ||
| 1438 | conf); | ||
| 1439 | drv_assign_vif_chanctx(local, sdata, ctx); | ||
| 1440 | } | ||
| 1441 | mutex_unlock(&local->chanctx_mtx); | ||
| 1442 | } | ||
| 1443 | |||
| 1444 | sdata = rtnl_dereference(local->monitor_sdata); | ||
| 1445 | if (sdata && local->use_chanctx && ieee80211_sdata_running(sdata)) { | ||
| 1446 | struct ieee80211_chanctx_conf *ctx_conf; | ||
| 1447 | |||
| 1448 | mutex_lock(&local->chanctx_mtx); | ||
| 1449 | ctx_conf = rcu_dereference_protected(sdata->vif.chanctx_conf, | ||
| 1450 | lockdep_is_held(&local->chanctx_mtx)); | ||
| 1451 | if (ctx_conf) { | ||
| 1452 | ctx = container_of(ctx_conf, struct ieee80211_chanctx, | ||
| 1453 | conf); | ||
| 1454 | drv_assign_vif_chanctx(local, sdata, ctx); | ||
| 1455 | } | ||
| 1456 | mutex_unlock(&local->chanctx_mtx); | ||
| 1457 | } | ||
| 1414 | 1458 | ||
| 1415 | /* add STAs back */ | 1459 | /* add STAs back */ |
| 1416 | mutex_lock(&local->sta_mtx); | 1460 | mutex_lock(&local->sta_mtx); |
| @@ -1452,22 +1496,11 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
| 1452 | 1496 | ||
| 1453 | /* Finally also reconfigure all the BSS information */ | 1497 | /* Finally also reconfigure all the BSS information */ |
| 1454 | list_for_each_entry(sdata, &local->interfaces, list) { | 1498 | list_for_each_entry(sdata, &local->interfaces, list) { |
| 1455 | struct ieee80211_chanctx_conf *ctx_conf; | ||
| 1456 | u32 changed; | 1499 | u32 changed; |
| 1457 | 1500 | ||
| 1458 | if (!ieee80211_sdata_running(sdata)) | 1501 | if (!ieee80211_sdata_running(sdata)) |
| 1459 | continue; | 1502 | continue; |
| 1460 | 1503 | ||
| 1461 | mutex_lock(&local->chanctx_mtx); | ||
| 1462 | ctx_conf = rcu_dereference_protected(sdata->vif.chanctx_conf, | ||
| 1463 | lockdep_is_held(&local->chanctx_mtx)); | ||
| 1464 | if (ctx_conf) { | ||
| 1465 | ctx = container_of(ctx_conf, struct ieee80211_chanctx, | ||
| 1466 | conf); | ||
| 1467 | drv_assign_vif_chanctx(local, sdata, ctx); | ||
| 1468 | } | ||
| 1469 | mutex_unlock(&local->chanctx_mtx); | ||
| 1470 | |||
| 1471 | /* common change flags for all interface types */ | 1504 | /* common change flags for all interface types */ |
| 1472 | changed = BSS_CHANGED_ERP_CTS_PROT | | 1505 | changed = BSS_CHANGED_ERP_CTS_PROT | |
| 1473 | BSS_CHANGED_ERP_PREAMBLE | | 1506 | BSS_CHANGED_ERP_PREAMBLE | |
| @@ -1478,7 +1511,8 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
| 1478 | BSS_CHANGED_BSSID | | 1511 | BSS_CHANGED_BSSID | |
| 1479 | BSS_CHANGED_CQM | | 1512 | BSS_CHANGED_CQM | |
| 1480 | BSS_CHANGED_QOS | | 1513 | BSS_CHANGED_QOS | |
| 1481 | BSS_CHANGED_IDLE; | 1514 | BSS_CHANGED_IDLE | |
| 1515 | BSS_CHANGED_TXPOWER; | ||
| 1482 | 1516 | ||
| 1483 | switch (sdata->vif.type) { | 1517 | switch (sdata->vif.type) { |
| 1484 | case NL80211_IFTYPE_STATION: | 1518 | case NL80211_IFTYPE_STATION: |
| @@ -1495,9 +1529,13 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
| 1495 | case NL80211_IFTYPE_AP: | 1529 | case NL80211_IFTYPE_AP: |
| 1496 | changed |= BSS_CHANGED_SSID; | 1530 | changed |= BSS_CHANGED_SSID; |
| 1497 | 1531 | ||
| 1498 | if (sdata->vif.type == NL80211_IFTYPE_AP) | 1532 | if (sdata->vif.type == NL80211_IFTYPE_AP) { |
| 1499 | changed |= BSS_CHANGED_AP_PROBE_RESP; | 1533 | changed |= BSS_CHANGED_AP_PROBE_RESP; |
| 1500 | 1534 | ||
| 1535 | if (rcu_access_pointer(sdata->u.ap.beacon)) | ||
| 1536 | drv_start_ap(local, sdata); | ||
| 1537 | } | ||
| 1538 | |||
| 1501 | /* fall through */ | 1539 | /* fall through */ |
| 1502 | case NL80211_IFTYPE_MESH_POINT: | 1540 | case NL80211_IFTYPE_MESH_POINT: |
| 1503 | changed |= BSS_CHANGED_BEACON | | 1541 | changed |= BSS_CHANGED_BEACON | |
| @@ -1596,8 +1634,10 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
| 1596 | * If this is for hw restart things are still running. | 1634 | * If this is for hw restart things are still running. |
| 1597 | * We may want to change that later, however. | 1635 | * We may want to change that later, however. |
| 1598 | */ | 1636 | */ |
| 1599 | if (!local->suspended) | 1637 | if (!local->suspended) { |
| 1638 | drv_restart_complete(local); | ||
| 1600 | return 0; | 1639 | return 0; |
| 1640 | } | ||
| 1601 | 1641 | ||
| 1602 | #ifdef CONFIG_PM | 1642 | #ifdef CONFIG_PM |
| 1603 | /* first set suspended false, then resuming */ | 1643 | /* first set suspended false, then resuming */ |
| @@ -1833,8 +1873,7 @@ u8 *ieee80211_ie_build_vht_cap(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap, | |||
| 1833 | } | 1873 | } |
| 1834 | 1874 | ||
| 1835 | u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, | 1875 | u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, |
| 1836 | struct ieee80211_channel *channel, | 1876 | const struct cfg80211_chan_def *chandef, |
| 1837 | enum nl80211_channel_type channel_type, | ||
| 1838 | u16 prot_mode) | 1877 | u16 prot_mode) |
| 1839 | { | 1878 | { |
| 1840 | struct ieee80211_ht_operation *ht_oper; | 1879 | struct ieee80211_ht_operation *ht_oper; |
| @@ -1842,23 +1881,25 @@ u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, | |||
| 1842 | *pos++ = WLAN_EID_HT_OPERATION; | 1881 | *pos++ = WLAN_EID_HT_OPERATION; |
| 1843 | *pos++ = sizeof(struct ieee80211_ht_operation); | 1882 | *pos++ = sizeof(struct ieee80211_ht_operation); |
| 1844 | ht_oper = (struct ieee80211_ht_operation *)pos; | 1883 | ht_oper = (struct ieee80211_ht_operation *)pos; |
| 1845 | ht_oper->primary_chan = | 1884 | ht_oper->primary_chan = ieee80211_frequency_to_channel( |
| 1846 | ieee80211_frequency_to_channel(channel->center_freq); | 1885 | chandef->chan->center_freq); |
| 1847 | switch (channel_type) { | 1886 | switch (chandef->width) { |
| 1848 | case NL80211_CHAN_HT40MINUS: | 1887 | case NL80211_CHAN_WIDTH_160: |
| 1849 | ht_oper->ht_param = IEEE80211_HT_PARAM_CHA_SEC_BELOW; | 1888 | case NL80211_CHAN_WIDTH_80P80: |
| 1850 | break; | 1889 | case NL80211_CHAN_WIDTH_80: |
| 1851 | case NL80211_CHAN_HT40PLUS: | 1890 | case NL80211_CHAN_WIDTH_40: |
| 1852 | ht_oper->ht_param = IEEE80211_HT_PARAM_CHA_SEC_ABOVE; | 1891 | if (chandef->center_freq1 > chandef->chan->center_freq) |
| 1892 | ht_oper->ht_param = IEEE80211_HT_PARAM_CHA_SEC_ABOVE; | ||
| 1893 | else | ||
| 1894 | ht_oper->ht_param = IEEE80211_HT_PARAM_CHA_SEC_BELOW; | ||
| 1853 | break; | 1895 | break; |
| 1854 | case NL80211_CHAN_HT20: | ||
| 1855 | default: | 1896 | default: |
| 1856 | ht_oper->ht_param = IEEE80211_HT_PARAM_CHA_SEC_NONE; | 1897 | ht_oper->ht_param = IEEE80211_HT_PARAM_CHA_SEC_NONE; |
| 1857 | break; | 1898 | break; |
| 1858 | } | 1899 | } |
| 1859 | if (ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 && | 1900 | if (ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 && |
| 1860 | channel_type != NL80211_CHAN_NO_HT && | 1901 | chandef->width != NL80211_CHAN_WIDTH_20_NOHT && |
| 1861 | channel_type != NL80211_CHAN_HT20) | 1902 | chandef->width != NL80211_CHAN_WIDTH_20) |
| 1862 | ht_oper->ht_param |= IEEE80211_HT_PARAM_CHAN_WIDTH_ANY; | 1903 | ht_oper->ht_param |= IEEE80211_HT_PARAM_CHAN_WIDTH_ANY; |
| 1863 | 1904 | ||
| 1864 | ht_oper->operation_mode = cpu_to_le16(prot_mode); | 1905 | ht_oper->operation_mode = cpu_to_le16(prot_mode); |
| @@ -1872,13 +1913,17 @@ u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, | |||
| 1872 | return pos + sizeof(struct ieee80211_ht_operation); | 1913 | return pos + sizeof(struct ieee80211_ht_operation); |
| 1873 | } | 1914 | } |
| 1874 | 1915 | ||
| 1875 | enum nl80211_channel_type | 1916 | void ieee80211_ht_oper_to_chandef(struct ieee80211_channel *control_chan, |
| 1876 | ieee80211_ht_oper_to_channel_type(struct ieee80211_ht_operation *ht_oper) | 1917 | struct ieee80211_ht_operation *ht_oper, |
| 1918 | struct cfg80211_chan_def *chandef) | ||
| 1877 | { | 1919 | { |
| 1878 | enum nl80211_channel_type channel_type; | 1920 | enum nl80211_channel_type channel_type; |
| 1879 | 1921 | ||
| 1880 | if (!ht_oper) | 1922 | if (!ht_oper) { |
| 1881 | return NL80211_CHAN_NO_HT; | 1923 | cfg80211_chandef_create(chandef, control_chan, |
| 1924 | NL80211_CHAN_NO_HT); | ||
| 1925 | return; | ||
| 1926 | } | ||
| 1882 | 1927 | ||
| 1883 | switch (ht_oper->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { | 1928 | switch (ht_oper->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { |
| 1884 | case IEEE80211_HT_PARAM_CHA_SEC_NONE: | 1929 | case IEEE80211_HT_PARAM_CHA_SEC_NONE: |
| @@ -1894,7 +1939,7 @@ ieee80211_ht_oper_to_channel_type(struct ieee80211_ht_operation *ht_oper) | |||
| 1894 | channel_type = NL80211_CHAN_NO_HT; | 1939 | channel_type = NL80211_CHAN_NO_HT; |
| 1895 | } | 1940 | } |
| 1896 | 1941 | ||
| 1897 | return channel_type; | 1942 | cfg80211_chandef_create(chandef, control_chan, channel_type); |
| 1898 | } | 1943 | } |
| 1899 | 1944 | ||
| 1900 | int ieee80211_add_srates_ie(struct ieee80211_sub_if_data *sdata, | 1945 | int ieee80211_add_srates_ie(struct ieee80211_sub_if_data *sdata, |
| @@ -1992,3 +2037,68 @@ u8 ieee80211_mcs_to_chains(const struct ieee80211_mcs_info *mcs) | |||
| 1992 | return 2; | 2037 | return 2; |
| 1993 | return 1; | 2038 | return 1; |
| 1994 | } | 2039 | } |
| 2040 | |||
| 2041 | /** | ||
| 2042 | * ieee80211_calculate_rx_timestamp - calculate timestamp in frame | ||
| 2043 | * @local: mac80211 hw info struct | ||
| 2044 | * @status: RX status | ||
| 2045 | * @mpdu_len: total MPDU length (including FCS) | ||
| 2046 | * @mpdu_offset: offset into MPDU to calculate timestamp at | ||
| 2047 | * | ||
| 2048 | * This function calculates the RX timestamp at the given MPDU offset, taking | ||
| 2049 | * into account what the RX timestamp was. An offset of 0 will just normalize | ||
| 2050 | * the timestamp to TSF at beginning of MPDU reception. | ||
| 2051 | */ | ||
| 2052 | u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local, | ||
| 2053 | struct ieee80211_rx_status *status, | ||
| 2054 | unsigned int mpdu_len, | ||
| 2055 | unsigned int mpdu_offset) | ||
| 2056 | { | ||
| 2057 | u64 ts = status->mactime; | ||
| 2058 | struct rate_info ri; | ||
| 2059 | u16 rate; | ||
| 2060 | |||
| 2061 | if (WARN_ON(!ieee80211_have_rx_timestamp(status))) | ||
| 2062 | return 0; | ||
| 2063 | |||
| 2064 | memset(&ri, 0, sizeof(ri)); | ||
| 2065 | |||
| 2066 | /* Fill cfg80211 rate info */ | ||
| 2067 | if (status->flag & RX_FLAG_HT) { | ||
| 2068 | ri.mcs = status->rate_idx; | ||
| 2069 | ri.flags |= RATE_INFO_FLAGS_MCS; | ||
| 2070 | if (status->flag & RX_FLAG_40MHZ) | ||
| 2071 | ri.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; | ||
| 2072 | if (status->flag & RX_FLAG_SHORT_GI) | ||
| 2073 | ri.flags |= RATE_INFO_FLAGS_SHORT_GI; | ||
| 2074 | } else if (status->flag & RX_FLAG_VHT) { | ||
| 2075 | ri.flags |= RATE_INFO_FLAGS_VHT_MCS; | ||
| 2076 | ri.mcs = status->rate_idx; | ||
| 2077 | ri.nss = status->vht_nss; | ||
| 2078 | if (status->flag & RX_FLAG_40MHZ) | ||
| 2079 | ri.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; | ||
| 2080 | if (status->flag & RX_FLAG_80MHZ) | ||
| 2081 | ri.flags |= RATE_INFO_FLAGS_80_MHZ_WIDTH; | ||
| 2082 | if (status->flag & RX_FLAG_80P80MHZ) | ||
| 2083 | ri.flags |= RATE_INFO_FLAGS_80P80_MHZ_WIDTH; | ||
| 2084 | if (status->flag & RX_FLAG_160MHZ) | ||
| 2085 | ri.flags |= RATE_INFO_FLAGS_160_MHZ_WIDTH; | ||
| 2086 | if (status->flag & RX_FLAG_SHORT_GI) | ||
| 2087 | ri.flags |= RATE_INFO_FLAGS_SHORT_GI; | ||
| 2088 | } else { | ||
| 2089 | struct ieee80211_supported_band *sband; | ||
| 2090 | |||
| 2091 | sband = local->hw.wiphy->bands[status->band]; | ||
| 2092 | ri.legacy = sband->bitrates[status->rate_idx].bitrate; | ||
| 2093 | } | ||
| 2094 | |||
| 2095 | rate = cfg80211_calculate_bitrate(&ri); | ||
| 2096 | |||
| 2097 | /* rewind from end of MPDU */ | ||
| 2098 | if (status->flag & RX_FLAG_MACTIME_END) | ||
| 2099 | ts -= mpdu_len * 8 * 10 / rate; | ||
| 2100 | |||
| 2101 | ts += mpdu_offset * 8 * 10 / rate; | ||
| 2102 | |||
| 2103 | return ts; | ||
| 2104 | } | ||
diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c index cea06e9f26f4..906f00cd6d2f 100644 --- a/net/mac80211/wme.c +++ b/net/mac80211/wme.c | |||
| @@ -160,31 +160,37 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata, | |||
| 160 | return ieee80211_downgrade_queue(sdata, skb); | 160 | return ieee80211_downgrade_queue(sdata, skb); |
| 161 | } | 161 | } |
| 162 | 162 | ||
| 163 | /** | ||
| 164 | * ieee80211_set_qos_hdr - Fill in the QoS header if there is one. | ||
| 165 | * | ||
| 166 | * @sdata: local subif | ||
| 167 | * @skb: packet to be updated | ||
| 168 | */ | ||
| 163 | void ieee80211_set_qos_hdr(struct ieee80211_sub_if_data *sdata, | 169 | void ieee80211_set_qos_hdr(struct ieee80211_sub_if_data *sdata, |
| 164 | struct sk_buff *skb) | 170 | struct sk_buff *skb) |
| 165 | { | 171 | { |
| 166 | struct ieee80211_hdr *hdr = (void *)skb->data; | 172 | struct ieee80211_hdr *hdr = (void *)skb->data; |
| 167 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 173 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
| 174 | u8 *p; | ||
| 175 | u8 ack_policy, tid; | ||
| 168 | 176 | ||
| 169 | /* Fill in the QoS header if there is one. */ | 177 | if (!ieee80211_is_data_qos(hdr->frame_control)) |
| 170 | if (ieee80211_is_data_qos(hdr->frame_control)) { | 178 | return; |
| 171 | u8 *p = ieee80211_get_qos_ctl(hdr); | ||
| 172 | u8 ack_policy, tid; | ||
| 173 | |||
| 174 | tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK; | ||
| 175 | 179 | ||
| 176 | /* preserve EOSP bit */ | 180 | p = ieee80211_get_qos_ctl(hdr); |
| 177 | ack_policy = *p & IEEE80211_QOS_CTL_EOSP; | 181 | tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK; |
| 178 | 182 | ||
| 179 | if (is_multicast_ether_addr(hdr->addr1) || | 183 | /* preserve EOSP bit */ |
| 180 | sdata->noack_map & BIT(tid)) { | 184 | ack_policy = *p & IEEE80211_QOS_CTL_EOSP; |
| 181 | ack_policy |= IEEE80211_QOS_CTL_ACK_POLICY_NOACK; | ||
| 182 | info->flags |= IEEE80211_TX_CTL_NO_ACK; | ||
| 183 | } | ||
| 184 | 185 | ||
| 185 | /* qos header is 2 bytes */ | 186 | if (is_multicast_ether_addr(hdr->addr1) || |
| 186 | *p++ = ack_policy | tid; | 187 | sdata->noack_map & BIT(tid)) { |
| 187 | *p = ieee80211_vif_is_mesh(&sdata->vif) ? | 188 | ack_policy |= IEEE80211_QOS_CTL_ACK_POLICY_NOACK; |
| 188 | (IEEE80211_QOS_CTL_MESH_CONTROL_PRESENT >> 8) : 0; | 189 | info->flags |= IEEE80211_TX_CTL_NO_ACK; |
| 189 | } | 190 | } |
| 191 | |||
| 192 | /* qos header is 2 bytes */ | ||
| 193 | *p++ = ack_policy | tid; | ||
| 194 | *p = ieee80211_vif_is_mesh(&sdata->vif) ? | ||
| 195 | (IEEE80211_QOS_CTL_MESH_CONTROL_PRESENT >> 8) : 0; | ||
| 190 | } | 196 | } |
diff --git a/net/mac802154/tx.c b/net/mac802154/tx.c index 1a4df39c722e..4e09d070995a 100644 --- a/net/mac802154/tx.c +++ b/net/mac802154/tx.c | |||
| @@ -85,6 +85,7 @@ netdev_tx_t mac802154_tx(struct mac802154_priv *priv, struct sk_buff *skb, | |||
| 85 | 85 | ||
| 86 | if (!(priv->phy->channels_supported[page] & (1 << chan))) { | 86 | if (!(priv->phy->channels_supported[page] & (1 << chan))) { |
| 87 | WARN_ON(1); | 87 | WARN_ON(1); |
| 88 | kfree_skb(skb); | ||
| 88 | return NETDEV_TX_OK; | 89 | return NETDEV_TX_OK; |
| 89 | } | 90 | } |
| 90 | 91 | ||
| @@ -98,13 +99,15 @@ netdev_tx_t mac802154_tx(struct mac802154_priv *priv, struct sk_buff *skb, | |||
| 98 | } | 99 | } |
| 99 | 100 | ||
| 100 | if (skb_cow_head(skb, priv->hw.extra_tx_headroom)) { | 101 | if (skb_cow_head(skb, priv->hw.extra_tx_headroom)) { |
| 101 | dev_kfree_skb(skb); | 102 | kfree_skb(skb); |
| 102 | return NETDEV_TX_OK; | 103 | return NETDEV_TX_OK; |
| 103 | } | 104 | } |
| 104 | 105 | ||
| 105 | work = kzalloc(sizeof(struct xmit_work), GFP_ATOMIC); | 106 | work = kzalloc(sizeof(struct xmit_work), GFP_ATOMIC); |
| 106 | if (!work) | 107 | if (!work) { |
| 108 | kfree_skb(skb); | ||
| 107 | return NETDEV_TX_BUSY; | 109 | return NETDEV_TX_BUSY; |
| 110 | } | ||
| 108 | 111 | ||
| 109 | INIT_WORK(&work->work, mac802154_xmit_worker); | 112 | INIT_WORK(&work->work, mac802154_xmit_worker); |
| 110 | work->skb = skb; | 113 | work->skb = skb; |
diff --git a/net/mac802154/wpan.c b/net/mac802154/wpan.c index f30f6d4beea1..1191039c2b1b 100644 --- a/net/mac802154/wpan.c +++ b/net/mac802154/wpan.c | |||
| @@ -327,8 +327,10 @@ mac802154_wpan_xmit(struct sk_buff *skb, struct net_device *dev) | |||
| 327 | 327 | ||
| 328 | if (chan == MAC802154_CHAN_NONE || | 328 | if (chan == MAC802154_CHAN_NONE || |
| 329 | page >= WPAN_NUM_PAGES || | 329 | page >= WPAN_NUM_PAGES || |
| 330 | chan >= WPAN_NUM_CHANNELS) | 330 | chan >= WPAN_NUM_CHANNELS) { |
| 331 | kfree_skb(skb); | ||
| 331 | return NETDEV_TX_OK; | 332 | return NETDEV_TX_OK; |
| 333 | } | ||
| 332 | 334 | ||
| 333 | skb->skb_iif = dev->ifindex; | 335 | skb->skb_iif = dev->ifindex; |
| 334 | dev->stats.tx_packets++; | 336 | dev->stats.tx_packets++; |
diff --git a/net/netfilter/ipset/ip_set_hash_netiface.c b/net/netfilter/ipset/ip_set_hash_netiface.c index b9a63381e349..45a101439bc5 100644 --- a/net/netfilter/ipset/ip_set_hash_netiface.c +++ b/net/netfilter/ipset/ip_set_hash_netiface.c | |||
| @@ -793,7 +793,7 @@ static struct ip_set_type hash_netiface_type __read_mostly = { | |||
| 793 | [IPSET_ATTR_IP] = { .type = NLA_NESTED }, | 793 | [IPSET_ATTR_IP] = { .type = NLA_NESTED }, |
| 794 | [IPSET_ATTR_IP_TO] = { .type = NLA_NESTED }, | 794 | [IPSET_ATTR_IP_TO] = { .type = NLA_NESTED }, |
| 795 | [IPSET_ATTR_IFACE] = { .type = NLA_NUL_STRING, | 795 | [IPSET_ATTR_IFACE] = { .type = NLA_NUL_STRING, |
| 796 | .len = IPSET_MAXNAMELEN - 1 }, | 796 | .len = IFNAMSIZ - 1 }, |
| 797 | [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 }, | 797 | [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 }, |
| 798 | [IPSET_ATTR_CIDR] = { .type = NLA_U8 }, | 798 | [IPSET_ATTR_CIDR] = { .type = NLA_U8 }, |
| 799 | [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, | 799 | [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, |
diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c index fb45640dc1fb..47edf5a40a59 100644 --- a/net/netfilter/ipvs/ip_vs_core.c +++ b/net/netfilter/ipvs/ip_vs_core.c | |||
| @@ -942,7 +942,7 @@ static int ip_vs_out_icmp_v6(struct sk_buff *skb, int *related, | |||
| 942 | /* Fragment header that is before ICMP header tells us that: | 942 | /* Fragment header that is before ICMP header tells us that: |
| 943 | * it's not an error message since they can't be fragmented. | 943 | * it's not an error message since they can't be fragmented. |
| 944 | */ | 944 | */ |
| 945 | if (ipvsh->flags & IP6T_FH_F_FRAG) | 945 | if (ipvsh->flags & IP6_FH_F_FRAG) |
| 946 | return NF_DROP; | 946 | return NF_DROP; |
| 947 | 947 | ||
| 948 | IP_VS_DBG(8, "Outgoing ICMPv6 (%d,%d) %pI6c->%pI6c\n", | 948 | IP_VS_DBG(8, "Outgoing ICMPv6 (%d,%d) %pI6c->%pI6c\n", |
| @@ -1475,7 +1475,7 @@ static int ip_vs_in_icmp_v6(struct sk_buff *skb, int *related, | |||
| 1475 | /* Fragment header that is before ICMP header tells us that: | 1475 | /* Fragment header that is before ICMP header tells us that: |
| 1476 | * it's not an error message since they can't be fragmented. | 1476 | * it's not an error message since they can't be fragmented. |
| 1477 | */ | 1477 | */ |
| 1478 | if (iph->flags & IP6T_FH_F_FRAG) | 1478 | if (iph->flags & IP6_FH_F_FRAG) |
| 1479 | return NF_DROP; | 1479 | return NF_DROP; |
| 1480 | 1480 | ||
| 1481 | IP_VS_DBG(8, "Incoming ICMPv6 (%d,%d) %pI6c->%pI6c\n", | 1481 | IP_VS_DBG(8, "Incoming ICMPv6 (%d,%d) %pI6c->%pI6c\n", |
diff --git a/net/netfilter/xt_HMARK.c b/net/netfilter/xt_HMARK.c index 1686ca1b53a1..73b73f687c58 100644 --- a/net/netfilter/xt_HMARK.c +++ b/net/netfilter/xt_HMARK.c | |||
| @@ -167,7 +167,7 @@ hmark_pkt_set_htuple_ipv6(const struct sk_buff *skb, struct hmark_tuple *t, | |||
| 167 | const struct xt_hmark_info *info) | 167 | const struct xt_hmark_info *info) |
| 168 | { | 168 | { |
| 169 | struct ipv6hdr *ip6, _ip6; | 169 | struct ipv6hdr *ip6, _ip6; |
| 170 | int flag = IP6T_FH_F_AUTH; | 170 | int flag = IP6_FH_F_AUTH; |
| 171 | unsigned int nhoff = 0; | 171 | unsigned int nhoff = 0; |
| 172 | u16 fragoff = 0; | 172 | u16 fragoff = 0; |
| 173 | int nexthdr; | 173 | int nexthdr; |
| @@ -177,7 +177,7 @@ hmark_pkt_set_htuple_ipv6(const struct sk_buff *skb, struct hmark_tuple *t, | |||
| 177 | if (nexthdr < 0) | 177 | if (nexthdr < 0) |
| 178 | return 0; | 178 | return 0; |
| 179 | /* No need to check for icmp errors on fragments */ | 179 | /* No need to check for icmp errors on fragments */ |
| 180 | if ((flag & IP6T_FH_F_FRAG) || (nexthdr != IPPROTO_ICMPV6)) | 180 | if ((flag & IP6_FH_F_FRAG) || (nexthdr != IPPROTO_ICMPV6)) |
| 181 | goto noicmp; | 181 | goto noicmp; |
| 182 | /* Use inner header in case of ICMP errors */ | 182 | /* Use inner header in case of ICMP errors */ |
| 183 | if (get_inner6_hdr(skb, &nhoff)) { | 183 | if (get_inner6_hdr(skb, &nhoff)) { |
| @@ -185,7 +185,7 @@ hmark_pkt_set_htuple_ipv6(const struct sk_buff *skb, struct hmark_tuple *t, | |||
| 185 | if (ip6 == NULL) | 185 | if (ip6 == NULL) |
| 186 | return -1; | 186 | return -1; |
| 187 | /* If AH present, use SPI like in ESP. */ | 187 | /* If AH present, use SPI like in ESP. */ |
| 188 | flag = IP6T_FH_F_AUTH; | 188 | flag = IP6_FH_F_AUTH; |
| 189 | nexthdr = ipv6_find_hdr(skb, &nhoff, -1, &fragoff, &flag); | 189 | nexthdr = ipv6_find_hdr(skb, &nhoff, -1, &fragoff, &flag); |
| 190 | if (nexthdr < 0) | 190 | if (nexthdr < 0) |
| 191 | return -1; | 191 | return -1; |
| @@ -201,7 +201,7 @@ noicmp: | |||
| 201 | if (t->proto == IPPROTO_ICMPV6) | 201 | if (t->proto == IPPROTO_ICMPV6) |
| 202 | return 0; | 202 | return 0; |
| 203 | 203 | ||
| 204 | if (flag & IP6T_FH_F_FRAG) | 204 | if (flag & IP6_FH_F_FRAG) |
| 205 | return 0; | 205 | return 0; |
| 206 | 206 | ||
| 207 | hmark_set_tuple_ports(skb, nhoff, t, info); | 207 | hmark_set_tuple_ports(skb, nhoff, t, info); |
diff --git a/net/nfc/hci/command.c b/net/nfc/hci/command.c index 07659cfd6d7b..7d99410e6c1a 100644 --- a/net/nfc/hci/command.c +++ b/net/nfc/hci/command.c | |||
| @@ -344,7 +344,7 @@ int nfc_hci_connect_gate(struct nfc_hci_dev *hdev, u8 dest_host, u8 dest_gate, | |||
| 344 | return -EADDRINUSE; | 344 | return -EADDRINUSE; |
| 345 | 345 | ||
| 346 | if (pipe != NFC_HCI_INVALID_PIPE) | 346 | if (pipe != NFC_HCI_INVALID_PIPE) |
| 347 | goto pipe_is_open; | 347 | goto open_pipe; |
| 348 | 348 | ||
| 349 | switch (dest_gate) { | 349 | switch (dest_gate) { |
| 350 | case NFC_HCI_LINK_MGMT_GATE: | 350 | case NFC_HCI_LINK_MGMT_GATE: |
| @@ -361,6 +361,7 @@ int nfc_hci_connect_gate(struct nfc_hci_dev *hdev, u8 dest_host, u8 dest_gate, | |||
| 361 | break; | 361 | break; |
| 362 | } | 362 | } |
| 363 | 363 | ||
| 364 | open_pipe: | ||
| 364 | r = nfc_hci_open_pipe(hdev, pipe); | 365 | r = nfc_hci_open_pipe(hdev, pipe); |
| 365 | if (r < 0) { | 366 | if (r < 0) { |
| 366 | if (pipe_created) | 367 | if (pipe_created) |
| @@ -371,7 +372,6 @@ int nfc_hci_connect_gate(struct nfc_hci_dev *hdev, u8 dest_host, u8 dest_gate, | |||
| 371 | return r; | 372 | return r; |
| 372 | } | 373 | } |
| 373 | 374 | ||
| 374 | pipe_is_open: | ||
| 375 | hdev->gate2pipe[dest_gate] = pipe; | 375 | hdev->gate2pipe[dest_gate] = pipe; |
| 376 | 376 | ||
| 377 | return 0; | 377 | return 0; |
diff --git a/net/nfc/hci/core.c b/net/nfc/hci/core.c index bc571b0efb92..7bea574d5934 100644 --- a/net/nfc/hci/core.c +++ b/net/nfc/hci/core.c | |||
| @@ -33,17 +33,20 @@ | |||
| 33 | /* Largest headroom needed for outgoing HCI commands */ | 33 | /* Largest headroom needed for outgoing HCI commands */ |
| 34 | #define HCI_CMDS_HEADROOM 1 | 34 | #define HCI_CMDS_HEADROOM 1 |
| 35 | 35 | ||
| 36 | static int nfc_hci_result_to_errno(u8 result) | 36 | int nfc_hci_result_to_errno(u8 result) |
| 37 | { | 37 | { |
| 38 | switch (result) { | 38 | switch (result) { |
| 39 | case NFC_HCI_ANY_OK: | 39 | case NFC_HCI_ANY_OK: |
| 40 | return 0; | 40 | return 0; |
| 41 | case NFC_HCI_ANY_E_REG_PAR_UNKNOWN: | ||
| 42 | return -EOPNOTSUPP; | ||
| 41 | case NFC_HCI_ANY_E_TIMEOUT: | 43 | case NFC_HCI_ANY_E_TIMEOUT: |
| 42 | return -ETIME; | 44 | return -ETIME; |
| 43 | default: | 45 | default: |
| 44 | return -1; | 46 | return -1; |
| 45 | } | 47 | } |
| 46 | } | 48 | } |
| 49 | EXPORT_SYMBOL(nfc_hci_result_to_errno); | ||
| 47 | 50 | ||
| 48 | static void nfc_hci_msg_tx_work(struct work_struct *work) | 51 | static void nfc_hci_msg_tx_work(struct work_struct *work) |
| 49 | { | 52 | { |
| @@ -167,7 +170,7 @@ void nfc_hci_cmd_received(struct nfc_hci_dev *hdev, u8 pipe, u8 cmd, | |||
| 167 | kfree_skb(skb); | 170 | kfree_skb(skb); |
| 168 | } | 171 | } |
| 169 | 172 | ||
| 170 | static u32 nfc_hci_sak_to_protocol(u8 sak) | 173 | u32 nfc_hci_sak_to_protocol(u8 sak) |
| 171 | { | 174 | { |
| 172 | switch (NFC_HCI_TYPE_A_SEL_PROT(sak)) { | 175 | switch (NFC_HCI_TYPE_A_SEL_PROT(sak)) { |
| 173 | case NFC_HCI_TYPE_A_SEL_PROT_MIFARE: | 176 | case NFC_HCI_TYPE_A_SEL_PROT_MIFARE: |
| @@ -182,6 +185,7 @@ static u32 nfc_hci_sak_to_protocol(u8 sak) | |||
| 182 | return 0xffffffff; | 185 | return 0xffffffff; |
| 183 | } | 186 | } |
| 184 | } | 187 | } |
| 188 | EXPORT_SYMBOL(nfc_hci_sak_to_protocol); | ||
| 185 | 189 | ||
| 186 | int nfc_hci_target_discovered(struct nfc_hci_dev *hdev, u8 gate) | 190 | int nfc_hci_target_discovered(struct nfc_hci_dev *hdev, u8 gate) |
| 187 | { | 191 | { |
| @@ -284,6 +288,12 @@ void nfc_hci_event_received(struct nfc_hci_dev *hdev, u8 pipe, u8 event, | |||
| 284 | struct sk_buff *skb) | 288 | struct sk_buff *skb) |
| 285 | { | 289 | { |
| 286 | int r = 0; | 290 | int r = 0; |
| 291 | u8 gate = nfc_hci_pipe2gate(hdev, pipe); | ||
| 292 | |||
| 293 | if (gate == 0xff) { | ||
| 294 | pr_err("Discarded event %x to unopened pipe %x\n", event, pipe); | ||
| 295 | goto exit; | ||
| 296 | } | ||
| 287 | 297 | ||
| 288 | switch (event) { | 298 | switch (event) { |
| 289 | case NFC_HCI_EVT_TARGET_DISCOVERED: | 299 | case NFC_HCI_EVT_TARGET_DISCOVERED: |
| @@ -307,14 +317,11 @@ void nfc_hci_event_received(struct nfc_hci_dev *hdev, u8 pipe, u8 event, | |||
| 307 | goto exit; | 317 | goto exit; |
| 308 | } | 318 | } |
| 309 | 319 | ||
| 310 | r = nfc_hci_target_discovered(hdev, | 320 | r = nfc_hci_target_discovered(hdev, gate); |
| 311 | nfc_hci_pipe2gate(hdev, pipe)); | ||
| 312 | break; | 321 | break; |
| 313 | default: | 322 | default: |
| 314 | if (hdev->ops->event_received) { | 323 | if (hdev->ops->event_received) { |
| 315 | hdev->ops->event_received(hdev, | 324 | hdev->ops->event_received(hdev, gate, event, skb); |
| 316 | nfc_hci_pipe2gate(hdev, pipe), | ||
| 317 | event, skb); | ||
| 318 | return; | 325 | return; |
| 319 | } | 326 | } |
| 320 | 327 | ||
| @@ -419,6 +426,10 @@ static int hci_dev_version(struct nfc_hci_dev *hdev) | |||
| 419 | 426 | ||
| 420 | r = nfc_hci_get_param(hdev, NFC_HCI_ID_MGMT_GATE, | 427 | r = nfc_hci_get_param(hdev, NFC_HCI_ID_MGMT_GATE, |
| 421 | NFC_HCI_ID_MGMT_VERSION_SW, &skb); | 428 | NFC_HCI_ID_MGMT_VERSION_SW, &skb); |
| 429 | if (r == -EOPNOTSUPP) { | ||
| 430 | pr_info("Software/Hardware info not available\n"); | ||
| 431 | return 0; | ||
| 432 | } | ||
| 422 | if (r < 0) | 433 | if (r < 0) |
| 423 | return r; | 434 | return r; |
| 424 | 435 | ||
diff --git a/net/nfc/llcp/commands.c b/net/nfc/llcp/commands.c index ed2d17312d61..df24be48d4da 100644 --- a/net/nfc/llcp/commands.c +++ b/net/nfc/llcp/commands.c | |||
| @@ -528,6 +528,23 @@ int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock, | |||
| 528 | if (local == NULL) | 528 | if (local == NULL) |
| 529 | return -ENODEV; | 529 | return -ENODEV; |
| 530 | 530 | ||
| 531 | /* Remote is ready but has not acknowledged our frames */ | ||
| 532 | if((sock->remote_ready && | ||
| 533 | skb_queue_len(&sock->tx_pending_queue) >= sock->rw && | ||
| 534 | skb_queue_len(&sock->tx_queue) >= 2 * sock->rw)) { | ||
| 535 | pr_err("Pending queue is full %d frames\n", | ||
| 536 | skb_queue_len(&sock->tx_pending_queue)); | ||
| 537 | return -ENOBUFS; | ||
| 538 | } | ||
| 539 | |||
| 540 | /* Remote is not ready and we've been queueing enough frames */ | ||
| 541 | if ((!sock->remote_ready && | ||
| 542 | skb_queue_len(&sock->tx_queue) >= 2 * sock->rw)) { | ||
| 543 | pr_err("Tx queue is full %d frames\n", | ||
| 544 | skb_queue_len(&sock->tx_queue)); | ||
| 545 | return -ENOBUFS; | ||
| 546 | } | ||
| 547 | |||
| 531 | msg_data = kzalloc(len, GFP_KERNEL); | 548 | msg_data = kzalloc(len, GFP_KERNEL); |
| 532 | if (msg_data == NULL) | 549 | if (msg_data == NULL) |
| 533 | return -ENOMEM; | 550 | return -ENOMEM; |
| @@ -579,7 +596,7 @@ int nfc_llcp_send_ui_frame(struct nfc_llcp_sock *sock, u8 ssap, u8 dsap, | |||
| 579 | struct sk_buff *pdu; | 596 | struct sk_buff *pdu; |
| 580 | struct nfc_llcp_local *local; | 597 | struct nfc_llcp_local *local; |
| 581 | size_t frag_len = 0, remaining_len; | 598 | size_t frag_len = 0, remaining_len; |
| 582 | u8 *msg_ptr; | 599 | u8 *msg_ptr, *msg_data; |
| 583 | int err; | 600 | int err; |
| 584 | 601 | ||
| 585 | pr_debug("Send UI frame len %zd\n", len); | 602 | pr_debug("Send UI frame len %zd\n", len); |
| @@ -588,8 +605,17 @@ int nfc_llcp_send_ui_frame(struct nfc_llcp_sock *sock, u8 ssap, u8 dsap, | |||
| 588 | if (local == NULL) | 605 | if (local == NULL) |
| 589 | return -ENODEV; | 606 | return -ENODEV; |
| 590 | 607 | ||
| 608 | msg_data = kzalloc(len, GFP_KERNEL); | ||
| 609 | if (msg_data == NULL) | ||
| 610 | return -ENOMEM; | ||
| 611 | |||
| 612 | if (memcpy_fromiovec(msg_data, msg->msg_iov, len)) { | ||
| 613 | kfree(msg_data); | ||
| 614 | return -EFAULT; | ||
| 615 | } | ||
| 616 | |||
| 591 | remaining_len = len; | 617 | remaining_len = len; |
| 592 | msg_ptr = (u8 *) msg->msg_iov; | 618 | msg_ptr = msg_data; |
| 593 | 619 | ||
| 594 | while (remaining_len > 0) { | 620 | while (remaining_len > 0) { |
| 595 | 621 | ||
| @@ -616,6 +642,8 @@ int nfc_llcp_send_ui_frame(struct nfc_llcp_sock *sock, u8 ssap, u8 dsap, | |||
| 616 | msg_ptr += frag_len; | 642 | msg_ptr += frag_len; |
| 617 | } | 643 | } |
| 618 | 644 | ||
| 645 | kfree(msg_data); | ||
| 646 | |||
| 619 | return len; | 647 | return len; |
| 620 | } | 648 | } |
| 621 | 649 | ||
diff --git a/net/nfc/llcp/llcp.c b/net/nfc/llcp/llcp.c index 2e9ddf34c099..2df87056c6df 100644 --- a/net/nfc/llcp/llcp.c +++ b/net/nfc/llcp/llcp.c | |||
| @@ -656,6 +656,8 @@ static void nfc_llcp_tx_work(struct work_struct *work) | |||
| 656 | if (llcp_sock == NULL && nfc_llcp_ptype(skb) == LLCP_PDU_I) { | 656 | if (llcp_sock == NULL && nfc_llcp_ptype(skb) == LLCP_PDU_I) { |
| 657 | nfc_llcp_send_symm(local->dev); | 657 | nfc_llcp_send_symm(local->dev); |
| 658 | } else { | 658 | } else { |
| 659 | struct sk_buff *copy_skb = NULL; | ||
| 660 | u8 ptype = nfc_llcp_ptype(skb); | ||
| 659 | int ret; | 661 | int ret; |
| 660 | 662 | ||
| 661 | pr_debug("Sending pending skb\n"); | 663 | pr_debug("Sending pending skb\n"); |
| @@ -663,22 +665,29 @@ static void nfc_llcp_tx_work(struct work_struct *work) | |||
| 663 | DUMP_PREFIX_OFFSET, 16, 1, | 665 | DUMP_PREFIX_OFFSET, 16, 1, |
| 664 | skb->data, skb->len, true); | 666 | skb->data, skb->len, true); |
| 665 | 667 | ||
| 668 | if (ptype == LLCP_PDU_I) | ||
| 669 | copy_skb = skb_copy(skb, GFP_ATOMIC); | ||
| 670 | |||
| 666 | nfc_llcp_send_to_raw_sock(local, skb, | 671 | nfc_llcp_send_to_raw_sock(local, skb, |
| 667 | NFC_LLCP_DIRECTION_TX); | 672 | NFC_LLCP_DIRECTION_TX); |
| 668 | 673 | ||
| 669 | ret = nfc_data_exchange(local->dev, local->target_idx, | 674 | ret = nfc_data_exchange(local->dev, local->target_idx, |
| 670 | skb, nfc_llcp_recv, local); | 675 | skb, nfc_llcp_recv, local); |
| 671 | 676 | ||
| 672 | if (!ret && nfc_llcp_ptype(skb) == LLCP_PDU_I) { | 677 | if (ret) { |
| 673 | skb = skb_get(skb); | 678 | kfree_skb(copy_skb); |
| 674 | skb_queue_tail(&llcp_sock->tx_pending_queue, | 679 | goto out; |
| 675 | skb); | ||
| 676 | } | 680 | } |
| 681 | |||
| 682 | if (ptype == LLCP_PDU_I && copy_skb) | ||
| 683 | skb_queue_tail(&llcp_sock->tx_pending_queue, | ||
| 684 | copy_skb); | ||
| 677 | } | 685 | } |
| 678 | } else { | 686 | } else { |
| 679 | nfc_llcp_send_symm(local->dev); | 687 | nfc_llcp_send_symm(local->dev); |
| 680 | } | 688 | } |
| 681 | 689 | ||
| 690 | out: | ||
| 682 | mod_timer(&local->link_timer, | 691 | mod_timer(&local->link_timer, |
| 683 | jiffies + msecs_to_jiffies(2 * local->remote_lto)); | 692 | jiffies + msecs_to_jiffies(2 * local->remote_lto)); |
| 684 | } | 693 | } |
diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c index 08114478cb85..ac2defeeba83 100644 --- a/net/openvswitch/actions.c +++ b/net/openvswitch/actions.c | |||
| @@ -28,6 +28,7 @@ | |||
| 28 | #include <linux/if_arp.h> | 28 | #include <linux/if_arp.h> |
| 29 | #include <linux/if_vlan.h> | 29 | #include <linux/if_vlan.h> |
| 30 | #include <net/ip.h> | 30 | #include <net/ip.h> |
| 31 | #include <net/ipv6.h> | ||
| 31 | #include <net/checksum.h> | 32 | #include <net/checksum.h> |
| 32 | #include <net/dsfield.h> | 33 | #include <net/dsfield.h> |
| 33 | 34 | ||
| @@ -162,6 +163,53 @@ static void set_ip_addr(struct sk_buff *skb, struct iphdr *nh, | |||
| 162 | *addr = new_addr; | 163 | *addr = new_addr; |
| 163 | } | 164 | } |
| 164 | 165 | ||
| 166 | static void update_ipv6_checksum(struct sk_buff *skb, u8 l4_proto, | ||
| 167 | __be32 addr[4], const __be32 new_addr[4]) | ||
| 168 | { | ||
| 169 | int transport_len = skb->len - skb_transport_offset(skb); | ||
| 170 | |||
| 171 | if (l4_proto == IPPROTO_TCP) { | ||
| 172 | if (likely(transport_len >= sizeof(struct tcphdr))) | ||
| 173 | inet_proto_csum_replace16(&tcp_hdr(skb)->check, skb, | ||
| 174 | addr, new_addr, 1); | ||
| 175 | } else if (l4_proto == IPPROTO_UDP) { | ||
| 176 | if (likely(transport_len >= sizeof(struct udphdr))) { | ||
| 177 | struct udphdr *uh = udp_hdr(skb); | ||
| 178 | |||
| 179 | if (uh->check || skb->ip_summed == CHECKSUM_PARTIAL) { | ||
| 180 | inet_proto_csum_replace16(&uh->check, skb, | ||
| 181 | addr, new_addr, 1); | ||
| 182 | if (!uh->check) | ||
| 183 | uh->check = CSUM_MANGLED_0; | ||
| 184 | } | ||
| 185 | } | ||
| 186 | } | ||
| 187 | } | ||
| 188 | |||
| 189 | static void set_ipv6_addr(struct sk_buff *skb, u8 l4_proto, | ||
| 190 | __be32 addr[4], const __be32 new_addr[4], | ||
| 191 | bool recalculate_csum) | ||
| 192 | { | ||
| 193 | if (recalculate_csum) | ||
| 194 | update_ipv6_checksum(skb, l4_proto, addr, new_addr); | ||
| 195 | |||
| 196 | skb->rxhash = 0; | ||
| 197 | memcpy(addr, new_addr, sizeof(__be32[4])); | ||
| 198 | } | ||
| 199 | |||
| 200 | static void set_ipv6_tc(struct ipv6hdr *nh, u8 tc) | ||
| 201 | { | ||
| 202 | nh->priority = tc >> 4; | ||
| 203 | nh->flow_lbl[0] = (nh->flow_lbl[0] & 0x0F) | ((tc & 0x0F) << 4); | ||
| 204 | } | ||
| 205 | |||
| 206 | static void set_ipv6_fl(struct ipv6hdr *nh, u32 fl) | ||
| 207 | { | ||
| 208 | nh->flow_lbl[0] = (nh->flow_lbl[0] & 0xF0) | (fl & 0x000F0000) >> 16; | ||
| 209 | nh->flow_lbl[1] = (fl & 0x0000FF00) >> 8; | ||
| 210 | nh->flow_lbl[2] = fl & 0x000000FF; | ||
| 211 | } | ||
| 212 | |||
| 165 | static void set_ip_ttl(struct sk_buff *skb, struct iphdr *nh, u8 new_ttl) | 213 | static void set_ip_ttl(struct sk_buff *skb, struct iphdr *nh, u8 new_ttl) |
| 166 | { | 214 | { |
| 167 | csum_replace2(&nh->check, htons(nh->ttl << 8), htons(new_ttl << 8)); | 215 | csum_replace2(&nh->check, htons(nh->ttl << 8), htons(new_ttl << 8)); |
| @@ -195,6 +243,47 @@ static int set_ipv4(struct sk_buff *skb, const struct ovs_key_ipv4 *ipv4_key) | |||
| 195 | return 0; | 243 | return 0; |
| 196 | } | 244 | } |
| 197 | 245 | ||
| 246 | static int set_ipv6(struct sk_buff *skb, const struct ovs_key_ipv6 *ipv6_key) | ||
| 247 | { | ||
| 248 | struct ipv6hdr *nh; | ||
| 249 | int err; | ||
| 250 | __be32 *saddr; | ||
| 251 | __be32 *daddr; | ||
| 252 | |||
| 253 | err = make_writable(skb, skb_network_offset(skb) + | ||
| 254 | sizeof(struct ipv6hdr)); | ||
| 255 | if (unlikely(err)) | ||
| 256 | return err; | ||
| 257 | |||
| 258 | nh = ipv6_hdr(skb); | ||
| 259 | saddr = (__be32 *)&nh->saddr; | ||
| 260 | daddr = (__be32 *)&nh->daddr; | ||
| 261 | |||
| 262 | if (memcmp(ipv6_key->ipv6_src, saddr, sizeof(ipv6_key->ipv6_src))) | ||
| 263 | set_ipv6_addr(skb, ipv6_key->ipv6_proto, saddr, | ||
| 264 | ipv6_key->ipv6_src, true); | ||
| 265 | |||
| 266 | if (memcmp(ipv6_key->ipv6_dst, daddr, sizeof(ipv6_key->ipv6_dst))) { | ||
| 267 | unsigned int offset = 0; | ||
| 268 | int flags = IP6_FH_F_SKIP_RH; | ||
| 269 | bool recalc_csum = true; | ||
| 270 | |||
| 271 | if (ipv6_ext_hdr(nh->nexthdr)) | ||
| 272 | recalc_csum = ipv6_find_hdr(skb, &offset, | ||
| 273 | NEXTHDR_ROUTING, NULL, | ||
| 274 | &flags) != NEXTHDR_ROUTING; | ||
| 275 | |||
| 276 | set_ipv6_addr(skb, ipv6_key->ipv6_proto, daddr, | ||
| 277 | ipv6_key->ipv6_dst, recalc_csum); | ||
| 278 | } | ||
| 279 | |||
| 280 | set_ipv6_tc(nh, ipv6_key->ipv6_tclass); | ||
| 281 | set_ipv6_fl(nh, ntohl(ipv6_key->ipv6_label)); | ||
| 282 | nh->hop_limit = ipv6_key->ipv6_hlimit; | ||
| 283 | |||
| 284 | return 0; | ||
| 285 | } | ||
| 286 | |||
| 198 | /* Must follow make_writable() since that can move the skb data. */ | 287 | /* Must follow make_writable() since that can move the skb data. */ |
| 199 | static void set_tp_port(struct sk_buff *skb, __be16 *port, | 288 | static void set_tp_port(struct sk_buff *skb, __be16 *port, |
| 200 | __be16 new_port, __sum16 *check) | 289 | __be16 new_port, __sum16 *check) |
| @@ -339,6 +428,10 @@ static int execute_set_action(struct sk_buff *skb, | |||
| 339 | skb->priority = nla_get_u32(nested_attr); | 428 | skb->priority = nla_get_u32(nested_attr); |
| 340 | break; | 429 | break; |
| 341 | 430 | ||
| 431 | case OVS_KEY_ATTR_SKB_MARK: | ||
| 432 | skb->mark = nla_get_u32(nested_attr); | ||
| 433 | break; | ||
| 434 | |||
| 342 | case OVS_KEY_ATTR_ETHERNET: | 435 | case OVS_KEY_ATTR_ETHERNET: |
| 343 | err = set_eth_addr(skb, nla_data(nested_attr)); | 436 | err = set_eth_addr(skb, nla_data(nested_attr)); |
| 344 | break; | 437 | break; |
| @@ -347,6 +440,10 @@ static int execute_set_action(struct sk_buff *skb, | |||
| 347 | err = set_ipv4(skb, nla_data(nested_attr)); | 440 | err = set_ipv4(skb, nla_data(nested_attr)); |
| 348 | break; | 441 | break; |
| 349 | 442 | ||
| 443 | case OVS_KEY_ATTR_IPV6: | ||
| 444 | err = set_ipv6(skb, nla_data(nested_attr)); | ||
| 445 | break; | ||
| 446 | |||
| 350 | case OVS_KEY_ATTR_TCP: | 447 | case OVS_KEY_ATTR_TCP: |
| 351 | err = set_tcp(skb, nla_data(nested_attr)); | 448 | err = set_tcp(skb, nla_data(nested_attr)); |
| 352 | break; | 449 | break; |
diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c index 4c4b62ccc7d7..f996db343247 100644 --- a/net/openvswitch/datapath.c +++ b/net/openvswitch/datapath.c | |||
| @@ -208,7 +208,7 @@ void ovs_dp_process_received_packet(struct vport *p, struct sk_buff *skb) | |||
| 208 | int error; | 208 | int error; |
| 209 | int key_len; | 209 | int key_len; |
| 210 | 210 | ||
| 211 | stats = per_cpu_ptr(dp->stats_percpu, smp_processor_id()); | 211 | stats = this_cpu_ptr(dp->stats_percpu); |
| 212 | 212 | ||
| 213 | /* Extract flow from 'skb' into 'key'. */ | 213 | /* Extract flow from 'skb' into 'key'. */ |
| 214 | error = ovs_flow_extract(skb, p->port_no, &key, &key_len); | 214 | error = ovs_flow_extract(skb, p->port_no, &key, &key_len); |
| @@ -282,7 +282,7 @@ int ovs_dp_upcall(struct datapath *dp, struct sk_buff *skb, | |||
| 282 | return 0; | 282 | return 0; |
| 283 | 283 | ||
| 284 | err: | 284 | err: |
| 285 | stats = per_cpu_ptr(dp->stats_percpu, smp_processor_id()); | 285 | stats = this_cpu_ptr(dp->stats_percpu); |
| 286 | 286 | ||
| 287 | u64_stats_update_begin(&stats->sync); | 287 | u64_stats_update_begin(&stats->sync); |
| 288 | stats->n_lost++; | 288 | stats->n_lost++; |
| @@ -479,8 +479,10 @@ static int validate_set(const struct nlattr *a, | |||
| 479 | 479 | ||
| 480 | switch (key_type) { | 480 | switch (key_type) { |
| 481 | const struct ovs_key_ipv4 *ipv4_key; | 481 | const struct ovs_key_ipv4 *ipv4_key; |
| 482 | const struct ovs_key_ipv6 *ipv6_key; | ||
| 482 | 483 | ||
| 483 | case OVS_KEY_ATTR_PRIORITY: | 484 | case OVS_KEY_ATTR_PRIORITY: |
| 485 | case OVS_KEY_ATTR_SKB_MARK: | ||
| 484 | case OVS_KEY_ATTR_ETHERNET: | 486 | case OVS_KEY_ATTR_ETHERNET: |
| 485 | break; | 487 | break; |
| 486 | 488 | ||
| @@ -500,6 +502,25 @@ static int validate_set(const struct nlattr *a, | |||
| 500 | 502 | ||
| 501 | break; | 503 | break; |
| 502 | 504 | ||
| 505 | case OVS_KEY_ATTR_IPV6: | ||
| 506 | if (flow_key->eth.type != htons(ETH_P_IPV6)) | ||
| 507 | return -EINVAL; | ||
| 508 | |||
| 509 | if (!flow_key->ip.proto) | ||
| 510 | return -EINVAL; | ||
| 511 | |||
| 512 | ipv6_key = nla_data(ovs_key); | ||
| 513 | if (ipv6_key->ipv6_proto != flow_key->ip.proto) | ||
| 514 | return -EINVAL; | ||
| 515 | |||
| 516 | if (ipv6_key->ipv6_frag != flow_key->ip.frag) | ||
| 517 | return -EINVAL; | ||
| 518 | |||
| 519 | if (ntohl(ipv6_key->ipv6_label) & 0xFFF00000) | ||
| 520 | return -EINVAL; | ||
| 521 | |||
| 522 | break; | ||
| 523 | |||
| 503 | case OVS_KEY_ATTR_TCP: | 524 | case OVS_KEY_ATTR_TCP: |
| 504 | if (flow_key->ip.proto != IPPROTO_TCP) | 525 | if (flow_key->ip.proto != IPPROTO_TCP) |
| 505 | return -EINVAL; | 526 | return -EINVAL; |
| @@ -675,6 +696,7 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info) | |||
| 675 | goto err_flow_free; | 696 | goto err_flow_free; |
| 676 | 697 | ||
| 677 | err = ovs_flow_metadata_from_nlattrs(&flow->key.phy.priority, | 698 | err = ovs_flow_metadata_from_nlattrs(&flow->key.phy.priority, |
| 699 | &flow->key.phy.skb_mark, | ||
| 678 | &flow->key.phy.in_port, | 700 | &flow->key.phy.in_port, |
| 679 | a[OVS_PACKET_ATTR_KEY]); | 701 | a[OVS_PACKET_ATTR_KEY]); |
| 680 | if (err) | 702 | if (err) |
| @@ -694,6 +716,7 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info) | |||
| 694 | 716 | ||
| 695 | OVS_CB(packet)->flow = flow; | 717 | OVS_CB(packet)->flow = flow; |
| 696 | packet->priority = flow->key.phy.priority; | 718 | packet->priority = flow->key.phy.priority; |
| 719 | packet->mark = flow->key.phy.skb_mark; | ||
| 697 | 720 | ||
| 698 | rcu_read_lock(); | 721 | rcu_read_lock(); |
| 699 | dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex); | 722 | dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex); |
diff --git a/net/openvswitch/flow.c b/net/openvswitch/flow.c index 98c70630ad06..c3294cebc4f2 100644 --- a/net/openvswitch/flow.c +++ b/net/openvswitch/flow.c | |||
| @@ -604,6 +604,7 @@ int ovs_flow_extract(struct sk_buff *skb, u16 in_port, struct sw_flow_key *key, | |||
| 604 | 604 | ||
| 605 | key->phy.priority = skb->priority; | 605 | key->phy.priority = skb->priority; |
| 606 | key->phy.in_port = in_port; | 606 | key->phy.in_port = in_port; |
| 607 | key->phy.skb_mark = skb->mark; | ||
| 607 | 608 | ||
| 608 | skb_reset_mac_header(skb); | 609 | skb_reset_mac_header(skb); |
| 609 | 610 | ||
| @@ -689,7 +690,8 @@ int ovs_flow_extract(struct sk_buff *skb, u16 in_port, struct sw_flow_key *key, | |||
| 689 | } | 690 | } |
| 690 | } | 691 | } |
| 691 | 692 | ||
| 692 | } else if (key->eth.type == htons(ETH_P_ARP) && arphdr_ok(skb)) { | 693 | } else if ((key->eth.type == htons(ETH_P_ARP) || |
| 694 | key->eth.type == htons(ETH_P_RARP)) && arphdr_ok(skb)) { | ||
| 693 | struct arp_eth_header *arp; | 695 | struct arp_eth_header *arp; |
| 694 | 696 | ||
| 695 | arp = (struct arp_eth_header *)skb_network_header(skb); | 697 | arp = (struct arp_eth_header *)skb_network_header(skb); |
| @@ -702,15 +704,11 @@ int ovs_flow_extract(struct sk_buff *skb, u16 in_port, struct sw_flow_key *key, | |||
| 702 | /* We only match on the lower 8 bits of the opcode. */ | 704 | /* We only match on the lower 8 bits of the opcode. */ |
| 703 | if (ntohs(arp->ar_op) <= 0xff) | 705 | if (ntohs(arp->ar_op) <= 0xff) |
| 704 | key->ip.proto = ntohs(arp->ar_op); | 706 | key->ip.proto = ntohs(arp->ar_op); |
| 705 | 707 | memcpy(&key->ipv4.addr.src, arp->ar_sip, sizeof(key->ipv4.addr.src)); | |
| 706 | if (key->ip.proto == ARPOP_REQUEST | 708 | memcpy(&key->ipv4.addr.dst, arp->ar_tip, sizeof(key->ipv4.addr.dst)); |
| 707 | || key->ip.proto == ARPOP_REPLY) { | 709 | memcpy(key->ipv4.arp.sha, arp->ar_sha, ETH_ALEN); |
| 708 | memcpy(&key->ipv4.addr.src, arp->ar_sip, sizeof(key->ipv4.addr.src)); | 710 | memcpy(key->ipv4.arp.tha, arp->ar_tha, ETH_ALEN); |
| 709 | memcpy(&key->ipv4.addr.dst, arp->ar_tip, sizeof(key->ipv4.addr.dst)); | 711 | key_len = SW_FLOW_KEY_OFFSET(ipv4.arp); |
| 710 | memcpy(key->ipv4.arp.sha, arp->ar_sha, ETH_ALEN); | ||
| 711 | memcpy(key->ipv4.arp.tha, arp->ar_tha, ETH_ALEN); | ||
| 712 | key_len = SW_FLOW_KEY_OFFSET(ipv4.arp); | ||
| 713 | } | ||
| 714 | } | 712 | } |
| 715 | } else if (key->eth.type == htons(ETH_P_IPV6)) { | 713 | } else if (key->eth.type == htons(ETH_P_IPV6)) { |
| 716 | int nh_len; /* IPv6 Header + Extensions */ | 714 | int nh_len; /* IPv6 Header + Extensions */ |
| @@ -806,6 +804,7 @@ const int ovs_key_lens[OVS_KEY_ATTR_MAX + 1] = { | |||
| 806 | [OVS_KEY_ATTR_ENCAP] = -1, | 804 | [OVS_KEY_ATTR_ENCAP] = -1, |
| 807 | [OVS_KEY_ATTR_PRIORITY] = sizeof(u32), | 805 | [OVS_KEY_ATTR_PRIORITY] = sizeof(u32), |
| 808 | [OVS_KEY_ATTR_IN_PORT] = sizeof(u32), | 806 | [OVS_KEY_ATTR_IN_PORT] = sizeof(u32), |
| 807 | [OVS_KEY_ATTR_SKB_MARK] = sizeof(u32), | ||
| 809 | [OVS_KEY_ATTR_ETHERNET] = sizeof(struct ovs_key_ethernet), | 808 | [OVS_KEY_ATTR_ETHERNET] = sizeof(struct ovs_key_ethernet), |
| 810 | [OVS_KEY_ATTR_VLAN] = sizeof(__be16), | 809 | [OVS_KEY_ATTR_VLAN] = sizeof(__be16), |
| 811 | [OVS_KEY_ATTR_ETHERTYPE] = sizeof(__be16), | 810 | [OVS_KEY_ATTR_ETHERTYPE] = sizeof(__be16), |
| @@ -991,6 +990,10 @@ int ovs_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp, | |||
| 991 | } else { | 990 | } else { |
| 992 | swkey->phy.in_port = DP_MAX_PORTS; | 991 | swkey->phy.in_port = DP_MAX_PORTS; |
| 993 | } | 992 | } |
| 993 | if (attrs & (1 << OVS_KEY_ATTR_SKB_MARK)) { | ||
| 994 | swkey->phy.skb_mark = nla_get_u32(a[OVS_KEY_ATTR_SKB_MARK]); | ||
| 995 | attrs &= ~(1 << OVS_KEY_ATTR_SKB_MARK); | ||
| 996 | } | ||
| 994 | 997 | ||
| 995 | /* Data attributes. */ | 998 | /* Data attributes. */ |
| 996 | if (!(attrs & (1 << OVS_KEY_ATTR_ETHERNET))) | 999 | if (!(attrs & (1 << OVS_KEY_ATTR_ETHERNET))) |
| @@ -1090,7 +1093,8 @@ int ovs_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp, | |||
| 1090 | if (err) | 1093 | if (err) |
| 1091 | return err; | 1094 | return err; |
| 1092 | } | 1095 | } |
| 1093 | } else if (swkey->eth.type == htons(ETH_P_ARP)) { | 1096 | } else if (swkey->eth.type == htons(ETH_P_ARP) || |
| 1097 | swkey->eth.type == htons(ETH_P_RARP)) { | ||
| 1094 | const struct ovs_key_arp *arp_key; | 1098 | const struct ovs_key_arp *arp_key; |
| 1095 | 1099 | ||
| 1096 | if (!(attrs & (1 << OVS_KEY_ATTR_ARP))) | 1100 | if (!(attrs & (1 << OVS_KEY_ATTR_ARP))) |
| @@ -1117,6 +1121,8 @@ int ovs_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp, | |||
| 1117 | 1121 | ||
| 1118 | /** | 1122 | /** |
| 1119 | * ovs_flow_metadata_from_nlattrs - parses Netlink attributes into a flow key. | 1123 | * ovs_flow_metadata_from_nlattrs - parses Netlink attributes into a flow key. |
| 1124 | * @priority: receives the skb priority | ||
| 1125 | * @mark: receives the skb mark | ||
| 1120 | * @in_port: receives the extracted input port. | 1126 | * @in_port: receives the extracted input port. |
| 1121 | * @key: Netlink attribute holding nested %OVS_KEY_ATTR_* Netlink attribute | 1127 | * @key: Netlink attribute holding nested %OVS_KEY_ATTR_* Netlink attribute |
| 1122 | * sequence. | 1128 | * sequence. |
| @@ -1126,7 +1132,7 @@ int ovs_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp, | |||
| 1126 | * get the metadata, that is, the parts of the flow key that cannot be | 1132 | * get the metadata, that is, the parts of the flow key that cannot be |
| 1127 | * extracted from the packet itself. | 1133 | * extracted from the packet itself. |
| 1128 | */ | 1134 | */ |
| 1129 | int ovs_flow_metadata_from_nlattrs(u32 *priority, u16 *in_port, | 1135 | int ovs_flow_metadata_from_nlattrs(u32 *priority, u32 *mark, u16 *in_port, |
| 1130 | const struct nlattr *attr) | 1136 | const struct nlattr *attr) |
| 1131 | { | 1137 | { |
| 1132 | const struct nlattr *nla; | 1138 | const struct nlattr *nla; |
| @@ -1134,6 +1140,7 @@ int ovs_flow_metadata_from_nlattrs(u32 *priority, u16 *in_port, | |||
| 1134 | 1140 | ||
| 1135 | *in_port = DP_MAX_PORTS; | 1141 | *in_port = DP_MAX_PORTS; |
| 1136 | *priority = 0; | 1142 | *priority = 0; |
| 1143 | *mark = 0; | ||
| 1137 | 1144 | ||
| 1138 | nla_for_each_nested(nla, attr, rem) { | 1145 | nla_for_each_nested(nla, attr, rem) { |
| 1139 | int type = nla_type(nla); | 1146 | int type = nla_type(nla); |
| @@ -1152,6 +1159,10 @@ int ovs_flow_metadata_from_nlattrs(u32 *priority, u16 *in_port, | |||
| 1152 | return -EINVAL; | 1159 | return -EINVAL; |
| 1153 | *in_port = nla_get_u32(nla); | 1160 | *in_port = nla_get_u32(nla); |
| 1154 | break; | 1161 | break; |
| 1162 | |||
| 1163 | case OVS_KEY_ATTR_SKB_MARK: | ||
| 1164 | *mark = nla_get_u32(nla); | ||
| 1165 | break; | ||
| 1155 | } | 1166 | } |
| 1156 | } | 1167 | } |
| 1157 | } | 1168 | } |
| @@ -1173,6 +1184,10 @@ int ovs_flow_to_nlattrs(const struct sw_flow_key *swkey, struct sk_buff *skb) | |||
| 1173 | nla_put_u32(skb, OVS_KEY_ATTR_IN_PORT, swkey->phy.in_port)) | 1184 | nla_put_u32(skb, OVS_KEY_ATTR_IN_PORT, swkey->phy.in_port)) |
| 1174 | goto nla_put_failure; | 1185 | goto nla_put_failure; |
| 1175 | 1186 | ||
| 1187 | if (swkey->phy.skb_mark && | ||
| 1188 | nla_put_u32(skb, OVS_KEY_ATTR_SKB_MARK, swkey->phy.skb_mark)) | ||
| 1189 | goto nla_put_failure; | ||
| 1190 | |||
| 1176 | nla = nla_reserve(skb, OVS_KEY_ATTR_ETHERNET, sizeof(*eth_key)); | 1191 | nla = nla_reserve(skb, OVS_KEY_ATTR_ETHERNET, sizeof(*eth_key)); |
| 1177 | if (!nla) | 1192 | if (!nla) |
| 1178 | goto nla_put_failure; | 1193 | goto nla_put_failure; |
| @@ -1226,7 +1241,8 @@ int ovs_flow_to_nlattrs(const struct sw_flow_key *swkey, struct sk_buff *skb) | |||
| 1226 | ipv6_key->ipv6_tclass = swkey->ip.tos; | 1241 | ipv6_key->ipv6_tclass = swkey->ip.tos; |
| 1227 | ipv6_key->ipv6_hlimit = swkey->ip.ttl; | 1242 | ipv6_key->ipv6_hlimit = swkey->ip.ttl; |
| 1228 | ipv6_key->ipv6_frag = swkey->ip.frag; | 1243 | ipv6_key->ipv6_frag = swkey->ip.frag; |
| 1229 | } else if (swkey->eth.type == htons(ETH_P_ARP)) { | 1244 | } else if (swkey->eth.type == htons(ETH_P_ARP) || |
| 1245 | swkey->eth.type == htons(ETH_P_RARP)) { | ||
| 1230 | struct ovs_key_arp *arp_key; | 1246 | struct ovs_key_arp *arp_key; |
| 1231 | 1247 | ||
| 1232 | nla = nla_reserve(skb, OVS_KEY_ATTR_ARP, sizeof(*arp_key)); | 1248 | nla = nla_reserve(skb, OVS_KEY_ATTR_ARP, sizeof(*arp_key)); |
diff --git a/net/openvswitch/flow.h b/net/openvswitch/flow.h index 14a324eb017b..a7bb60ff3b5b 100644 --- a/net/openvswitch/flow.h +++ b/net/openvswitch/flow.h | |||
| @@ -43,6 +43,7 @@ struct sw_flow_actions { | |||
| 43 | struct sw_flow_key { | 43 | struct sw_flow_key { |
| 44 | struct { | 44 | struct { |
| 45 | u32 priority; /* Packet QoS priority. */ | 45 | u32 priority; /* Packet QoS priority. */ |
| 46 | u32 skb_mark; /* SKB mark. */ | ||
| 46 | u16 in_port; /* Input switch port (or DP_MAX_PORTS). */ | 47 | u16 in_port; /* Input switch port (or DP_MAX_PORTS). */ |
| 47 | } phy; | 48 | } phy; |
| 48 | struct { | 49 | struct { |
| @@ -144,6 +145,7 @@ u64 ovs_flow_used_time(unsigned long flow_jiffies); | |||
| 144 | * ------ --- ------ ----- | 145 | * ------ --- ------ ----- |
| 145 | * OVS_KEY_ATTR_PRIORITY 4 -- 4 8 | 146 | * OVS_KEY_ATTR_PRIORITY 4 -- 4 8 |
| 146 | * OVS_KEY_ATTR_IN_PORT 4 -- 4 8 | 147 | * OVS_KEY_ATTR_IN_PORT 4 -- 4 8 |
| 148 | * OVS_KEY_ATTR_SKB_MARK 4 -- 4 8 | ||
| 147 | * OVS_KEY_ATTR_ETHERNET 12 -- 4 16 | 149 | * OVS_KEY_ATTR_ETHERNET 12 -- 4 16 |
| 148 | * OVS_KEY_ATTR_ETHERTYPE 2 2 4 8 (outer VLAN ethertype) | 150 | * OVS_KEY_ATTR_ETHERTYPE 2 2 4 8 (outer VLAN ethertype) |
| 149 | * OVS_KEY_ATTR_8021Q 4 -- 4 8 | 151 | * OVS_KEY_ATTR_8021Q 4 -- 4 8 |
| @@ -153,14 +155,14 @@ u64 ovs_flow_used_time(unsigned long flow_jiffies); | |||
| 153 | * OVS_KEY_ATTR_ICMPV6 2 2 4 8 | 155 | * OVS_KEY_ATTR_ICMPV6 2 2 4 8 |
| 154 | * OVS_KEY_ATTR_ND 28 -- 4 32 | 156 | * OVS_KEY_ATTR_ND 28 -- 4 32 |
| 155 | * ------------------------------------------------- | 157 | * ------------------------------------------------- |
| 156 | * total 144 | 158 | * total 152 |
| 157 | */ | 159 | */ |
| 158 | #define FLOW_BUFSIZE 144 | 160 | #define FLOW_BUFSIZE 152 |
| 159 | 161 | ||
| 160 | int ovs_flow_to_nlattrs(const struct sw_flow_key *, struct sk_buff *); | 162 | int ovs_flow_to_nlattrs(const struct sw_flow_key *, struct sk_buff *); |
| 161 | int ovs_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp, | 163 | int ovs_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp, |
| 162 | const struct nlattr *); | 164 | const struct nlattr *); |
| 163 | int ovs_flow_metadata_from_nlattrs(u32 *priority, u16 *in_port, | 165 | int ovs_flow_metadata_from_nlattrs(u32 *priority, u32 *mark, u16 *in_port, |
| 164 | const struct nlattr *); | 166 | const struct nlattr *); |
| 165 | 167 | ||
| 166 | #define MAX_ACTIONS_BUFSIZE (16 * 1024) | 168 | #define MAX_ACTIONS_BUFSIZE (16 * 1024) |
diff --git a/net/openvswitch/vport-netdev.c b/net/openvswitch/vport-netdev.c index 3c1e58ba714b..a9327e2e48ce 100644 --- a/net/openvswitch/vport-netdev.c +++ b/net/openvswitch/vport-netdev.c | |||
| @@ -114,6 +114,15 @@ error: | |||
| 114 | return ERR_PTR(err); | 114 | return ERR_PTR(err); |
| 115 | } | 115 | } |
| 116 | 116 | ||
| 117 | static void free_port_rcu(struct rcu_head *rcu) | ||
| 118 | { | ||
| 119 | struct netdev_vport *netdev_vport = container_of(rcu, | ||
| 120 | struct netdev_vport, rcu); | ||
| 121 | |||
| 122 | dev_put(netdev_vport->dev); | ||
| 123 | ovs_vport_free(vport_from_priv(netdev_vport)); | ||
| 124 | } | ||
| 125 | |||
| 117 | static void netdev_destroy(struct vport *vport) | 126 | static void netdev_destroy(struct vport *vport) |
| 118 | { | 127 | { |
| 119 | struct netdev_vport *netdev_vport = netdev_vport_priv(vport); | 128 | struct netdev_vport *netdev_vport = netdev_vport_priv(vport); |
| @@ -122,10 +131,7 @@ static void netdev_destroy(struct vport *vport) | |||
| 122 | netdev_rx_handler_unregister(netdev_vport->dev); | 131 | netdev_rx_handler_unregister(netdev_vport->dev); |
| 123 | dev_set_promiscuity(netdev_vport->dev, -1); | 132 | dev_set_promiscuity(netdev_vport->dev, -1); |
| 124 | 133 | ||
| 125 | synchronize_rcu(); | 134 | call_rcu(&netdev_vport->rcu, free_port_rcu); |
| 126 | |||
| 127 | dev_put(netdev_vport->dev); | ||
| 128 | ovs_vport_free(vport); | ||
| 129 | } | 135 | } |
| 130 | 136 | ||
| 131 | const char *ovs_netdev_get_name(const struct vport *vport) | 137 | const char *ovs_netdev_get_name(const struct vport *vport) |
| @@ -158,7 +164,7 @@ static int netdev_send(struct vport *vport, struct sk_buff *skb) | |||
| 158 | 164 | ||
| 159 | if (unlikely(packet_length(skb) > mtu && !skb_is_gso(skb))) { | 165 | if (unlikely(packet_length(skb) > mtu && !skb_is_gso(skb))) { |
| 160 | net_warn_ratelimited("%s: dropped over-mtu packet: %d > %d\n", | 166 | net_warn_ratelimited("%s: dropped over-mtu packet: %d > %d\n", |
| 161 | ovs_dp_name(vport->dp), | 167 | netdev_vport->dev->name, |
| 162 | packet_length(skb), mtu); | 168 | packet_length(skb), mtu); |
| 163 | goto error; | 169 | goto error; |
| 164 | } | 170 | } |
diff --git a/net/openvswitch/vport-netdev.h b/net/openvswitch/vport-netdev.h index f7072a25c604..6478079b3417 100644 --- a/net/openvswitch/vport-netdev.h +++ b/net/openvswitch/vport-netdev.h | |||
| @@ -20,12 +20,15 @@ | |||
| 20 | #define VPORT_NETDEV_H 1 | 20 | #define VPORT_NETDEV_H 1 |
| 21 | 21 | ||
| 22 | #include <linux/netdevice.h> | 22 | #include <linux/netdevice.h> |
| 23 | #include <linux/rcupdate.h> | ||
| 23 | 24 | ||
| 24 | #include "vport.h" | 25 | #include "vport.h" |
| 25 | 26 | ||
| 26 | struct vport *ovs_netdev_get_vport(struct net_device *dev); | 27 | struct vport *ovs_netdev_get_vport(struct net_device *dev); |
| 27 | 28 | ||
| 28 | struct netdev_vport { | 29 | struct netdev_vport { |
| 30 | struct rcu_head rcu; | ||
| 31 | |||
| 29 | struct net_device *dev; | 32 | struct net_device *dev; |
| 30 | }; | 33 | }; |
| 31 | 34 | ||
diff --git a/net/openvswitch/vport.c b/net/openvswitch/vport.c index 03779e8a2622..70af0bedbac4 100644 --- a/net/openvswitch/vport.c +++ b/net/openvswitch/vport.c | |||
| @@ -333,8 +333,7 @@ void ovs_vport_receive(struct vport *vport, struct sk_buff *skb) | |||
| 333 | { | 333 | { |
| 334 | struct vport_percpu_stats *stats; | 334 | struct vport_percpu_stats *stats; |
| 335 | 335 | ||
| 336 | stats = per_cpu_ptr(vport->percpu_stats, smp_processor_id()); | 336 | stats = this_cpu_ptr(vport->percpu_stats); |
| 337 | |||
| 338 | u64_stats_update_begin(&stats->sync); | 337 | u64_stats_update_begin(&stats->sync); |
| 339 | stats->rx_packets++; | 338 | stats->rx_packets++; |
| 340 | stats->rx_bytes += skb->len; | 339 | stats->rx_bytes += skb->len; |
| @@ -359,7 +358,7 @@ int ovs_vport_send(struct vport *vport, struct sk_buff *skb) | |||
| 359 | if (likely(sent)) { | 358 | if (likely(sent)) { |
| 360 | struct vport_percpu_stats *stats; | 359 | struct vport_percpu_stats *stats; |
| 361 | 360 | ||
| 362 | stats = per_cpu_ptr(vport->percpu_stats, smp_processor_id()); | 361 | stats = this_cpu_ptr(vport->percpu_stats); |
| 363 | 362 | ||
| 364 | u64_stats_update_begin(&stats->sync); | 363 | u64_stats_update_begin(&stats->sync); |
| 365 | stats->tx_packets++; | 364 | stats->tx_packets++; |
diff --git a/net/sched/sch_qfq.c b/net/sched/sch_qfq.c index 9687fa1c2275..6ed37652a4c3 100644 --- a/net/sched/sch_qfq.c +++ b/net/sched/sch_qfq.c | |||
| @@ -1,7 +1,8 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * net/sched/sch_qfq.c Quick Fair Queueing Scheduler. | 2 | * net/sched/sch_qfq.c Quick Fair Queueing Plus Scheduler. |
| 3 | * | 3 | * |
| 4 | * Copyright (c) 2009 Fabio Checconi, Luigi Rizzo, and Paolo Valente. | 4 | * Copyright (c) 2009 Fabio Checconi, Luigi Rizzo, and Paolo Valente. |
| 5 | * Copyright (c) 2012 Paolo Valente. | ||
| 5 | * | 6 | * |
| 6 | * This program is free software; you can redistribute it and/or | 7 | * This program is free software; you can redistribute it and/or |
| 7 | * modify it under the terms of the GNU General Public License | 8 | * modify it under the terms of the GNU General Public License |
| @@ -19,12 +20,18 @@ | |||
| 19 | #include <net/pkt_cls.h> | 20 | #include <net/pkt_cls.h> |
| 20 | 21 | ||
| 21 | 22 | ||
| 22 | /* Quick Fair Queueing | 23 | /* Quick Fair Queueing Plus |
| 23 | =================== | 24 | ======================== |
| 24 | 25 | ||
| 25 | Sources: | 26 | Sources: |
| 26 | 27 | ||
| 27 | Fabio Checconi, Luigi Rizzo, and Paolo Valente: "QFQ: Efficient | 28 | [1] Paolo Valente, |
| 29 | "Reducing the Execution Time of Fair-Queueing Schedulers." | ||
| 30 | http://algo.ing.unimo.it/people/paolo/agg-sched/agg-sched.pdf | ||
| 31 | |||
| 32 | Sources for QFQ: | ||
| 33 | |||
| 34 | [2] Fabio Checconi, Luigi Rizzo, and Paolo Valente: "QFQ: Efficient | ||
| 28 | Packet Scheduling with Tight Bandwidth Distribution Guarantees." | 35 | Packet Scheduling with Tight Bandwidth Distribution Guarantees." |
| 29 | 36 | ||
| 30 | See also: | 37 | See also: |
| @@ -33,6 +40,20 @@ | |||
| 33 | 40 | ||
| 34 | /* | 41 | /* |
| 35 | 42 | ||
| 43 | QFQ+ divides classes into aggregates of at most MAX_AGG_CLASSES | ||
| 44 | classes. Each aggregate is timestamped with a virtual start time S | ||
| 45 | and a virtual finish time F, and scheduled according to its | ||
| 46 | timestamps. S and F are computed as a function of a system virtual | ||
| 47 | time function V. The classes within each aggregate are instead | ||
| 48 | scheduled with DRR. | ||
| 49 | |||
| 50 | To speed up operations, QFQ+ divides also aggregates into a limited | ||
| 51 | number of groups. Which group a class belongs to depends on the | ||
| 52 | ratio between the maximum packet length for the class and the weight | ||
| 53 | of the class. Groups have their own S and F. In the end, QFQ+ | ||
| 54 | schedules groups, then aggregates within groups, then classes within | ||
| 55 | aggregates. See [1] and [2] for a full description. | ||
| 56 | |||
| 36 | Virtual time computations. | 57 | Virtual time computations. |
| 37 | 58 | ||
| 38 | S, F and V are all computed in fixed point arithmetic with | 59 | S, F and V are all computed in fixed point arithmetic with |
| @@ -76,27 +97,28 @@ | |||
| 76 | #define QFQ_MAX_SLOTS 32 | 97 | #define QFQ_MAX_SLOTS 32 |
| 77 | 98 | ||
| 78 | /* | 99 | /* |
| 79 | * Shifts used for class<->group mapping. We allow class weights that are | 100 | * Shifts used for aggregate<->group mapping. We allow class weights that are |
| 80 | * in the range [1, 2^MAX_WSHIFT], and we try to map each class i to the | 101 | * in the range [1, 2^MAX_WSHIFT], and we try to map each aggregate i to the |
| 81 | * group with the smallest index that can support the L_i / r_i configured | 102 | * group with the smallest index that can support the L_i / r_i configured |
| 82 | * for the class. | 103 | * for the classes in the aggregate. |
| 83 | * | 104 | * |
| 84 | * grp->index is the index of the group; and grp->slot_shift | 105 | * grp->index is the index of the group; and grp->slot_shift |
| 85 | * is the shift for the corresponding (scaled) sigma_i. | 106 | * is the shift for the corresponding (scaled) sigma_i. |
| 86 | */ | 107 | */ |
| 87 | #define QFQ_MAX_INDEX 24 | 108 | #define QFQ_MAX_INDEX 24 |
| 88 | #define QFQ_MAX_WSHIFT 12 | 109 | #define QFQ_MAX_WSHIFT 10 |
| 89 | 110 | ||
| 90 | #define QFQ_MAX_WEIGHT (1<<QFQ_MAX_WSHIFT) | 111 | #define QFQ_MAX_WEIGHT (1<<QFQ_MAX_WSHIFT) /* see qfq_slot_insert */ |
| 91 | #define QFQ_MAX_WSUM (16*QFQ_MAX_WEIGHT) | 112 | #define QFQ_MAX_WSUM (64*QFQ_MAX_WEIGHT) |
| 92 | 113 | ||
| 93 | #define FRAC_BITS 30 /* fixed point arithmetic */ | 114 | #define FRAC_BITS 30 /* fixed point arithmetic */ |
| 94 | #define ONE_FP (1UL << FRAC_BITS) | 115 | #define ONE_FP (1UL << FRAC_BITS) |
| 95 | #define IWSUM (ONE_FP/QFQ_MAX_WSUM) | 116 | #define IWSUM (ONE_FP/QFQ_MAX_WSUM) |
| 96 | 117 | ||
| 97 | #define QFQ_MTU_SHIFT 16 /* to support TSO/GSO */ | 118 | #define QFQ_MTU_SHIFT 16 /* to support TSO/GSO */ |
| 98 | #define QFQ_MIN_SLOT_SHIFT (FRAC_BITS + QFQ_MTU_SHIFT - QFQ_MAX_INDEX) | 119 | #define QFQ_MIN_LMAX 512 /* see qfq_slot_insert */ |
| 99 | #define QFQ_MIN_LMAX 256 /* min possible lmax for a class */ | 120 | |
| 121 | #define QFQ_MAX_AGG_CLASSES 8 /* max num classes per aggregate allowed */ | ||
| 100 | 122 | ||
| 101 | /* | 123 | /* |
| 102 | * Possible group states. These values are used as indexes for the bitmaps | 124 | * Possible group states. These values are used as indexes for the bitmaps |
| @@ -106,6 +128,8 @@ enum qfq_state { ER, IR, EB, IB, QFQ_MAX_STATE }; | |||
| 106 | 128 | ||
| 107 | struct qfq_group; | 129 | struct qfq_group; |
| 108 | 130 | ||
| 131 | struct qfq_aggregate; | ||
| 132 | |||
| 109 | struct qfq_class { | 133 | struct qfq_class { |
| 110 | struct Qdisc_class_common common; | 134 | struct Qdisc_class_common common; |
| 111 | 135 | ||
| @@ -116,7 +140,12 @@ struct qfq_class { | |||
| 116 | struct gnet_stats_queue qstats; | 140 | struct gnet_stats_queue qstats; |
| 117 | struct gnet_stats_rate_est rate_est; | 141 | struct gnet_stats_rate_est rate_est; |
| 118 | struct Qdisc *qdisc; | 142 | struct Qdisc *qdisc; |
| 143 | struct list_head alist; /* Link for active-classes list. */ | ||
| 144 | struct qfq_aggregate *agg; /* Parent aggregate. */ | ||
| 145 | int deficit; /* DRR deficit counter. */ | ||
| 146 | }; | ||
| 119 | 147 | ||
| 148 | struct qfq_aggregate { | ||
| 120 | struct hlist_node next; /* Link for the slot list. */ | 149 | struct hlist_node next; /* Link for the slot list. */ |
| 121 | u64 S, F; /* flow timestamps (exact) */ | 150 | u64 S, F; /* flow timestamps (exact) */ |
| 122 | 151 | ||
| @@ -127,8 +156,18 @@ struct qfq_class { | |||
| 127 | struct qfq_group *grp; | 156 | struct qfq_group *grp; |
| 128 | 157 | ||
| 129 | /* these are copied from the flowset. */ | 158 | /* these are copied from the flowset. */ |
| 130 | u32 inv_w; /* ONE_FP/weight */ | 159 | u32 class_weight; /* Weight of each class in this aggregate. */ |
| 131 | u32 lmax; /* Max packet size for this flow. */ | 160 | /* Max pkt size for the classes in this aggregate, DRR quantum. */ |
| 161 | int lmax; | ||
| 162 | |||
| 163 | u32 inv_w; /* ONE_FP/(sum of weights of classes in aggr.). */ | ||
| 164 | u32 budgetmax; /* Max budget for this aggregate. */ | ||
| 165 | u32 initial_budget, budget; /* Initial and current budget. */ | ||
| 166 | |||
| 167 | int num_classes; /* Number of classes in this aggr. */ | ||
| 168 | struct list_head active; /* DRR queue of active classes. */ | ||
| 169 | |||
| 170 | struct hlist_node nonfull_next; /* See nonfull_aggs in qfq_sched. */ | ||
| 132 | }; | 171 | }; |
| 133 | 172 | ||
| 134 | struct qfq_group { | 173 | struct qfq_group { |
| @@ -138,7 +177,7 @@ struct qfq_group { | |||
| 138 | unsigned int front; /* Index of the front slot. */ | 177 | unsigned int front; /* Index of the front slot. */ |
| 139 | unsigned long full_slots; /* non-empty slots */ | 178 | unsigned long full_slots; /* non-empty slots */ |
| 140 | 179 | ||
| 141 | /* Array of RR lists of active classes. */ | 180 | /* Array of RR lists of active aggregates. */ |
| 142 | struct hlist_head slots[QFQ_MAX_SLOTS]; | 181 | struct hlist_head slots[QFQ_MAX_SLOTS]; |
| 143 | }; | 182 | }; |
| 144 | 183 | ||
| @@ -146,13 +185,28 @@ struct qfq_sched { | |||
| 146 | struct tcf_proto *filter_list; | 185 | struct tcf_proto *filter_list; |
| 147 | struct Qdisc_class_hash clhash; | 186 | struct Qdisc_class_hash clhash; |
| 148 | 187 | ||
| 149 | u64 V; /* Precise virtual time. */ | 188 | u64 oldV, V; /* Precise virtual times. */ |
| 150 | u32 wsum; /* weight sum */ | 189 | struct qfq_aggregate *in_serv_agg; /* Aggregate being served. */ |
| 190 | u32 num_active_agg; /* Num. of active aggregates */ | ||
| 191 | u32 wsum; /* weight sum */ | ||
| 151 | 192 | ||
| 152 | unsigned long bitmaps[QFQ_MAX_STATE]; /* Group bitmaps. */ | 193 | unsigned long bitmaps[QFQ_MAX_STATE]; /* Group bitmaps. */ |
| 153 | struct qfq_group groups[QFQ_MAX_INDEX + 1]; /* The groups. */ | 194 | struct qfq_group groups[QFQ_MAX_INDEX + 1]; /* The groups. */ |
| 195 | u32 min_slot_shift; /* Index of the group-0 bit in the bitmaps. */ | ||
| 196 | |||
| 197 | u32 max_agg_classes; /* Max number of classes per aggr. */ | ||
| 198 | struct hlist_head nonfull_aggs; /* Aggs with room for more classes. */ | ||
| 154 | }; | 199 | }; |
| 155 | 200 | ||
| 201 | /* | ||
| 202 | * Possible reasons why the timestamps of an aggregate are updated | ||
| 203 | * enqueue: the aggregate switches from idle to active and must scheduled | ||
| 204 | * for service | ||
| 205 | * requeue: the aggregate finishes its budget, so it stops being served and | ||
| 206 | * must be rescheduled for service | ||
| 207 | */ | ||
| 208 | enum update_reason {enqueue, requeue}; | ||
| 209 | |||
| 156 | static struct qfq_class *qfq_find_class(struct Qdisc *sch, u32 classid) | 210 | static struct qfq_class *qfq_find_class(struct Qdisc *sch, u32 classid) |
| 157 | { | 211 | { |
| 158 | struct qfq_sched *q = qdisc_priv(sch); | 212 | struct qfq_sched *q = qdisc_priv(sch); |
| @@ -182,18 +236,18 @@ static const struct nla_policy qfq_policy[TCA_QFQ_MAX + 1] = { | |||
| 182 | * index = log_2(maxlen/weight) but we need to apply the scaling. | 236 | * index = log_2(maxlen/weight) but we need to apply the scaling. |
| 183 | * This is used only once at flow creation. | 237 | * This is used only once at flow creation. |
| 184 | */ | 238 | */ |
| 185 | static int qfq_calc_index(u32 inv_w, unsigned int maxlen) | 239 | static int qfq_calc_index(u32 inv_w, unsigned int maxlen, u32 min_slot_shift) |
| 186 | { | 240 | { |
| 187 | u64 slot_size = (u64)maxlen * inv_w; | 241 | u64 slot_size = (u64)maxlen * inv_w; |
| 188 | unsigned long size_map; | 242 | unsigned long size_map; |
| 189 | int index = 0; | 243 | int index = 0; |
| 190 | 244 | ||
| 191 | size_map = slot_size >> QFQ_MIN_SLOT_SHIFT; | 245 | size_map = slot_size >> min_slot_shift; |
| 192 | if (!size_map) | 246 | if (!size_map) |
| 193 | goto out; | 247 | goto out; |
| 194 | 248 | ||
| 195 | index = __fls(size_map) + 1; /* basically a log_2 */ | 249 | index = __fls(size_map) + 1; /* basically a log_2 */ |
| 196 | index -= !(slot_size - (1ULL << (index + QFQ_MIN_SLOT_SHIFT - 1))); | 250 | index -= !(slot_size - (1ULL << (index + min_slot_shift - 1))); |
| 197 | 251 | ||
| 198 | if (index < 0) | 252 | if (index < 0) |
| 199 | index = 0; | 253 | index = 0; |
| @@ -204,66 +258,150 @@ out: | |||
| 204 | return index; | 258 | return index; |
| 205 | } | 259 | } |
| 206 | 260 | ||
| 207 | /* Length of the next packet (0 if the queue is empty). */ | 261 | static void qfq_deactivate_agg(struct qfq_sched *, struct qfq_aggregate *); |
| 208 | static unsigned int qdisc_peek_len(struct Qdisc *sch) | 262 | static void qfq_activate_agg(struct qfq_sched *, struct qfq_aggregate *, |
| 263 | enum update_reason); | ||
| 264 | |||
| 265 | static void qfq_init_agg(struct qfq_sched *q, struct qfq_aggregate *agg, | ||
| 266 | u32 lmax, u32 weight) | ||
| 209 | { | 267 | { |
| 210 | struct sk_buff *skb; | 268 | INIT_LIST_HEAD(&agg->active); |
| 269 | hlist_add_head(&agg->nonfull_next, &q->nonfull_aggs); | ||
| 270 | |||
| 271 | agg->lmax = lmax; | ||
| 272 | agg->class_weight = weight; | ||
| 273 | } | ||
| 274 | |||
| 275 | static struct qfq_aggregate *qfq_find_agg(struct qfq_sched *q, | ||
| 276 | u32 lmax, u32 weight) | ||
| 277 | { | ||
| 278 | struct qfq_aggregate *agg; | ||
| 279 | struct hlist_node *n; | ||
| 280 | |||
| 281 | hlist_for_each_entry(agg, n, &q->nonfull_aggs, nonfull_next) | ||
| 282 | if (agg->lmax == lmax && agg->class_weight == weight) | ||
| 283 | return agg; | ||
| 284 | |||
| 285 | return NULL; | ||
| 286 | } | ||
| 287 | |||
| 211 | 288 | ||
| 212 | skb = sch->ops->peek(sch); | 289 | /* Update aggregate as a function of the new number of classes. */ |
| 213 | return skb ? qdisc_pkt_len(skb) : 0; | 290 | static void qfq_update_agg(struct qfq_sched *q, struct qfq_aggregate *agg, |
| 291 | int new_num_classes) | ||
| 292 | { | ||
| 293 | u32 new_agg_weight; | ||
| 294 | |||
| 295 | if (new_num_classes == q->max_agg_classes) | ||
| 296 | hlist_del_init(&agg->nonfull_next); | ||
| 297 | |||
| 298 | if (agg->num_classes > new_num_classes && | ||
| 299 | new_num_classes == q->max_agg_classes - 1) /* agg no more full */ | ||
| 300 | hlist_add_head(&agg->nonfull_next, &q->nonfull_aggs); | ||
| 301 | |||
| 302 | agg->budgetmax = new_num_classes * agg->lmax; | ||
| 303 | new_agg_weight = agg->class_weight * new_num_classes; | ||
| 304 | agg->inv_w = ONE_FP/new_agg_weight; | ||
| 305 | |||
| 306 | if (agg->grp == NULL) { | ||
| 307 | int i = qfq_calc_index(agg->inv_w, agg->budgetmax, | ||
| 308 | q->min_slot_shift); | ||
| 309 | agg->grp = &q->groups[i]; | ||
| 310 | } | ||
| 311 | |||
| 312 | q->wsum += | ||
| 313 | (int) agg->class_weight * (new_num_classes - agg->num_classes); | ||
| 314 | |||
| 315 | agg->num_classes = new_num_classes; | ||
| 316 | } | ||
| 317 | |||
| 318 | /* Add class to aggregate. */ | ||
| 319 | static void qfq_add_to_agg(struct qfq_sched *q, | ||
| 320 | struct qfq_aggregate *agg, | ||
| 321 | struct qfq_class *cl) | ||
| 322 | { | ||
| 323 | cl->agg = agg; | ||
| 324 | |||
| 325 | qfq_update_agg(q, agg, agg->num_classes+1); | ||
| 326 | if (cl->qdisc->q.qlen > 0) { /* adding an active class */ | ||
| 327 | list_add_tail(&cl->alist, &agg->active); | ||
| 328 | if (list_first_entry(&agg->active, struct qfq_class, alist) == | ||
| 329 | cl && q->in_serv_agg != agg) /* agg was inactive */ | ||
| 330 | qfq_activate_agg(q, agg, enqueue); /* schedule agg */ | ||
| 331 | } | ||
| 214 | } | 332 | } |
| 215 | 333 | ||
| 216 | static void qfq_deactivate_class(struct qfq_sched *, struct qfq_class *); | 334 | static struct qfq_aggregate *qfq_choose_next_agg(struct qfq_sched *); |
| 217 | static void qfq_activate_class(struct qfq_sched *q, struct qfq_class *cl, | ||
| 218 | unsigned int len); | ||
| 219 | 335 | ||
| 220 | static void qfq_update_class_params(struct qfq_sched *q, struct qfq_class *cl, | 336 | static void qfq_destroy_agg(struct qfq_sched *q, struct qfq_aggregate *agg) |
| 221 | u32 lmax, u32 inv_w, int delta_w) | ||
| 222 | { | 337 | { |
| 223 | int i; | 338 | if (!hlist_unhashed(&agg->nonfull_next)) |
| 339 | hlist_del_init(&agg->nonfull_next); | ||
| 340 | if (q->in_serv_agg == agg) | ||
| 341 | q->in_serv_agg = qfq_choose_next_agg(q); | ||
| 342 | kfree(agg); | ||
| 343 | } | ||
| 224 | 344 | ||
| 225 | /* update qfq-specific data */ | 345 | /* Deschedule class from within its parent aggregate. */ |
| 226 | cl->lmax = lmax; | 346 | static void qfq_deactivate_class(struct qfq_sched *q, struct qfq_class *cl) |
| 227 | cl->inv_w = inv_w; | 347 | { |
| 228 | i = qfq_calc_index(cl->inv_w, cl->lmax); | 348 | struct qfq_aggregate *agg = cl->agg; |
| 229 | 349 | ||
| 230 | cl->grp = &q->groups[i]; | ||
| 231 | 350 | ||
| 232 | q->wsum += delta_w; | 351 | list_del(&cl->alist); /* remove from RR queue of the aggregate */ |
| 352 | if (list_empty(&agg->active)) /* agg is now inactive */ | ||
| 353 | qfq_deactivate_agg(q, agg); | ||
| 233 | } | 354 | } |
| 234 | 355 | ||
| 235 | static void qfq_update_reactivate_class(struct qfq_sched *q, | 356 | /* Remove class from its parent aggregate. */ |
| 236 | struct qfq_class *cl, | 357 | static void qfq_rm_from_agg(struct qfq_sched *q, struct qfq_class *cl) |
| 237 | u32 inv_w, u32 lmax, int delta_w) | ||
| 238 | { | 358 | { |
| 239 | bool need_reactivation = false; | 359 | struct qfq_aggregate *agg = cl->agg; |
| 240 | int i = qfq_calc_index(inv_w, lmax); | ||
| 241 | 360 | ||
| 242 | if (&q->groups[i] != cl->grp && cl->qdisc->q.qlen > 0) { | 361 | cl->agg = NULL; |
| 243 | /* | 362 | if (agg->num_classes == 1) { /* agg being emptied, destroy it */ |
| 244 | * shift cl->F back, to not charge the | 363 | qfq_destroy_agg(q, agg); |
| 245 | * class for the not-yet-served head | 364 | return; |
| 246 | * packet | ||
| 247 | */ | ||
| 248 | cl->F = cl->S; | ||
| 249 | /* remove class from its slot in the old group */ | ||
| 250 | qfq_deactivate_class(q, cl); | ||
| 251 | need_reactivation = true; | ||
| 252 | } | 365 | } |
| 366 | qfq_update_agg(q, agg, agg->num_classes-1); | ||
| 367 | } | ||
| 253 | 368 | ||
| 254 | qfq_update_class_params(q, cl, lmax, inv_w, delta_w); | 369 | /* Deschedule class and remove it from its parent aggregate. */ |
| 370 | static void qfq_deact_rm_from_agg(struct qfq_sched *q, struct qfq_class *cl) | ||
| 371 | { | ||
| 372 | if (cl->qdisc->q.qlen > 0) /* class is active */ | ||
| 373 | qfq_deactivate_class(q, cl); | ||
| 255 | 374 | ||
| 256 | if (need_reactivation) /* activate in new group */ | 375 | qfq_rm_from_agg(q, cl); |
| 257 | qfq_activate_class(q, cl, qdisc_peek_len(cl->qdisc)); | ||
| 258 | } | 376 | } |
| 259 | 377 | ||
| 378 | /* Move class to a new aggregate, matching the new class weight and/or lmax */ | ||
| 379 | static int qfq_change_agg(struct Qdisc *sch, struct qfq_class *cl, u32 weight, | ||
| 380 | u32 lmax) | ||
| 381 | { | ||
| 382 | struct qfq_sched *q = qdisc_priv(sch); | ||
| 383 | struct qfq_aggregate *new_agg = qfq_find_agg(q, lmax, weight); | ||
| 384 | |||
| 385 | if (new_agg == NULL) { /* create new aggregate */ | ||
| 386 | new_agg = kzalloc(sizeof(*new_agg), GFP_ATOMIC); | ||
| 387 | if (new_agg == NULL) | ||
| 388 | return -ENOBUFS; | ||
| 389 | qfq_init_agg(q, new_agg, lmax, weight); | ||
| 390 | } | ||
| 391 | qfq_deact_rm_from_agg(q, cl); | ||
| 392 | qfq_add_to_agg(q, new_agg, cl); | ||
| 393 | |||
| 394 | return 0; | ||
| 395 | } | ||
| 260 | 396 | ||
| 261 | static int qfq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, | 397 | static int qfq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, |
| 262 | struct nlattr **tca, unsigned long *arg) | 398 | struct nlattr **tca, unsigned long *arg) |
| 263 | { | 399 | { |
| 264 | struct qfq_sched *q = qdisc_priv(sch); | 400 | struct qfq_sched *q = qdisc_priv(sch); |
| 265 | struct qfq_class *cl = (struct qfq_class *)*arg; | 401 | struct qfq_class *cl = (struct qfq_class *)*arg; |
| 402 | bool existing = false; | ||
| 266 | struct nlattr *tb[TCA_QFQ_MAX + 1]; | 403 | struct nlattr *tb[TCA_QFQ_MAX + 1]; |
| 404 | struct qfq_aggregate *new_agg = NULL; | ||
| 267 | u32 weight, lmax, inv_w; | 405 | u32 weight, lmax, inv_w; |
| 268 | int err; | 406 | int err; |
| 269 | int delta_w; | 407 | int delta_w; |
| @@ -286,15 +424,6 @@ static int qfq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, | |||
| 286 | } else | 424 | } else |
| 287 | weight = 1; | 425 | weight = 1; |
| 288 | 426 | ||
| 289 | inv_w = ONE_FP / weight; | ||
| 290 | weight = ONE_FP / inv_w; | ||
| 291 | delta_w = weight - (cl ? ONE_FP / cl->inv_w : 0); | ||
| 292 | if (q->wsum + delta_w > QFQ_MAX_WSUM) { | ||
| 293 | pr_notice("qfq: total weight out of range (%u + %u)\n", | ||
| 294 | delta_w, q->wsum); | ||
| 295 | return -EINVAL; | ||
| 296 | } | ||
| 297 | |||
| 298 | if (tb[TCA_QFQ_LMAX]) { | 427 | if (tb[TCA_QFQ_LMAX]) { |
| 299 | lmax = nla_get_u32(tb[TCA_QFQ_LMAX]); | 428 | lmax = nla_get_u32(tb[TCA_QFQ_LMAX]); |
| 300 | if (lmax < QFQ_MIN_LMAX || lmax > (1UL << QFQ_MTU_SHIFT)) { | 429 | if (lmax < QFQ_MIN_LMAX || lmax > (1UL << QFQ_MTU_SHIFT)) { |
| @@ -304,7 +433,23 @@ static int qfq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, | |||
| 304 | } else | 433 | } else |
| 305 | lmax = psched_mtu(qdisc_dev(sch)); | 434 | lmax = psched_mtu(qdisc_dev(sch)); |
| 306 | 435 | ||
| 307 | if (cl != NULL) { | 436 | inv_w = ONE_FP / weight; |
| 437 | weight = ONE_FP / inv_w; | ||
| 438 | |||
| 439 | if (cl != NULL && | ||
| 440 | lmax == cl->agg->lmax && | ||
| 441 | weight == cl->agg->class_weight) | ||
| 442 | return 0; /* nothing to change */ | ||
| 443 | |||
| 444 | delta_w = weight - (cl ? cl->agg->class_weight : 0); | ||
| 445 | |||
| 446 | if (q->wsum + delta_w > QFQ_MAX_WSUM) { | ||
| 447 | pr_notice("qfq: total weight out of range (%d + %u)\n", | ||
| 448 | delta_w, q->wsum); | ||
| 449 | return -EINVAL; | ||
| 450 | } | ||
| 451 | |||
| 452 | if (cl != NULL) { /* modify existing class */ | ||
| 308 | if (tca[TCA_RATE]) { | 453 | if (tca[TCA_RATE]) { |
| 309 | err = gen_replace_estimator(&cl->bstats, &cl->rate_est, | 454 | err = gen_replace_estimator(&cl->bstats, &cl->rate_est, |
| 310 | qdisc_root_sleeping_lock(sch), | 455 | qdisc_root_sleeping_lock(sch), |
| @@ -312,25 +457,18 @@ static int qfq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, | |||
| 312 | if (err) | 457 | if (err) |
| 313 | return err; | 458 | return err; |
| 314 | } | 459 | } |
| 315 | 460 | existing = true; | |
| 316 | if (lmax == cl->lmax && inv_w == cl->inv_w) | 461 | goto set_change_agg; |
| 317 | return 0; /* nothing to update */ | ||
| 318 | |||
| 319 | sch_tree_lock(sch); | ||
| 320 | qfq_update_reactivate_class(q, cl, inv_w, lmax, delta_w); | ||
| 321 | sch_tree_unlock(sch); | ||
| 322 | |||
| 323 | return 0; | ||
| 324 | } | 462 | } |
| 325 | 463 | ||
| 464 | /* create and init new class */ | ||
| 326 | cl = kzalloc(sizeof(struct qfq_class), GFP_KERNEL); | 465 | cl = kzalloc(sizeof(struct qfq_class), GFP_KERNEL); |
| 327 | if (cl == NULL) | 466 | if (cl == NULL) |
| 328 | return -ENOBUFS; | 467 | return -ENOBUFS; |
| 329 | 468 | ||
| 330 | cl->refcnt = 1; | 469 | cl->refcnt = 1; |
| 331 | cl->common.classid = classid; | 470 | cl->common.classid = classid; |
| 332 | 471 | cl->deficit = lmax; | |
| 333 | qfq_update_class_params(q, cl, lmax, inv_w, delta_w); | ||
| 334 | 472 | ||
| 335 | cl->qdisc = qdisc_create_dflt(sch->dev_queue, | 473 | cl->qdisc = qdisc_create_dflt(sch->dev_queue, |
| 336 | &pfifo_qdisc_ops, classid); | 474 | &pfifo_qdisc_ops, classid); |
| @@ -341,11 +479,8 @@ static int qfq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, | |||
| 341 | err = gen_new_estimator(&cl->bstats, &cl->rate_est, | 479 | err = gen_new_estimator(&cl->bstats, &cl->rate_est, |
| 342 | qdisc_root_sleeping_lock(sch), | 480 | qdisc_root_sleeping_lock(sch), |
| 343 | tca[TCA_RATE]); | 481 | tca[TCA_RATE]); |
| 344 | if (err) { | 482 | if (err) |
| 345 | qdisc_destroy(cl->qdisc); | 483 | goto destroy_class; |
| 346 | kfree(cl); | ||
| 347 | return err; | ||
| 348 | } | ||
| 349 | } | 484 | } |
| 350 | 485 | ||
| 351 | sch_tree_lock(sch); | 486 | sch_tree_lock(sch); |
| @@ -354,19 +489,39 @@ static int qfq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, | |||
| 354 | 489 | ||
| 355 | qdisc_class_hash_grow(sch, &q->clhash); | 490 | qdisc_class_hash_grow(sch, &q->clhash); |
| 356 | 491 | ||
| 492 | set_change_agg: | ||
| 493 | sch_tree_lock(sch); | ||
| 494 | new_agg = qfq_find_agg(q, lmax, weight); | ||
| 495 | if (new_agg == NULL) { /* create new aggregate */ | ||
| 496 | sch_tree_unlock(sch); | ||
| 497 | new_agg = kzalloc(sizeof(*new_agg), GFP_KERNEL); | ||
| 498 | if (new_agg == NULL) { | ||
| 499 | err = -ENOBUFS; | ||
| 500 | gen_kill_estimator(&cl->bstats, &cl->rate_est); | ||
| 501 | goto destroy_class; | ||
| 502 | } | ||
| 503 | sch_tree_lock(sch); | ||
| 504 | qfq_init_agg(q, new_agg, lmax, weight); | ||
| 505 | } | ||
| 506 | if (existing) | ||
| 507 | qfq_deact_rm_from_agg(q, cl); | ||
| 508 | qfq_add_to_agg(q, new_agg, cl); | ||
| 509 | sch_tree_unlock(sch); | ||
| 510 | |||
| 357 | *arg = (unsigned long)cl; | 511 | *arg = (unsigned long)cl; |
| 358 | return 0; | 512 | return 0; |
| 513 | |||
| 514 | destroy_class: | ||
| 515 | qdisc_destroy(cl->qdisc); | ||
| 516 | kfree(cl); | ||
| 517 | return err; | ||
| 359 | } | 518 | } |
| 360 | 519 | ||
| 361 | static void qfq_destroy_class(struct Qdisc *sch, struct qfq_class *cl) | 520 | static void qfq_destroy_class(struct Qdisc *sch, struct qfq_class *cl) |
| 362 | { | 521 | { |
| 363 | struct qfq_sched *q = qdisc_priv(sch); | 522 | struct qfq_sched *q = qdisc_priv(sch); |
| 364 | 523 | ||
| 365 | if (cl->inv_w) { | 524 | qfq_rm_from_agg(q, cl); |
| 366 | q->wsum -= ONE_FP / cl->inv_w; | ||
| 367 | cl->inv_w = 0; | ||
| 368 | } | ||
| 369 | |||
| 370 | gen_kill_estimator(&cl->bstats, &cl->rate_est); | 525 | gen_kill_estimator(&cl->bstats, &cl->rate_est); |
| 371 | qdisc_destroy(cl->qdisc); | 526 | qdisc_destroy(cl->qdisc); |
| 372 | kfree(cl); | 527 | kfree(cl); |
| @@ -481,8 +636,8 @@ static int qfq_dump_class(struct Qdisc *sch, unsigned long arg, | |||
| 481 | nest = nla_nest_start(skb, TCA_OPTIONS); | 636 | nest = nla_nest_start(skb, TCA_OPTIONS); |
| 482 | if (nest == NULL) | 637 | if (nest == NULL) |
| 483 | goto nla_put_failure; | 638 | goto nla_put_failure; |
| 484 | if (nla_put_u32(skb, TCA_QFQ_WEIGHT, ONE_FP/cl->inv_w) || | 639 | if (nla_put_u32(skb, TCA_QFQ_WEIGHT, cl->agg->class_weight) || |
| 485 | nla_put_u32(skb, TCA_QFQ_LMAX, cl->lmax)) | 640 | nla_put_u32(skb, TCA_QFQ_LMAX, cl->agg->lmax)) |
| 486 | goto nla_put_failure; | 641 | goto nla_put_failure; |
| 487 | return nla_nest_end(skb, nest); | 642 | return nla_nest_end(skb, nest); |
| 488 | 643 | ||
| @@ -500,8 +655,8 @@ static int qfq_dump_class_stats(struct Qdisc *sch, unsigned long arg, | |||
| 500 | memset(&xstats, 0, sizeof(xstats)); | 655 | memset(&xstats, 0, sizeof(xstats)); |
| 501 | cl->qdisc->qstats.qlen = cl->qdisc->q.qlen; | 656 | cl->qdisc->qstats.qlen = cl->qdisc->q.qlen; |
| 502 | 657 | ||
| 503 | xstats.weight = ONE_FP/cl->inv_w; | 658 | xstats.weight = cl->agg->class_weight; |
| 504 | xstats.lmax = cl->lmax; | 659 | xstats.lmax = cl->agg->lmax; |
| 505 | 660 | ||
| 506 | if (gnet_stats_copy_basic(d, &cl->bstats) < 0 || | 661 | if (gnet_stats_copy_basic(d, &cl->bstats) < 0 || |
| 507 | gnet_stats_copy_rate_est(d, &cl->bstats, &cl->rate_est) < 0 || | 662 | gnet_stats_copy_rate_est(d, &cl->bstats, &cl->rate_est) < 0 || |
| @@ -652,16 +807,16 @@ static void qfq_unblock_groups(struct qfq_sched *q, int index, u64 old_F) | |||
| 652 | * perhaps | 807 | * perhaps |
| 653 | * | 808 | * |
| 654 | old_V ^= q->V; | 809 | old_V ^= q->V; |
| 655 | old_V >>= QFQ_MIN_SLOT_SHIFT; | 810 | old_V >>= q->min_slot_shift; |
| 656 | if (old_V) { | 811 | if (old_V) { |
| 657 | ... | 812 | ... |
| 658 | } | 813 | } |
| 659 | * | 814 | * |
| 660 | */ | 815 | */ |
| 661 | static void qfq_make_eligible(struct qfq_sched *q, u64 old_V) | 816 | static void qfq_make_eligible(struct qfq_sched *q) |
| 662 | { | 817 | { |
| 663 | unsigned long vslot = q->V >> QFQ_MIN_SLOT_SHIFT; | 818 | unsigned long vslot = q->V >> q->min_slot_shift; |
| 664 | unsigned long old_vslot = old_V >> QFQ_MIN_SLOT_SHIFT; | 819 | unsigned long old_vslot = q->oldV >> q->min_slot_shift; |
| 665 | 820 | ||
| 666 | if (vslot != old_vslot) { | 821 | if (vslot != old_vslot) { |
| 667 | unsigned long mask = (1UL << fls(vslot ^ old_vslot)) - 1; | 822 | unsigned long mask = (1UL << fls(vslot ^ old_vslot)) - 1; |
| @@ -672,34 +827,38 @@ static void qfq_make_eligible(struct qfq_sched *q, u64 old_V) | |||
| 672 | 827 | ||
| 673 | 828 | ||
| 674 | /* | 829 | /* |
| 675 | * If the weight and lmax (max_pkt_size) of the classes do not change, | 830 | * The index of the slot in which the aggregate is to be inserted must |
| 676 | * then QFQ guarantees that the slot index is never higher than | 831 | * not be higher than QFQ_MAX_SLOTS-2. There is a '-2' and not a '-1' |
| 677 | * 2 + ((1<<QFQ_MTU_SHIFT)/QFQ_MIN_LMAX) * (QFQ_MAX_WEIGHT/QFQ_MAX_WSUM). | 832 | * because the start time of the group may be moved backward by one |
| 833 | * slot after the aggregate has been inserted, and this would cause | ||
| 834 | * non-empty slots to be right-shifted by one position. | ||
| 678 | * | 835 | * |
| 679 | * With the current values of the above constants, the index is | 836 | * If the weight and lmax (max_pkt_size) of the classes do not change, |
| 680 | * then guaranteed to never be higher than 2 + 256 * (1 / 16) = 18. | 837 | * then QFQ+ does meet the above contraint according to the current |
| 838 | * values of its parameters. In fact, if the weight and lmax of the | ||
| 839 | * classes do not change, then, from the theory, QFQ+ guarantees that | ||
| 840 | * the slot index is never higher than | ||
| 841 | * 2 + QFQ_MAX_AGG_CLASSES * ((1<<QFQ_MTU_SHIFT)/QFQ_MIN_LMAX) * | ||
| 842 | * (QFQ_MAX_WEIGHT/QFQ_MAX_WSUM) = 2 + 8 * 128 * (1 / 64) = 18 | ||
| 681 | * | 843 | * |
| 682 | * When the weight of a class is increased or the lmax of the class is | 844 | * When the weight of a class is increased or the lmax of the class is |
| 683 | * decreased, a new class with smaller slot size may happen to be | 845 | * decreased, a new aggregate with smaller slot size than the original |
| 684 | * activated. The activation of this class should be properly delayed | 846 | * parent aggregate of the class may happen to be activated. The |
| 685 | * to when the service of the class has finished in the ideal system | 847 | * activation of this aggregate should be properly delayed to when the |
| 686 | * tracked by QFQ. If the activation of the class is not delayed to | 848 | * service of the class has finished in the ideal system tracked by |
| 687 | * this reference time instant, then this class may be unjustly served | 849 | * QFQ+. If the activation of the aggregate is not delayed to this |
| 688 | * before other classes waiting for service. This may cause | 850 | * reference time instant, then this aggregate may be unjustly served |
| 689 | * (unfrequently) the above bound to the slot index to be violated for | 851 | * before other aggregates waiting for service. This may cause the |
| 690 | * some of these unlucky classes. | 852 | * above bound to the slot index to be violated for some of these |
| 853 | * unlucky aggregates. | ||
| 691 | * | 854 | * |
| 692 | * Instead of delaying the activation of the new class, which is quite | 855 | * Instead of delaying the activation of the new aggregate, which is |
| 693 | * complex, the following inaccurate but simple solution is used: if | 856 | * quite complex, the following inaccurate but simple solution is used: |
| 694 | * the slot index is higher than QFQ_MAX_SLOTS-2, then the timestamps | 857 | * if the slot index is higher than QFQ_MAX_SLOTS-2, then the |
| 695 | * of the class are shifted backward so as to let the slot index | 858 | * timestamps of the aggregate are shifted backward so as to let the |
| 696 | * become equal to QFQ_MAX_SLOTS-2. This threshold is used because, if | 859 | * slot index become equal to QFQ_MAX_SLOTS-2. |
| 697 | * the slot index is above it, then the data structure implementing | ||
| 698 | * the bucket list either gets immediately corrupted or may get | ||
| 699 | * corrupted on a possible next packet arrival that causes the start | ||
| 700 | * time of the group to be shifted backward. | ||
| 701 | */ | 860 | */ |
| 702 | static void qfq_slot_insert(struct qfq_group *grp, struct qfq_class *cl, | 861 | static void qfq_slot_insert(struct qfq_group *grp, struct qfq_aggregate *agg, |
| 703 | u64 roundedS) | 862 | u64 roundedS) |
| 704 | { | 863 | { |
| 705 | u64 slot = (roundedS - grp->S) >> grp->slot_shift; | 864 | u64 slot = (roundedS - grp->S) >> grp->slot_shift; |
| @@ -708,22 +867,22 @@ static void qfq_slot_insert(struct qfq_group *grp, struct qfq_class *cl, | |||
| 708 | if (unlikely(slot > QFQ_MAX_SLOTS - 2)) { | 867 | if (unlikely(slot > QFQ_MAX_SLOTS - 2)) { |
| 709 | u64 deltaS = roundedS - grp->S - | 868 | u64 deltaS = roundedS - grp->S - |
| 710 | ((u64)(QFQ_MAX_SLOTS - 2)<<grp->slot_shift); | 869 | ((u64)(QFQ_MAX_SLOTS - 2)<<grp->slot_shift); |
| 711 | cl->S -= deltaS; | 870 | agg->S -= deltaS; |
| 712 | cl->F -= deltaS; | 871 | agg->F -= deltaS; |
| 713 | slot = QFQ_MAX_SLOTS - 2; | 872 | slot = QFQ_MAX_SLOTS - 2; |
| 714 | } | 873 | } |
| 715 | 874 | ||
| 716 | i = (grp->front + slot) % QFQ_MAX_SLOTS; | 875 | i = (grp->front + slot) % QFQ_MAX_SLOTS; |
| 717 | 876 | ||
| 718 | hlist_add_head(&cl->next, &grp->slots[i]); | 877 | hlist_add_head(&agg->next, &grp->slots[i]); |
| 719 | __set_bit(slot, &grp->full_slots); | 878 | __set_bit(slot, &grp->full_slots); |
| 720 | } | 879 | } |
| 721 | 880 | ||
| 722 | /* Maybe introduce hlist_first_entry?? */ | 881 | /* Maybe introduce hlist_first_entry?? */ |
| 723 | static struct qfq_class *qfq_slot_head(struct qfq_group *grp) | 882 | static struct qfq_aggregate *qfq_slot_head(struct qfq_group *grp) |
| 724 | { | 883 | { |
| 725 | return hlist_entry(grp->slots[grp->front].first, | 884 | return hlist_entry(grp->slots[grp->front].first, |
| 726 | struct qfq_class, next); | 885 | struct qfq_aggregate, next); |
| 727 | } | 886 | } |
| 728 | 887 | ||
| 729 | /* | 888 | /* |
| @@ -731,20 +890,20 @@ static struct qfq_class *qfq_slot_head(struct qfq_group *grp) | |||
| 731 | */ | 890 | */ |
| 732 | static void qfq_front_slot_remove(struct qfq_group *grp) | 891 | static void qfq_front_slot_remove(struct qfq_group *grp) |
| 733 | { | 892 | { |
| 734 | struct qfq_class *cl = qfq_slot_head(grp); | 893 | struct qfq_aggregate *agg = qfq_slot_head(grp); |
| 735 | 894 | ||
| 736 | BUG_ON(!cl); | 895 | BUG_ON(!agg); |
| 737 | hlist_del(&cl->next); | 896 | hlist_del(&agg->next); |
| 738 | if (hlist_empty(&grp->slots[grp->front])) | 897 | if (hlist_empty(&grp->slots[grp->front])) |
| 739 | __clear_bit(0, &grp->full_slots); | 898 | __clear_bit(0, &grp->full_slots); |
| 740 | } | 899 | } |
| 741 | 900 | ||
| 742 | /* | 901 | /* |
| 743 | * Returns the first full queue in a group. As a side effect, | 902 | * Returns the first aggregate in the first non-empty bucket of the |
| 744 | * adjust the bucket list so the first non-empty bucket is at | 903 | * group. As a side effect, adjusts the bucket list so the first |
| 745 | * position 0 in full_slots. | 904 | * non-empty bucket is at position 0 in full_slots. |
| 746 | */ | 905 | */ |
| 747 | static struct qfq_class *qfq_slot_scan(struct qfq_group *grp) | 906 | static struct qfq_aggregate *qfq_slot_scan(struct qfq_group *grp) |
| 748 | { | 907 | { |
| 749 | unsigned int i; | 908 | unsigned int i; |
| 750 | 909 | ||
| @@ -780,7 +939,7 @@ static void qfq_slot_rotate(struct qfq_group *grp, u64 roundedS) | |||
| 780 | grp->front = (grp->front - i) % QFQ_MAX_SLOTS; | 939 | grp->front = (grp->front - i) % QFQ_MAX_SLOTS; |
| 781 | } | 940 | } |
| 782 | 941 | ||
| 783 | static void qfq_update_eligible(struct qfq_sched *q, u64 old_V) | 942 | static void qfq_update_eligible(struct qfq_sched *q) |
| 784 | { | 943 | { |
| 785 | struct qfq_group *grp; | 944 | struct qfq_group *grp; |
| 786 | unsigned long ineligible; | 945 | unsigned long ineligible; |
| @@ -792,137 +951,226 @@ static void qfq_update_eligible(struct qfq_sched *q, u64 old_V) | |||
| 792 | if (qfq_gt(grp->S, q->V)) | 951 | if (qfq_gt(grp->S, q->V)) |
| 793 | q->V = grp->S; | 952 | q->V = grp->S; |
| 794 | } | 953 | } |
| 795 | qfq_make_eligible(q, old_V); | 954 | qfq_make_eligible(q); |
| 796 | } | 955 | } |
| 797 | } | 956 | } |
| 798 | 957 | ||
| 799 | /* | 958 | /* Dequeue head packet of the head class in the DRR queue of the aggregate. */ |
| 800 | * Updates the class, returns true if also the group needs to be updated. | 959 | static void agg_dequeue(struct qfq_aggregate *agg, |
| 801 | */ | 960 | struct qfq_class *cl, unsigned int len) |
| 802 | static bool qfq_update_class(struct qfq_group *grp, struct qfq_class *cl) | ||
| 803 | { | 961 | { |
| 804 | unsigned int len = qdisc_peek_len(cl->qdisc); | 962 | qdisc_dequeue_peeked(cl->qdisc); |
| 805 | 963 | ||
| 806 | cl->S = cl->F; | 964 | cl->deficit -= (int) len; |
| 807 | if (!len) | ||
| 808 | qfq_front_slot_remove(grp); /* queue is empty */ | ||
| 809 | else { | ||
| 810 | u64 roundedS; | ||
| 811 | 965 | ||
| 812 | cl->F = cl->S + (u64)len * cl->inv_w; | 966 | if (cl->qdisc->q.qlen == 0) /* no more packets, remove from list */ |
| 813 | roundedS = qfq_round_down(cl->S, grp->slot_shift); | 967 | list_del(&cl->alist); |
| 814 | if (roundedS == grp->S) | 968 | else if (cl->deficit < qdisc_pkt_len(cl->qdisc->ops->peek(cl->qdisc))) { |
| 815 | return false; | 969 | cl->deficit += agg->lmax; |
| 816 | 970 | list_move_tail(&cl->alist, &agg->active); | |
| 817 | qfq_front_slot_remove(grp); | ||
| 818 | qfq_slot_insert(grp, cl, roundedS); | ||
| 819 | } | 971 | } |
| 972 | } | ||
| 973 | |||
| 974 | static inline struct sk_buff *qfq_peek_skb(struct qfq_aggregate *agg, | ||
| 975 | struct qfq_class **cl, | ||
| 976 | unsigned int *len) | ||
| 977 | { | ||
| 978 | struct sk_buff *skb; | ||
| 820 | 979 | ||
| 821 | return true; | 980 | *cl = list_first_entry(&agg->active, struct qfq_class, alist); |
| 981 | skb = (*cl)->qdisc->ops->peek((*cl)->qdisc); | ||
| 982 | if (skb == NULL) | ||
| 983 | WARN_ONCE(1, "qfq_dequeue: non-workconserving leaf\n"); | ||
| 984 | else | ||
| 985 | *len = qdisc_pkt_len(skb); | ||
| 986 | |||
| 987 | return skb; | ||
| 988 | } | ||
| 989 | |||
| 990 | /* Update F according to the actual service received by the aggregate. */ | ||
| 991 | static inline void charge_actual_service(struct qfq_aggregate *agg) | ||
| 992 | { | ||
| 993 | /* compute the service received by the aggregate */ | ||
| 994 | u32 service_received = agg->initial_budget - agg->budget; | ||
| 995 | |||
| 996 | agg->F = agg->S + (u64)service_received * agg->inv_w; | ||
| 822 | } | 997 | } |
| 823 | 998 | ||
| 824 | static struct sk_buff *qfq_dequeue(struct Qdisc *sch) | 999 | static struct sk_buff *qfq_dequeue(struct Qdisc *sch) |
| 825 | { | 1000 | { |
| 826 | struct qfq_sched *q = qdisc_priv(sch); | 1001 | struct qfq_sched *q = qdisc_priv(sch); |
| 827 | struct qfq_group *grp; | 1002 | struct qfq_aggregate *in_serv_agg = q->in_serv_agg; |
| 828 | struct qfq_class *cl; | 1003 | struct qfq_class *cl; |
| 829 | struct sk_buff *skb; | 1004 | struct sk_buff *skb = NULL; |
| 830 | unsigned int len; | 1005 | /* next-packet len, 0 means no more active classes in in-service agg */ |
| 831 | u64 old_V; | 1006 | unsigned int len = 0; |
| 832 | 1007 | ||
| 833 | if (!q->bitmaps[ER]) | 1008 | if (in_serv_agg == NULL) |
| 834 | return NULL; | 1009 | return NULL; |
| 835 | 1010 | ||
| 836 | grp = qfq_ffs(q, q->bitmaps[ER]); | 1011 | if (!list_empty(&in_serv_agg->active)) |
| 1012 | skb = qfq_peek_skb(in_serv_agg, &cl, &len); | ||
| 837 | 1013 | ||
| 838 | cl = qfq_slot_head(grp); | 1014 | /* |
| 839 | skb = qdisc_dequeue_peeked(cl->qdisc); | 1015 | * If there are no active classes in the in-service aggregate, |
| 840 | if (!skb) { | 1016 | * or if the aggregate has not enough budget to serve its next |
| 841 | WARN_ONCE(1, "qfq_dequeue: non-workconserving leaf\n"); | 1017 | * class, then choose the next aggregate to serve. |
| 842 | return NULL; | 1018 | */ |
| 1019 | if (len == 0 || in_serv_agg->budget < len) { | ||
| 1020 | charge_actual_service(in_serv_agg); | ||
| 1021 | |||
| 1022 | /* recharge the budget of the aggregate */ | ||
| 1023 | in_serv_agg->initial_budget = in_serv_agg->budget = | ||
| 1024 | in_serv_agg->budgetmax; | ||
| 1025 | |||
| 1026 | if (!list_empty(&in_serv_agg->active)) | ||
| 1027 | /* | ||
| 1028 | * Still active: reschedule for | ||
| 1029 | * service. Possible optimization: if no other | ||
| 1030 | * aggregate is active, then there is no point | ||
| 1031 | * in rescheduling this aggregate, and we can | ||
| 1032 | * just keep it as the in-service one. This | ||
| 1033 | * should be however a corner case, and to | ||
| 1034 | * handle it, we would need to maintain an | ||
| 1035 | * extra num_active_aggs field. | ||
| 1036 | */ | ||
| 1037 | qfq_activate_agg(q, in_serv_agg, requeue); | ||
| 1038 | else if (sch->q.qlen == 0) { /* no aggregate to serve */ | ||
| 1039 | q->in_serv_agg = NULL; | ||
| 1040 | return NULL; | ||
| 1041 | } | ||
| 1042 | |||
| 1043 | /* | ||
| 1044 | * If we get here, there are other aggregates queued: | ||
| 1045 | * choose the new aggregate to serve. | ||
| 1046 | */ | ||
| 1047 | in_serv_agg = q->in_serv_agg = qfq_choose_next_agg(q); | ||
| 1048 | skb = qfq_peek_skb(in_serv_agg, &cl, &len); | ||
| 843 | } | 1049 | } |
| 1050 | if (!skb) | ||
| 1051 | return NULL; | ||
| 844 | 1052 | ||
| 845 | sch->q.qlen--; | 1053 | sch->q.qlen--; |
| 846 | qdisc_bstats_update(sch, skb); | 1054 | qdisc_bstats_update(sch, skb); |
| 847 | 1055 | ||
| 848 | old_V = q->V; | 1056 | agg_dequeue(in_serv_agg, cl, len); |
| 849 | len = qdisc_pkt_len(skb); | 1057 | in_serv_agg->budget -= len; |
| 850 | q->V += (u64)len * IWSUM; | 1058 | q->V += (u64)len * IWSUM; |
| 851 | pr_debug("qfq dequeue: len %u F %lld now %lld\n", | 1059 | pr_debug("qfq dequeue: len %u F %lld now %lld\n", |
| 852 | len, (unsigned long long) cl->F, (unsigned long long) q->V); | 1060 | len, (unsigned long long) in_serv_agg->F, |
| 1061 | (unsigned long long) q->V); | ||
| 853 | 1062 | ||
| 854 | if (qfq_update_class(grp, cl)) { | 1063 | return skb; |
| 855 | u64 old_F = grp->F; | 1064 | } |
| 856 | 1065 | ||
| 857 | cl = qfq_slot_scan(grp); | 1066 | static struct qfq_aggregate *qfq_choose_next_agg(struct qfq_sched *q) |
| 858 | if (!cl) | 1067 | { |
| 859 | __clear_bit(grp->index, &q->bitmaps[ER]); | 1068 | struct qfq_group *grp; |
| 860 | else { | 1069 | struct qfq_aggregate *agg, *new_front_agg; |
| 861 | u64 roundedS = qfq_round_down(cl->S, grp->slot_shift); | 1070 | u64 old_F; |
| 862 | unsigned int s; | ||
| 863 | 1071 | ||
| 864 | if (grp->S == roundedS) | 1072 | qfq_update_eligible(q); |
| 865 | goto skip_unblock; | 1073 | q->oldV = q->V; |
| 866 | grp->S = roundedS; | 1074 | |
| 867 | grp->F = roundedS + (2ULL << grp->slot_shift); | 1075 | if (!q->bitmaps[ER]) |
| 868 | __clear_bit(grp->index, &q->bitmaps[ER]); | 1076 | return NULL; |
| 869 | s = qfq_calc_state(q, grp); | 1077 | |
| 870 | __set_bit(grp->index, &q->bitmaps[s]); | 1078 | grp = qfq_ffs(q, q->bitmaps[ER]); |
| 871 | } | 1079 | old_F = grp->F; |
| 1080 | |||
| 1081 | agg = qfq_slot_head(grp); | ||
| 872 | 1082 | ||
| 873 | qfq_unblock_groups(q, grp->index, old_F); | 1083 | /* agg starts to be served, remove it from schedule */ |
| 1084 | qfq_front_slot_remove(grp); | ||
| 1085 | |||
| 1086 | new_front_agg = qfq_slot_scan(grp); | ||
| 1087 | |||
| 1088 | if (new_front_agg == NULL) /* group is now inactive, remove from ER */ | ||
| 1089 | __clear_bit(grp->index, &q->bitmaps[ER]); | ||
| 1090 | else { | ||
| 1091 | u64 roundedS = qfq_round_down(new_front_agg->S, | ||
| 1092 | grp->slot_shift); | ||
| 1093 | unsigned int s; | ||
| 1094 | |||
| 1095 | if (grp->S == roundedS) | ||
| 1096 | return agg; | ||
| 1097 | grp->S = roundedS; | ||
| 1098 | grp->F = roundedS + (2ULL << grp->slot_shift); | ||
| 1099 | __clear_bit(grp->index, &q->bitmaps[ER]); | ||
| 1100 | s = qfq_calc_state(q, grp); | ||
| 1101 | __set_bit(grp->index, &q->bitmaps[s]); | ||
| 874 | } | 1102 | } |
| 875 | 1103 | ||
| 876 | skip_unblock: | 1104 | qfq_unblock_groups(q, grp->index, old_F); |
| 877 | qfq_update_eligible(q, old_V); | ||
| 878 | 1105 | ||
| 879 | return skb; | 1106 | return agg; |
| 880 | } | 1107 | } |
| 881 | 1108 | ||
| 882 | /* | 1109 | /* |
| 883 | * Assign a reasonable start time for a new flow k in group i. | 1110 | * Assign a reasonable start time for a new aggregate in group i. |
| 884 | * Admissible values for \hat(F) are multiples of \sigma_i | 1111 | * Admissible values for \hat(F) are multiples of \sigma_i |
| 885 | * no greater than V+\sigma_i . Larger values mean that | 1112 | * no greater than V+\sigma_i . Larger values mean that |
| 886 | * we had a wraparound so we consider the timestamp to be stale. | 1113 | * we had a wraparound so we consider the timestamp to be stale. |
| 887 | * | 1114 | * |
| 888 | * If F is not stale and F >= V then we set S = F. | 1115 | * If F is not stale and F >= V then we set S = F. |
| 889 | * Otherwise we should assign S = V, but this may violate | 1116 | * Otherwise we should assign S = V, but this may violate |
| 890 | * the ordering in ER. So, if we have groups in ER, set S to | 1117 | * the ordering in EB (see [2]). So, if we have groups in ER, |
| 891 | * the F_j of the first group j which would be blocking us. | 1118 | * set S to the F_j of the first group j which would be blocking us. |
| 892 | * We are guaranteed not to move S backward because | 1119 | * We are guaranteed not to move S backward because |
| 893 | * otherwise our group i would still be blocked. | 1120 | * otherwise our group i would still be blocked. |
| 894 | */ | 1121 | */ |
| 895 | static void qfq_update_start(struct qfq_sched *q, struct qfq_class *cl) | 1122 | static void qfq_update_start(struct qfq_sched *q, struct qfq_aggregate *agg) |
| 896 | { | 1123 | { |
| 897 | unsigned long mask; | 1124 | unsigned long mask; |
| 898 | u64 limit, roundedF; | 1125 | u64 limit, roundedF; |
| 899 | int slot_shift = cl->grp->slot_shift; | 1126 | int slot_shift = agg->grp->slot_shift; |
| 900 | 1127 | ||
| 901 | roundedF = qfq_round_down(cl->F, slot_shift); | 1128 | roundedF = qfq_round_down(agg->F, slot_shift); |
| 902 | limit = qfq_round_down(q->V, slot_shift) + (1ULL << slot_shift); | 1129 | limit = qfq_round_down(q->V, slot_shift) + (1ULL << slot_shift); |
| 903 | 1130 | ||
| 904 | if (!qfq_gt(cl->F, q->V) || qfq_gt(roundedF, limit)) { | 1131 | if (!qfq_gt(agg->F, q->V) || qfq_gt(roundedF, limit)) { |
| 905 | /* timestamp was stale */ | 1132 | /* timestamp was stale */ |
| 906 | mask = mask_from(q->bitmaps[ER], cl->grp->index); | 1133 | mask = mask_from(q->bitmaps[ER], agg->grp->index); |
| 907 | if (mask) { | 1134 | if (mask) { |
| 908 | struct qfq_group *next = qfq_ffs(q, mask); | 1135 | struct qfq_group *next = qfq_ffs(q, mask); |
| 909 | if (qfq_gt(roundedF, next->F)) { | 1136 | if (qfq_gt(roundedF, next->F)) { |
| 910 | if (qfq_gt(limit, next->F)) | 1137 | if (qfq_gt(limit, next->F)) |
| 911 | cl->S = next->F; | 1138 | agg->S = next->F; |
| 912 | else /* preserve timestamp correctness */ | 1139 | else /* preserve timestamp correctness */ |
| 913 | cl->S = limit; | 1140 | agg->S = limit; |
| 914 | return; | 1141 | return; |
| 915 | } | 1142 | } |
| 916 | } | 1143 | } |
| 917 | cl->S = q->V; | 1144 | agg->S = q->V; |
| 918 | } else /* timestamp is not stale */ | 1145 | } else /* timestamp is not stale */ |
| 919 | cl->S = cl->F; | 1146 | agg->S = agg->F; |
| 920 | } | 1147 | } |
| 921 | 1148 | ||
| 1149 | /* | ||
| 1150 | * Update the timestamps of agg before scheduling/rescheduling it for | ||
| 1151 | * service. In particular, assign to agg->F its maximum possible | ||
| 1152 | * value, i.e., the virtual finish time with which the aggregate | ||
| 1153 | * should be labeled if it used all its budget once in service. | ||
| 1154 | */ | ||
| 1155 | static inline void | ||
| 1156 | qfq_update_agg_ts(struct qfq_sched *q, | ||
| 1157 | struct qfq_aggregate *agg, enum update_reason reason) | ||
| 1158 | { | ||
| 1159 | if (reason != requeue) | ||
| 1160 | qfq_update_start(q, agg); | ||
| 1161 | else /* just charge agg for the service received */ | ||
| 1162 | agg->S = agg->F; | ||
| 1163 | |||
| 1164 | agg->F = agg->S + (u64)agg->budgetmax * agg->inv_w; | ||
| 1165 | } | ||
| 1166 | |||
| 1167 | static void qfq_schedule_agg(struct qfq_sched *, struct qfq_aggregate *); | ||
| 1168 | |||
| 922 | static int qfq_enqueue(struct sk_buff *skb, struct Qdisc *sch) | 1169 | static int qfq_enqueue(struct sk_buff *skb, struct Qdisc *sch) |
| 923 | { | 1170 | { |
| 924 | struct qfq_sched *q = qdisc_priv(sch); | 1171 | struct qfq_sched *q = qdisc_priv(sch); |
| 925 | struct qfq_class *cl; | 1172 | struct qfq_class *cl; |
| 1173 | struct qfq_aggregate *agg; | ||
| 926 | int err = 0; | 1174 | int err = 0; |
| 927 | 1175 | ||
| 928 | cl = qfq_classify(skb, sch, &err); | 1176 | cl = qfq_classify(skb, sch, &err); |
| @@ -934,11 +1182,13 @@ static int qfq_enqueue(struct sk_buff *skb, struct Qdisc *sch) | |||
| 934 | } | 1182 | } |
| 935 | pr_debug("qfq_enqueue: cl = %x\n", cl->common.classid); | 1183 | pr_debug("qfq_enqueue: cl = %x\n", cl->common.classid); |
| 936 | 1184 | ||
| 937 | if (unlikely(cl->lmax < qdisc_pkt_len(skb))) { | 1185 | if (unlikely(cl->agg->lmax < qdisc_pkt_len(skb))) { |
| 938 | pr_debug("qfq: increasing maxpkt from %u to %u for class %u", | 1186 | pr_debug("qfq: increasing maxpkt from %u to %u for class %u", |
| 939 | cl->lmax, qdisc_pkt_len(skb), cl->common.classid); | 1187 | cl->agg->lmax, qdisc_pkt_len(skb), cl->common.classid); |
| 940 | qfq_update_reactivate_class(q, cl, cl->inv_w, | 1188 | err = qfq_change_agg(sch, cl, cl->agg->class_weight, |
| 941 | qdisc_pkt_len(skb), 0); | 1189 | qdisc_pkt_len(skb)); |
| 1190 | if (err) | ||
| 1191 | return err; | ||
| 942 | } | 1192 | } |
| 943 | 1193 | ||
| 944 | err = qdisc_enqueue(skb, cl->qdisc); | 1194 | err = qdisc_enqueue(skb, cl->qdisc); |
| @@ -954,35 +1204,50 @@ static int qfq_enqueue(struct sk_buff *skb, struct Qdisc *sch) | |||
| 954 | bstats_update(&cl->bstats, skb); | 1204 | bstats_update(&cl->bstats, skb); |
| 955 | ++sch->q.qlen; | 1205 | ++sch->q.qlen; |
| 956 | 1206 | ||
| 957 | /* If the new skb is not the head of queue, then done here. */ | 1207 | agg = cl->agg; |
| 958 | if (cl->qdisc->q.qlen != 1) | 1208 | /* if the queue was not empty, then done here */ |
| 1209 | if (cl->qdisc->q.qlen != 1) { | ||
| 1210 | if (unlikely(skb == cl->qdisc->ops->peek(cl->qdisc)) && | ||
| 1211 | list_first_entry(&agg->active, struct qfq_class, alist) | ||
| 1212 | == cl && cl->deficit < qdisc_pkt_len(skb)) | ||
| 1213 | list_move_tail(&cl->alist, &agg->active); | ||
| 1214 | |||
| 959 | return err; | 1215 | return err; |
| 1216 | } | ||
| 1217 | |||
| 1218 | /* schedule class for service within the aggregate */ | ||
| 1219 | cl->deficit = agg->lmax; | ||
| 1220 | list_add_tail(&cl->alist, &agg->active); | ||
| 960 | 1221 | ||
| 961 | /* If reach this point, queue q was idle */ | 1222 | if (list_first_entry(&agg->active, struct qfq_class, alist) != cl) |
| 962 | qfq_activate_class(q, cl, qdisc_pkt_len(skb)); | 1223 | return err; /* aggregate was not empty, nothing else to do */ |
| 1224 | |||
| 1225 | /* recharge budget */ | ||
| 1226 | agg->initial_budget = agg->budget = agg->budgetmax; | ||
| 1227 | |||
| 1228 | qfq_update_agg_ts(q, agg, enqueue); | ||
| 1229 | if (q->in_serv_agg == NULL) | ||
| 1230 | q->in_serv_agg = agg; | ||
| 1231 | else if (agg != q->in_serv_agg) | ||
| 1232 | qfq_schedule_agg(q, agg); | ||
| 963 | 1233 | ||
| 964 | return err; | 1234 | return err; |
| 965 | } | 1235 | } |
| 966 | 1236 | ||
| 967 | /* | 1237 | /* |
| 968 | * Handle class switch from idle to backlogged. | 1238 | * Schedule aggregate according to its timestamps. |
| 969 | */ | 1239 | */ |
| 970 | static void qfq_activate_class(struct qfq_sched *q, struct qfq_class *cl, | 1240 | static void qfq_schedule_agg(struct qfq_sched *q, struct qfq_aggregate *agg) |
| 971 | unsigned int pkt_len) | ||
| 972 | { | 1241 | { |
| 973 | struct qfq_group *grp = cl->grp; | 1242 | struct qfq_group *grp = agg->grp; |
| 974 | u64 roundedS; | 1243 | u64 roundedS; |
| 975 | int s; | 1244 | int s; |
| 976 | 1245 | ||
| 977 | qfq_update_start(q, cl); | 1246 | roundedS = qfq_round_down(agg->S, grp->slot_shift); |
| 978 | |||
| 979 | /* compute new finish time and rounded start. */ | ||
| 980 | cl->F = cl->S + (u64)pkt_len * cl->inv_w; | ||
| 981 | roundedS = qfq_round_down(cl->S, grp->slot_shift); | ||
| 982 | 1247 | ||
| 983 | /* | 1248 | /* |
| 984 | * insert cl in the correct bucket. | 1249 | * Insert agg in the correct bucket. |
| 985 | * If cl->S >= grp->S we don't need to adjust the | 1250 | * If agg->S >= grp->S we don't need to adjust the |
| 986 | * bucket list and simply go to the insertion phase. | 1251 | * bucket list and simply go to the insertion phase. |
| 987 | * Otherwise grp->S is decreasing, we must make room | 1252 | * Otherwise grp->S is decreasing, we must make room |
| 988 | * in the bucket list, and also recompute the group state. | 1253 | * in the bucket list, and also recompute the group state. |
| @@ -990,10 +1255,10 @@ static void qfq_activate_class(struct qfq_sched *q, struct qfq_class *cl, | |||
| 990 | * was in ER make sure to adjust V. | 1255 | * was in ER make sure to adjust V. |
| 991 | */ | 1256 | */ |
| 992 | if (grp->full_slots) { | 1257 | if (grp->full_slots) { |
| 993 | if (!qfq_gt(grp->S, cl->S)) | 1258 | if (!qfq_gt(grp->S, agg->S)) |
| 994 | goto skip_update; | 1259 | goto skip_update; |
| 995 | 1260 | ||
| 996 | /* create a slot for this cl->S */ | 1261 | /* create a slot for this agg->S */ |
| 997 | qfq_slot_rotate(grp, roundedS); | 1262 | qfq_slot_rotate(grp, roundedS); |
| 998 | /* group was surely ineligible, remove */ | 1263 | /* group was surely ineligible, remove */ |
| 999 | __clear_bit(grp->index, &q->bitmaps[IR]); | 1264 | __clear_bit(grp->index, &q->bitmaps[IR]); |
| @@ -1008,46 +1273,61 @@ static void qfq_activate_class(struct qfq_sched *q, struct qfq_class *cl, | |||
| 1008 | 1273 | ||
| 1009 | pr_debug("qfq enqueue: new state %d %#lx S %lld F %lld V %lld\n", | 1274 | pr_debug("qfq enqueue: new state %d %#lx S %lld F %lld V %lld\n", |
| 1010 | s, q->bitmaps[s], | 1275 | s, q->bitmaps[s], |
| 1011 | (unsigned long long) cl->S, | 1276 | (unsigned long long) agg->S, |
| 1012 | (unsigned long long) cl->F, | 1277 | (unsigned long long) agg->F, |
| 1013 | (unsigned long long) q->V); | 1278 | (unsigned long long) q->V); |
| 1014 | 1279 | ||
| 1015 | skip_update: | 1280 | skip_update: |
| 1016 | qfq_slot_insert(grp, cl, roundedS); | 1281 | qfq_slot_insert(grp, agg, roundedS); |
| 1017 | } | 1282 | } |
| 1018 | 1283 | ||
| 1019 | 1284 | ||
| 1285 | /* Update agg ts and schedule agg for service */ | ||
| 1286 | static void qfq_activate_agg(struct qfq_sched *q, struct qfq_aggregate *agg, | ||
| 1287 | enum update_reason reason) | ||
| 1288 | { | ||
| 1289 | qfq_update_agg_ts(q, agg, reason); | ||
| 1290 | qfq_schedule_agg(q, agg); | ||
| 1291 | } | ||
| 1292 | |||
| 1020 | static void qfq_slot_remove(struct qfq_sched *q, struct qfq_group *grp, | 1293 | static void qfq_slot_remove(struct qfq_sched *q, struct qfq_group *grp, |
| 1021 | struct qfq_class *cl) | 1294 | struct qfq_aggregate *agg) |
| 1022 | { | 1295 | { |
| 1023 | unsigned int i, offset; | 1296 | unsigned int i, offset; |
| 1024 | u64 roundedS; | 1297 | u64 roundedS; |
| 1025 | 1298 | ||
| 1026 | roundedS = qfq_round_down(cl->S, grp->slot_shift); | 1299 | roundedS = qfq_round_down(agg->S, grp->slot_shift); |
| 1027 | offset = (roundedS - grp->S) >> grp->slot_shift; | 1300 | offset = (roundedS - grp->S) >> grp->slot_shift; |
| 1301 | |||
| 1028 | i = (grp->front + offset) % QFQ_MAX_SLOTS; | 1302 | i = (grp->front + offset) % QFQ_MAX_SLOTS; |
| 1029 | 1303 | ||
| 1030 | hlist_del(&cl->next); | 1304 | hlist_del(&agg->next); |
| 1031 | if (hlist_empty(&grp->slots[i])) | 1305 | if (hlist_empty(&grp->slots[i])) |
| 1032 | __clear_bit(offset, &grp->full_slots); | 1306 | __clear_bit(offset, &grp->full_slots); |
| 1033 | } | 1307 | } |
| 1034 | 1308 | ||
| 1035 | /* | 1309 | /* |
| 1036 | * called to forcibly destroy a queue. | 1310 | * Called to forcibly deschedule an aggregate. If the aggregate is |
| 1037 | * If the queue is not in the front bucket, or if it has | 1311 | * not in the front bucket, or if the latter has other aggregates in |
| 1038 | * other queues in the front bucket, we can simply remove | 1312 | * the front bucket, we can simply remove the aggregate with no other |
| 1039 | * the queue with no other side effects. | 1313 | * side effects. |
| 1040 | * Otherwise we must propagate the event up. | 1314 | * Otherwise we must propagate the event up. |
| 1041 | */ | 1315 | */ |
| 1042 | static void qfq_deactivate_class(struct qfq_sched *q, struct qfq_class *cl) | 1316 | static void qfq_deactivate_agg(struct qfq_sched *q, struct qfq_aggregate *agg) |
| 1043 | { | 1317 | { |
| 1044 | struct qfq_group *grp = cl->grp; | 1318 | struct qfq_group *grp = agg->grp; |
| 1045 | unsigned long mask; | 1319 | unsigned long mask; |
| 1046 | u64 roundedS; | 1320 | u64 roundedS; |
| 1047 | int s; | 1321 | int s; |
| 1048 | 1322 | ||
| 1049 | cl->F = cl->S; | 1323 | if (agg == q->in_serv_agg) { |
| 1050 | qfq_slot_remove(q, grp, cl); | 1324 | charge_actual_service(agg); |
| 1325 | q->in_serv_agg = qfq_choose_next_agg(q); | ||
| 1326 | return; | ||
| 1327 | } | ||
| 1328 | |||
| 1329 | agg->F = agg->S; | ||
| 1330 | qfq_slot_remove(q, grp, agg); | ||
| 1051 | 1331 | ||
| 1052 | if (!grp->full_slots) { | 1332 | if (!grp->full_slots) { |
| 1053 | __clear_bit(grp->index, &q->bitmaps[IR]); | 1333 | __clear_bit(grp->index, &q->bitmaps[IR]); |
| @@ -1066,8 +1346,8 @@ static void qfq_deactivate_class(struct qfq_sched *q, struct qfq_class *cl) | |||
| 1066 | } | 1346 | } |
| 1067 | __clear_bit(grp->index, &q->bitmaps[ER]); | 1347 | __clear_bit(grp->index, &q->bitmaps[ER]); |
| 1068 | } else if (hlist_empty(&grp->slots[grp->front])) { | 1348 | } else if (hlist_empty(&grp->slots[grp->front])) { |
| 1069 | cl = qfq_slot_scan(grp); | 1349 | agg = qfq_slot_scan(grp); |
| 1070 | roundedS = qfq_round_down(cl->S, grp->slot_shift); | 1350 | roundedS = qfq_round_down(agg->S, grp->slot_shift); |
| 1071 | if (grp->S != roundedS) { | 1351 | if (grp->S != roundedS) { |
| 1072 | __clear_bit(grp->index, &q->bitmaps[ER]); | 1352 | __clear_bit(grp->index, &q->bitmaps[ER]); |
| 1073 | __clear_bit(grp->index, &q->bitmaps[IR]); | 1353 | __clear_bit(grp->index, &q->bitmaps[IR]); |
| @@ -1080,7 +1360,7 @@ static void qfq_deactivate_class(struct qfq_sched *q, struct qfq_class *cl) | |||
| 1080 | } | 1360 | } |
| 1081 | } | 1361 | } |
| 1082 | 1362 | ||
| 1083 | qfq_update_eligible(q, q->V); | 1363 | qfq_update_eligible(q); |
| 1084 | } | 1364 | } |
| 1085 | 1365 | ||
| 1086 | static void qfq_qlen_notify(struct Qdisc *sch, unsigned long arg) | 1366 | static void qfq_qlen_notify(struct Qdisc *sch, unsigned long arg) |
| @@ -1092,6 +1372,32 @@ static void qfq_qlen_notify(struct Qdisc *sch, unsigned long arg) | |||
| 1092 | qfq_deactivate_class(q, cl); | 1372 | qfq_deactivate_class(q, cl); |
| 1093 | } | 1373 | } |
| 1094 | 1374 | ||
| 1375 | static unsigned int qfq_drop_from_slot(struct qfq_sched *q, | ||
| 1376 | struct hlist_head *slot) | ||
| 1377 | { | ||
| 1378 | struct qfq_aggregate *agg; | ||
| 1379 | struct hlist_node *n; | ||
| 1380 | struct qfq_class *cl; | ||
| 1381 | unsigned int len; | ||
| 1382 | |||
| 1383 | hlist_for_each_entry(agg, n, slot, next) { | ||
| 1384 | list_for_each_entry(cl, &agg->active, alist) { | ||
| 1385 | |||
| 1386 | if (!cl->qdisc->ops->drop) | ||
| 1387 | continue; | ||
| 1388 | |||
| 1389 | len = cl->qdisc->ops->drop(cl->qdisc); | ||
| 1390 | if (len > 0) { | ||
| 1391 | if (cl->qdisc->q.qlen == 0) | ||
| 1392 | qfq_deactivate_class(q, cl); | ||
| 1393 | |||
| 1394 | return len; | ||
| 1395 | } | ||
| 1396 | } | ||
| 1397 | } | ||
| 1398 | return 0; | ||
| 1399 | } | ||
| 1400 | |||
| 1095 | static unsigned int qfq_drop(struct Qdisc *sch) | 1401 | static unsigned int qfq_drop(struct Qdisc *sch) |
| 1096 | { | 1402 | { |
| 1097 | struct qfq_sched *q = qdisc_priv(sch); | 1403 | struct qfq_sched *q = qdisc_priv(sch); |
| @@ -1101,24 +1407,13 @@ static unsigned int qfq_drop(struct Qdisc *sch) | |||
| 1101 | for (i = 0; i <= QFQ_MAX_INDEX; i++) { | 1407 | for (i = 0; i <= QFQ_MAX_INDEX; i++) { |
| 1102 | grp = &q->groups[i]; | 1408 | grp = &q->groups[i]; |
| 1103 | for (j = 0; j < QFQ_MAX_SLOTS; j++) { | 1409 | for (j = 0; j < QFQ_MAX_SLOTS; j++) { |
| 1104 | struct qfq_class *cl; | 1410 | len = qfq_drop_from_slot(q, &grp->slots[j]); |
| 1105 | struct hlist_node *n; | 1411 | if (len > 0) { |
| 1106 | 1412 | sch->q.qlen--; | |
| 1107 | hlist_for_each_entry(cl, n, &grp->slots[j], next) { | 1413 | return len; |
| 1108 | |||
| 1109 | if (!cl->qdisc->ops->drop) | ||
| 1110 | continue; | ||
| 1111 | |||
| 1112 | len = cl->qdisc->ops->drop(cl->qdisc); | ||
| 1113 | if (len > 0) { | ||
| 1114 | sch->q.qlen--; | ||
| 1115 | if (!cl->qdisc->q.qlen) | ||
| 1116 | qfq_deactivate_class(q, cl); | ||
| 1117 | |||
| 1118 | return len; | ||
| 1119 | } | ||
| 1120 | } | 1414 | } |
| 1121 | } | 1415 | } |
| 1416 | |||
| 1122 | } | 1417 | } |
| 1123 | 1418 | ||
| 1124 | return 0; | 1419 | return 0; |
| @@ -1129,44 +1424,51 @@ static int qfq_init_qdisc(struct Qdisc *sch, struct nlattr *opt) | |||
| 1129 | struct qfq_sched *q = qdisc_priv(sch); | 1424 | struct qfq_sched *q = qdisc_priv(sch); |
| 1130 | struct qfq_group *grp; | 1425 | struct qfq_group *grp; |
| 1131 | int i, j, err; | 1426 | int i, j, err; |
| 1427 | u32 max_cl_shift, maxbudg_shift, max_classes; | ||
| 1132 | 1428 | ||
| 1133 | err = qdisc_class_hash_init(&q->clhash); | 1429 | err = qdisc_class_hash_init(&q->clhash); |
| 1134 | if (err < 0) | 1430 | if (err < 0) |
| 1135 | return err; | 1431 | return err; |
| 1136 | 1432 | ||
| 1433 | if (qdisc_dev(sch)->tx_queue_len + 1 > QFQ_MAX_AGG_CLASSES) | ||
| 1434 | max_classes = QFQ_MAX_AGG_CLASSES; | ||
| 1435 | else | ||
| 1436 | max_classes = qdisc_dev(sch)->tx_queue_len + 1; | ||
| 1437 | /* max_cl_shift = floor(log_2(max_classes)) */ | ||
| 1438 | max_cl_shift = __fls(max_classes); | ||
| 1439 | q->max_agg_classes = 1<<max_cl_shift; | ||
| 1440 | |||
| 1441 | /* maxbudg_shift = log2(max_len * max_classes_per_agg) */ | ||
| 1442 | maxbudg_shift = QFQ_MTU_SHIFT + max_cl_shift; | ||
| 1443 | q->min_slot_shift = FRAC_BITS + maxbudg_shift - QFQ_MAX_INDEX; | ||
| 1444 | |||
| 1137 | for (i = 0; i <= QFQ_MAX_INDEX; i++) { | 1445 | for (i = 0; i <= QFQ_MAX_INDEX; i++) { |
| 1138 | grp = &q->groups[i]; | 1446 | grp = &q->groups[i]; |
| 1139 | grp->index = i; | 1447 | grp->index = i; |
| 1140 | grp->slot_shift = QFQ_MTU_SHIFT + FRAC_BITS | 1448 | grp->slot_shift = q->min_slot_shift + i; |
| 1141 | - (QFQ_MAX_INDEX - i); | ||
| 1142 | for (j = 0; j < QFQ_MAX_SLOTS; j++) | 1449 | for (j = 0; j < QFQ_MAX_SLOTS; j++) |
| 1143 | INIT_HLIST_HEAD(&grp->slots[j]); | 1450 | INIT_HLIST_HEAD(&grp->slots[j]); |
| 1144 | } | 1451 | } |
| 1145 | 1452 | ||
| 1453 | INIT_HLIST_HEAD(&q->nonfull_aggs); | ||
| 1454 | |||
| 1146 | return 0; | 1455 | return 0; |
| 1147 | } | 1456 | } |
| 1148 | 1457 | ||
| 1149 | static void qfq_reset_qdisc(struct Qdisc *sch) | 1458 | static void qfq_reset_qdisc(struct Qdisc *sch) |
| 1150 | { | 1459 | { |
| 1151 | struct qfq_sched *q = qdisc_priv(sch); | 1460 | struct qfq_sched *q = qdisc_priv(sch); |
| 1152 | struct qfq_group *grp; | ||
| 1153 | struct qfq_class *cl; | 1461 | struct qfq_class *cl; |
| 1154 | struct hlist_node *n, *tmp; | 1462 | struct hlist_node *n; |
| 1155 | unsigned int i, j; | 1463 | unsigned int i; |
| 1156 | 1464 | ||
| 1157 | for (i = 0; i <= QFQ_MAX_INDEX; i++) { | 1465 | for (i = 0; i < q->clhash.hashsize; i++) { |
| 1158 | grp = &q->groups[i]; | 1466 | hlist_for_each_entry(cl, n, &q->clhash.hash[i], common.hnode) { |
| 1159 | for (j = 0; j < QFQ_MAX_SLOTS; j++) { | 1467 | if (cl->qdisc->q.qlen > 0) |
| 1160 | hlist_for_each_entry_safe(cl, n, tmp, | ||
| 1161 | &grp->slots[j], next) { | ||
| 1162 | qfq_deactivate_class(q, cl); | 1468 | qfq_deactivate_class(q, cl); |
| 1163 | } | ||
| 1164 | } | ||
| 1165 | } | ||
| 1166 | 1469 | ||
| 1167 | for (i = 0; i < q->clhash.hashsize; i++) { | ||
| 1168 | hlist_for_each_entry(cl, n, &q->clhash.hash[i], common.hnode) | ||
| 1169 | qdisc_reset(cl->qdisc); | 1470 | qdisc_reset(cl->qdisc); |
| 1471 | } | ||
| 1170 | } | 1472 | } |
| 1171 | sch->q.qlen = 0; | 1473 | sch->q.qlen = 0; |
| 1172 | } | 1474 | } |
diff --git a/net/sctp/chunk.c b/net/sctp/chunk.c index 7c2df9c33df3..69ce21e3716f 100644 --- a/net/sctp/chunk.c +++ b/net/sctp/chunk.c | |||
| @@ -183,7 +183,7 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc, | |||
| 183 | 183 | ||
| 184 | msg = sctp_datamsg_new(GFP_KERNEL); | 184 | msg = sctp_datamsg_new(GFP_KERNEL); |
| 185 | if (!msg) | 185 | if (!msg) |
| 186 | return NULL; | 186 | return ERR_PTR(-ENOMEM); |
| 187 | 187 | ||
| 188 | /* Note: Calculate this outside of the loop, so that all fragments | 188 | /* Note: Calculate this outside of the loop, so that all fragments |
| 189 | * have the same expiration. | 189 | * have the same expiration. |
| @@ -280,11 +280,14 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc, | |||
| 280 | 280 | ||
| 281 | chunk = sctp_make_datafrag_empty(asoc, sinfo, len, frag, 0); | 281 | chunk = sctp_make_datafrag_empty(asoc, sinfo, len, frag, 0); |
| 282 | 282 | ||
| 283 | if (!chunk) | 283 | if (!chunk) { |
| 284 | err = -ENOMEM; | ||
| 284 | goto errout; | 285 | goto errout; |
| 286 | } | ||
| 287 | |||
| 285 | err = sctp_user_addto_chunk(chunk, offset, len, msgh->msg_iov); | 288 | err = sctp_user_addto_chunk(chunk, offset, len, msgh->msg_iov); |
| 286 | if (err < 0) | 289 | if (err < 0) |
| 287 | goto errout; | 290 | goto errout_chunk_free; |
| 288 | 291 | ||
| 289 | offset += len; | 292 | offset += len; |
| 290 | 293 | ||
| @@ -315,8 +318,10 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc, | |||
| 315 | 318 | ||
| 316 | chunk = sctp_make_datafrag_empty(asoc, sinfo, over, frag, 0); | 319 | chunk = sctp_make_datafrag_empty(asoc, sinfo, over, frag, 0); |
| 317 | 320 | ||
| 318 | if (!chunk) | 321 | if (!chunk) { |
| 322 | err = -ENOMEM; | ||
| 319 | goto errout; | 323 | goto errout; |
| 324 | } | ||
| 320 | 325 | ||
| 321 | err = sctp_user_addto_chunk(chunk, offset, over,msgh->msg_iov); | 326 | err = sctp_user_addto_chunk(chunk, offset, over,msgh->msg_iov); |
| 322 | 327 | ||
| @@ -324,7 +329,7 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc, | |||
| 324 | __skb_pull(chunk->skb, (__u8 *)chunk->chunk_hdr | 329 | __skb_pull(chunk->skb, (__u8 *)chunk->chunk_hdr |
| 325 | - (__u8 *)chunk->skb->data); | 330 | - (__u8 *)chunk->skb->data); |
| 326 | if (err < 0) | 331 | if (err < 0) |
| 327 | goto errout; | 332 | goto errout_chunk_free; |
| 328 | 333 | ||
| 329 | sctp_datamsg_assign(msg, chunk); | 334 | sctp_datamsg_assign(msg, chunk); |
| 330 | list_add_tail(&chunk->frag_list, &msg->chunks); | 335 | list_add_tail(&chunk->frag_list, &msg->chunks); |
| @@ -332,6 +337,9 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc, | |||
| 332 | 337 | ||
| 333 | return msg; | 338 | return msg; |
| 334 | 339 | ||
| 340 | errout_chunk_free: | ||
| 341 | sctp_chunk_free(chunk); | ||
| 342 | |||
| 335 | errout: | 343 | errout: |
| 336 | list_for_each_safe(pos, temp, &msg->chunks) { | 344 | list_for_each_safe(pos, temp, &msg->chunks) { |
| 337 | list_del_init(pos); | 345 | list_del_init(pos); |
| @@ -339,7 +347,7 @@ errout: | |||
| 339 | sctp_chunk_free(chunk); | 347 | sctp_chunk_free(chunk); |
| 340 | } | 348 | } |
| 341 | sctp_datamsg_put(msg); | 349 | sctp_datamsg_put(msg); |
| 342 | return NULL; | 350 | return ERR_PTR(err); |
| 343 | } | 351 | } |
| 344 | 352 | ||
| 345 | /* Check whether this message has expired. */ | 353 | /* Check whether this message has expired. */ |
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index ea14cb445295..f3f0f4dc31dd 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c | |||
| @@ -345,7 +345,7 @@ static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr, | |||
| 345 | } | 345 | } |
| 346 | 346 | ||
| 347 | out: | 347 | out: |
| 348 | if (!IS_ERR(dst)) { | 348 | if (!IS_ERR_OR_NULL(dst)) { |
| 349 | struct rt6_info *rt; | 349 | struct rt6_info *rt; |
| 350 | rt = (struct rt6_info *)dst; | 350 | rt = (struct rt6_info *)dst; |
| 351 | t->dst = dst; | 351 | t->dst = dst; |
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index b6adef8a1e93..e92079d27eae 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c | |||
| @@ -1055,6 +1055,7 @@ sctp_disposition_t sctp_sf_beat_8_3(struct net *net, | |||
| 1055 | void *arg, | 1055 | void *arg, |
| 1056 | sctp_cmd_seq_t *commands) | 1056 | sctp_cmd_seq_t *commands) |
| 1057 | { | 1057 | { |
| 1058 | sctp_paramhdr_t *param_hdr; | ||
| 1058 | struct sctp_chunk *chunk = arg; | 1059 | struct sctp_chunk *chunk = arg; |
| 1059 | struct sctp_chunk *reply; | 1060 | struct sctp_chunk *reply; |
| 1060 | size_t paylen = 0; | 1061 | size_t paylen = 0; |
| @@ -1072,12 +1073,17 @@ sctp_disposition_t sctp_sf_beat_8_3(struct net *net, | |||
| 1072 | * Information field copied from the received HEARTBEAT chunk. | 1073 | * Information field copied from the received HEARTBEAT chunk. |
| 1073 | */ | 1074 | */ |
| 1074 | chunk->subh.hb_hdr = (sctp_heartbeathdr_t *) chunk->skb->data; | 1075 | chunk->subh.hb_hdr = (sctp_heartbeathdr_t *) chunk->skb->data; |
| 1076 | param_hdr = (sctp_paramhdr_t *) chunk->subh.hb_hdr; | ||
| 1075 | paylen = ntohs(chunk->chunk_hdr->length) - sizeof(sctp_chunkhdr_t); | 1077 | paylen = ntohs(chunk->chunk_hdr->length) - sizeof(sctp_chunkhdr_t); |
| 1078 | |||
| 1079 | if (ntohs(param_hdr->length) > paylen) | ||
| 1080 | return sctp_sf_violation_paramlen(net, ep, asoc, type, arg, | ||
| 1081 | param_hdr, commands); | ||
| 1082 | |||
| 1076 | if (!pskb_pull(chunk->skb, paylen)) | 1083 | if (!pskb_pull(chunk->skb, paylen)) |
| 1077 | goto nomem; | 1084 | goto nomem; |
| 1078 | 1085 | ||
| 1079 | reply = sctp_make_heartbeat_ack(asoc, chunk, | 1086 | reply = sctp_make_heartbeat_ack(asoc, chunk, param_hdr, paylen); |
| 1080 | chunk->subh.hb_hdr, paylen); | ||
| 1081 | if (!reply) | 1087 | if (!reply) |
| 1082 | goto nomem; | 1088 | goto nomem; |
| 1083 | 1089 | ||
diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 2e897069310a..bc1624913c42 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c | |||
| @@ -1916,8 +1916,8 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
| 1916 | 1916 | ||
| 1917 | /* Break the message into multiple chunks of maximum size. */ | 1917 | /* Break the message into multiple chunks of maximum size. */ |
| 1918 | datamsg = sctp_datamsg_from_user(asoc, sinfo, msg, msg_len); | 1918 | datamsg = sctp_datamsg_from_user(asoc, sinfo, msg, msg_len); |
| 1919 | if (!datamsg) { | 1919 | if (IS_ERR(datamsg)) { |
| 1920 | err = -ENOMEM; | 1920 | err = PTR_ERR(datamsg); |
| 1921 | goto out_free; | 1921 | goto out_free; |
| 1922 | } | 1922 | } |
| 1923 | 1923 | ||
diff --git a/net/sctp/transport.c b/net/sctp/transport.c index 953c21e4af97..206cf5238fd3 100644 --- a/net/sctp/transport.c +++ b/net/sctp/transport.c | |||
| @@ -331,7 +331,7 @@ void sctp_transport_update_rto(struct sctp_transport *tp, __u32 rtt) | |||
| 331 | * 1/8, rto_alpha would be expressed as 3. | 331 | * 1/8, rto_alpha would be expressed as 3. |
| 332 | */ | 332 | */ |
| 333 | tp->rttvar = tp->rttvar - (tp->rttvar >> net->sctp.rto_beta) | 333 | tp->rttvar = tp->rttvar - (tp->rttvar >> net->sctp.rto_beta) |
| 334 | + ((abs(tp->srtt - rtt)) >> net->sctp.rto_beta); | 334 | + (((__u32)abs64((__s64)tp->srtt - (__s64)rtt)) >> net->sctp.rto_beta); |
| 335 | tp->srtt = tp->srtt - (tp->srtt >> net->sctp.rto_alpha) | 335 | tp->srtt = tp->srtt - (tp->srtt >> net->sctp.rto_alpha) |
| 336 | + (rtt >> net->sctp.rto_alpha); | 336 | + (rtt >> net->sctp.rto_alpha); |
| 337 | } else { | 337 | } else { |
diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig index fe4adb12b3ef..16d08b399210 100644 --- a/net/wireless/Kconfig +++ b/net/wireless/Kconfig | |||
| @@ -140,14 +140,13 @@ config CFG80211_WEXT | |||
| 140 | extensions with cfg80211-based drivers. | 140 | extensions with cfg80211-based drivers. |
| 141 | 141 | ||
| 142 | config LIB80211 | 142 | config LIB80211 |
| 143 | tristate "Common routines for IEEE802.11 drivers" | 143 | tristate |
| 144 | default n | 144 | default n |
| 145 | help | 145 | help |
| 146 | This options enables a library of common routines used | 146 | This options enables a library of common routines used |
| 147 | by IEEE802.11 wireless LAN drivers. | 147 | by IEEE802.11 wireless LAN drivers. |
| 148 | 148 | ||
| 149 | Drivers should select this themselves if needed. Say Y if | 149 | Drivers should select this themselves if needed. |
| 150 | you want this built into your kernel. | ||
| 151 | 150 | ||
| 152 | config LIB80211_CRYPT_WEP | 151 | config LIB80211_CRYPT_WEP |
| 153 | tristate | 152 | tristate |
diff --git a/net/wireless/ap.c b/net/wireless/ap.c index e143505f05bc..324e8d851dc4 100644 --- a/net/wireless/ap.c +++ b/net/wireless/ap.c | |||
| @@ -28,6 +28,7 @@ static int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev, | |||
| 28 | if (!err) { | 28 | if (!err) { |
| 29 | wdev->beacon_interval = 0; | 29 | wdev->beacon_interval = 0; |
| 30 | wdev->channel = NULL; | 30 | wdev->channel = NULL; |
| 31 | wdev->ssid_len = 0; | ||
| 31 | } | 32 | } |
| 32 | 33 | ||
| 33 | return err; | 34 | return err; |
diff --git a/net/wireless/chan.c b/net/wireless/chan.c index 48febd2160ba..bf2dfd54ff3b 100644 --- a/net/wireless/chan.c +++ b/net/wireless/chan.c | |||
| @@ -11,96 +11,264 @@ | |||
| 11 | #include "core.h" | 11 | #include "core.h" |
| 12 | #include "rdev-ops.h" | 12 | #include "rdev-ops.h" |
| 13 | 13 | ||
| 14 | struct ieee80211_channel * | 14 | void cfg80211_chandef_create(struct cfg80211_chan_def *chandef, |
| 15 | rdev_freq_to_chan(struct cfg80211_registered_device *rdev, | 15 | struct ieee80211_channel *chan, |
| 16 | int freq, enum nl80211_channel_type channel_type) | 16 | enum nl80211_channel_type chan_type) |
| 17 | { | 17 | { |
| 18 | struct ieee80211_channel *chan; | 18 | if (WARN_ON(!chan)) |
| 19 | struct ieee80211_sta_ht_cap *ht_cap; | 19 | return; |
| 20 | 20 | ||
| 21 | chan = ieee80211_get_channel(&rdev->wiphy, freq); | 21 | chandef->chan = chan; |
| 22 | chandef->center_freq2 = 0; | ||
| 22 | 23 | ||
| 23 | /* Primary channel not allowed */ | 24 | switch (chan_type) { |
| 24 | if (!chan || chan->flags & IEEE80211_CHAN_DISABLED) | 25 | case NL80211_CHAN_NO_HT: |
| 25 | return NULL; | 26 | chandef->width = NL80211_CHAN_WIDTH_20_NOHT; |
| 27 | chandef->center_freq1 = chan->center_freq; | ||
| 28 | break; | ||
| 29 | case NL80211_CHAN_HT20: | ||
| 30 | chandef->width = NL80211_CHAN_WIDTH_20; | ||
| 31 | chandef->center_freq1 = chan->center_freq; | ||
| 32 | break; | ||
| 33 | case NL80211_CHAN_HT40PLUS: | ||
| 34 | chandef->width = NL80211_CHAN_WIDTH_40; | ||
| 35 | chandef->center_freq1 = chan->center_freq + 10; | ||
| 36 | break; | ||
| 37 | case NL80211_CHAN_HT40MINUS: | ||
| 38 | chandef->width = NL80211_CHAN_WIDTH_40; | ||
| 39 | chandef->center_freq1 = chan->center_freq - 10; | ||
| 40 | break; | ||
| 41 | default: | ||
| 42 | WARN_ON(1); | ||
| 43 | } | ||
| 44 | } | ||
| 45 | EXPORT_SYMBOL(cfg80211_chandef_create); | ||
| 26 | 46 | ||
| 27 | if (channel_type == NL80211_CHAN_HT40MINUS && | 47 | bool cfg80211_chan_def_valid(const struct cfg80211_chan_def *chandef) |
| 28 | chan->flags & IEEE80211_CHAN_NO_HT40MINUS) | 48 | { |
| 29 | return NULL; | 49 | u32 control_freq; |
| 30 | else if (channel_type == NL80211_CHAN_HT40PLUS && | ||
| 31 | chan->flags & IEEE80211_CHAN_NO_HT40PLUS) | ||
| 32 | return NULL; | ||
| 33 | 50 | ||
| 34 | ht_cap = &rdev->wiphy.bands[chan->band]->ht_cap; | 51 | if (!chandef->chan) |
| 52 | return false; | ||
| 35 | 53 | ||
| 36 | if (channel_type != NL80211_CHAN_NO_HT) { | 54 | control_freq = chandef->chan->center_freq; |
| 37 | if (!ht_cap->ht_supported) | ||
| 38 | return NULL; | ||
| 39 | 55 | ||
| 40 | if (channel_type != NL80211_CHAN_HT20 && | 56 | switch (chandef->width) { |
| 41 | (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) || | 57 | case NL80211_CHAN_WIDTH_20: |
| 42 | ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT)) | 58 | case NL80211_CHAN_WIDTH_20_NOHT: |
| 43 | return NULL; | 59 | if (chandef->center_freq1 != control_freq) |
| 60 | return false; | ||
| 61 | if (chandef->center_freq2) | ||
| 62 | return false; | ||
| 63 | break; | ||
| 64 | case NL80211_CHAN_WIDTH_40: | ||
| 65 | if (chandef->center_freq1 != control_freq + 10 && | ||
| 66 | chandef->center_freq1 != control_freq - 10) | ||
| 67 | return false; | ||
| 68 | if (chandef->center_freq2) | ||
| 69 | return false; | ||
| 70 | break; | ||
| 71 | case NL80211_CHAN_WIDTH_80P80: | ||
| 72 | if (chandef->center_freq1 != control_freq + 30 && | ||
| 73 | chandef->center_freq1 != control_freq + 10 && | ||
| 74 | chandef->center_freq1 != control_freq - 10 && | ||
| 75 | chandef->center_freq1 != control_freq - 30) | ||
| 76 | return false; | ||
| 77 | if (!chandef->center_freq2) | ||
| 78 | return false; | ||
| 79 | break; | ||
| 80 | case NL80211_CHAN_WIDTH_80: | ||
| 81 | if (chandef->center_freq1 != control_freq + 30 && | ||
| 82 | chandef->center_freq1 != control_freq + 10 && | ||
| 83 | chandef->center_freq1 != control_freq - 10 && | ||
| 84 | chandef->center_freq1 != control_freq - 30) | ||
| 85 | return false; | ||
| 86 | if (chandef->center_freq2) | ||
| 87 | return false; | ||
| 88 | break; | ||
| 89 | case NL80211_CHAN_WIDTH_160: | ||
| 90 | if (chandef->center_freq1 != control_freq + 70 && | ||
| 91 | chandef->center_freq1 != control_freq + 50 && | ||
| 92 | chandef->center_freq1 != control_freq + 30 && | ||
| 93 | chandef->center_freq1 != control_freq + 10 && | ||
| 94 | chandef->center_freq1 != control_freq - 10 && | ||
| 95 | chandef->center_freq1 != control_freq - 30 && | ||
| 96 | chandef->center_freq1 != control_freq - 50 && | ||
| 97 | chandef->center_freq1 != control_freq - 70) | ||
| 98 | return false; | ||
| 99 | if (chandef->center_freq2) | ||
| 100 | return false; | ||
| 101 | break; | ||
| 102 | default: | ||
| 103 | return false; | ||
| 44 | } | 104 | } |
| 45 | 105 | ||
| 46 | return chan; | 106 | return true; |
| 47 | } | 107 | } |
| 48 | 108 | ||
| 49 | bool cfg80211_can_beacon_sec_chan(struct wiphy *wiphy, | 109 | static void chandef_primary_freqs(const struct cfg80211_chan_def *c, |
| 50 | struct ieee80211_channel *chan, | 110 | int *pri40, int *pri80) |
| 51 | enum nl80211_channel_type channel_type) | ||
| 52 | { | 111 | { |
| 53 | struct ieee80211_channel *sec_chan; | 112 | int tmp; |
| 54 | int diff; | ||
| 55 | |||
| 56 | trace_cfg80211_can_beacon_sec_chan(wiphy, chan, channel_type); | ||
| 57 | 113 | ||
| 58 | switch (channel_type) { | 114 | switch (c->width) { |
| 59 | case NL80211_CHAN_HT40PLUS: | 115 | case NL80211_CHAN_WIDTH_40: |
| 60 | diff = 20; | 116 | *pri40 = c->center_freq1; |
| 117 | *pri80 = 0; | ||
| 61 | break; | 118 | break; |
| 62 | case NL80211_CHAN_HT40MINUS: | 119 | case NL80211_CHAN_WIDTH_80: |
| 63 | diff = -20; | 120 | case NL80211_CHAN_WIDTH_80P80: |
| 121 | *pri80 = c->center_freq1; | ||
| 122 | /* n_P20 */ | ||
| 123 | tmp = (30 + c->chan->center_freq - c->center_freq1)/20; | ||
| 124 | /* n_P40 */ | ||
| 125 | tmp /= 2; | ||
| 126 | /* freq_P40 */ | ||
| 127 | *pri40 = c->center_freq1 - 20 + 40 * tmp; | ||
| 128 | break; | ||
| 129 | case NL80211_CHAN_WIDTH_160: | ||
| 130 | /* n_P20 */ | ||
| 131 | tmp = (70 + c->chan->center_freq - c->center_freq1)/20; | ||
| 132 | /* n_P40 */ | ||
| 133 | tmp /= 2; | ||
| 134 | /* freq_P40 */ | ||
| 135 | *pri40 = c->center_freq1 - 60 + 40 * tmp; | ||
| 136 | /* n_P80 */ | ||
| 137 | tmp /= 2; | ||
| 138 | *pri80 = c->center_freq1 - 40 + 80 * tmp; | ||
| 64 | break; | 139 | break; |
| 65 | default: | 140 | default: |
| 66 | trace_cfg80211_return_bool(true); | 141 | WARN_ON_ONCE(1); |
| 67 | return true; | ||
| 68 | } | 142 | } |
| 143 | } | ||
| 144 | |||
| 145 | const struct cfg80211_chan_def * | ||
| 146 | cfg80211_chandef_compatible(const struct cfg80211_chan_def *c1, | ||
| 147 | const struct cfg80211_chan_def *c2) | ||
| 148 | { | ||
| 149 | u32 c1_pri40, c1_pri80, c2_pri40, c2_pri80; | ||
| 69 | 150 | ||
| 70 | sec_chan = ieee80211_get_channel(wiphy, chan->center_freq + diff); | 151 | /* If they are identical, return */ |
| 71 | if (!sec_chan) { | 152 | if (cfg80211_chandef_identical(c1, c2)) |
| 153 | return c1; | ||
| 154 | |||
| 155 | /* otherwise, must have same control channel */ | ||
| 156 | if (c1->chan != c2->chan) | ||
| 157 | return NULL; | ||
| 158 | |||
| 159 | /* | ||
| 160 | * If they have the same width, but aren't identical, | ||
| 161 | * then they can't be compatible. | ||
| 162 | */ | ||
| 163 | if (c1->width == c2->width) | ||
| 164 | return NULL; | ||
| 165 | |||
| 166 | if (c1->width == NL80211_CHAN_WIDTH_20_NOHT || | ||
| 167 | c1->width == NL80211_CHAN_WIDTH_20) | ||
| 168 | return c2; | ||
| 169 | |||
| 170 | if (c2->width == NL80211_CHAN_WIDTH_20_NOHT || | ||
| 171 | c2->width == NL80211_CHAN_WIDTH_20) | ||
| 172 | return c1; | ||
| 173 | |||
| 174 | chandef_primary_freqs(c1, &c1_pri40, &c1_pri80); | ||
| 175 | chandef_primary_freqs(c2, &c2_pri40, &c2_pri80); | ||
| 176 | |||
| 177 | if (c1_pri40 != c2_pri40) | ||
| 178 | return NULL; | ||
| 179 | |||
| 180 | WARN_ON(!c1_pri80 && !c2_pri80); | ||
| 181 | if (c1_pri80 && c2_pri80 && c1_pri80 != c2_pri80) | ||
| 182 | return NULL; | ||
| 183 | |||
| 184 | if (c1->width > c2->width) | ||
| 185 | return c1; | ||
| 186 | return c2; | ||
| 187 | } | ||
| 188 | EXPORT_SYMBOL(cfg80211_chandef_compatible); | ||
| 189 | |||
| 190 | bool cfg80211_secondary_chans_ok(struct wiphy *wiphy, | ||
| 191 | u32 center_freq, u32 bandwidth, | ||
| 192 | u32 prohibited_flags) | ||
| 193 | { | ||
| 194 | struct ieee80211_channel *c; | ||
| 195 | u32 freq; | ||
| 196 | |||
| 197 | for (freq = center_freq - bandwidth/2 + 10; | ||
| 198 | freq <= center_freq + bandwidth/2 - 10; | ||
| 199 | freq += 20) { | ||
| 200 | c = ieee80211_get_channel(wiphy, freq); | ||
| 201 | if (!c || c->flags & prohibited_flags) | ||
| 202 | return false; | ||
| 203 | } | ||
| 204 | |||
| 205 | return true; | ||
| 206 | } | ||
| 207 | |||
| 208 | static bool cfg80211_check_beacon_chans(struct wiphy *wiphy, | ||
| 209 | u32 center_freq, u32 bw) | ||
| 210 | { | ||
| 211 | return cfg80211_secondary_chans_ok(wiphy, center_freq, bw, | ||
| 212 | IEEE80211_CHAN_DISABLED | | ||
| 213 | IEEE80211_CHAN_PASSIVE_SCAN | | ||
| 214 | IEEE80211_CHAN_NO_IBSS | | ||
| 215 | IEEE80211_CHAN_RADAR); | ||
| 216 | } | ||
| 217 | |||
| 218 | bool cfg80211_reg_can_beacon(struct wiphy *wiphy, | ||
| 219 | struct cfg80211_chan_def *chandef) | ||
| 220 | { | ||
| 221 | u32 width; | ||
| 222 | bool res; | ||
| 223 | |||
| 224 | trace_cfg80211_reg_can_beacon(wiphy, chandef); | ||
| 225 | |||
| 226 | if (WARN_ON(!cfg80211_chan_def_valid(chandef))) { | ||
| 72 | trace_cfg80211_return_bool(false); | 227 | trace_cfg80211_return_bool(false); |
| 73 | return false; | 228 | return false; |
| 74 | } | 229 | } |
| 75 | 230 | ||
| 76 | /* we'll need a DFS capability later */ | 231 | switch (chandef->width) { |
| 77 | if (sec_chan->flags & (IEEE80211_CHAN_DISABLED | | 232 | case NL80211_CHAN_WIDTH_20_NOHT: |
| 78 | IEEE80211_CHAN_PASSIVE_SCAN | | 233 | case NL80211_CHAN_WIDTH_20: |
| 79 | IEEE80211_CHAN_NO_IBSS | | 234 | width = 20; |
| 80 | IEEE80211_CHAN_RADAR)) { | 235 | break; |
| 236 | case NL80211_CHAN_WIDTH_40: | ||
| 237 | width = 40; | ||
| 238 | break; | ||
| 239 | case NL80211_CHAN_WIDTH_80: | ||
| 240 | case NL80211_CHAN_WIDTH_80P80: | ||
| 241 | width = 80; | ||
| 242 | break; | ||
| 243 | case NL80211_CHAN_WIDTH_160: | ||
| 244 | width = 160; | ||
| 245 | break; | ||
| 246 | default: | ||
| 247 | WARN_ON_ONCE(1); | ||
| 81 | trace_cfg80211_return_bool(false); | 248 | trace_cfg80211_return_bool(false); |
| 82 | return false; | 249 | return false; |
| 83 | } | 250 | } |
| 84 | trace_cfg80211_return_bool(true); | 251 | |
| 85 | return true; | 252 | res = cfg80211_check_beacon_chans(wiphy, chandef->center_freq1, width); |
| 253 | |||
| 254 | if (res && chandef->center_freq2) | ||
| 255 | res = cfg80211_check_beacon_chans(wiphy, chandef->center_freq2, | ||
| 256 | width); | ||
| 257 | |||
| 258 | trace_cfg80211_return_bool(res); | ||
| 259 | return res; | ||
| 86 | } | 260 | } |
| 87 | EXPORT_SYMBOL(cfg80211_can_beacon_sec_chan); | 261 | EXPORT_SYMBOL(cfg80211_reg_can_beacon); |
| 88 | 262 | ||
| 89 | int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev, | 263 | int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev, |
| 90 | int freq, enum nl80211_channel_type chantype) | 264 | struct cfg80211_chan_def *chandef) |
| 91 | { | 265 | { |
| 92 | struct ieee80211_channel *chan; | ||
| 93 | |||
| 94 | if (!rdev->ops->set_monitor_channel) | 266 | if (!rdev->ops->set_monitor_channel) |
| 95 | return -EOPNOTSUPP; | 267 | return -EOPNOTSUPP; |
| 96 | if (!cfg80211_has_monitors_only(rdev)) | 268 | if (!cfg80211_has_monitors_only(rdev)) |
| 97 | return -EBUSY; | 269 | return -EBUSY; |
| 98 | 270 | ||
| 99 | chan = rdev_freq_to_chan(rdev, freq, chantype); | 271 | return rdev_set_monitor_channel(rdev, chandef); |
| 100 | if (!chan) | ||
| 101 | return -EINVAL; | ||
| 102 | |||
| 103 | return rdev_set_monitor_channel(rdev, chan, chantype); | ||
| 104 | } | 272 | } |
| 105 | 273 | ||
| 106 | void | 274 | void |
diff --git a/net/wireless/core.c b/net/wireless/core.c index 26711f46a3be..14d990400354 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
| @@ -326,6 +326,8 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) | |||
| 326 | mutex_init(&rdev->devlist_mtx); | 326 | mutex_init(&rdev->devlist_mtx); |
| 327 | mutex_init(&rdev->sched_scan_mtx); | 327 | mutex_init(&rdev->sched_scan_mtx); |
| 328 | INIT_LIST_HEAD(&rdev->wdev_list); | 328 | INIT_LIST_HEAD(&rdev->wdev_list); |
| 329 | INIT_LIST_HEAD(&rdev->beacon_registrations); | ||
| 330 | spin_lock_init(&rdev->beacon_registrations_lock); | ||
| 329 | spin_lock_init(&rdev->bss_lock); | 331 | spin_lock_init(&rdev->bss_lock); |
| 330 | INIT_LIST_HEAD(&rdev->bss_list); | 332 | INIT_LIST_HEAD(&rdev->bss_list); |
| 331 | INIT_WORK(&rdev->scan_done_wk, __cfg80211_scan_done); | 333 | INIT_WORK(&rdev->scan_done_wk, __cfg80211_scan_done); |
| @@ -698,10 +700,15 @@ EXPORT_SYMBOL(wiphy_unregister); | |||
| 698 | void cfg80211_dev_free(struct cfg80211_registered_device *rdev) | 700 | void cfg80211_dev_free(struct cfg80211_registered_device *rdev) |
| 699 | { | 701 | { |
| 700 | struct cfg80211_internal_bss *scan, *tmp; | 702 | struct cfg80211_internal_bss *scan, *tmp; |
| 703 | struct cfg80211_beacon_registration *reg, *treg; | ||
| 701 | rfkill_destroy(rdev->rfkill); | 704 | rfkill_destroy(rdev->rfkill); |
| 702 | mutex_destroy(&rdev->mtx); | 705 | mutex_destroy(&rdev->mtx); |
| 703 | mutex_destroy(&rdev->devlist_mtx); | 706 | mutex_destroy(&rdev->devlist_mtx); |
| 704 | mutex_destroy(&rdev->sched_scan_mtx); | 707 | mutex_destroy(&rdev->sched_scan_mtx); |
| 708 | list_for_each_entry_safe(reg, treg, &rdev->beacon_registrations, list) { | ||
| 709 | list_del(®->list); | ||
| 710 | kfree(reg); | ||
| 711 | } | ||
| 705 | list_for_each_entry_safe(scan, tmp, &rdev->bss_list, list) | 712 | list_for_each_entry_safe(scan, tmp, &rdev->bss_list, list) |
| 706 | cfg80211_put_bss(&scan->pub); | 713 | cfg80211_put_bss(&scan->pub); |
| 707 | kfree(rdev); | 714 | kfree(rdev); |
diff --git a/net/wireless/core.h b/net/wireless/core.h index b8eb743fe7da..a0c8decf6a47 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
| @@ -55,7 +55,8 @@ struct cfg80211_registered_device { | |||
| 55 | int opencount; /* also protected by devlist_mtx */ | 55 | int opencount; /* also protected by devlist_mtx */ |
| 56 | wait_queue_head_t dev_wait; | 56 | wait_queue_head_t dev_wait; |
| 57 | 57 | ||
| 58 | u32 ap_beacons_nlportid; | 58 | struct list_head beacon_registrations; |
| 59 | spinlock_t beacon_registrations_lock; | ||
| 59 | 60 | ||
| 60 | /* protected by RTNL only */ | 61 | /* protected by RTNL only */ |
| 61 | int num_running_ifaces; | 62 | int num_running_ifaces; |
| @@ -260,6 +261,10 @@ enum cfg80211_chan_mode { | |||
| 260 | CHAN_MODE_EXCLUSIVE, | 261 | CHAN_MODE_EXCLUSIVE, |
| 261 | }; | 262 | }; |
| 262 | 263 | ||
| 264 | struct cfg80211_beacon_registration { | ||
| 265 | struct list_head list; | ||
| 266 | u32 nlportid; | ||
| 267 | }; | ||
| 263 | 268 | ||
| 264 | /* free object */ | 269 | /* free object */ |
| 265 | extern void cfg80211_dev_free(struct cfg80211_registered_device *rdev); | 270 | extern void cfg80211_dev_free(struct cfg80211_registered_device *rdev); |
| @@ -304,9 +309,9 @@ int cfg80211_join_mesh(struct cfg80211_registered_device *rdev, | |||
| 304 | const struct mesh_config *conf); | 309 | const struct mesh_config *conf); |
| 305 | int cfg80211_leave_mesh(struct cfg80211_registered_device *rdev, | 310 | int cfg80211_leave_mesh(struct cfg80211_registered_device *rdev, |
| 306 | struct net_device *dev); | 311 | struct net_device *dev); |
| 307 | int cfg80211_set_mesh_freq(struct cfg80211_registered_device *rdev, | 312 | int cfg80211_set_mesh_channel(struct cfg80211_registered_device *rdev, |
| 308 | struct wireless_dev *wdev, int freq, | 313 | struct wireless_dev *wdev, |
| 309 | enum nl80211_channel_type channel_type); | 314 | struct cfg80211_chan_def *chandef); |
| 310 | 315 | ||
| 311 | /* AP */ | 316 | /* AP */ |
| 312 | int cfg80211_stop_ap(struct cfg80211_registered_device *rdev, | 317 | int cfg80211_stop_ap(struct cfg80211_registered_device *rdev, |
| @@ -373,10 +378,8 @@ void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev); | |||
| 373 | int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, | 378 | int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, |
| 374 | struct wireless_dev *wdev, | 379 | struct wireless_dev *wdev, |
| 375 | struct ieee80211_channel *chan, bool offchan, | 380 | struct ieee80211_channel *chan, bool offchan, |
| 376 | enum nl80211_channel_type channel_type, | 381 | unsigned int wait, const u8 *buf, size_t len, |
| 377 | bool channel_type_valid, unsigned int wait, | 382 | bool no_cck, bool dont_wait_for_ack, u64 *cookie); |
| 378 | const u8 *buf, size_t len, bool no_cck, | ||
| 379 | bool dont_wait_for_ack, u64 *cookie); | ||
| 380 | void cfg80211_oper_and_ht_capa(struct ieee80211_ht_cap *ht_capa, | 383 | void cfg80211_oper_and_ht_capa(struct ieee80211_ht_cap *ht_capa, |
| 381 | const struct ieee80211_ht_cap *ht_capa_mask); | 384 | const struct ieee80211_ht_cap *ht_capa_mask); |
| 382 | 385 | ||
| @@ -467,11 +470,8 @@ cfg80211_get_chan_state(struct wireless_dev *wdev, | |||
| 467 | struct ieee80211_channel **chan, | 470 | struct ieee80211_channel **chan, |
| 468 | enum cfg80211_chan_mode *chanmode); | 471 | enum cfg80211_chan_mode *chanmode); |
| 469 | 472 | ||
| 470 | struct ieee80211_channel * | ||
| 471 | rdev_freq_to_chan(struct cfg80211_registered_device *rdev, | ||
| 472 | int freq, enum nl80211_channel_type channel_type); | ||
| 473 | int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev, | 473 | int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev, |
| 474 | int freq, enum nl80211_channel_type chantype); | 474 | struct cfg80211_chan_def *chandef); |
| 475 | 475 | ||
| 476 | int ieee80211_get_ratemask(struct ieee80211_supported_band *sband, | 476 | int ieee80211_get_ratemask(struct ieee80211_supported_band *sband, |
| 477 | const u8 *rates, unsigned int n_rates, | 477 | const u8 *rates, unsigned int n_rates, |
| @@ -483,6 +483,12 @@ int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, | |||
| 483 | void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev, | 483 | void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev, |
| 484 | enum nl80211_iftype iftype, int num); | 484 | enum nl80211_iftype iftype, int num); |
| 485 | 485 | ||
| 486 | bool cfg80211_chan_def_valid(const struct cfg80211_chan_def *chandef); | ||
| 487 | |||
| 488 | bool cfg80211_secondary_chans_ok(struct wiphy *wiphy, | ||
| 489 | u32 center_freq, u32 bandwidth, | ||
| 490 | u32 prohibited_flags); | ||
| 491 | |||
| 486 | #define CFG80211_MAX_NUM_DIFFERENT_CHANNELS 10 | 492 | #define CFG80211_MAX_NUM_DIFFERENT_CHANNELS 10 |
| 487 | 493 | ||
| 488 | #ifdef CONFIG_CFG80211_DEVELOPER_WARNINGS | 494 | #ifdef CONFIG_CFG80211_DEVELOPER_WARNINGS |
diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c index 27941d5db72b..9b9551e4a6f9 100644 --- a/net/wireless/ibss.c +++ b/net/wireless/ibss.c | |||
| @@ -100,9 +100,9 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev, | |||
| 100 | * 11a for maximum compatibility. | 100 | * 11a for maximum compatibility. |
| 101 | */ | 101 | */ |
| 102 | struct ieee80211_supported_band *sband = | 102 | struct ieee80211_supported_band *sband = |
| 103 | rdev->wiphy.bands[params->channel->band]; | 103 | rdev->wiphy.bands[params->chandef.chan->band]; |
| 104 | int j; | 104 | int j; |
| 105 | u32 flag = params->channel->band == IEEE80211_BAND_5GHZ ? | 105 | u32 flag = params->chandef.chan->band == IEEE80211_BAND_5GHZ ? |
| 106 | IEEE80211_RATE_MANDATORY_A : | 106 | IEEE80211_RATE_MANDATORY_A : |
| 107 | IEEE80211_RATE_MANDATORY_B; | 107 | IEEE80211_RATE_MANDATORY_B; |
| 108 | 108 | ||
| @@ -118,11 +118,11 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev, | |||
| 118 | 118 | ||
| 119 | wdev->ibss_fixed = params->channel_fixed; | 119 | wdev->ibss_fixed = params->channel_fixed; |
| 120 | #ifdef CONFIG_CFG80211_WEXT | 120 | #ifdef CONFIG_CFG80211_WEXT |
| 121 | wdev->wext.ibss.channel = params->channel; | 121 | wdev->wext.ibss.chandef = params->chandef; |
| 122 | #endif | 122 | #endif |
| 123 | wdev->sme_state = CFG80211_SME_CONNECTING; | 123 | wdev->sme_state = CFG80211_SME_CONNECTING; |
| 124 | 124 | ||
| 125 | err = cfg80211_can_use_chan(rdev, wdev, params->channel, | 125 | err = cfg80211_can_use_chan(rdev, wdev, params->chandef.chan, |
| 126 | params->channel_fixed | 126 | params->channel_fixed |
| 127 | ? CHAN_MODE_SHARED | 127 | ? CHAN_MODE_SHARED |
| 128 | : CHAN_MODE_EXCLUSIVE); | 128 | : CHAN_MODE_EXCLUSIVE); |
| @@ -251,7 +251,9 @@ int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev, | |||
| 251 | wdev->wext.ibss.beacon_interval = 100; | 251 | wdev->wext.ibss.beacon_interval = 100; |
| 252 | 252 | ||
| 253 | /* try to find an IBSS channel if none requested ... */ | 253 | /* try to find an IBSS channel if none requested ... */ |
| 254 | if (!wdev->wext.ibss.channel) { | 254 | if (!wdev->wext.ibss.chandef.chan) { |
| 255 | wdev->wext.ibss.chandef.width = NL80211_CHAN_WIDTH_20_NOHT; | ||
| 256 | |||
| 255 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { | 257 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { |
| 256 | struct ieee80211_supported_band *sband; | 258 | struct ieee80211_supported_band *sband; |
| 257 | struct ieee80211_channel *chan; | 259 | struct ieee80211_channel *chan; |
| @@ -266,15 +268,15 @@ int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev, | |||
| 266 | continue; | 268 | continue; |
| 267 | if (chan->flags & IEEE80211_CHAN_DISABLED) | 269 | if (chan->flags & IEEE80211_CHAN_DISABLED) |
| 268 | continue; | 270 | continue; |
| 269 | wdev->wext.ibss.channel = chan; | 271 | wdev->wext.ibss.chandef.chan = chan; |
| 270 | break; | 272 | break; |
| 271 | } | 273 | } |
| 272 | 274 | ||
| 273 | if (wdev->wext.ibss.channel) | 275 | if (wdev->wext.ibss.chandef.chan) |
| 274 | break; | 276 | break; |
| 275 | } | 277 | } |
| 276 | 278 | ||
| 277 | if (!wdev->wext.ibss.channel) | 279 | if (!wdev->wext.ibss.chandef.chan) |
| 278 | return -EINVAL; | 280 | return -EINVAL; |
| 279 | } | 281 | } |
| 280 | 282 | ||
| @@ -336,7 +338,7 @@ int cfg80211_ibss_wext_siwfreq(struct net_device *dev, | |||
| 336 | return -EINVAL; | 338 | return -EINVAL; |
| 337 | } | 339 | } |
| 338 | 340 | ||
| 339 | if (wdev->wext.ibss.channel == chan) | 341 | if (wdev->wext.ibss.chandef.chan == chan) |
| 340 | return 0; | 342 | return 0; |
| 341 | 343 | ||
| 342 | wdev_lock(wdev); | 344 | wdev_lock(wdev); |
| @@ -349,7 +351,8 @@ int cfg80211_ibss_wext_siwfreq(struct net_device *dev, | |||
| 349 | return err; | 351 | return err; |
| 350 | 352 | ||
| 351 | if (chan) { | 353 | if (chan) { |
| 352 | wdev->wext.ibss.channel = chan; | 354 | wdev->wext.ibss.chandef.chan = chan; |
| 355 | wdev->wext.ibss.chandef.width = NL80211_CHAN_WIDTH_20_NOHT; | ||
| 353 | wdev->wext.ibss.channel_fixed = true; | 356 | wdev->wext.ibss.channel_fixed = true; |
| 354 | } else { | 357 | } else { |
| 355 | /* cfg80211_ibss_wext_join will pick one if needed */ | 358 | /* cfg80211_ibss_wext_join will pick one if needed */ |
| @@ -379,8 +382,8 @@ int cfg80211_ibss_wext_giwfreq(struct net_device *dev, | |||
| 379 | wdev_lock(wdev); | 382 | wdev_lock(wdev); |
| 380 | if (wdev->current_bss) | 383 | if (wdev->current_bss) |
| 381 | chan = wdev->current_bss->pub.channel; | 384 | chan = wdev->current_bss->pub.channel; |
| 382 | else if (wdev->wext.ibss.channel) | 385 | else if (wdev->wext.ibss.chandef.chan) |
| 383 | chan = wdev->wext.ibss.channel; | 386 | chan = wdev->wext.ibss.chandef.chan; |
| 384 | wdev_unlock(wdev); | 387 | wdev_unlock(wdev); |
| 385 | 388 | ||
| 386 | if (chan) { | 389 | if (chan) { |
diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c index 966cfc4cd79d..3ee5a7282283 100644 --- a/net/wireless/mesh.c +++ b/net/wireless/mesh.c | |||
| @@ -73,8 +73,6 @@ const struct mesh_config default_mesh_config = { | |||
| 73 | 73 | ||
| 74 | const struct mesh_setup default_mesh_setup = { | 74 | const struct mesh_setup default_mesh_setup = { |
| 75 | /* cfg80211_join_mesh() will pick a channel if needed */ | 75 | /* cfg80211_join_mesh() will pick a channel if needed */ |
| 76 | .channel = NULL, | ||
| 77 | .channel_type = NL80211_CHAN_NO_HT, | ||
| 78 | .sync_method = IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET, | 76 | .sync_method = IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET, |
| 79 | .path_sel_proto = IEEE80211_PATH_PROTOCOL_HWMP, | 77 | .path_sel_proto = IEEE80211_PATH_PROTOCOL_HWMP, |
| 80 | .path_metric = IEEE80211_PATH_METRIC_AIRTIME, | 78 | .path_metric = IEEE80211_PATH_METRIC_AIRTIME, |
| @@ -111,13 +109,12 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev, | |||
| 111 | if (!rdev->ops->join_mesh) | 109 | if (!rdev->ops->join_mesh) |
| 112 | return -EOPNOTSUPP; | 110 | return -EOPNOTSUPP; |
| 113 | 111 | ||
| 114 | if (!setup->channel) { | 112 | if (!setup->chandef.chan) { |
| 115 | /* if no channel explicitly given, use preset channel */ | 113 | /* if no channel explicitly given, use preset channel */ |
| 116 | setup->channel = wdev->preset_chan; | 114 | setup->chandef = wdev->preset_chandef; |
| 117 | setup->channel_type = wdev->preset_chantype; | ||
| 118 | } | 115 | } |
| 119 | 116 | ||
| 120 | if (!setup->channel) { | 117 | if (!setup->chandef.chan) { |
| 121 | /* if we don't have that either, use the first usable channel */ | 118 | /* if we don't have that either, use the first usable channel */ |
| 122 | enum ieee80211_band band; | 119 | enum ieee80211_band band; |
| 123 | 120 | ||
| @@ -137,26 +134,25 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev, | |||
| 137 | IEEE80211_CHAN_DISABLED | | 134 | IEEE80211_CHAN_DISABLED | |
| 138 | IEEE80211_CHAN_RADAR)) | 135 | IEEE80211_CHAN_RADAR)) |
| 139 | continue; | 136 | continue; |
| 140 | setup->channel = chan; | 137 | setup->chandef.chan = chan; |
| 141 | break; | 138 | break; |
| 142 | } | 139 | } |
| 143 | 140 | ||
| 144 | if (setup->channel) | 141 | if (setup->chandef.chan) |
| 145 | break; | 142 | break; |
| 146 | } | 143 | } |
| 147 | 144 | ||
| 148 | /* no usable channel ... */ | 145 | /* no usable channel ... */ |
| 149 | if (!setup->channel) | 146 | if (!setup->chandef.chan) |
| 150 | return -EINVAL; | 147 | return -EINVAL; |
| 151 | 148 | ||
| 152 | setup->channel_type = NL80211_CHAN_NO_HT; | 149 | setup->chandef.width = NL80211_CHAN_WIDTH_20_NOHT;; |
| 153 | } | 150 | } |
| 154 | 151 | ||
| 155 | if (!cfg80211_can_beacon_sec_chan(&rdev->wiphy, setup->channel, | 152 | if (!cfg80211_reg_can_beacon(&rdev->wiphy, &setup->chandef)) |
| 156 | setup->channel_type)) | ||
| 157 | return -EINVAL; | 153 | return -EINVAL; |
| 158 | 154 | ||
| 159 | err = cfg80211_can_use_chan(rdev, wdev, setup->channel, | 155 | err = cfg80211_can_use_chan(rdev, wdev, setup->chandef.chan, |
| 160 | CHAN_MODE_SHARED); | 156 | CHAN_MODE_SHARED); |
| 161 | if (err) | 157 | if (err) |
| 162 | return err; | 158 | return err; |
| @@ -165,7 +161,7 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev, | |||
| 165 | if (!err) { | 161 | if (!err) { |
| 166 | memcpy(wdev->ssid, setup->mesh_id, setup->mesh_id_len); | 162 | memcpy(wdev->ssid, setup->mesh_id, setup->mesh_id_len); |
| 167 | wdev->mesh_id_len = setup->mesh_id_len; | 163 | wdev->mesh_id_len = setup->mesh_id_len; |
| 168 | wdev->channel = setup->channel; | 164 | wdev->channel = setup->chandef.chan; |
| 169 | } | 165 | } |
| 170 | 166 | ||
| 171 | return err; | 167 | return err; |
| @@ -188,20 +184,12 @@ int cfg80211_join_mesh(struct cfg80211_registered_device *rdev, | |||
| 188 | return err; | 184 | return err; |
| 189 | } | 185 | } |
| 190 | 186 | ||
| 191 | int cfg80211_set_mesh_freq(struct cfg80211_registered_device *rdev, | 187 | int cfg80211_set_mesh_channel(struct cfg80211_registered_device *rdev, |
| 192 | struct wireless_dev *wdev, int freq, | 188 | struct wireless_dev *wdev, |
| 193 | enum nl80211_channel_type channel_type) | 189 | struct cfg80211_chan_def *chandef) |
| 194 | { | 190 | { |
| 195 | struct ieee80211_channel *channel; | ||
| 196 | int err; | 191 | int err; |
| 197 | 192 | ||
| 198 | channel = rdev_freq_to_chan(rdev, freq, channel_type); | ||
| 199 | if (!channel || !cfg80211_can_beacon_sec_chan(&rdev->wiphy, | ||
| 200 | channel, | ||
| 201 | channel_type)) { | ||
| 202 | return -EINVAL; | ||
| 203 | } | ||
| 204 | |||
| 205 | /* | 193 | /* |
| 206 | * Workaround for libertas (only!), it puts the interface | 194 | * Workaround for libertas (only!), it puts the interface |
| 207 | * into mesh mode but doesn't implement join_mesh. Instead, | 195 | * into mesh mode but doesn't implement join_mesh. Instead, |
| @@ -210,21 +198,21 @@ int cfg80211_set_mesh_freq(struct cfg80211_registered_device *rdev, | |||
| 210 | * compatible with 802.11 mesh. | 198 | * compatible with 802.11 mesh. |
| 211 | */ | 199 | */ |
| 212 | if (rdev->ops->libertas_set_mesh_channel) { | 200 | if (rdev->ops->libertas_set_mesh_channel) { |
| 213 | if (channel_type != NL80211_CHAN_NO_HT) | 201 | if (chandef->width != NL80211_CHAN_WIDTH_20_NOHT) |
| 214 | return -EINVAL; | 202 | return -EINVAL; |
| 215 | 203 | ||
| 216 | if (!netif_running(wdev->netdev)) | 204 | if (!netif_running(wdev->netdev)) |
| 217 | return -ENETDOWN; | 205 | return -ENETDOWN; |
| 218 | 206 | ||
| 219 | err = cfg80211_can_use_chan(rdev, wdev, channel, | 207 | err = cfg80211_can_use_chan(rdev, wdev, chandef->chan, |
| 220 | CHAN_MODE_SHARED); | 208 | CHAN_MODE_SHARED); |
| 221 | if (err) | 209 | if (err) |
| 222 | return err; | 210 | return err; |
| 223 | 211 | ||
| 224 | err = rdev_libertas_set_mesh_channel(rdev, wdev->netdev, | 212 | err = rdev_libertas_set_mesh_channel(rdev, wdev->netdev, |
| 225 | channel); | 213 | chandef->chan); |
| 226 | if (!err) | 214 | if (!err) |
| 227 | wdev->channel = channel; | 215 | wdev->channel = chandef->chan; |
| 228 | 216 | ||
| 229 | return err; | 217 | return err; |
| 230 | } | 218 | } |
| @@ -232,8 +220,7 @@ int cfg80211_set_mesh_freq(struct cfg80211_registered_device *rdev, | |||
| 232 | if (wdev->mesh_id_len) | 220 | if (wdev->mesh_id_len) |
| 233 | return -EBUSY; | 221 | return -EBUSY; |
| 234 | 222 | ||
| 235 | wdev->preset_chan = channel; | 223 | wdev->preset_chandef = *chandef; |
| 236 | wdev->preset_chantype = channel_type; | ||
| 237 | return 0; | 224 | return 0; |
| 238 | } | 225 | } |
| 239 | 226 | ||
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 4bfd14f7c592..5e8123ee63fd 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c | |||
| @@ -579,31 +579,25 @@ void cfg80211_mlme_down(struct cfg80211_registered_device *rdev, | |||
| 579 | 579 | ||
| 580 | void cfg80211_ready_on_channel(struct wireless_dev *wdev, u64 cookie, | 580 | void cfg80211_ready_on_channel(struct wireless_dev *wdev, u64 cookie, |
| 581 | struct ieee80211_channel *chan, | 581 | struct ieee80211_channel *chan, |
| 582 | enum nl80211_channel_type channel_type, | ||
| 583 | unsigned int duration, gfp_t gfp) | 582 | unsigned int duration, gfp_t gfp) |
| 584 | { | 583 | { |
| 585 | struct wiphy *wiphy = wdev->wiphy; | 584 | struct wiphy *wiphy = wdev->wiphy; |
| 586 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | 585 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); |
| 587 | 586 | ||
| 588 | trace_cfg80211_ready_on_channel(wdev, cookie, chan, channel_type, | 587 | trace_cfg80211_ready_on_channel(wdev, cookie, chan, duration); |
| 589 | duration); | 588 | nl80211_send_remain_on_channel(rdev, wdev, cookie, chan, duration, gfp); |
| 590 | nl80211_send_remain_on_channel(rdev, wdev, cookie, chan, channel_type, | ||
| 591 | duration, gfp); | ||
| 592 | } | 589 | } |
| 593 | EXPORT_SYMBOL(cfg80211_ready_on_channel); | 590 | EXPORT_SYMBOL(cfg80211_ready_on_channel); |
| 594 | 591 | ||
| 595 | void cfg80211_remain_on_channel_expired(struct wireless_dev *wdev, u64 cookie, | 592 | void cfg80211_remain_on_channel_expired(struct wireless_dev *wdev, u64 cookie, |
| 596 | struct ieee80211_channel *chan, | 593 | struct ieee80211_channel *chan, |
| 597 | enum nl80211_channel_type channel_type, | ||
| 598 | gfp_t gfp) | 594 | gfp_t gfp) |
| 599 | { | 595 | { |
| 600 | struct wiphy *wiphy = wdev->wiphy; | 596 | struct wiphy *wiphy = wdev->wiphy; |
| 601 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | 597 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); |
| 602 | 598 | ||
| 603 | trace_cfg80211_ready_on_channel_expired(wdev, cookie, chan, | 599 | trace_cfg80211_ready_on_channel_expired(wdev, cookie, chan); |
| 604 | channel_type); | 600 | nl80211_send_remain_on_channel_cancel(rdev, wdev, cookie, chan, gfp); |
| 605 | nl80211_send_remain_on_channel_cancel(rdev, wdev, cookie, chan, | ||
| 606 | channel_type, gfp); | ||
| 607 | } | 601 | } |
| 608 | EXPORT_SYMBOL(cfg80211_remain_on_channel_expired); | 602 | EXPORT_SYMBOL(cfg80211_remain_on_channel_expired); |
| 609 | 603 | ||
| @@ -758,10 +752,8 @@ void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev) | |||
| 758 | int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, | 752 | int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, |
| 759 | struct wireless_dev *wdev, | 753 | struct wireless_dev *wdev, |
| 760 | struct ieee80211_channel *chan, bool offchan, | 754 | struct ieee80211_channel *chan, bool offchan, |
| 761 | enum nl80211_channel_type channel_type, | 755 | unsigned int wait, const u8 *buf, size_t len, |
| 762 | bool channel_type_valid, unsigned int wait, | 756 | bool no_cck, bool dont_wait_for_ack, u64 *cookie) |
| 763 | const u8 *buf, size_t len, bool no_cck, | ||
| 764 | bool dont_wait_for_ack, u64 *cookie) | ||
| 765 | { | 757 | { |
| 766 | const struct ieee80211_mgmt *mgmt; | 758 | const struct ieee80211_mgmt *mgmt; |
| 767 | u16 stype; | 759 | u16 stype; |
| @@ -855,7 +847,6 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, | |||
| 855 | 847 | ||
| 856 | /* Transmit the Action frame as requested by user space */ | 848 | /* Transmit the Action frame as requested by user space */ |
| 857 | return rdev_mgmt_tx(rdev, wdev, chan, offchan, | 849 | return rdev_mgmt_tx(rdev, wdev, chan, offchan, |
| 858 | channel_type, channel_type_valid, | ||
| 859 | wait, buf, len, no_cck, dont_wait_for_ack, | 850 | wait, buf, len, no_cck, dont_wait_for_ack, |
| 860 | cookie); | 851 | cookie); |
| 861 | } | 852 | } |
| @@ -997,15 +988,14 @@ void cfg80211_pmksa_candidate_notify(struct net_device *dev, int index, | |||
| 997 | } | 988 | } |
| 998 | EXPORT_SYMBOL(cfg80211_pmksa_candidate_notify); | 989 | EXPORT_SYMBOL(cfg80211_pmksa_candidate_notify); |
| 999 | 990 | ||
| 1000 | void cfg80211_ch_switch_notify(struct net_device *dev, int freq, | 991 | void cfg80211_ch_switch_notify(struct net_device *dev, |
| 1001 | enum nl80211_channel_type type) | 992 | struct cfg80211_chan_def *chandef) |
| 1002 | { | 993 | { |
| 1003 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 994 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
| 1004 | struct wiphy *wiphy = wdev->wiphy; | 995 | struct wiphy *wiphy = wdev->wiphy; |
| 1005 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | 996 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); |
| 1006 | struct ieee80211_channel *chan; | ||
| 1007 | 997 | ||
| 1008 | trace_cfg80211_ch_switch_notify(dev, freq, type); | 998 | trace_cfg80211_ch_switch_notify(dev, chandef); |
| 1009 | 999 | ||
| 1010 | wdev_lock(wdev); | 1000 | wdev_lock(wdev); |
| 1011 | 1001 | ||
| @@ -1013,12 +1003,8 @@ void cfg80211_ch_switch_notify(struct net_device *dev, int freq, | |||
| 1013 | wdev->iftype != NL80211_IFTYPE_P2P_GO)) | 1003 | wdev->iftype != NL80211_IFTYPE_P2P_GO)) |
| 1014 | goto out; | 1004 | goto out; |
| 1015 | 1005 | ||
| 1016 | chan = rdev_freq_to_chan(rdev, freq, type); | 1006 | wdev->channel = chandef->chan; |
| 1017 | if (WARN_ON(!chan)) | 1007 | nl80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL); |
| 1018 | goto out; | ||
| 1019 | |||
| 1020 | wdev->channel = chan; | ||
| 1021 | nl80211_ch_switch_notify(rdev, dev, freq, type, GFP_KERNEL); | ||
| 1022 | out: | 1008 | out: |
| 1023 | wdev_unlock(wdev); | 1009 | wdev_unlock(wdev); |
| 1024 | return; | 1010 | return; |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 8c0857815a90..d038fa45ecd1 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
| @@ -223,8 +223,13 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { | |||
| 223 | [NL80211_ATTR_WIPHY_NAME] = { .type = NLA_NUL_STRING, | 223 | [NL80211_ATTR_WIPHY_NAME] = { .type = NLA_NUL_STRING, |
| 224 | .len = 20-1 }, | 224 | .len = 20-1 }, |
| 225 | [NL80211_ATTR_WIPHY_TXQ_PARAMS] = { .type = NLA_NESTED }, | 225 | [NL80211_ATTR_WIPHY_TXQ_PARAMS] = { .type = NLA_NESTED }, |
| 226 | |||
| 226 | [NL80211_ATTR_WIPHY_FREQ] = { .type = NLA_U32 }, | 227 | [NL80211_ATTR_WIPHY_FREQ] = { .type = NLA_U32 }, |
| 227 | [NL80211_ATTR_WIPHY_CHANNEL_TYPE] = { .type = NLA_U32 }, | 228 | [NL80211_ATTR_WIPHY_CHANNEL_TYPE] = { .type = NLA_U32 }, |
| 229 | [NL80211_ATTR_CHANNEL_WIDTH] = { .type = NLA_U32 }, | ||
| 230 | [NL80211_ATTR_CENTER_FREQ1] = { .type = NLA_U32 }, | ||
| 231 | [NL80211_ATTR_CENTER_FREQ2] = { .type = NLA_U32 }, | ||
| 232 | |||
| 228 | [NL80211_ATTR_WIPHY_RETRY_SHORT] = { .type = NLA_U8 }, | 233 | [NL80211_ATTR_WIPHY_RETRY_SHORT] = { .type = NLA_U8 }, |
| 229 | [NL80211_ATTR_WIPHY_RETRY_LONG] = { .type = NLA_U8 }, | 234 | [NL80211_ATTR_WIPHY_RETRY_LONG] = { .type = NLA_U8 }, |
| 230 | [NL80211_ATTR_WIPHY_FRAG_THRESHOLD] = { .type = NLA_U32 }, | 235 | [NL80211_ATTR_WIPHY_FRAG_THRESHOLD] = { .type = NLA_U32 }, |
| @@ -1110,6 +1115,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 portid, u32 seq, int flag | |||
| 1110 | goto nla_put_failure; | 1115 | goto nla_put_failure; |
| 1111 | } | 1116 | } |
| 1112 | CMD(start_p2p_device, START_P2P_DEVICE); | 1117 | CMD(start_p2p_device, START_P2P_DEVICE); |
| 1118 | CMD(set_mcast_rate, SET_MCAST_RATE); | ||
| 1113 | 1119 | ||
| 1114 | #ifdef CONFIG_NL80211_TESTMODE | 1120 | #ifdef CONFIG_NL80211_TESTMODE |
| 1115 | CMD(testmode_cmd, TESTMODE); | 1121 | CMD(testmode_cmd, TESTMODE); |
| @@ -1359,51 +1365,139 @@ static bool nl80211_can_set_dev_channel(struct wireless_dev *wdev) | |||
| 1359 | wdev->iftype == NL80211_IFTYPE_P2P_GO; | 1365 | wdev->iftype == NL80211_IFTYPE_P2P_GO; |
| 1360 | } | 1366 | } |
| 1361 | 1367 | ||
| 1362 | static bool nl80211_valid_channel_type(struct genl_info *info, | 1368 | static int nl80211_parse_chandef(struct cfg80211_registered_device *rdev, |
| 1363 | enum nl80211_channel_type *channel_type) | 1369 | struct genl_info *info, |
| 1370 | struct cfg80211_chan_def *chandef) | ||
| 1364 | { | 1371 | { |
| 1365 | enum nl80211_channel_type tmp; | 1372 | struct ieee80211_sta_ht_cap *ht_cap; |
| 1373 | struct ieee80211_sta_vht_cap *vht_cap; | ||
| 1374 | u32 control_freq, width; | ||
| 1366 | 1375 | ||
| 1367 | if (!info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) | 1376 | if (!info->attrs[NL80211_ATTR_WIPHY_FREQ]) |
| 1368 | return false; | 1377 | return -EINVAL; |
| 1369 | 1378 | ||
| 1370 | tmp = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]); | 1379 | control_freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); |
| 1371 | if (tmp != NL80211_CHAN_NO_HT && | ||
| 1372 | tmp != NL80211_CHAN_HT20 && | ||
| 1373 | tmp != NL80211_CHAN_HT40PLUS && | ||
| 1374 | tmp != NL80211_CHAN_HT40MINUS) | ||
| 1375 | return false; | ||
| 1376 | 1380 | ||
| 1377 | if (channel_type) | 1381 | chandef->chan = ieee80211_get_channel(&rdev->wiphy, control_freq); |
| 1378 | *channel_type = tmp; | 1382 | chandef->width = NL80211_CHAN_WIDTH_20_NOHT; |
| 1383 | chandef->center_freq1 = control_freq; | ||
| 1384 | chandef->center_freq2 = 0; | ||
| 1379 | 1385 | ||
| 1380 | return true; | 1386 | /* Primary channel not allowed */ |
| 1387 | if (!chandef->chan || chandef->chan->flags & IEEE80211_CHAN_DISABLED) | ||
| 1388 | return -EINVAL; | ||
| 1389 | |||
| 1390 | if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { | ||
| 1391 | enum nl80211_channel_type chantype; | ||
| 1392 | |||
| 1393 | chantype = nla_get_u32( | ||
| 1394 | info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]); | ||
| 1395 | |||
| 1396 | switch (chantype) { | ||
| 1397 | case NL80211_CHAN_NO_HT: | ||
| 1398 | case NL80211_CHAN_HT20: | ||
| 1399 | case NL80211_CHAN_HT40PLUS: | ||
| 1400 | case NL80211_CHAN_HT40MINUS: | ||
| 1401 | cfg80211_chandef_create(chandef, chandef->chan, | ||
| 1402 | chantype); | ||
| 1403 | break; | ||
| 1404 | default: | ||
| 1405 | return -EINVAL; | ||
| 1406 | } | ||
| 1407 | } else if (info->attrs[NL80211_ATTR_CHANNEL_WIDTH]) { | ||
| 1408 | chandef->width = | ||
| 1409 | nla_get_u32(info->attrs[NL80211_ATTR_CHANNEL_WIDTH]); | ||
| 1410 | if (info->attrs[NL80211_ATTR_CENTER_FREQ1]) | ||
| 1411 | chandef->center_freq1 = | ||
| 1412 | nla_get_u32( | ||
| 1413 | info->attrs[NL80211_ATTR_CENTER_FREQ1]); | ||
| 1414 | if (info->attrs[NL80211_ATTR_CENTER_FREQ2]) | ||
| 1415 | chandef->center_freq2 = | ||
| 1416 | nla_get_u32( | ||
| 1417 | info->attrs[NL80211_ATTR_CENTER_FREQ2]); | ||
| 1418 | } | ||
| 1419 | |||
| 1420 | ht_cap = &rdev->wiphy.bands[chandef->chan->band]->ht_cap; | ||
| 1421 | vht_cap = &rdev->wiphy.bands[chandef->chan->band]->vht_cap; | ||
| 1422 | |||
| 1423 | if (!cfg80211_chan_def_valid(chandef)) | ||
| 1424 | return -EINVAL; | ||
| 1425 | |||
| 1426 | switch (chandef->width) { | ||
| 1427 | case NL80211_CHAN_WIDTH_20: | ||
| 1428 | if (!ht_cap->ht_supported) | ||
| 1429 | return -EINVAL; | ||
| 1430 | case NL80211_CHAN_WIDTH_20_NOHT: | ||
| 1431 | width = 20; | ||
| 1432 | break; | ||
| 1433 | case NL80211_CHAN_WIDTH_40: | ||
| 1434 | width = 40; | ||
| 1435 | /* quick early regulatory check */ | ||
| 1436 | if (chandef->center_freq1 < control_freq && | ||
| 1437 | chandef->chan->flags & IEEE80211_CHAN_NO_HT40MINUS) | ||
| 1438 | return -EINVAL; | ||
| 1439 | if (chandef->center_freq1 > control_freq && | ||
| 1440 | chandef->chan->flags & IEEE80211_CHAN_NO_HT40PLUS) | ||
| 1441 | return -EINVAL; | ||
| 1442 | if (!ht_cap->ht_supported) | ||
| 1443 | return -EINVAL; | ||
| 1444 | if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) || | ||
| 1445 | ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT) | ||
| 1446 | return -EINVAL; | ||
| 1447 | break; | ||
| 1448 | case NL80211_CHAN_WIDTH_80: | ||
| 1449 | width = 80; | ||
| 1450 | if (!vht_cap->vht_supported) | ||
| 1451 | return -EINVAL; | ||
| 1452 | break; | ||
| 1453 | case NL80211_CHAN_WIDTH_80P80: | ||
| 1454 | width = 80; | ||
| 1455 | if (!vht_cap->vht_supported) | ||
| 1456 | return -EINVAL; | ||
| 1457 | if (!(vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ)) | ||
| 1458 | return -EINVAL; | ||
| 1459 | break; | ||
| 1460 | case NL80211_CHAN_WIDTH_160: | ||
| 1461 | width = 160; | ||
| 1462 | if (!vht_cap->vht_supported) | ||
| 1463 | return -EINVAL; | ||
| 1464 | if (!(vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ)) | ||
| 1465 | return -EINVAL; | ||
| 1466 | break; | ||
| 1467 | default: | ||
| 1468 | return -EINVAL; | ||
| 1469 | } | ||
| 1470 | |||
| 1471 | if (!cfg80211_secondary_chans_ok(&rdev->wiphy, chandef->center_freq1, | ||
| 1472 | width, IEEE80211_CHAN_DISABLED)) | ||
| 1473 | return -EINVAL; | ||
| 1474 | if (chandef->center_freq2 && | ||
| 1475 | !cfg80211_secondary_chans_ok(&rdev->wiphy, chandef->center_freq2, | ||
| 1476 | width, IEEE80211_CHAN_DISABLED)) | ||
| 1477 | return -EINVAL; | ||
| 1478 | |||
| 1479 | /* TODO: missing regulatory check on bandwidth */ | ||
| 1480 | |||
| 1481 | return 0; | ||
| 1381 | } | 1482 | } |
| 1382 | 1483 | ||
| 1383 | static int __nl80211_set_channel(struct cfg80211_registered_device *rdev, | 1484 | static int __nl80211_set_channel(struct cfg80211_registered_device *rdev, |
| 1384 | struct wireless_dev *wdev, | 1485 | struct wireless_dev *wdev, |
| 1385 | struct genl_info *info) | 1486 | struct genl_info *info) |
| 1386 | { | 1487 | { |
| 1387 | struct ieee80211_channel *channel; | 1488 | struct cfg80211_chan_def chandef; |
| 1388 | enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; | ||
| 1389 | u32 freq; | ||
| 1390 | int result; | 1489 | int result; |
| 1391 | enum nl80211_iftype iftype = NL80211_IFTYPE_MONITOR; | 1490 | enum nl80211_iftype iftype = NL80211_IFTYPE_MONITOR; |
| 1392 | 1491 | ||
| 1393 | if (wdev) | 1492 | if (wdev) |
| 1394 | iftype = wdev->iftype; | 1493 | iftype = wdev->iftype; |
| 1395 | 1494 | ||
| 1396 | if (!info->attrs[NL80211_ATTR_WIPHY_FREQ]) | ||
| 1397 | return -EINVAL; | ||
| 1398 | |||
| 1399 | if (!nl80211_can_set_dev_channel(wdev)) | 1495 | if (!nl80211_can_set_dev_channel(wdev)) |
| 1400 | return -EOPNOTSUPP; | 1496 | return -EOPNOTSUPP; |
| 1401 | 1497 | ||
| 1402 | if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE] && | 1498 | result = nl80211_parse_chandef(rdev, info, &chandef); |
| 1403 | !nl80211_valid_channel_type(info, &channel_type)) | 1499 | if (result) |
| 1404 | return -EINVAL; | 1500 | return result; |
| 1405 | |||
| 1406 | freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); | ||
| 1407 | 1501 | ||
| 1408 | mutex_lock(&rdev->devlist_mtx); | 1502 | mutex_lock(&rdev->devlist_mtx); |
| 1409 | switch (iftype) { | 1503 | switch (iftype) { |
| @@ -1413,22 +1507,18 @@ static int __nl80211_set_channel(struct cfg80211_registered_device *rdev, | |||
| 1413 | result = -EBUSY; | 1507 | result = -EBUSY; |
| 1414 | break; | 1508 | break; |
| 1415 | } | 1509 | } |
| 1416 | channel = rdev_freq_to_chan(rdev, freq, channel_type); | 1510 | if (!cfg80211_reg_can_beacon(&rdev->wiphy, &chandef)) { |
| 1417 | if (!channel || !cfg80211_can_beacon_sec_chan(&rdev->wiphy, | ||
| 1418 | channel, | ||
| 1419 | channel_type)) { | ||
| 1420 | result = -EINVAL; | 1511 | result = -EINVAL; |
| 1421 | break; | 1512 | break; |
| 1422 | } | 1513 | } |
| 1423 | wdev->preset_chan = channel; | 1514 | wdev->preset_chandef = chandef; |
| 1424 | wdev->preset_chantype = channel_type; | ||
| 1425 | result = 0; | 1515 | result = 0; |
| 1426 | break; | 1516 | break; |
| 1427 | case NL80211_IFTYPE_MESH_POINT: | 1517 | case NL80211_IFTYPE_MESH_POINT: |
| 1428 | result = cfg80211_set_mesh_freq(rdev, wdev, freq, channel_type); | 1518 | result = cfg80211_set_mesh_channel(rdev, wdev, &chandef); |
| 1429 | break; | 1519 | break; |
| 1430 | case NL80211_IFTYPE_MONITOR: | 1520 | case NL80211_IFTYPE_MONITOR: |
| 1431 | result = cfg80211_set_monitor_channel(rdev, freq, channel_type); | 1521 | result = cfg80211_set_monitor_channel(rdev, &chandef); |
| 1432 | break; | 1522 | break; |
| 1433 | default: | 1523 | default: |
| 1434 | result = -EINVAL; | 1524 | result = -EINVAL; |
| @@ -1516,10 +1606,8 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
| 1516 | result = 0; | 1606 | result = 0; |
| 1517 | 1607 | ||
| 1518 | mutex_lock(&rdev->mtx); | 1608 | mutex_lock(&rdev->mtx); |
| 1519 | } else if (nl80211_can_set_dev_channel(netdev->ieee80211_ptr)) | 1609 | } else |
| 1520 | wdev = netdev->ieee80211_ptr; | 1610 | wdev = netdev->ieee80211_ptr; |
| 1521 | else | ||
| 1522 | wdev = NULL; | ||
| 1523 | 1611 | ||
| 1524 | /* | 1612 | /* |
| 1525 | * end workaround code, by now the rdev is available | 1613 | * end workaround code, by now the rdev is available |
| @@ -1579,15 +1667,21 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
| 1579 | } | 1667 | } |
| 1580 | 1668 | ||
| 1581 | if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { | 1669 | if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { |
| 1582 | result = __nl80211_set_channel(rdev, wdev, info); | 1670 | result = __nl80211_set_channel(rdev, |
| 1671 | nl80211_can_set_dev_channel(wdev) ? wdev : NULL, | ||
| 1672 | info); | ||
| 1583 | if (result) | 1673 | if (result) |
| 1584 | goto bad_res; | 1674 | goto bad_res; |
| 1585 | } | 1675 | } |
| 1586 | 1676 | ||
| 1587 | if (info->attrs[NL80211_ATTR_WIPHY_TX_POWER_SETTING]) { | 1677 | if (info->attrs[NL80211_ATTR_WIPHY_TX_POWER_SETTING]) { |
| 1678 | struct wireless_dev *txp_wdev = wdev; | ||
| 1588 | enum nl80211_tx_power_setting type; | 1679 | enum nl80211_tx_power_setting type; |
| 1589 | int idx, mbm = 0; | 1680 | int idx, mbm = 0; |
| 1590 | 1681 | ||
| 1682 | if (!(rdev->wiphy.features & NL80211_FEATURE_VIF_TXPOWER)) | ||
| 1683 | txp_wdev = NULL; | ||
| 1684 | |||
| 1591 | if (!rdev->ops->set_tx_power) { | 1685 | if (!rdev->ops->set_tx_power) { |
| 1592 | result = -EOPNOTSUPP; | 1686 | result = -EOPNOTSUPP; |
| 1593 | goto bad_res; | 1687 | goto bad_res; |
| @@ -1607,7 +1701,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
| 1607 | mbm = nla_get_u32(info->attrs[idx]); | 1701 | mbm = nla_get_u32(info->attrs[idx]); |
| 1608 | } | 1702 | } |
| 1609 | 1703 | ||
| 1610 | result = rdev_set_tx_power(rdev, type, mbm); | 1704 | result = rdev_set_tx_power(rdev, txp_wdev, type, mbm); |
| 1611 | if (result) | 1705 | if (result) |
| 1612 | goto bad_res; | 1706 | goto bad_res; |
| 1613 | } | 1707 | } |
| @@ -1744,6 +1838,35 @@ static inline u64 wdev_id(struct wireless_dev *wdev) | |||
| 1744 | ((u64)wiphy_to_dev(wdev->wiphy)->wiphy_idx << 32); | 1838 | ((u64)wiphy_to_dev(wdev->wiphy)->wiphy_idx << 32); |
| 1745 | } | 1839 | } |
| 1746 | 1840 | ||
| 1841 | static int nl80211_send_chandef(struct sk_buff *msg, | ||
| 1842 | struct cfg80211_chan_def *chandef) | ||
| 1843 | { | ||
| 1844 | WARN_ON(!cfg80211_chan_def_valid(chandef)); | ||
| 1845 | |||
| 1846 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, | ||
| 1847 | chandef->chan->center_freq)) | ||
| 1848 | return -ENOBUFS; | ||
| 1849 | switch (chandef->width) { | ||
| 1850 | case NL80211_CHAN_WIDTH_20_NOHT: | ||
| 1851 | case NL80211_CHAN_WIDTH_20: | ||
| 1852 | case NL80211_CHAN_WIDTH_40: | ||
| 1853 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, | ||
| 1854 | cfg80211_get_chandef_type(chandef))) | ||
| 1855 | return -ENOBUFS; | ||
| 1856 | break; | ||
| 1857 | default: | ||
| 1858 | break; | ||
| 1859 | } | ||
| 1860 | if (nla_put_u32(msg, NL80211_ATTR_CHANNEL_WIDTH, chandef->width)) | ||
| 1861 | return -ENOBUFS; | ||
| 1862 | if (nla_put_u32(msg, NL80211_ATTR_CENTER_FREQ1, chandef->center_freq1)) | ||
| 1863 | return -ENOBUFS; | ||
| 1864 | if (chandef->center_freq2 && | ||
| 1865 | nla_put_u32(msg, NL80211_ATTR_CENTER_FREQ2, chandef->center_freq2)) | ||
| 1866 | return -ENOBUFS; | ||
| 1867 | return 0; | ||
| 1868 | } | ||
| 1869 | |||
| 1747 | static int nl80211_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flags, | 1870 | static int nl80211_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flags, |
| 1748 | struct cfg80211_registered_device *rdev, | 1871 | struct cfg80211_registered_device *rdev, |
| 1749 | struct wireless_dev *wdev) | 1872 | struct wireless_dev *wdev) |
| @@ -1770,15 +1893,18 @@ static int nl80211_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flag | |||
| 1770 | goto nla_put_failure; | 1893 | goto nla_put_failure; |
| 1771 | 1894 | ||
| 1772 | if (rdev->ops->get_channel) { | 1895 | if (rdev->ops->get_channel) { |
| 1773 | struct ieee80211_channel *chan; | 1896 | int ret; |
| 1774 | enum nl80211_channel_type channel_type; | 1897 | struct cfg80211_chan_def chandef; |
| 1775 | 1898 | ||
| 1776 | chan = rdev_get_channel(rdev, wdev, &channel_type); | 1899 | ret = rdev_get_channel(rdev, wdev, &chandef); |
| 1777 | if (chan && | 1900 | if (ret == 0) { |
| 1778 | (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, | 1901 | if (nl80211_send_chandef(msg, &chandef)) |
| 1779 | chan->center_freq) || | 1902 | goto nla_put_failure; |
| 1780 | nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, | 1903 | } |
| 1781 | channel_type))) | 1904 | } |
| 1905 | |||
| 1906 | if (wdev->ssid_len) { | ||
| 1907 | if (nla_put(msg, NL80211_ATTR_SSID, wdev->ssid_len, wdev->ssid)) | ||
| 1782 | goto nla_put_failure; | 1908 | goto nla_put_failure; |
| 1783 | } | 1909 | } |
| 1784 | 1910 | ||
| @@ -2482,11 +2608,10 @@ static bool nl80211_get_ap_channel(struct cfg80211_registered_device *rdev, | |||
| 2482 | wdev->iftype != NL80211_IFTYPE_P2P_GO) | 2608 | wdev->iftype != NL80211_IFTYPE_P2P_GO) |
| 2483 | continue; | 2609 | continue; |
| 2484 | 2610 | ||
| 2485 | if (!wdev->preset_chan) | 2611 | if (!wdev->preset_chandef.chan) |
| 2486 | continue; | 2612 | continue; |
| 2487 | 2613 | ||
| 2488 | params->channel = wdev->preset_chan; | 2614 | params->chandef = wdev->preset_chandef; |
| 2489 | params->channel_type = wdev->preset_chantype; | ||
| 2490 | ret = true; | 2615 | ret = true; |
| 2491 | break; | 2616 | break; |
| 2492 | } | 2617 | } |
| @@ -2608,30 +2733,19 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) | |||
| 2608 | } | 2733 | } |
| 2609 | 2734 | ||
| 2610 | if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { | 2735 | if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { |
| 2611 | enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; | 2736 | err = nl80211_parse_chandef(rdev, info, ¶ms.chandef); |
| 2612 | 2737 | if (err) | |
| 2613 | if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE] && | 2738 | return err; |
| 2614 | !nl80211_valid_channel_type(info, &channel_type)) | 2739 | } else if (wdev->preset_chandef.chan) { |
| 2615 | return -EINVAL; | 2740 | params.chandef = wdev->preset_chandef; |
| 2616 | |||
| 2617 | params.channel = rdev_freq_to_chan(rdev, | ||
| 2618 | nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]), | ||
| 2619 | channel_type); | ||
| 2620 | if (!params.channel) | ||
| 2621 | return -EINVAL; | ||
| 2622 | params.channel_type = channel_type; | ||
| 2623 | } else if (wdev->preset_chan) { | ||
| 2624 | params.channel = wdev->preset_chan; | ||
| 2625 | params.channel_type = wdev->preset_chantype; | ||
| 2626 | } else if (!nl80211_get_ap_channel(rdev, ¶ms)) | 2741 | } else if (!nl80211_get_ap_channel(rdev, ¶ms)) |
| 2627 | return -EINVAL; | 2742 | return -EINVAL; |
| 2628 | 2743 | ||
| 2629 | if (!cfg80211_can_beacon_sec_chan(&rdev->wiphy, params.channel, | 2744 | if (!cfg80211_reg_can_beacon(&rdev->wiphy, ¶ms.chandef)) |
| 2630 | params.channel_type)) | ||
| 2631 | return -EINVAL; | 2745 | return -EINVAL; |
| 2632 | 2746 | ||
| 2633 | mutex_lock(&rdev->devlist_mtx); | 2747 | mutex_lock(&rdev->devlist_mtx); |
| 2634 | err = cfg80211_can_use_chan(rdev, wdev, params.channel, | 2748 | err = cfg80211_can_use_chan(rdev, wdev, params.chandef.chan, |
| 2635 | CHAN_MODE_SHARED); | 2749 | CHAN_MODE_SHARED); |
| 2636 | mutex_unlock(&rdev->devlist_mtx); | 2750 | mutex_unlock(&rdev->devlist_mtx); |
| 2637 | 2751 | ||
| @@ -2640,10 +2754,11 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) | |||
| 2640 | 2754 | ||
| 2641 | err = rdev_start_ap(rdev, dev, ¶ms); | 2755 | err = rdev_start_ap(rdev, dev, ¶ms); |
| 2642 | if (!err) { | 2756 | if (!err) { |
| 2643 | wdev->preset_chan = params.channel; | 2757 | wdev->preset_chandef = params.chandef; |
| 2644 | wdev->preset_chantype = params.channel_type; | ||
| 2645 | wdev->beacon_interval = params.beacon_interval; | 2758 | wdev->beacon_interval = params.beacon_interval; |
| 2646 | wdev->channel = params.channel; | 2759 | wdev->channel = params.chandef.chan; |
| 2760 | wdev->ssid_len = params.ssid_len; | ||
| 2761 | memcpy(wdev->ssid, params.ssid, wdev->ssid_len); | ||
| 2647 | } | 2762 | } |
| 2648 | return err; | 2763 | return err; |
| 2649 | } | 2764 | } |
| @@ -2775,29 +2890,52 @@ static bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info, | |||
| 2775 | 2890 | ||
| 2776 | rate = nla_nest_start(msg, attr); | 2891 | rate = nla_nest_start(msg, attr); |
| 2777 | if (!rate) | 2892 | if (!rate) |
| 2778 | goto nla_put_failure; | 2893 | return false; |
| 2779 | 2894 | ||
| 2780 | /* cfg80211_calculate_bitrate will return 0 for mcs >= 32 */ | 2895 | /* cfg80211_calculate_bitrate will return 0 for mcs >= 32 */ |
| 2781 | bitrate = cfg80211_calculate_bitrate(info); | 2896 | bitrate = cfg80211_calculate_bitrate(info); |
| 2782 | /* report 16-bit bitrate only if we can */ | 2897 | /* report 16-bit bitrate only if we can */ |
| 2783 | bitrate_compat = bitrate < (1UL << 16) ? bitrate : 0; | 2898 | bitrate_compat = bitrate < (1UL << 16) ? bitrate : 0; |
| 2784 | if ((bitrate > 0 && | 2899 | if (bitrate > 0 && |
| 2785 | nla_put_u32(msg, NL80211_RATE_INFO_BITRATE32, bitrate)) || | 2900 | nla_put_u32(msg, NL80211_RATE_INFO_BITRATE32, bitrate)) |
| 2786 | (bitrate_compat > 0 && | 2901 | return false; |
| 2787 | nla_put_u16(msg, NL80211_RATE_INFO_BITRATE, bitrate_compat)) || | 2902 | if (bitrate_compat > 0 && |
| 2788 | ((info->flags & RATE_INFO_FLAGS_MCS) && | 2903 | nla_put_u16(msg, NL80211_RATE_INFO_BITRATE, bitrate_compat)) |
| 2789 | nla_put_u8(msg, NL80211_RATE_INFO_MCS, info->mcs)) || | 2904 | return false; |
| 2790 | ((info->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH) && | 2905 | |
| 2791 | nla_put_flag(msg, NL80211_RATE_INFO_40_MHZ_WIDTH)) || | 2906 | if (info->flags & RATE_INFO_FLAGS_MCS) { |
| 2792 | ((info->flags & RATE_INFO_FLAGS_SHORT_GI) && | 2907 | if (nla_put_u8(msg, NL80211_RATE_INFO_MCS, info->mcs)) |
| 2793 | nla_put_flag(msg, NL80211_RATE_INFO_SHORT_GI))) | 2908 | return false; |
| 2794 | goto nla_put_failure; | 2909 | if (info->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH && |
| 2910 | nla_put_flag(msg, NL80211_RATE_INFO_40_MHZ_WIDTH)) | ||
| 2911 | return false; | ||
| 2912 | if (info->flags & RATE_INFO_FLAGS_SHORT_GI && | ||
| 2913 | nla_put_flag(msg, NL80211_RATE_INFO_SHORT_GI)) | ||
| 2914 | return false; | ||
| 2915 | } else if (info->flags & RATE_INFO_FLAGS_VHT_MCS) { | ||
| 2916 | if (nla_put_u8(msg, NL80211_RATE_INFO_VHT_MCS, info->mcs)) | ||
| 2917 | return false; | ||
| 2918 | if (nla_put_u8(msg, NL80211_RATE_INFO_VHT_NSS, info->nss)) | ||
| 2919 | return false; | ||
| 2920 | if (info->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH && | ||
| 2921 | nla_put_flag(msg, NL80211_RATE_INFO_40_MHZ_WIDTH)) | ||
| 2922 | return false; | ||
| 2923 | if (info->flags & RATE_INFO_FLAGS_80_MHZ_WIDTH && | ||
| 2924 | nla_put_flag(msg, NL80211_RATE_INFO_80_MHZ_WIDTH)) | ||
| 2925 | return false; | ||
| 2926 | if (info->flags & RATE_INFO_FLAGS_80P80_MHZ_WIDTH && | ||
| 2927 | nla_put_flag(msg, NL80211_RATE_INFO_80P80_MHZ_WIDTH)) | ||
| 2928 | return false; | ||
| 2929 | if (info->flags & RATE_INFO_FLAGS_160_MHZ_WIDTH && | ||
| 2930 | nla_put_flag(msg, NL80211_RATE_INFO_160_MHZ_WIDTH)) | ||
| 2931 | return false; | ||
| 2932 | if (info->flags & RATE_INFO_FLAGS_SHORT_GI && | ||
| 2933 | nla_put_flag(msg, NL80211_RATE_INFO_SHORT_GI)) | ||
| 2934 | return false; | ||
| 2935 | } | ||
| 2795 | 2936 | ||
| 2796 | nla_nest_end(msg, rate); | 2937 | nla_nest_end(msg, rate); |
| 2797 | return true; | 2938 | return true; |
| 2798 | |||
| 2799 | nla_put_failure: | ||
| 2800 | return false; | ||
| 2801 | } | 2939 | } |
| 2802 | 2940 | ||
| 2803 | static int nl80211_send_station(struct sk_buff *msg, u32 portid, u32 seq, | 2941 | static int nl80211_send_station(struct sk_buff *msg, u32 portid, u32 seq, |
| @@ -5318,8 +5456,7 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) | |||
| 5318 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) | 5456 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) |
| 5319 | return -EINVAL; | 5457 | return -EINVAL; |
| 5320 | 5458 | ||
| 5321 | if (!info->attrs[NL80211_ATTR_WIPHY_FREQ] || | 5459 | if (!info->attrs[NL80211_ATTR_SSID] || |
| 5322 | !info->attrs[NL80211_ATTR_SSID] || | ||
| 5323 | !nla_len(info->attrs[NL80211_ATTR_SSID])) | 5460 | !nla_len(info->attrs[NL80211_ATTR_SSID])) |
| 5324 | return -EINVAL; | 5461 | return -EINVAL; |
| 5325 | 5462 | ||
| @@ -5354,35 +5491,17 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) | |||
| 5354 | ibss.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); | 5491 | ibss.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); |
| 5355 | } | 5492 | } |
| 5356 | 5493 | ||
| 5357 | if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { | 5494 | err = nl80211_parse_chandef(rdev, info, &ibss.chandef); |
| 5358 | enum nl80211_channel_type channel_type; | 5495 | if (err) |
| 5359 | 5496 | return err; | |
| 5360 | if (!nl80211_valid_channel_type(info, &channel_type)) | ||
| 5361 | return -EINVAL; | ||
| 5362 | |||
| 5363 | if (channel_type != NL80211_CHAN_NO_HT && | ||
| 5364 | !(wiphy->features & NL80211_FEATURE_HT_IBSS)) | ||
| 5365 | return -EINVAL; | ||
| 5366 | |||
| 5367 | ibss.channel_type = channel_type; | ||
| 5368 | } else { | ||
| 5369 | ibss.channel_type = NL80211_CHAN_NO_HT; | ||
| 5370 | } | ||
| 5371 | 5497 | ||
| 5372 | ibss.channel = rdev_freq_to_chan(rdev, | 5498 | if (!cfg80211_reg_can_beacon(&rdev->wiphy, &ibss.chandef)) |
| 5373 | nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]), | ||
| 5374 | ibss.channel_type); | ||
| 5375 | if (!ibss.channel || | ||
| 5376 | ibss.channel->flags & IEEE80211_CHAN_NO_IBSS || | ||
| 5377 | ibss.channel->flags & IEEE80211_CHAN_DISABLED) | ||
| 5378 | return -EINVAL; | 5499 | return -EINVAL; |
| 5379 | 5500 | ||
| 5380 | /* Both channels should be able to initiate communication */ | 5501 | if (ibss.chandef.width > NL80211_CHAN_WIDTH_40) |
| 5381 | if ((ibss.channel_type == NL80211_CHAN_HT40PLUS || | ||
| 5382 | ibss.channel_type == NL80211_CHAN_HT40MINUS) && | ||
| 5383 | !cfg80211_can_beacon_sec_chan(&rdev->wiphy, ibss.channel, | ||
| 5384 | ibss.channel_type)) | ||
| 5385 | return -EINVAL; | 5502 | return -EINVAL; |
| 5503 | if (ibss.chandef.width != NL80211_CHAN_WIDTH_20_NOHT && | ||
| 5504 | !(rdev->wiphy.features & NL80211_FEATURE_HT_IBSS)) | ||
| 5386 | 5505 | ||
| 5387 | ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED]; | 5506 | ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED]; |
| 5388 | ibss.privacy = !!info->attrs[NL80211_ATTR_PRIVACY]; | 5507 | ibss.privacy = !!info->attrs[NL80211_ATTR_PRIVACY]; |
| @@ -5393,7 +5512,7 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) | |||
| 5393 | int n_rates = | 5512 | int n_rates = |
| 5394 | nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]); | 5513 | nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]); |
| 5395 | struct ieee80211_supported_band *sband = | 5514 | struct ieee80211_supported_band *sband = |
| 5396 | wiphy->bands[ibss.channel->band]; | 5515 | wiphy->bands[ibss.chandef.chan->band]; |
| 5397 | 5516 | ||
| 5398 | err = ieee80211_get_ratemask(sband, rates, n_rates, | 5517 | err = ieee80211_get_ratemask(sband, rates, n_rates, |
| 5399 | &ibss.basic_rates); | 5518 | &ibss.basic_rates); |
| @@ -5415,7 +5534,8 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) | |||
| 5415 | if (IS_ERR(connkeys)) | 5534 | if (IS_ERR(connkeys)) |
| 5416 | return PTR_ERR(connkeys); | 5535 | return PTR_ERR(connkeys); |
| 5417 | 5536 | ||
| 5418 | if ((ibss.channel_type != NL80211_CHAN_NO_HT) && no_ht) { | 5537 | if ((ibss.chandef.width != NL80211_CHAN_WIDTH_20_NOHT) && |
| 5538 | no_ht) { | ||
| 5419 | kfree(connkeys); | 5539 | kfree(connkeys); |
| 5420 | return -EINVAL; | 5540 | return -EINVAL; |
| 5421 | } | 5541 | } |
| @@ -5444,6 +5564,36 @@ static int nl80211_leave_ibss(struct sk_buff *skb, struct genl_info *info) | |||
| 5444 | return cfg80211_leave_ibss(rdev, dev, false); | 5564 | return cfg80211_leave_ibss(rdev, dev, false); |
| 5445 | } | 5565 | } |
| 5446 | 5566 | ||
| 5567 | static int nl80211_set_mcast_rate(struct sk_buff *skb, struct genl_info *info) | ||
| 5568 | { | ||
| 5569 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
| 5570 | struct net_device *dev = info->user_ptr[1]; | ||
| 5571 | int mcast_rate[IEEE80211_NUM_BANDS]; | ||
| 5572 | u32 nla_rate; | ||
| 5573 | int err; | ||
| 5574 | |||
| 5575 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC && | ||
| 5576 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) | ||
| 5577 | return -EOPNOTSUPP; | ||
| 5578 | |||
| 5579 | if (!rdev->ops->set_mcast_rate) | ||
| 5580 | return -EOPNOTSUPP; | ||
| 5581 | |||
| 5582 | memset(mcast_rate, 0, sizeof(mcast_rate)); | ||
| 5583 | |||
| 5584 | if (!info->attrs[NL80211_ATTR_MCAST_RATE]) | ||
| 5585 | return -EINVAL; | ||
| 5586 | |||
| 5587 | nla_rate = nla_get_u32(info->attrs[NL80211_ATTR_MCAST_RATE]); | ||
| 5588 | if (!nl80211_parse_mcast_rate(rdev, mcast_rate, nla_rate)) | ||
| 5589 | return -EINVAL; | ||
| 5590 | |||
| 5591 | err = rdev->ops->set_mcast_rate(&rdev->wiphy, dev, mcast_rate); | ||
| 5592 | |||
| 5593 | return err; | ||
| 5594 | } | ||
| 5595 | |||
| 5596 | |||
| 5447 | #ifdef CONFIG_NL80211_TESTMODE | 5597 | #ifdef CONFIG_NL80211_TESTMODE |
| 5448 | static struct genl_multicast_group nl80211_testmode_mcgrp = { | 5598 | static struct genl_multicast_group nl80211_testmode_mcgrp = { |
| 5449 | .name = "testmode", | 5599 | .name = "testmode", |
| @@ -5906,12 +6056,11 @@ static int nl80211_remain_on_channel(struct sk_buff *skb, | |||
| 5906 | { | 6056 | { |
| 5907 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 6057 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
| 5908 | struct wireless_dev *wdev = info->user_ptr[1]; | 6058 | struct wireless_dev *wdev = info->user_ptr[1]; |
| 5909 | struct ieee80211_channel *chan; | 6059 | struct cfg80211_chan_def chandef; |
| 5910 | struct sk_buff *msg; | 6060 | struct sk_buff *msg; |
| 5911 | void *hdr; | 6061 | void *hdr; |
| 5912 | u64 cookie; | 6062 | u64 cookie; |
| 5913 | enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; | 6063 | u32 duration; |
| 5914 | u32 freq, duration; | ||
| 5915 | int err; | 6064 | int err; |
| 5916 | 6065 | ||
| 5917 | if (!info->attrs[NL80211_ATTR_WIPHY_FREQ] || | 6066 | if (!info->attrs[NL80211_ATTR_WIPHY_FREQ] || |
| @@ -5932,14 +6081,9 @@ static int nl80211_remain_on_channel(struct sk_buff *skb, | |||
| 5932 | duration > rdev->wiphy.max_remain_on_channel_duration) | 6081 | duration > rdev->wiphy.max_remain_on_channel_duration) |
| 5933 | return -EINVAL; | 6082 | return -EINVAL; |
| 5934 | 6083 | ||
| 5935 | if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE] && | 6084 | err = nl80211_parse_chandef(rdev, info, &chandef); |
| 5936 | !nl80211_valid_channel_type(info, &channel_type)) | 6085 | if (err) |
| 5937 | return -EINVAL; | 6086 | return err; |
| 5938 | |||
| 5939 | freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); | ||
| 5940 | chan = rdev_freq_to_chan(rdev, freq, channel_type); | ||
| 5941 | if (chan == NULL) | ||
| 5942 | return -EINVAL; | ||
| 5943 | 6087 | ||
| 5944 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 6088 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
| 5945 | if (!msg) | 6089 | if (!msg) |
| @@ -5953,8 +6097,8 @@ static int nl80211_remain_on_channel(struct sk_buff *skb, | |||
| 5953 | goto free_msg; | 6097 | goto free_msg; |
| 5954 | } | 6098 | } |
| 5955 | 6099 | ||
| 5956 | err = rdev_remain_on_channel(rdev, wdev, chan, channel_type, duration, | 6100 | err = rdev_remain_on_channel(rdev, wdev, chandef.chan, |
| 5957 | &cookie); | 6101 | duration, &cookie); |
| 5958 | 6102 | ||
| 5959 | if (err) | 6103 | if (err) |
| 5960 | goto free_msg; | 6104 | goto free_msg; |
| @@ -6173,10 +6317,7 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) | |||
| 6173 | { | 6317 | { |
| 6174 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 6318 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
| 6175 | struct wireless_dev *wdev = info->user_ptr[1]; | 6319 | struct wireless_dev *wdev = info->user_ptr[1]; |
| 6176 | struct ieee80211_channel *chan; | 6320 | struct cfg80211_chan_def chandef; |
| 6177 | enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; | ||
| 6178 | bool channel_type_valid = false; | ||
| 6179 | u32 freq; | ||
| 6180 | int err; | 6321 | int err; |
| 6181 | void *hdr = NULL; | 6322 | void *hdr = NULL; |
| 6182 | u64 cookie; | 6323 | u64 cookie; |
| @@ -6186,8 +6327,7 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) | |||
| 6186 | 6327 | ||
| 6187 | dont_wait_for_ack = info->attrs[NL80211_ATTR_DONT_WAIT_FOR_ACK]; | 6328 | dont_wait_for_ack = info->attrs[NL80211_ATTR_DONT_WAIT_FOR_ACK]; |
| 6188 | 6329 | ||
| 6189 | if (!info->attrs[NL80211_ATTR_FRAME] || | 6330 | if (!info->attrs[NL80211_ATTR_FRAME]) |
| 6190 | !info->attrs[NL80211_ATTR_WIPHY_FREQ]) | ||
| 6191 | return -EINVAL; | 6331 | return -EINVAL; |
| 6192 | 6332 | ||
| 6193 | if (!rdev->ops->mgmt_tx) | 6333 | if (!rdev->ops->mgmt_tx) |
| @@ -6222,12 +6362,6 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) | |||
| 6222 | 6362 | ||
| 6223 | } | 6363 | } |
| 6224 | 6364 | ||
| 6225 | if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { | ||
| 6226 | if (!nl80211_valid_channel_type(info, &channel_type)) | ||
| 6227 | return -EINVAL; | ||
| 6228 | channel_type_valid = true; | ||
| 6229 | } | ||
| 6230 | |||
| 6231 | offchan = info->attrs[NL80211_ATTR_OFFCHANNEL_TX_OK]; | 6365 | offchan = info->attrs[NL80211_ATTR_OFFCHANNEL_TX_OK]; |
| 6232 | 6366 | ||
| 6233 | if (offchan && !(rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX)) | 6367 | if (offchan && !(rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX)) |
| @@ -6235,10 +6369,9 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) | |||
| 6235 | 6369 | ||
| 6236 | no_cck = nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]); | 6370 | no_cck = nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]); |
| 6237 | 6371 | ||
| 6238 | freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); | 6372 | err = nl80211_parse_chandef(rdev, info, &chandef); |
| 6239 | chan = rdev_freq_to_chan(rdev, freq, channel_type); | 6373 | if (err) |
| 6240 | if (chan == NULL) | 6374 | return err; |
| 6241 | return -EINVAL; | ||
| 6242 | 6375 | ||
| 6243 | if (!dont_wait_for_ack) { | 6376 | if (!dont_wait_for_ack) { |
| 6244 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 6377 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
| @@ -6254,8 +6387,7 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) | |||
| 6254 | } | 6387 | } |
| 6255 | } | 6388 | } |
| 6256 | 6389 | ||
| 6257 | err = cfg80211_mlme_mgmt_tx(rdev, wdev, chan, offchan, channel_type, | 6390 | err = cfg80211_mlme_mgmt_tx(rdev, wdev, chandef.chan, offchan, wait, |
| 6258 | channel_type_valid, wait, | ||
| 6259 | nla_data(info->attrs[NL80211_ATTR_FRAME]), | 6391 | nla_data(info->attrs[NL80211_ATTR_FRAME]), |
| 6260 | nla_len(info->attrs[NL80211_ATTR_FRAME]), | 6392 | nla_len(info->attrs[NL80211_ATTR_FRAME]), |
| 6261 | no_cck, dont_wait_for_ack, &cookie); | 6393 | no_cck, dont_wait_for_ack, &cookie); |
| @@ -6519,21 +6651,12 @@ static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info) | |||
| 6519 | } | 6651 | } |
| 6520 | 6652 | ||
| 6521 | if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { | 6653 | if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { |
| 6522 | enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; | 6654 | err = nl80211_parse_chandef(rdev, info, &setup.chandef); |
| 6523 | 6655 | if (err) | |
| 6524 | if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE] && | 6656 | return err; |
| 6525 | !nl80211_valid_channel_type(info, &channel_type)) | ||
| 6526 | return -EINVAL; | ||
| 6527 | |||
| 6528 | setup.channel = rdev_freq_to_chan(rdev, | ||
| 6529 | nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]), | ||
| 6530 | channel_type); | ||
| 6531 | if (!setup.channel) | ||
| 6532 | return -EINVAL; | ||
| 6533 | setup.channel_type = channel_type; | ||
| 6534 | } else { | 6657 | } else { |
| 6535 | /* cfg80211_join_mesh() will sort it out */ | 6658 | /* cfg80211_join_mesh() will sort it out */ |
| 6536 | setup.channel = NULL; | 6659 | setup.chandef.chan = NULL; |
| 6537 | } | 6660 | } |
| 6538 | 6661 | ||
| 6539 | return cfg80211_join_mesh(rdev, dev, &setup, &cfg); | 6662 | return cfg80211_join_mesh(rdev, dev, &setup, &cfg); |
| @@ -6899,16 +7022,35 @@ static int nl80211_probe_client(struct sk_buff *skb, | |||
| 6899 | static int nl80211_register_beacons(struct sk_buff *skb, struct genl_info *info) | 7022 | static int nl80211_register_beacons(struct sk_buff *skb, struct genl_info *info) |
| 6900 | { | 7023 | { |
| 6901 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 7024 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
| 7025 | struct cfg80211_beacon_registration *reg, *nreg; | ||
| 7026 | int rv; | ||
| 6902 | 7027 | ||
| 6903 | if (!(rdev->wiphy.flags & WIPHY_FLAG_REPORTS_OBSS)) | 7028 | if (!(rdev->wiphy.flags & WIPHY_FLAG_REPORTS_OBSS)) |
| 6904 | return -EOPNOTSUPP; | 7029 | return -EOPNOTSUPP; |
| 6905 | 7030 | ||
| 6906 | if (rdev->ap_beacons_nlportid) | 7031 | nreg = kzalloc(sizeof(*nreg), GFP_KERNEL); |
| 6907 | return -EBUSY; | 7032 | if (!nreg) |
| 7033 | return -ENOMEM; | ||
| 6908 | 7034 | ||
| 6909 | rdev->ap_beacons_nlportid = info->snd_portid; | 7035 | /* First, check if already registered. */ |
| 7036 | spin_lock_bh(&rdev->beacon_registrations_lock); | ||
| 7037 | list_for_each_entry(reg, &rdev->beacon_registrations, list) { | ||
| 7038 | if (reg->nlportid == info->snd_portid) { | ||
| 7039 | rv = -EALREADY; | ||
| 7040 | goto out_err; | ||
| 7041 | } | ||
| 7042 | } | ||
| 7043 | /* Add it to the list */ | ||
| 7044 | nreg->nlportid = info->snd_portid; | ||
| 7045 | list_add(&nreg->list, &rdev->beacon_registrations); | ||
| 7046 | |||
| 7047 | spin_unlock_bh(&rdev->beacon_registrations_lock); | ||
| 6910 | 7048 | ||
| 6911 | return 0; | 7049 | return 0; |
| 7050 | out_err: | ||
| 7051 | spin_unlock_bh(&rdev->beacon_registrations_lock); | ||
| 7052 | kfree(nreg); | ||
| 7053 | return rv; | ||
| 6912 | } | 7054 | } |
| 6913 | 7055 | ||
| 6914 | static int nl80211_start_p2p_device(struct sk_buff *skb, struct genl_info *info) | 7056 | static int nl80211_start_p2p_device(struct sk_buff *skb, struct genl_info *info) |
| @@ -7625,6 +7767,14 @@ static struct genl_ops nl80211_ops[] = { | |||
| 7625 | .internal_flags = NL80211_FLAG_NEED_WDEV_UP | | 7767 | .internal_flags = NL80211_FLAG_NEED_WDEV_UP | |
| 7626 | NL80211_FLAG_NEED_RTNL, | 7768 | NL80211_FLAG_NEED_RTNL, |
| 7627 | }, | 7769 | }, |
| 7770 | { | ||
| 7771 | .cmd = NL80211_CMD_SET_MCAST_RATE, | ||
| 7772 | .doit = nl80211_set_mcast_rate, | ||
| 7773 | .policy = nl80211_policy, | ||
| 7774 | .flags = GENL_ADMIN_PERM, | ||
| 7775 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
| 7776 | NL80211_FLAG_NEED_RTNL, | ||
| 7777 | }, | ||
| 7628 | }; | 7778 | }; |
| 7629 | 7779 | ||
| 7630 | static struct genl_multicast_group nl80211_mlme_mcgrp = { | 7780 | static struct genl_multicast_group nl80211_mlme_mcgrp = { |
| @@ -8326,7 +8476,6 @@ static void nl80211_send_remain_on_chan_event( | |||
| 8326 | int cmd, struct cfg80211_registered_device *rdev, | 8476 | int cmd, struct cfg80211_registered_device *rdev, |
| 8327 | struct wireless_dev *wdev, u64 cookie, | 8477 | struct wireless_dev *wdev, u64 cookie, |
| 8328 | struct ieee80211_channel *chan, | 8478 | struct ieee80211_channel *chan, |
| 8329 | enum nl80211_channel_type channel_type, | ||
| 8330 | unsigned int duration, gfp_t gfp) | 8479 | unsigned int duration, gfp_t gfp) |
| 8331 | { | 8480 | { |
| 8332 | struct sk_buff *msg; | 8481 | struct sk_buff *msg; |
| @@ -8347,7 +8496,8 @@ static void nl80211_send_remain_on_chan_event( | |||
| 8347 | wdev->netdev->ifindex)) || | 8496 | wdev->netdev->ifindex)) || |
| 8348 | nla_put_u64(msg, NL80211_ATTR_WDEV, wdev_id(wdev)) || | 8497 | nla_put_u64(msg, NL80211_ATTR_WDEV, wdev_id(wdev)) || |
| 8349 | nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, chan->center_freq) || | 8498 | nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, chan->center_freq) || |
| 8350 | nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, channel_type) || | 8499 | nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, |
| 8500 | NL80211_CHAN_NO_HT) || | ||
| 8351 | nla_put_u64(msg, NL80211_ATTR_COOKIE, cookie)) | 8501 | nla_put_u64(msg, NL80211_ATTR_COOKIE, cookie)) |
| 8352 | goto nla_put_failure; | 8502 | goto nla_put_failure; |
| 8353 | 8503 | ||
| @@ -8369,23 +8519,20 @@ static void nl80211_send_remain_on_chan_event( | |||
| 8369 | void nl80211_send_remain_on_channel(struct cfg80211_registered_device *rdev, | 8519 | void nl80211_send_remain_on_channel(struct cfg80211_registered_device *rdev, |
| 8370 | struct wireless_dev *wdev, u64 cookie, | 8520 | struct wireless_dev *wdev, u64 cookie, |
| 8371 | struct ieee80211_channel *chan, | 8521 | struct ieee80211_channel *chan, |
| 8372 | enum nl80211_channel_type channel_type, | ||
| 8373 | unsigned int duration, gfp_t gfp) | 8522 | unsigned int duration, gfp_t gfp) |
| 8374 | { | 8523 | { |
| 8375 | nl80211_send_remain_on_chan_event(NL80211_CMD_REMAIN_ON_CHANNEL, | 8524 | nl80211_send_remain_on_chan_event(NL80211_CMD_REMAIN_ON_CHANNEL, |
| 8376 | rdev, wdev, cookie, chan, | 8525 | rdev, wdev, cookie, chan, |
| 8377 | channel_type, duration, gfp); | 8526 | duration, gfp); |
| 8378 | } | 8527 | } |
| 8379 | 8528 | ||
| 8380 | void nl80211_send_remain_on_channel_cancel( | 8529 | void nl80211_send_remain_on_channel_cancel( |
| 8381 | struct cfg80211_registered_device *rdev, | 8530 | struct cfg80211_registered_device *rdev, |
| 8382 | struct wireless_dev *wdev, | 8531 | struct wireless_dev *wdev, |
| 8383 | u64 cookie, struct ieee80211_channel *chan, | 8532 | u64 cookie, struct ieee80211_channel *chan, gfp_t gfp) |
| 8384 | enum nl80211_channel_type channel_type, gfp_t gfp) | ||
| 8385 | { | 8533 | { |
| 8386 | nl80211_send_remain_on_chan_event(NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL, | 8534 | nl80211_send_remain_on_chan_event(NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL, |
| 8387 | rdev, wdev, cookie, chan, | 8535 | rdev, wdev, cookie, chan, 0, gfp); |
| 8388 | channel_type, 0, gfp); | ||
| 8389 | } | 8536 | } |
| 8390 | 8537 | ||
| 8391 | void nl80211_send_sta_event(struct cfg80211_registered_device *rdev, | 8538 | void nl80211_send_sta_event(struct cfg80211_registered_device *rdev, |
| @@ -8741,8 +8888,8 @@ void nl80211_pmksa_candidate_notify(struct cfg80211_registered_device *rdev, | |||
| 8741 | } | 8888 | } |
| 8742 | 8889 | ||
| 8743 | void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev, | 8890 | void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev, |
| 8744 | struct net_device *netdev, int freq, | 8891 | struct net_device *netdev, |
| 8745 | enum nl80211_channel_type type, gfp_t gfp) | 8892 | struct cfg80211_chan_def *chandef, gfp_t gfp) |
| 8746 | { | 8893 | { |
| 8747 | struct sk_buff *msg; | 8894 | struct sk_buff *msg; |
| 8748 | void *hdr; | 8895 | void *hdr; |
| @@ -8757,9 +8904,10 @@ void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev, | |||
| 8757 | return; | 8904 | return; |
| 8758 | } | 8905 | } |
| 8759 | 8906 | ||
| 8760 | if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) || | 8907 | if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex)) |
| 8761 | nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq) || | 8908 | goto nla_put_failure; |
| 8762 | nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, type)) | 8909 | |
| 8910 | if (nl80211_send_chandef(msg, chandef)) | ||
| 8763 | goto nla_put_failure; | 8911 | goto nla_put_failure; |
| 8764 | 8912 | ||
| 8765 | genlmsg_end(msg, hdr); | 8913 | genlmsg_end(msg, hdr); |
| @@ -8914,46 +9062,96 @@ EXPORT_SYMBOL(cfg80211_probe_status); | |||
| 8914 | 9062 | ||
| 8915 | void cfg80211_report_obss_beacon(struct wiphy *wiphy, | 9063 | void cfg80211_report_obss_beacon(struct wiphy *wiphy, |
| 8916 | const u8 *frame, size_t len, | 9064 | const u8 *frame, size_t len, |
| 8917 | int freq, int sig_dbm, gfp_t gfp) | 9065 | int freq, int sig_dbm) |
| 8918 | { | 9066 | { |
| 8919 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | 9067 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); |
| 8920 | struct sk_buff *msg; | 9068 | struct sk_buff *msg; |
| 8921 | void *hdr; | 9069 | void *hdr; |
| 8922 | u32 nlportid = ACCESS_ONCE(rdev->ap_beacons_nlportid); | 9070 | struct cfg80211_beacon_registration *reg; |
| 8923 | 9071 | ||
| 8924 | trace_cfg80211_report_obss_beacon(wiphy, frame, len, freq, sig_dbm); | 9072 | trace_cfg80211_report_obss_beacon(wiphy, frame, len, freq, sig_dbm); |
| 8925 | 9073 | ||
| 8926 | if (!nlportid) | 9074 | spin_lock_bh(&rdev->beacon_registrations_lock); |
| 8927 | return; | 9075 | list_for_each_entry(reg, &rdev->beacon_registrations, list) { |
| 9076 | msg = nlmsg_new(len + 100, GFP_ATOMIC); | ||
| 9077 | if (!msg) { | ||
| 9078 | spin_unlock_bh(&rdev->beacon_registrations_lock); | ||
| 9079 | return; | ||
| 9080 | } | ||
| 9081 | |||
| 9082 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME); | ||
| 9083 | if (!hdr) | ||
| 9084 | goto nla_put_failure; | ||
| 9085 | |||
| 9086 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || | ||
| 9087 | (freq && | ||
| 9088 | nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq)) || | ||
| 9089 | (sig_dbm && | ||
| 9090 | nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm)) || | ||
| 9091 | nla_put(msg, NL80211_ATTR_FRAME, len, frame)) | ||
| 9092 | goto nla_put_failure; | ||
| 9093 | |||
| 9094 | genlmsg_end(msg, hdr); | ||
| 8928 | 9095 | ||
| 8929 | msg = nlmsg_new(len + 100, gfp); | 9096 | genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, reg->nlportid); |
| 9097 | } | ||
| 9098 | spin_unlock_bh(&rdev->beacon_registrations_lock); | ||
| 9099 | return; | ||
| 9100 | |||
| 9101 | nla_put_failure: | ||
| 9102 | spin_unlock_bh(&rdev->beacon_registrations_lock); | ||
| 9103 | if (hdr) | ||
| 9104 | genlmsg_cancel(msg, hdr); | ||
| 9105 | nlmsg_free(msg); | ||
| 9106 | } | ||
| 9107 | EXPORT_SYMBOL(cfg80211_report_obss_beacon); | ||
| 9108 | |||
| 9109 | void cfg80211_tdls_oper_request(struct net_device *dev, const u8 *peer, | ||
| 9110 | enum nl80211_tdls_operation oper, | ||
| 9111 | u16 reason_code, gfp_t gfp) | ||
| 9112 | { | ||
| 9113 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
| 9114 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | ||
| 9115 | struct sk_buff *msg; | ||
| 9116 | void *hdr; | ||
| 9117 | int err; | ||
| 9118 | |||
| 9119 | trace_cfg80211_tdls_oper_request(wdev->wiphy, dev, peer, oper, | ||
| 9120 | reason_code); | ||
| 9121 | |||
| 9122 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); | ||
| 8930 | if (!msg) | 9123 | if (!msg) |
| 8931 | return; | 9124 | return; |
| 8932 | 9125 | ||
| 8933 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME); | 9126 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_TDLS_OPER); |
| 8934 | if (!hdr) { | 9127 | if (!hdr) { |
| 8935 | nlmsg_free(msg); | 9128 | nlmsg_free(msg); |
| 8936 | return; | 9129 | return; |
| 8937 | } | 9130 | } |
| 8938 | 9131 | ||
| 8939 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || | 9132 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || |
| 8940 | (freq && | 9133 | nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) || |
| 8941 | nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq)) || | 9134 | nla_put_u8(msg, NL80211_ATTR_TDLS_OPERATION, oper) || |
| 8942 | (sig_dbm && | 9135 | nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, peer) || |
| 8943 | nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm)) || | 9136 | (reason_code > 0 && |
| 8944 | nla_put(msg, NL80211_ATTR_FRAME, len, frame)) | 9137 | nla_put_u16(msg, NL80211_ATTR_REASON_CODE, reason_code))) |
| 8945 | goto nla_put_failure; | 9138 | goto nla_put_failure; |
| 8946 | 9139 | ||
| 8947 | genlmsg_end(msg, hdr); | 9140 | err = genlmsg_end(msg, hdr); |
| 9141 | if (err < 0) { | ||
| 9142 | nlmsg_free(msg); | ||
| 9143 | return; | ||
| 9144 | } | ||
| 8948 | 9145 | ||
| 8949 | genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlportid); | 9146 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, |
| 9147 | nl80211_mlme_mcgrp.id, gfp); | ||
| 8950 | return; | 9148 | return; |
| 8951 | 9149 | ||
| 8952 | nla_put_failure: | 9150 | nla_put_failure: |
| 8953 | genlmsg_cancel(msg, hdr); | 9151 | genlmsg_cancel(msg, hdr); |
| 8954 | nlmsg_free(msg); | 9152 | nlmsg_free(msg); |
| 8955 | } | 9153 | } |
| 8956 | EXPORT_SYMBOL(cfg80211_report_obss_beacon); | 9154 | EXPORT_SYMBOL(cfg80211_tdls_oper_request); |
| 8957 | 9155 | ||
| 8958 | static int nl80211_netlink_notify(struct notifier_block * nb, | 9156 | static int nl80211_netlink_notify(struct notifier_block * nb, |
| 8959 | unsigned long state, | 9157 | unsigned long state, |
| @@ -8962,6 +9160,7 @@ static int nl80211_netlink_notify(struct notifier_block * nb, | |||
| 8962 | struct netlink_notify *notify = _notify; | 9160 | struct netlink_notify *notify = _notify; |
| 8963 | struct cfg80211_registered_device *rdev; | 9161 | struct cfg80211_registered_device *rdev; |
| 8964 | struct wireless_dev *wdev; | 9162 | struct wireless_dev *wdev; |
| 9163 | struct cfg80211_beacon_registration *reg, *tmp; | ||
| 8965 | 9164 | ||
| 8966 | if (state != NETLINK_URELEASE) | 9165 | if (state != NETLINK_URELEASE) |
| 8967 | return NOTIFY_DONE; | 9166 | return NOTIFY_DONE; |
| @@ -8971,8 +9170,17 @@ static int nl80211_netlink_notify(struct notifier_block * nb, | |||
| 8971 | list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) { | 9170 | list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) { |
| 8972 | list_for_each_entry_rcu(wdev, &rdev->wdev_list, list) | 9171 | list_for_each_entry_rcu(wdev, &rdev->wdev_list, list) |
| 8973 | cfg80211_mlme_unregister_socket(wdev, notify->portid); | 9172 | cfg80211_mlme_unregister_socket(wdev, notify->portid); |
| 8974 | if (rdev->ap_beacons_nlportid == notify->portid) | 9173 | |
| 8975 | rdev->ap_beacons_nlportid = 0; | 9174 | spin_lock_bh(&rdev->beacon_registrations_lock); |
| 9175 | list_for_each_entry_safe(reg, tmp, &rdev->beacon_registrations, | ||
| 9176 | list) { | ||
| 9177 | if (reg->nlportid == notify->portid) { | ||
| 9178 | list_del(®->list); | ||
| 9179 | kfree(reg); | ||
| 9180 | break; | ||
| 9181 | } | ||
| 9182 | } | ||
| 9183 | spin_unlock_bh(&rdev->beacon_registrations_lock); | ||
| 8976 | } | 9184 | } |
| 8977 | 9185 | ||
| 8978 | rcu_read_unlock(); | 9186 | rcu_read_unlock(); |
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h index f6153516068c..2acba8477e9d 100644 --- a/net/wireless/nl80211.h +++ b/net/wireless/nl80211.h | |||
| @@ -76,13 +76,11 @@ void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev, | |||
| 76 | void nl80211_send_remain_on_channel(struct cfg80211_registered_device *rdev, | 76 | void nl80211_send_remain_on_channel(struct cfg80211_registered_device *rdev, |
| 77 | struct wireless_dev *wdev, u64 cookie, | 77 | struct wireless_dev *wdev, u64 cookie, |
| 78 | struct ieee80211_channel *chan, | 78 | struct ieee80211_channel *chan, |
| 79 | enum nl80211_channel_type channel_type, | ||
| 80 | unsigned int duration, gfp_t gfp); | 79 | unsigned int duration, gfp_t gfp); |
| 81 | void nl80211_send_remain_on_channel_cancel( | 80 | void nl80211_send_remain_on_channel_cancel( |
| 82 | struct cfg80211_registered_device *rdev, | 81 | struct cfg80211_registered_device *rdev, |
| 83 | struct wireless_dev *wdev, | 82 | struct wireless_dev *wdev, |
| 84 | u64 cookie, struct ieee80211_channel *chan, | 83 | u64 cookie, struct ieee80211_channel *chan, gfp_t gfp); |
| 85 | enum nl80211_channel_type channel_type, gfp_t gfp); | ||
| 86 | 84 | ||
| 87 | void nl80211_send_sta_event(struct cfg80211_registered_device *rdev, | 85 | void nl80211_send_sta_event(struct cfg80211_registered_device *rdev, |
| 88 | struct net_device *dev, const u8 *mac_addr, | 86 | struct net_device *dev, const u8 *mac_addr, |
| @@ -129,8 +127,8 @@ void nl80211_pmksa_candidate_notify(struct cfg80211_registered_device *rdev, | |||
| 129 | const u8 *bssid, bool preauth, gfp_t gfp); | 127 | const u8 *bssid, bool preauth, gfp_t gfp); |
| 130 | 128 | ||
| 131 | void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev, | 129 | void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev, |
| 132 | struct net_device *dev, int freq, | 130 | struct net_device *dev, |
| 133 | enum nl80211_channel_type type, gfp_t gfp); | 131 | struct cfg80211_chan_def *chandef, gfp_t gfp); |
| 134 | 132 | ||
| 135 | bool nl80211_unexpected_frame(struct net_device *dev, | 133 | bool nl80211_unexpected_frame(struct net_device *dev, |
| 136 | const u8 *addr, gfp_t gfp); | 134 | const u8 *addr, gfp_t gfp); |
diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h index eb5f8974e148..6c0c8191f837 100644 --- a/net/wireless/rdev-ops.h +++ b/net/wireless/rdev-ops.h | |||
| @@ -359,12 +359,11 @@ rdev_libertas_set_mesh_channel(struct cfg80211_registered_device *rdev, | |||
| 359 | 359 | ||
| 360 | static inline int | 360 | static inline int |
| 361 | rdev_set_monitor_channel(struct cfg80211_registered_device *rdev, | 361 | rdev_set_monitor_channel(struct cfg80211_registered_device *rdev, |
| 362 | struct ieee80211_channel *chan, | 362 | struct cfg80211_chan_def *chandef) |
| 363 | enum nl80211_channel_type channel_type) | ||
| 364 | { | 363 | { |
| 365 | int ret; | 364 | int ret; |
| 366 | trace_rdev_set_monitor_channel(&rdev->wiphy, chan, channel_type); | 365 | trace_rdev_set_monitor_channel(&rdev->wiphy, chandef); |
| 367 | ret = rdev->ops->set_monitor_channel(&rdev->wiphy, chan, channel_type); | 366 | ret = rdev->ops->set_monitor_channel(&rdev->wiphy, chandef); |
| 368 | trace_rdev_return_int(&rdev->wiphy, ret); | 367 | trace_rdev_return_int(&rdev->wiphy, ret); |
| 369 | return ret; | 368 | return ret; |
| 370 | } | 369 | } |
| @@ -476,21 +475,22 @@ rdev_set_wiphy_params(struct cfg80211_registered_device *rdev, u32 changed) | |||
| 476 | } | 475 | } |
| 477 | 476 | ||
| 478 | static inline int rdev_set_tx_power(struct cfg80211_registered_device *rdev, | 477 | static inline int rdev_set_tx_power(struct cfg80211_registered_device *rdev, |
| 478 | struct wireless_dev *wdev, | ||
| 479 | enum nl80211_tx_power_setting type, int mbm) | 479 | enum nl80211_tx_power_setting type, int mbm) |
| 480 | { | 480 | { |
| 481 | int ret; | 481 | int ret; |
| 482 | trace_rdev_set_tx_power(&rdev->wiphy, type, mbm); | 482 | trace_rdev_set_tx_power(&rdev->wiphy, wdev, type, mbm); |
| 483 | ret = rdev->ops->set_tx_power(&rdev->wiphy, type, mbm); | 483 | ret = rdev->ops->set_tx_power(&rdev->wiphy, wdev, type, mbm); |
| 484 | trace_rdev_return_int(&rdev->wiphy, ret); | 484 | trace_rdev_return_int(&rdev->wiphy, ret); |
| 485 | return ret; | 485 | return ret; |
| 486 | } | 486 | } |
| 487 | 487 | ||
| 488 | static inline int rdev_get_tx_power(struct cfg80211_registered_device *rdev, | 488 | static inline int rdev_get_tx_power(struct cfg80211_registered_device *rdev, |
| 489 | int *dbm) | 489 | struct wireless_dev *wdev, int *dbm) |
| 490 | { | 490 | { |
| 491 | int ret; | 491 | int ret; |
| 492 | trace_rdev_get_tx_power(&rdev->wiphy); | 492 | trace_rdev_get_tx_power(&rdev->wiphy, wdev); |
| 493 | ret = rdev->ops->get_tx_power(&rdev->wiphy, dbm); | 493 | ret = rdev->ops->get_tx_power(&rdev->wiphy, wdev, dbm); |
| 494 | trace_rdev_return_int_int(&rdev->wiphy, ret, *dbm); | 494 | trace_rdev_return_int_int(&rdev->wiphy, ret, *dbm); |
| 495 | return ret; | 495 | return ret; |
| 496 | } | 496 | } |
| @@ -599,14 +599,12 @@ static inline int | |||
| 599 | rdev_remain_on_channel(struct cfg80211_registered_device *rdev, | 599 | rdev_remain_on_channel(struct cfg80211_registered_device *rdev, |
| 600 | struct wireless_dev *wdev, | 600 | struct wireless_dev *wdev, |
| 601 | struct ieee80211_channel *chan, | 601 | struct ieee80211_channel *chan, |
| 602 | enum nl80211_channel_type channel_type, | ||
| 603 | unsigned int duration, u64 *cookie) | 602 | unsigned int duration, u64 *cookie) |
| 604 | { | 603 | { |
| 605 | int ret; | 604 | int ret; |
| 606 | trace_rdev_remain_on_channel(&rdev->wiphy, wdev, chan, channel_type, | 605 | trace_rdev_remain_on_channel(&rdev->wiphy, wdev, chan, duration); |
| 607 | duration); | ||
| 608 | ret = rdev->ops->remain_on_channel(&rdev->wiphy, wdev, chan, | 606 | ret = rdev->ops->remain_on_channel(&rdev->wiphy, wdev, chan, |
| 609 | channel_type, duration, cookie); | 607 | duration, cookie); |
| 610 | trace_rdev_return_int_cookie(&rdev->wiphy, ret, *cookie); | 608 | trace_rdev_return_int_cookie(&rdev->wiphy, ret, *cookie); |
| 611 | return ret; | 609 | return ret; |
| 612 | } | 610 | } |
| @@ -625,17 +623,15 @@ rdev_cancel_remain_on_channel(struct cfg80211_registered_device *rdev, | |||
| 625 | static inline int rdev_mgmt_tx(struct cfg80211_registered_device *rdev, | 623 | static inline int rdev_mgmt_tx(struct cfg80211_registered_device *rdev, |
| 626 | struct wireless_dev *wdev, | 624 | struct wireless_dev *wdev, |
| 627 | struct ieee80211_channel *chan, bool offchan, | 625 | struct ieee80211_channel *chan, bool offchan, |
| 628 | enum nl80211_channel_type channel_type, | 626 | unsigned int wait, const u8 *buf, size_t len, |
| 629 | bool channel_type_valid, unsigned int wait, | 627 | bool no_cck, bool dont_wait_for_ack, u64 *cookie) |
| 630 | const u8 *buf, size_t len, bool no_cck, | ||
| 631 | bool dont_wait_for_ack, u64 *cookie) | ||
| 632 | { | 628 | { |
| 633 | int ret; | 629 | int ret; |
| 634 | trace_rdev_mgmt_tx(&rdev->wiphy, wdev, chan, offchan, channel_type, | 630 | trace_rdev_mgmt_tx(&rdev->wiphy, wdev, chan, offchan, |
| 635 | channel_type_valid, wait, no_cck, dont_wait_for_ack); | 631 | wait, no_cck, dont_wait_for_ack); |
| 636 | ret = rdev->ops->mgmt_tx(&rdev->wiphy, wdev, chan, offchan, | 632 | ret = rdev->ops->mgmt_tx(&rdev->wiphy, wdev, chan, offchan, |
| 637 | channel_type, channel_type_valid, wait, buf, | 633 | wait, buf, len, no_cck, |
| 638 | len, no_cck, dont_wait_for_ack, cookie); | 634 | dont_wait_for_ack, cookie); |
| 639 | trace_rdev_return_int_cookie(&rdev->wiphy, ret, *cookie); | 635 | trace_rdev_return_int_cookie(&rdev->wiphy, ret, *cookie); |
| 640 | return ret; | 636 | return ret; |
| 641 | } | 637 | } |
| @@ -847,14 +843,17 @@ static inline void rdev_get_et_strings(struct cfg80211_registered_device *rdev, | |||
| 847 | trace_rdev_return_void(&rdev->wiphy); | 843 | trace_rdev_return_void(&rdev->wiphy); |
| 848 | } | 844 | } |
| 849 | 845 | ||
| 850 | static inline struct ieee80211_channel | 846 | static inline int |
| 851 | *rdev_get_channel(struct cfg80211_registered_device *rdev, | 847 | rdev_get_channel(struct cfg80211_registered_device *rdev, |
| 852 | struct wireless_dev *wdev, enum nl80211_channel_type *type) | 848 | struct wireless_dev *wdev, |
| 849 | struct cfg80211_chan_def *chandef) | ||
| 853 | { | 850 | { |
| 854 | struct ieee80211_channel *ret; | 851 | int ret; |
| 852 | |||
| 855 | trace_rdev_get_channel(&rdev->wiphy, wdev); | 853 | trace_rdev_get_channel(&rdev->wiphy, wdev); |
| 856 | ret = rdev->ops->get_channel(&rdev->wiphy, wdev, type); | 854 | ret = rdev->ops->get_channel(&rdev->wiphy, wdev, chandef); |
| 857 | trace_rdev_return_channel(&rdev->wiphy, ret, *type); | 855 | trace_rdev_return_chandef(&rdev->wiphy, ret, chandef); |
| 856 | |||
| 858 | return ret; | 857 | return ret; |
| 859 | } | 858 | } |
| 860 | 859 | ||
diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 7f97a087f452..9596015975d2 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c | |||
| @@ -771,6 +771,38 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev, | |||
| 771 | return found; | 771 | return found; |
| 772 | } | 772 | } |
| 773 | 773 | ||
| 774 | static struct ieee80211_channel * | ||
| 775 | cfg80211_get_bss_channel(struct wiphy *wiphy, const u8 *ie, size_t ielen, | ||
| 776 | struct ieee80211_channel *channel) | ||
| 777 | { | ||
| 778 | const u8 *tmp; | ||
| 779 | u32 freq; | ||
| 780 | int channel_number = -1; | ||
| 781 | |||
| 782 | tmp = cfg80211_find_ie(WLAN_EID_DS_PARAMS, ie, ielen); | ||
| 783 | if (tmp && tmp[1] == 1) { | ||
| 784 | channel_number = tmp[2]; | ||
| 785 | } else { | ||
| 786 | tmp = cfg80211_find_ie(WLAN_EID_HT_OPERATION, ie, ielen); | ||
| 787 | if (tmp && tmp[1] >= sizeof(struct ieee80211_ht_operation)) { | ||
| 788 | struct ieee80211_ht_operation *htop = (void *)(tmp + 2); | ||
| 789 | |||
| 790 | channel_number = htop->primary_chan; | ||
| 791 | } | ||
| 792 | } | ||
| 793 | |||
| 794 | if (channel_number < 0) | ||
| 795 | return channel; | ||
| 796 | |||
| 797 | freq = ieee80211_channel_to_frequency(channel_number, channel->band); | ||
| 798 | channel = ieee80211_get_channel(wiphy, freq); | ||
| 799 | if (!channel) | ||
| 800 | return NULL; | ||
| 801 | if (channel->flags & IEEE80211_CHAN_DISABLED) | ||
| 802 | return NULL; | ||
| 803 | return channel; | ||
| 804 | } | ||
| 805 | |||
| 774 | struct cfg80211_bss* | 806 | struct cfg80211_bss* |
| 775 | cfg80211_inform_bss(struct wiphy *wiphy, | 807 | cfg80211_inform_bss(struct wiphy *wiphy, |
| 776 | struct ieee80211_channel *channel, | 808 | struct ieee80211_channel *channel, |
| @@ -790,6 +822,10 @@ cfg80211_inform_bss(struct wiphy *wiphy, | |||
| 790 | (signal < 0 || signal > 100))) | 822 | (signal < 0 || signal > 100))) |
| 791 | return NULL; | 823 | return NULL; |
| 792 | 824 | ||
| 825 | channel = cfg80211_get_bss_channel(wiphy, ie, ielen, channel); | ||
| 826 | if (!channel) | ||
| 827 | return NULL; | ||
| 828 | |||
| 793 | res = kzalloc(sizeof(*res) + privsz + ielen, gfp); | 829 | res = kzalloc(sizeof(*res) + privsz + ielen, gfp); |
| 794 | if (!res) | 830 | if (!res) |
| 795 | return NULL; | 831 | return NULL; |
| @@ -839,11 +875,13 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy, | |||
| 839 | s32 signal, gfp_t gfp) | 875 | s32 signal, gfp_t gfp) |
| 840 | { | 876 | { |
| 841 | struct cfg80211_internal_bss *res; | 877 | struct cfg80211_internal_bss *res; |
| 842 | |||
| 843 | size_t ielen = len - offsetof(struct ieee80211_mgmt, | 878 | size_t ielen = len - offsetof(struct ieee80211_mgmt, |
| 844 | u.probe_resp.variable); | 879 | u.probe_resp.variable); |
| 845 | size_t privsz; | 880 | size_t privsz; |
| 846 | 881 | ||
| 882 | BUILD_BUG_ON(offsetof(struct ieee80211_mgmt, u.probe_resp.variable) != | ||
| 883 | offsetof(struct ieee80211_mgmt, u.beacon.variable)); | ||
| 884 | |||
| 847 | trace_cfg80211_inform_bss_frame(wiphy, channel, mgmt, len, signal); | 885 | trace_cfg80211_inform_bss_frame(wiphy, channel, mgmt, len, signal); |
| 848 | 886 | ||
| 849 | if (WARN_ON(!mgmt)) | 887 | if (WARN_ON(!mgmt)) |
| @@ -861,6 +899,11 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy, | |||
| 861 | 899 | ||
| 862 | privsz = wiphy->bss_priv_size; | 900 | privsz = wiphy->bss_priv_size; |
| 863 | 901 | ||
| 902 | channel = cfg80211_get_bss_channel(wiphy, mgmt->u.beacon.variable, | ||
| 903 | ielen, channel); | ||
| 904 | if (!channel) | ||
| 905 | return NULL; | ||
| 906 | |||
| 864 | res = kzalloc(sizeof(*res) + privsz + ielen, gfp); | 907 | res = kzalloc(sizeof(*res) + privsz + ielen, gfp); |
| 865 | if (!res) | 908 | if (!res) |
| 866 | return NULL; | 909 | return NULL; |
diff --git a/net/wireless/trace.h b/net/wireless/trace.h index 0ca71caf85fb..2134576f426e 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h | |||
| @@ -20,29 +20,26 @@ | |||
| 20 | #define MAC_PR_FMT "%pM" | 20 | #define MAC_PR_FMT "%pM" |
| 21 | #define MAC_PR_ARG(entry_mac) (__entry->entry_mac) | 21 | #define MAC_PR_ARG(entry_mac) (__entry->entry_mac) |
| 22 | 22 | ||
| 23 | #define WIPHY_ENTRY MAC_ENTRY(wiphy_mac) | 23 | #define MAXNAME 32 |
| 24 | #define WIPHY_ASSIGN MAC_ASSIGN(wiphy_mac, wiphy->perm_addr) | 24 | #define WIPHY_ENTRY __array(char, wiphy_name, 32) |
| 25 | #define WIPHY_PR_FMT "wiphy " MAC_PR_FMT | 25 | #define WIPHY_ASSIGN strlcpy(__entry->wiphy_name, wiphy_name(wiphy), MAXNAME) |
| 26 | #define WIPHY_PR_ARG MAC_PR_ARG(wiphy_mac) | 26 | #define WIPHY_PR_FMT "%s" |
| 27 | 27 | #define WIPHY_PR_ARG __entry->wiphy_name | |
| 28 | #define WDEV_ENTRY __field(u32, id) | 28 | |
| 29 | #define WDEV_ASSIGN (__entry->id) = (wdev->identifier) | 29 | #define WDEV_ENTRY __field(u32, id) |
| 30 | #define WDEV_PR_FMT ", wdev id: %u" | 30 | #define WDEV_ASSIGN (__entry->id) = (wdev ? wdev->identifier : 0) |
| 31 | #define WDEV_PR_ARG (__entry->id) | 31 | #define WDEV_PR_FMT "wdev(%u)" |
| 32 | 32 | #define WDEV_PR_ARG (__entry->id) | |
| 33 | #define NETDEV_ENTRY __array(char, name, IFNAMSIZ) \ | 33 | |
| 34 | MAC_ENTRY(netdev_addr) \ | 34 | #define NETDEV_ENTRY __array(char, name, IFNAMSIZ) \ |
| 35 | __field(int, ifindex) | 35 | __field(int, ifindex) |
| 36 | #define NETDEV_ASSIGN \ | 36 | #define NETDEV_ASSIGN \ |
| 37 | do { \ | 37 | do { \ |
| 38 | memcpy(__entry->name, netdev->name, IFNAMSIZ); \ | 38 | memcpy(__entry->name, netdev->name, IFNAMSIZ); \ |
| 39 | MAC_ASSIGN(netdev_addr, netdev->dev_addr); \ | ||
| 40 | (__entry->ifindex) = (netdev->ifindex); \ | 39 | (__entry->ifindex) = (netdev->ifindex); \ |
| 41 | } while (0) | 40 | } while (0) |
| 42 | #define NETDEV_PR_FMT ", netdev - name: %s, addr: " MAC_PR_FMT \ | 41 | #define NETDEV_PR_FMT "netdev:%s(%d)" |
| 43 | ", intf index: %d" | 42 | #define NETDEV_PR_ARG __entry->name, __entry->ifindex |
| 44 | #define NETDEV_PR_ARG (__entry->name), MAC_PR_ARG(netdev_addr), \ | ||
| 45 | (__entry->ifindex) | ||
| 46 | 43 | ||
| 47 | #define MESH_CFG_ENTRY __field(u16, dot11MeshRetryTimeout) \ | 44 | #define MESH_CFG_ENTRY __field(u16, dot11MeshRetryTimeout) \ |
| 48 | __field(u16, dot11MeshConfirmTimeout) \ | 45 | __field(u16, dot11MeshConfirmTimeout) \ |
| @@ -123,9 +120,37 @@ | |||
| 123 | __entry->center_freq = 0; \ | 120 | __entry->center_freq = 0; \ |
| 124 | } \ | 121 | } \ |
| 125 | } while (0) | 122 | } while (0) |
| 126 | #define CHAN_PR_FMT ", band: %d, freq: %u" | 123 | #define CHAN_PR_FMT "band: %d, freq: %u" |
| 127 | #define CHAN_PR_ARG __entry->band, __entry->center_freq | 124 | #define CHAN_PR_ARG __entry->band, __entry->center_freq |
| 128 | 125 | ||
| 126 | #define CHAN_DEF_ENTRY __field(enum ieee80211_band, band) \ | ||
| 127 | __field(u32, control_freq) \ | ||
| 128 | __field(u32, width) \ | ||
| 129 | __field(u32, center_freq1) \ | ||
| 130 | __field(u32, center_freq2) | ||
| 131 | #define CHAN_DEF_ASSIGN(chandef) \ | ||
| 132 | do { \ | ||
| 133 | if ((chandef) && (chandef)->chan) { \ | ||
| 134 | __entry->band = (chandef)->chan->band; \ | ||
| 135 | __entry->control_freq = \ | ||
| 136 | (chandef)->chan->center_freq; \ | ||
| 137 | __entry->width = (chandef)->width; \ | ||
| 138 | __entry->center_freq1 = (chandef)->center_freq1;\ | ||
| 139 | __entry->center_freq2 = (chandef)->center_freq2;\ | ||
| 140 | } else { \ | ||
| 141 | __entry->band = 0; \ | ||
| 142 | __entry->control_freq = 0; \ | ||
| 143 | __entry->width = 0; \ | ||
| 144 | __entry->center_freq1 = 0; \ | ||
| 145 | __entry->center_freq2 = 0; \ | ||
| 146 | } \ | ||
| 147 | } while (0) | ||
| 148 | #define CHAN_DEF_PR_FMT \ | ||
| 149 | "band: %d, control freq: %u, width: %d, cf1: %u, cf2: %u" | ||
| 150 | #define CHAN_DEF_PR_ARG __entry->band, __entry->control_freq, \ | ||
| 151 | __entry->width, __entry->center_freq1, \ | ||
| 152 | __entry->center_freq2 | ||
| 153 | |||
| 129 | #define SINFO_ENTRY __field(int, generation) \ | 154 | #define SINFO_ENTRY __field(int, generation) \ |
| 130 | __field(u32, connected_time) \ | 155 | __field(u32, connected_time) \ |
| 131 | __field(u32, inactive_time) \ | 156 | __field(u32, inactive_time) \ |
| @@ -260,11 +285,6 @@ DEFINE_EVENT(wiphy_only_evt, rdev_get_antenna, | |||
| 260 | TP_ARGS(wiphy) | 285 | TP_ARGS(wiphy) |
| 261 | ); | 286 | ); |
| 262 | 287 | ||
| 263 | DEFINE_EVENT(wiphy_only_evt, rdev_get_tx_power, | ||
| 264 | TP_PROTO(struct wiphy *wiphy), | ||
| 265 | TP_ARGS(wiphy) | ||
| 266 | ); | ||
| 267 | |||
| 268 | DEFINE_EVENT(wiphy_only_evt, rdev_rfkill_poll, | 288 | DEFINE_EVENT(wiphy_only_evt, rdev_rfkill_poll, |
| 269 | TP_PROTO(struct wiphy *wiphy), | 289 | TP_PROTO(struct wiphy *wiphy), |
| 270 | TP_ARGS(wiphy) | 290 | TP_ARGS(wiphy) |
| @@ -318,7 +338,7 @@ DECLARE_EVENT_CLASS(wiphy_wdev_evt, | |||
| 318 | WIPHY_ASSIGN; | 338 | WIPHY_ASSIGN; |
| 319 | WDEV_ASSIGN; | 339 | WDEV_ASSIGN; |
| 320 | ), | 340 | ), |
| 321 | TP_printk(WIPHY_PR_FMT WDEV_PR_FMT, WIPHY_PR_ARG, WDEV_PR_ARG) | 341 | TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT, WIPHY_PR_ARG, WDEV_PR_ARG) |
| 322 | ); | 342 | ); |
| 323 | 343 | ||
| 324 | DEFINE_EVENT(wiphy_wdev_evt, rdev_return_wdev, | 344 | DEFINE_EVENT(wiphy_wdev_evt, rdev_return_wdev, |
| @@ -345,7 +365,7 @@ TRACE_EVENT(rdev_change_virtual_intf, | |||
| 345 | NETDEV_ASSIGN; | 365 | NETDEV_ASSIGN; |
| 346 | __entry->type = type; | 366 | __entry->type = type; |
| 347 | ), | 367 | ), |
| 348 | TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", type: %d", | 368 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", type: %d", |
| 349 | WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->type) | 369 | WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->type) |
| 350 | ); | 370 | ); |
| 351 | 371 | ||
| @@ -367,7 +387,7 @@ DECLARE_EVENT_CLASS(key_handle, | |||
| 367 | __entry->key_index = key_index; | 387 | __entry->key_index = key_index; |
| 368 | __entry->pairwise = pairwise; | 388 | __entry->pairwise = pairwise; |
| 369 | ), | 389 | ), |
| 370 | TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", key_index: %u, pairwise: %s, mac addr: " MAC_PR_FMT, | 390 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", key_index: %u, pairwise: %s, mac addr: " MAC_PR_FMT, |
| 371 | WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->key_index, | 391 | WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->key_index, |
| 372 | BOOL_TO_STR(__entry->pairwise), MAC_PR_ARG(mac_addr)) | 392 | BOOL_TO_STR(__entry->pairwise), MAC_PR_ARG(mac_addr)) |
| 373 | ); | 393 | ); |
| @@ -408,7 +428,7 @@ TRACE_EVENT(rdev_set_default_key, | |||
| 408 | __entry->unicast = unicast; | 428 | __entry->unicast = unicast; |
| 409 | __entry->multicast = multicast; | 429 | __entry->multicast = multicast; |
| 410 | ), | 430 | ), |
| 411 | TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", key index: %u, unicast: %s, multicast: %s", | 431 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", key index: %u, unicast: %s, multicast: %s", |
| 412 | WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->key_index, | 432 | WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->key_index, |
| 413 | BOOL_TO_STR(__entry->unicast), | 433 | BOOL_TO_STR(__entry->unicast), |
| 414 | BOOL_TO_STR(__entry->multicast)) | 434 | BOOL_TO_STR(__entry->multicast)) |
| @@ -427,7 +447,7 @@ TRACE_EVENT(rdev_set_default_mgmt_key, | |||
| 427 | NETDEV_ASSIGN; | 447 | NETDEV_ASSIGN; |
| 428 | __entry->key_index = key_index; | 448 | __entry->key_index = key_index; |
| 429 | ), | 449 | ), |
| 430 | TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", key index: %u", | 450 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", key index: %u", |
| 431 | WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->key_index) | 451 | WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->key_index) |
| 432 | ); | 452 | ); |
| 433 | 453 | ||
| @@ -438,7 +458,7 @@ TRACE_EVENT(rdev_start_ap, | |||
| 438 | TP_STRUCT__entry( | 458 | TP_STRUCT__entry( |
| 439 | WIPHY_ENTRY | 459 | WIPHY_ENTRY |
| 440 | NETDEV_ENTRY | 460 | NETDEV_ENTRY |
| 441 | CHAN_ENTRY | 461 | CHAN_DEF_ENTRY |
| 442 | __field(int, beacon_interval) | 462 | __field(int, beacon_interval) |
| 443 | __field(int, dtim_period) | 463 | __field(int, dtim_period) |
| 444 | __array(char, ssid, IEEE80211_MAX_SSID_LEN + 1) | 464 | __array(char, ssid, IEEE80211_MAX_SSID_LEN + 1) |
| @@ -451,7 +471,7 @@ TRACE_EVENT(rdev_start_ap, | |||
| 451 | TP_fast_assign( | 471 | TP_fast_assign( |
| 452 | WIPHY_ASSIGN; | 472 | WIPHY_ASSIGN; |
| 453 | NETDEV_ASSIGN; | 473 | NETDEV_ASSIGN; |
| 454 | CHAN_ASSIGN(settings->channel); | 474 | CHAN_DEF_ASSIGN(&settings->chandef); |
| 455 | __entry->beacon_interval = settings->beacon_interval; | 475 | __entry->beacon_interval = settings->beacon_interval; |
| 456 | __entry->dtim_period = settings->dtim_period; | 476 | __entry->dtim_period = settings->dtim_period; |
| 457 | __entry->hidden_ssid = settings->hidden_ssid; | 477 | __entry->hidden_ssid = settings->hidden_ssid; |
| @@ -462,11 +482,11 @@ TRACE_EVENT(rdev_start_ap, | |||
| 462 | memset(__entry->ssid, 0, IEEE80211_MAX_SSID_LEN + 1); | 482 | memset(__entry->ssid, 0, IEEE80211_MAX_SSID_LEN + 1); |
| 463 | memcpy(__entry->ssid, settings->ssid, settings->ssid_len); | 483 | memcpy(__entry->ssid, settings->ssid, settings->ssid_len); |
| 464 | ), | 484 | ), |
| 465 | TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", AP settings - ssid: %s, " | 485 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", AP settings - ssid: %s, " |
| 466 | CHAN_PR_FMT ", beacon interval: %d, dtim period: %d, " | 486 | CHAN_DEF_PR_FMT ", beacon interval: %d, dtim period: %d, " |
| 467 | "hidden ssid: %d, wpa versions: %u, privacy: %s, " | 487 | "hidden ssid: %d, wpa versions: %u, privacy: %s, " |
| 468 | "auth type: %d, inactivity timeout: %d", | 488 | "auth type: %d, inactivity timeout: %d", |
| 469 | WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->ssid, CHAN_PR_ARG, | 489 | WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->ssid, CHAN_DEF_PR_ARG, |
| 470 | __entry->beacon_interval, __entry->dtim_period, | 490 | __entry->beacon_interval, __entry->dtim_period, |
| 471 | __entry->hidden_ssid, __entry->wpa_ver, | 491 | __entry->hidden_ssid, __entry->wpa_ver, |
| 472 | BOOL_TO_STR(__entry->privacy), __entry->auth_type, | 492 | BOOL_TO_STR(__entry->privacy), __entry->auth_type, |
| @@ -515,7 +535,7 @@ TRACE_EVENT(rdev_change_beacon, | |||
| 515 | info->probe_resp, info->probe_resp_len); | 535 | info->probe_resp, info->probe_resp_len); |
| 516 | } | 536 | } |
| 517 | ), | 537 | ), |
| 518 | TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT, WIPHY_PR_ARG, NETDEV_PR_ARG) | 538 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT, WIPHY_PR_ARG, NETDEV_PR_ARG) |
| 519 | ); | 539 | ); |
| 520 | 540 | ||
| 521 | DECLARE_EVENT_CLASS(wiphy_netdev_evt, | 541 | DECLARE_EVENT_CLASS(wiphy_netdev_evt, |
| @@ -529,7 +549,7 @@ DECLARE_EVENT_CLASS(wiphy_netdev_evt, | |||
| 529 | WIPHY_ASSIGN; | 549 | WIPHY_ASSIGN; |
| 530 | NETDEV_ASSIGN; | 550 | NETDEV_ASSIGN; |
| 531 | ), | 551 | ), |
| 532 | TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT, WIPHY_PR_ARG, NETDEV_PR_ARG) | 552 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT, WIPHY_PR_ARG, NETDEV_PR_ARG) |
| 533 | ); | 553 | ); |
| 534 | 554 | ||
| 535 | DEFINE_EVENT(wiphy_netdev_evt, rdev_stop_ap, | 555 | DEFINE_EVENT(wiphy_netdev_evt, rdev_stop_ap, |
| @@ -607,7 +627,7 @@ DECLARE_EVENT_CLASS(station_add_change, | |||
| 607 | memcpy(__entry->ht_capa, params->ht_capa, | 627 | memcpy(__entry->ht_capa, params->ht_capa, |
| 608 | sizeof(struct ieee80211_ht_cap)); | 628 | sizeof(struct ieee80211_ht_cap)); |
| 609 | ), | 629 | ), |
| 610 | TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", station mac: " MAC_PR_FMT | 630 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", station mac: " MAC_PR_FMT |
| 611 | ", station flags mask: %u, station flags set: %u, " | 631 | ", station flags mask: %u, station flags set: %u, " |
| 612 | "station modify mask: %u, listen interval: %d, aid: %u, " | 632 | "station modify mask: %u, listen interval: %d, aid: %u, " |
| 613 | "plink action: %u, plink state: %u, uapsd queues: %u", | 633 | "plink action: %u, plink state: %u, uapsd queues: %u", |
| @@ -643,7 +663,7 @@ DECLARE_EVENT_CLASS(wiphy_netdev_mac_evt, | |||
| 643 | NETDEV_ASSIGN; | 663 | NETDEV_ASSIGN; |
| 644 | MAC_ASSIGN(sta_mac, mac); | 664 | MAC_ASSIGN(sta_mac, mac); |
| 645 | ), | 665 | ), |
| 646 | TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", mac: " MAC_PR_FMT, | 666 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", mac: " MAC_PR_FMT, |
| 647 | WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(sta_mac)) | 667 | WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(sta_mac)) |
| 648 | ); | 668 | ); |
| 649 | 669 | ||
| @@ -683,7 +703,7 @@ TRACE_EVENT(rdev_dump_station, | |||
| 683 | MAC_ASSIGN(sta_mac, mac); | 703 | MAC_ASSIGN(sta_mac, mac); |
| 684 | __entry->idx = idx; | 704 | __entry->idx = idx; |
| 685 | ), | 705 | ), |
| 686 | TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", station mac: " MAC_PR_FMT ", idx: %d", | 706 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", station mac: " MAC_PR_FMT ", idx: %d", |
| 687 | WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(sta_mac), | 707 | WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(sta_mac), |
| 688 | __entry->idx) | 708 | __entry->idx) |
| 689 | ); | 709 | ); |
| @@ -721,7 +741,7 @@ DECLARE_EVENT_CLASS(mpath_evt, | |||
| 721 | MAC_ASSIGN(dst, dst); | 741 | MAC_ASSIGN(dst, dst); |
| 722 | MAC_ASSIGN(next_hop, next_hop); | 742 | MAC_ASSIGN(next_hop, next_hop); |
| 723 | ), | 743 | ), |
| 724 | TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", destination: " MAC_PR_FMT ", next hop: " MAC_PR_FMT, | 744 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", destination: " MAC_PR_FMT ", next hop: " MAC_PR_FMT, |
| 725 | WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(dst), | 745 | WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(dst), |
| 726 | MAC_PR_ARG(next_hop)) | 746 | MAC_PR_ARG(next_hop)) |
| 727 | ); | 747 | ); |
| @@ -762,7 +782,7 @@ TRACE_EVENT(rdev_dump_mpath, | |||
| 762 | MAC_ASSIGN(next_hop, next_hop); | 782 | MAC_ASSIGN(next_hop, next_hop); |
| 763 | __entry->idx = idx; | 783 | __entry->idx = idx; |
| 764 | ), | 784 | ), |
| 765 | TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", index: %d, destination: " | 785 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", index: %d, destination: " |
| 766 | MAC_PR_FMT ", next hop: " MAC_PR_FMT, | 786 | MAC_PR_FMT ", next hop: " MAC_PR_FMT, |
| 767 | WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->idx, MAC_PR_ARG(dst), | 787 | WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->idx, MAC_PR_ARG(dst), |
| 768 | MAC_PR_ARG(next_hop)) | 788 | MAC_PR_ARG(next_hop)) |
| @@ -839,7 +859,7 @@ TRACE_EVENT(rdev_update_mesh_config, | |||
| 839 | MESH_CFG_ASSIGN; | 859 | MESH_CFG_ASSIGN; |
| 840 | __entry->mask = mask; | 860 | __entry->mask = mask; |
| 841 | ), | 861 | ), |
| 842 | TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", mask: %u", | 862 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", mask: %u", |
| 843 | WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->mask) | 863 | WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->mask) |
| 844 | ); | 864 | ); |
| 845 | 865 | ||
| @@ -858,7 +878,7 @@ TRACE_EVENT(rdev_join_mesh, | |||
| 858 | NETDEV_ASSIGN; | 878 | NETDEV_ASSIGN; |
| 859 | MESH_CFG_ASSIGN; | 879 | MESH_CFG_ASSIGN; |
| 860 | ), | 880 | ), |
| 861 | TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT, | 881 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT, |
| 862 | WIPHY_PR_ARG, NETDEV_PR_ARG) | 882 | WIPHY_PR_ARG, NETDEV_PR_ARG) |
| 863 | ); | 883 | ); |
| 864 | 884 | ||
| @@ -884,7 +904,7 @@ TRACE_EVENT(rdev_change_bss, | |||
| 884 | __entry->ap_isolate = params->ap_isolate; | 904 | __entry->ap_isolate = params->ap_isolate; |
| 885 | __entry->ht_opmode = params->ht_opmode; | 905 | __entry->ht_opmode = params->ht_opmode; |
| 886 | ), | 906 | ), |
| 887 | TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", use cts prot: %d, " | 907 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", use cts prot: %d, " |
| 888 | "use short preamble: %d, use short slot time: %d, " | 908 | "use short preamble: %d, use short slot time: %d, " |
| 889 | "ap isolate: %d, ht opmode: %d", | 909 | "ap isolate: %d, ht opmode: %d", |
| 890 | WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->use_cts_prot, | 910 | WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->use_cts_prot, |
| @@ -914,7 +934,7 @@ TRACE_EVENT(rdev_set_txq_params, | |||
| 914 | __entry->cwmax = params->cwmax; | 934 | __entry->cwmax = params->cwmax; |
| 915 | __entry->aifs = params->aifs; | 935 | __entry->aifs = params->aifs; |
| 916 | ), | 936 | ), |
| 917 | TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", ac: %d, txop: %u, cwmin: %u, cwmax: %u, aifs: %u", | 937 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", ac: %d, txop: %u, cwmin: %u, cwmax: %u, aifs: %u", |
| 918 | WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->ac, __entry->txop, | 938 | WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->ac, __entry->txop, |
| 919 | __entry->cwmin, __entry->cwmax, __entry->aifs) | 939 | __entry->cwmin, __entry->cwmax, __entry->aifs) |
| 920 | ); | 940 | ); |
| @@ -933,26 +953,24 @@ TRACE_EVENT(rdev_libertas_set_mesh_channel, | |||
| 933 | NETDEV_ASSIGN; | 953 | NETDEV_ASSIGN; |
| 934 | CHAN_ASSIGN(chan); | 954 | CHAN_ASSIGN(chan); |
| 935 | ), | 955 | ), |
| 936 | TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT CHAN_PR_FMT, WIPHY_PR_ARG, | 956 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", " CHAN_PR_FMT, WIPHY_PR_ARG, |
| 937 | NETDEV_PR_ARG, CHAN_PR_ARG) | 957 | NETDEV_PR_ARG, CHAN_PR_ARG) |
| 938 | ); | 958 | ); |
| 939 | 959 | ||
| 940 | TRACE_EVENT(rdev_set_monitor_channel, | 960 | TRACE_EVENT(rdev_set_monitor_channel, |
| 941 | TP_PROTO(struct wiphy *wiphy, struct ieee80211_channel *chan, | 961 | TP_PROTO(struct wiphy *wiphy, |
| 942 | enum nl80211_channel_type chan_type), | 962 | struct cfg80211_chan_def *chandef), |
| 943 | TP_ARGS(wiphy, chan, chan_type), | 963 | TP_ARGS(wiphy, chandef), |
| 944 | TP_STRUCT__entry( | 964 | TP_STRUCT__entry( |
| 945 | WIPHY_ENTRY | 965 | WIPHY_ENTRY |
| 946 | CHAN_ENTRY | 966 | CHAN_DEF_ENTRY |
| 947 | __field(enum nl80211_channel_type, chan_type) | ||
| 948 | ), | 967 | ), |
| 949 | TP_fast_assign( | 968 | TP_fast_assign( |
| 950 | WIPHY_ASSIGN; | 969 | WIPHY_ASSIGN; |
| 951 | CHAN_ASSIGN(chan); | 970 | CHAN_DEF_ASSIGN(chandef); |
| 952 | __entry->chan_type = chan_type; | ||
| 953 | ), | 971 | ), |
| 954 | TP_printk(WIPHY_PR_FMT CHAN_PR_FMT ", channel type : %d", | 972 | TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT, |
| 955 | WIPHY_PR_ARG, CHAN_PR_ARG, __entry->chan_type) | 973 | WIPHY_PR_ARG, CHAN_DEF_PR_ARG) |
| 956 | ); | 974 | ); |
| 957 | 975 | ||
| 958 | TRACE_EVENT(rdev_auth, | 976 | TRACE_EVENT(rdev_auth, |
| @@ -974,7 +992,7 @@ TRACE_EVENT(rdev_auth, | |||
| 974 | memset(__entry->bssid, 0, ETH_ALEN); | 992 | memset(__entry->bssid, 0, ETH_ALEN); |
| 975 | __entry->auth_type = req->auth_type; | 993 | __entry->auth_type = req->auth_type; |
| 976 | ), | 994 | ), |
| 977 | TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", auth type: %d, bssid: " MAC_PR_FMT, | 995 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", auth type: %d, bssid: " MAC_PR_FMT, |
| 978 | WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->auth_type, | 996 | WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->auth_type, |
| 979 | MAC_PR_ARG(bssid)) | 997 | MAC_PR_ARG(bssid)) |
| 980 | ); | 998 | ); |
| @@ -1002,7 +1020,7 @@ TRACE_EVENT(rdev_assoc, | |||
| 1002 | __entry->use_mfp = req->use_mfp; | 1020 | __entry->use_mfp = req->use_mfp; |
| 1003 | __entry->flags = req->flags; | 1021 | __entry->flags = req->flags; |
| 1004 | ), | 1022 | ), |
| 1005 | TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", bssid: " MAC_PR_FMT | 1023 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", bssid: " MAC_PR_FMT |
| 1006 | ", previous bssid: " MAC_PR_FMT ", use mfp: %s, flags: %u", | 1024 | ", previous bssid: " MAC_PR_FMT ", use mfp: %s, flags: %u", |
| 1007 | WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(bssid), | 1025 | WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(bssid), |
| 1008 | MAC_PR_ARG(prev_bssid), BOOL_TO_STR(__entry->use_mfp), | 1026 | MAC_PR_ARG(prev_bssid), BOOL_TO_STR(__entry->use_mfp), |
| @@ -1025,7 +1043,7 @@ TRACE_EVENT(rdev_deauth, | |||
| 1025 | MAC_ASSIGN(bssid, req->bssid); | 1043 | MAC_ASSIGN(bssid, req->bssid); |
| 1026 | __entry->reason_code = req->reason_code; | 1044 | __entry->reason_code = req->reason_code; |
| 1027 | ), | 1045 | ), |
| 1028 | TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", bssid: " MAC_PR_FMT ", reason: %u", | 1046 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", bssid: " MAC_PR_FMT ", reason: %u", |
| 1029 | WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(bssid), | 1047 | WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(bssid), |
| 1030 | __entry->reason_code) | 1048 | __entry->reason_code) |
| 1031 | ); | 1049 | ); |
| @@ -1051,7 +1069,7 @@ TRACE_EVENT(rdev_disassoc, | |||
| 1051 | __entry->reason_code = req->reason_code; | 1069 | __entry->reason_code = req->reason_code; |
| 1052 | __entry->local_state_change = req->local_state_change; | 1070 | __entry->local_state_change = req->local_state_change; |
| 1053 | ), | 1071 | ), |
| 1054 | TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", bssid: " MAC_PR_FMT | 1072 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", bssid: " MAC_PR_FMT |
| 1055 | ", reason: %u, local state change: %s", | 1073 | ", reason: %u, local state change: %s", |
| 1056 | WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(bssid), | 1074 | WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(bssid), |
| 1057 | __entry->reason_code, | 1075 | __entry->reason_code, |
| @@ -1072,7 +1090,7 @@ TRACE_EVENT(rdev_mgmt_tx_cancel_wait, | |||
| 1072 | WDEV_ASSIGN; | 1090 | WDEV_ASSIGN; |
| 1073 | __entry->cookie = cookie; | 1091 | __entry->cookie = cookie; |
| 1074 | ), | 1092 | ), |
| 1075 | TP_printk(WIPHY_PR_FMT WDEV_PR_FMT ", cookie: %llu ", | 1093 | TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT ", cookie: %llu ", |
| 1076 | WIPHY_PR_ARG, WDEV_PR_ARG, __entry->cookie) | 1094 | WIPHY_PR_ARG, WDEV_PR_ARG, __entry->cookie) |
| 1077 | ); | 1095 | ); |
| 1078 | 1096 | ||
| @@ -1092,7 +1110,7 @@ TRACE_EVENT(rdev_set_power_mgmt, | |||
| 1092 | __entry->enabled = enabled; | 1110 | __entry->enabled = enabled; |
| 1093 | __entry->timeout = timeout; | 1111 | __entry->timeout = timeout; |
| 1094 | ), | 1112 | ), |
| 1095 | TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", %senabled, timeout: %d ", | 1113 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", %senabled, timeout: %d ", |
| 1096 | WIPHY_PR_ARG, NETDEV_PR_ARG, | 1114 | WIPHY_PR_ARG, NETDEV_PR_ARG, |
| 1097 | __entry->enabled ? "" : "not ", __entry->timeout) | 1115 | __entry->enabled ? "" : "not ", __entry->timeout) |
| 1098 | ); | 1116 | ); |
| @@ -1122,7 +1140,7 @@ TRACE_EVENT(rdev_connect, | |||
| 1122 | __entry->wpa_versions = sme->crypto.wpa_versions; | 1140 | __entry->wpa_versions = sme->crypto.wpa_versions; |
| 1123 | __entry->flags = sme->flags; | 1141 | __entry->flags = sme->flags; |
| 1124 | ), | 1142 | ), |
| 1125 | TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", bssid: " MAC_PR_FMT | 1143 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", bssid: " MAC_PR_FMT |
| 1126 | ", ssid: %s, auth type: %d, privacy: %s, wpa versions: %u, " | 1144 | ", ssid: %s, auth type: %d, privacy: %s, wpa versions: %u, " |
| 1127 | "flags: %u", | 1145 | "flags: %u", |
| 1128 | WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(bssid), __entry->ssid, | 1146 | WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(bssid), __entry->ssid, |
| @@ -1147,7 +1165,7 @@ TRACE_EVENT(rdev_set_cqm_rssi_config, | |||
| 1147 | __entry->rssi_thold = rssi_thold; | 1165 | __entry->rssi_thold = rssi_thold; |
| 1148 | __entry->rssi_hyst = rssi_hyst; | 1166 | __entry->rssi_hyst = rssi_hyst; |
| 1149 | ), | 1167 | ), |
| 1150 | TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT | 1168 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT |
| 1151 | ", rssi_thold: %d, rssi_hyst: %u ", | 1169 | ", rssi_thold: %d, rssi_hyst: %u ", |
| 1152 | WIPHY_PR_ARG, NETDEV_PR_ARG, | 1170 | WIPHY_PR_ARG, NETDEV_PR_ARG, |
| 1153 | __entry->rssi_thold, __entry->rssi_hyst) | 1171 | __entry->rssi_thold, __entry->rssi_hyst) |
| @@ -1171,7 +1189,7 @@ TRACE_EVENT(rdev_set_cqm_txe_config, | |||
| 1171 | __entry->pkts = pkts; | 1189 | __entry->pkts = pkts; |
| 1172 | __entry->intvl = intvl; | 1190 | __entry->intvl = intvl; |
| 1173 | ), | 1191 | ), |
| 1174 | TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", rate: %u, packets: %u, interval: %u", | 1192 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", rate: %u, packets: %u, interval: %u", |
| 1175 | WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->rate, __entry->pkts, | 1193 | WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->rate, __entry->pkts, |
| 1176 | __entry->intvl) | 1194 | __entry->intvl) |
| 1177 | ); | 1195 | ); |
| @@ -1190,7 +1208,7 @@ TRACE_EVENT(rdev_disconnect, | |||
| 1190 | NETDEV_ASSIGN; | 1208 | NETDEV_ASSIGN; |
| 1191 | __entry->reason_code = reason_code; | 1209 | __entry->reason_code = reason_code; |
| 1192 | ), | 1210 | ), |
| 1193 | TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", reason code: %u", WIPHY_PR_ARG, | 1211 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", reason code: %u", WIPHY_PR_ARG, |
| 1194 | NETDEV_PR_ARG, __entry->reason_code) | 1212 | NETDEV_PR_ARG, __entry->reason_code) |
| 1195 | ); | 1213 | ); |
| 1196 | 1214 | ||
| @@ -1211,7 +1229,7 @@ TRACE_EVENT(rdev_join_ibss, | |||
| 1211 | memset(__entry->ssid, 0, IEEE80211_MAX_SSID_LEN + 1); | 1229 | memset(__entry->ssid, 0, IEEE80211_MAX_SSID_LEN + 1); |
| 1212 | memcpy(__entry->ssid, params->ssid, params->ssid_len); | 1230 | memcpy(__entry->ssid, params->ssid, params->ssid_len); |
| 1213 | ), | 1231 | ), |
| 1214 | TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", bssid: " MAC_PR_FMT ", ssid: %s", | 1232 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", bssid: " MAC_PR_FMT ", ssid: %s", |
| 1215 | WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(bssid), __entry->ssid) | 1233 | WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(bssid), __entry->ssid) |
| 1216 | ); | 1234 | ); |
| 1217 | 1235 | ||
| @@ -1230,22 +1248,29 @@ TRACE_EVENT(rdev_set_wiphy_params, | |||
| 1230 | WIPHY_PR_ARG, __entry->changed) | 1248 | WIPHY_PR_ARG, __entry->changed) |
| 1231 | ); | 1249 | ); |
| 1232 | 1250 | ||
| 1251 | DEFINE_EVENT(wiphy_wdev_evt, rdev_get_tx_power, | ||
| 1252 | TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev), | ||
| 1253 | TP_ARGS(wiphy, wdev) | ||
| 1254 | ); | ||
| 1255 | |||
| 1233 | TRACE_EVENT(rdev_set_tx_power, | 1256 | TRACE_EVENT(rdev_set_tx_power, |
| 1234 | TP_PROTO(struct wiphy *wiphy, enum nl80211_tx_power_setting type, | 1257 | TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev, |
| 1235 | int mbm), | 1258 | enum nl80211_tx_power_setting type, int mbm), |
| 1236 | TP_ARGS(wiphy, type, mbm), | 1259 | TP_ARGS(wiphy, wdev, type, mbm), |
| 1237 | TP_STRUCT__entry( | 1260 | TP_STRUCT__entry( |
| 1238 | WIPHY_ENTRY | 1261 | WIPHY_ENTRY |
| 1262 | WDEV_ENTRY | ||
| 1239 | __field(enum nl80211_tx_power_setting, type) | 1263 | __field(enum nl80211_tx_power_setting, type) |
| 1240 | __field(int, mbm) | 1264 | __field(int, mbm) |
| 1241 | ), | 1265 | ), |
| 1242 | TP_fast_assign( | 1266 | TP_fast_assign( |
| 1243 | WIPHY_ASSIGN; | 1267 | WIPHY_ASSIGN; |
| 1268 | WDEV_ASSIGN; | ||
| 1244 | __entry->type = type; | 1269 | __entry->type = type; |
| 1245 | __entry->mbm = mbm; | 1270 | __entry->mbm = mbm; |
| 1246 | ), | 1271 | ), |
| 1247 | TP_printk(WIPHY_PR_FMT ", type: %d, mbm: %d", | 1272 | TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT ", type: %u, mbm: %d", |
| 1248 | WIPHY_PR_ARG, __entry->type, __entry->mbm) | 1273 | WIPHY_PR_ARG, WDEV_PR_ARG,__entry->type, __entry->mbm) |
| 1249 | ); | 1274 | ); |
| 1250 | 1275 | ||
| 1251 | TRACE_EVENT(rdev_return_int_int, | 1276 | TRACE_EVENT(rdev_return_int_int, |
| @@ -1305,7 +1330,7 @@ TRACE_EVENT(rdev_set_bitrate_mask, | |||
| 1305 | NETDEV_ASSIGN; | 1330 | NETDEV_ASSIGN; |
| 1306 | MAC_ASSIGN(peer, peer); | 1331 | MAC_ASSIGN(peer, peer); |
| 1307 | ), | 1332 | ), |
| 1308 | TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", peer: " MAC_PR_FMT, | 1333 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", peer: " MAC_PR_FMT, |
| 1309 | WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(peer)) | 1334 | WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(peer)) |
| 1310 | ); | 1335 | ); |
| 1311 | 1336 | ||
| @@ -1325,7 +1350,7 @@ TRACE_EVENT(rdev_mgmt_frame_register, | |||
| 1325 | __entry->frame_type = frame_type; | 1350 | __entry->frame_type = frame_type; |
| 1326 | __entry->reg = reg; | 1351 | __entry->reg = reg; |
| 1327 | ), | 1352 | ), |
| 1328 | TP_printk(WIPHY_PR_FMT WDEV_PR_FMT ", frame_type: %u, reg: %s ", | 1353 | TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT ", frame_type: 0x%.2x, reg: %s ", |
| 1329 | WIPHY_PR_ARG, WDEV_PR_ARG, __entry->frame_type, | 1354 | WIPHY_PR_ARG, WDEV_PR_ARG, __entry->frame_type, |
| 1330 | __entry->reg ? "true" : "false") | 1355 | __entry->reg ? "true" : "false") |
| 1331 | ); | 1356 | ); |
| @@ -1411,7 +1436,7 @@ TRACE_EVENT(rdev_sched_scan_start, | |||
| 1411 | WIPHY_ASSIGN; | 1436 | WIPHY_ASSIGN; |
| 1412 | NETDEV_ASSIGN; | 1437 | NETDEV_ASSIGN; |
| 1413 | ), | 1438 | ), |
| 1414 | TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT, | 1439 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT, |
| 1415 | WIPHY_PR_ARG, NETDEV_PR_ARG) | 1440 | WIPHY_PR_ARG, NETDEV_PR_ARG) |
| 1416 | ); | 1441 | ); |
| 1417 | 1442 | ||
| @@ -1439,7 +1464,7 @@ TRACE_EVENT(rdev_tdls_mgmt, | |||
| 1439 | __entry->status_code = status_code; | 1464 | __entry->status_code = status_code; |
| 1440 | memcpy(__get_dynamic_array(buf), buf, len); | 1465 | memcpy(__get_dynamic_array(buf), buf, len); |
| 1441 | ), | 1466 | ), |
| 1442 | TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT MAC_PR_FMT ", action_code: %u, " | 1467 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", " MAC_PR_FMT ", action_code: %u, " |
| 1443 | "dialog_token: %u, status_code: %u, buf: %#.2x ", | 1468 | "dialog_token: %u, status_code: %u, buf: %#.2x ", |
| 1444 | WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(peer), | 1469 | WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(peer), |
| 1445 | __entry->action_code, __entry->dialog_token, | 1470 | __entry->action_code, __entry->dialog_token, |
| @@ -1459,7 +1484,7 @@ TRACE_EVENT(rdev_dump_survey, | |||
| 1459 | NETDEV_ASSIGN; | 1484 | NETDEV_ASSIGN; |
| 1460 | __entry->idx = idx; | 1485 | __entry->idx = idx; |
| 1461 | ), | 1486 | ), |
| 1462 | TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", index: %d", | 1487 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", index: %d", |
| 1463 | WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->idx) | 1488 | WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->idx) |
| 1464 | ); | 1489 | ); |
| 1465 | 1490 | ||
| @@ -1516,7 +1541,7 @@ TRACE_EVENT(rdev_tdls_oper, | |||
| 1516 | MAC_ASSIGN(peer, peer); | 1541 | MAC_ASSIGN(peer, peer); |
| 1517 | __entry->oper = oper; | 1542 | __entry->oper = oper; |
| 1518 | ), | 1543 | ), |
| 1519 | TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT MAC_PR_FMT ", oper: %d", | 1544 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", " MAC_PR_FMT ", oper: %d", |
| 1520 | WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(peer), __entry->oper) | 1545 | WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(peer), __entry->oper) |
| 1521 | ); | 1546 | ); |
| 1522 | 1547 | ||
| @@ -1534,7 +1559,7 @@ DECLARE_EVENT_CLASS(rdev_pmksa, | |||
| 1534 | NETDEV_ASSIGN; | 1559 | NETDEV_ASSIGN; |
| 1535 | MAC_ASSIGN(bssid, pmksa->bssid); | 1560 | MAC_ASSIGN(bssid, pmksa->bssid); |
| 1536 | ), | 1561 | ), |
| 1537 | TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", bssid: " MAC_PR_FMT, | 1562 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", bssid: " MAC_PR_FMT, |
| 1538 | WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(bssid)) | 1563 | WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(bssid)) |
| 1539 | ); | 1564 | ); |
| 1540 | 1565 | ||
| @@ -1552,7 +1577,7 @@ TRACE_EVENT(rdev_probe_client, | |||
| 1552 | NETDEV_ASSIGN; | 1577 | NETDEV_ASSIGN; |
| 1553 | MAC_ASSIGN(peer, peer); | 1578 | MAC_ASSIGN(peer, peer); |
| 1554 | ), | 1579 | ), |
| 1555 | TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT MAC_PR_FMT, | 1580 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", " MAC_PR_FMT, |
| 1556 | WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(peer)) | 1581 | WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(peer)) |
| 1557 | ); | 1582 | ); |
| 1558 | 1583 | ||
| @@ -1571,25 +1596,22 @@ DEFINE_EVENT(rdev_pmksa, rdev_del_pmksa, | |||
| 1571 | TRACE_EVENT(rdev_remain_on_channel, | 1596 | TRACE_EVENT(rdev_remain_on_channel, |
| 1572 | TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev, | 1597 | TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev, |
| 1573 | struct ieee80211_channel *chan, | 1598 | struct ieee80211_channel *chan, |
| 1574 | enum nl80211_channel_type channel_type, unsigned int duration), | 1599 | unsigned int duration), |
| 1575 | TP_ARGS(wiphy, wdev, chan, channel_type, duration), | 1600 | TP_ARGS(wiphy, wdev, chan, duration), |
| 1576 | TP_STRUCT__entry( | 1601 | TP_STRUCT__entry( |
| 1577 | WIPHY_ENTRY | 1602 | WIPHY_ENTRY |
| 1578 | WDEV_ENTRY | 1603 | WDEV_ENTRY |
| 1579 | CHAN_ENTRY | 1604 | CHAN_ENTRY |
| 1580 | __field(enum nl80211_channel_type, channel_type) | ||
| 1581 | __field(unsigned int, duration) | 1605 | __field(unsigned int, duration) |
| 1582 | ), | 1606 | ), |
| 1583 | TP_fast_assign( | 1607 | TP_fast_assign( |
| 1584 | WIPHY_ASSIGN; | 1608 | WIPHY_ASSIGN; |
| 1585 | WDEV_ASSIGN; | 1609 | WDEV_ASSIGN; |
| 1586 | CHAN_ASSIGN(chan); | 1610 | CHAN_ASSIGN(chan); |
| 1587 | __entry->channel_type = channel_type; | ||
| 1588 | __entry->duration = duration; | 1611 | __entry->duration = duration; |
| 1589 | ), | 1612 | ), |
| 1590 | TP_printk(WIPHY_PR_FMT WDEV_PR_FMT CHAN_PR_FMT ", channel type: %d, duration: %u", | 1613 | TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT ", " CHAN_PR_FMT ", duration: %u", |
| 1591 | WIPHY_PR_ARG, WDEV_PR_ARG, CHAN_PR_ARG, __entry->channel_type, | 1614 | WIPHY_PR_ARG, WDEV_PR_ARG, CHAN_PR_ARG, __entry->duration) |
| 1592 | __entry->duration) | ||
| 1593 | ); | 1615 | ); |
| 1594 | 1616 | ||
| 1595 | TRACE_EVENT(rdev_return_int_cookie, | 1617 | TRACE_EVENT(rdev_return_int_cookie, |
| @@ -1622,25 +1644,20 @@ TRACE_EVENT(rdev_cancel_remain_on_channel, | |||
| 1622 | WDEV_ASSIGN; | 1644 | WDEV_ASSIGN; |
| 1623 | __entry->cookie = cookie; | 1645 | __entry->cookie = cookie; |
| 1624 | ), | 1646 | ), |
| 1625 | TP_printk(WIPHY_PR_FMT WDEV_PR_FMT ", cookie: %llu", | 1647 | TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT ", cookie: %llu", |
| 1626 | WIPHY_PR_ARG, WDEV_PR_ARG, __entry->cookie) | 1648 | WIPHY_PR_ARG, WDEV_PR_ARG, __entry->cookie) |
| 1627 | ); | 1649 | ); |
| 1628 | 1650 | ||
| 1629 | TRACE_EVENT(rdev_mgmt_tx, | 1651 | TRACE_EVENT(rdev_mgmt_tx, |
| 1630 | TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev, | 1652 | TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev, |
| 1631 | struct ieee80211_channel *chan, bool offchan, | 1653 | struct ieee80211_channel *chan, bool offchan, |
| 1632 | enum nl80211_channel_type channel_type, | 1654 | unsigned int wait, bool no_cck, bool dont_wait_for_ack), |
| 1633 | bool channel_type_valid, unsigned int wait, bool no_cck, | 1655 | TP_ARGS(wiphy, wdev, chan, offchan, wait, no_cck, dont_wait_for_ack), |
| 1634 | bool dont_wait_for_ack), | ||
| 1635 | TP_ARGS(wiphy, wdev, chan, offchan, channel_type, channel_type_valid, | ||
| 1636 | wait, no_cck, dont_wait_for_ack), | ||
| 1637 | TP_STRUCT__entry( | 1656 | TP_STRUCT__entry( |
| 1638 | WIPHY_ENTRY | 1657 | WIPHY_ENTRY |
| 1639 | WDEV_ENTRY | 1658 | WDEV_ENTRY |
| 1640 | CHAN_ENTRY | 1659 | CHAN_ENTRY |
| 1641 | __field(bool, offchan) | 1660 | __field(bool, offchan) |
| 1642 | __field(enum nl80211_channel_type, channel_type) | ||
| 1643 | __field(bool, channel_type_valid) | ||
| 1644 | __field(unsigned int, wait) | 1661 | __field(unsigned int, wait) |
| 1645 | __field(bool, no_cck) | 1662 | __field(bool, no_cck) |
| 1646 | __field(bool, dont_wait_for_ack) | 1663 | __field(bool, dont_wait_for_ack) |
| @@ -1650,18 +1667,14 @@ TRACE_EVENT(rdev_mgmt_tx, | |||
| 1650 | WDEV_ASSIGN; | 1667 | WDEV_ASSIGN; |
| 1651 | CHAN_ASSIGN(chan); | 1668 | CHAN_ASSIGN(chan); |
| 1652 | __entry->offchan = offchan; | 1669 | __entry->offchan = offchan; |
| 1653 | __entry->channel_type = channel_type; | ||
| 1654 | __entry->channel_type_valid = channel_type_valid; | ||
| 1655 | __entry->wait = wait; | 1670 | __entry->wait = wait; |
| 1656 | __entry->no_cck = no_cck; | 1671 | __entry->no_cck = no_cck; |
| 1657 | __entry->dont_wait_for_ack = dont_wait_for_ack; | 1672 | __entry->dont_wait_for_ack = dont_wait_for_ack; |
| 1658 | ), | 1673 | ), |
| 1659 | TP_printk(WIPHY_PR_FMT WDEV_PR_FMT CHAN_PR_FMT ", offchan: %s, " | 1674 | TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT ", " CHAN_PR_FMT ", offchan: %s," |
| 1660 | "channel type: %d, channel type valid: %s, wait: %u, " | 1675 | " wait: %u, no cck: %s, dont wait for ack: %s", |
| 1661 | "no cck: %s, dont wait for ack: %s", | ||
| 1662 | WIPHY_PR_ARG, WDEV_PR_ARG, CHAN_PR_ARG, | 1676 | WIPHY_PR_ARG, WDEV_PR_ARG, CHAN_PR_ARG, |
| 1663 | BOOL_TO_STR(__entry->offchan), __entry->channel_type, | 1677 | BOOL_TO_STR(__entry->offchan), __entry->wait, |
| 1664 | BOOL_TO_STR(__entry->channel_type_valid), __entry->wait, | ||
| 1665 | BOOL_TO_STR(__entry->no_cck), | 1678 | BOOL_TO_STR(__entry->no_cck), |
| 1666 | BOOL_TO_STR(__entry->dont_wait_for_ack)) | 1679 | BOOL_TO_STR(__entry->dont_wait_for_ack)) |
| 1667 | ); | 1680 | ); |
| @@ -1680,7 +1693,7 @@ TRACE_EVENT(rdev_set_noack_map, | |||
| 1680 | NETDEV_ASSIGN; | 1693 | NETDEV_ASSIGN; |
| 1681 | __entry->noack_map = noack_map; | 1694 | __entry->noack_map = noack_map; |
| 1682 | ), | 1695 | ), |
| 1683 | TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", noack_map: %u", | 1696 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", noack_map: %u", |
| 1684 | WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->noack_map) | 1697 | WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->noack_map) |
| 1685 | ); | 1698 | ); |
| 1686 | 1699 | ||
| @@ -1697,7 +1710,7 @@ TRACE_EVENT(rdev_get_et_sset_count, | |||
| 1697 | NETDEV_ASSIGN; | 1710 | NETDEV_ASSIGN; |
| 1698 | __entry->sset = sset; | 1711 | __entry->sset = sset; |
| 1699 | ), | 1712 | ), |
| 1700 | TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", sset: %d", | 1713 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", sset: %d", |
| 1701 | WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->sset) | 1714 | WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->sset) |
| 1702 | ); | 1715 | ); |
| 1703 | 1716 | ||
| @@ -1714,7 +1727,7 @@ TRACE_EVENT(rdev_get_et_strings, | |||
| 1714 | NETDEV_ASSIGN; | 1727 | NETDEV_ASSIGN; |
| 1715 | __entry->sset = sset; | 1728 | __entry->sset = sset; |
| 1716 | ), | 1729 | ), |
| 1717 | TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", sset: %u", | 1730 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", sset: %u", |
| 1718 | WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->sset) | 1731 | WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->sset) |
| 1719 | ); | 1732 | ); |
| 1720 | 1733 | ||
| @@ -1723,22 +1736,25 @@ DEFINE_EVENT(wiphy_wdev_evt, rdev_get_channel, | |||
| 1723 | TP_ARGS(wiphy, wdev) | 1736 | TP_ARGS(wiphy, wdev) |
| 1724 | ); | 1737 | ); |
| 1725 | 1738 | ||
| 1726 | TRACE_EVENT(rdev_return_channel, | 1739 | TRACE_EVENT(rdev_return_chandef, |
| 1727 | TP_PROTO(struct wiphy *wiphy, struct ieee80211_channel *chan, | 1740 | TP_PROTO(struct wiphy *wiphy, int ret, |
| 1728 | enum nl80211_channel_type type), | 1741 | struct cfg80211_chan_def *chandef), |
| 1729 | TP_ARGS(wiphy, chan, type), | 1742 | TP_ARGS(wiphy, ret, chandef), |
| 1730 | TP_STRUCT__entry( | 1743 | TP_STRUCT__entry( |
| 1731 | WIPHY_ENTRY | 1744 | WIPHY_ENTRY |
| 1732 | CHAN_ENTRY | 1745 | __field(int, ret) |
| 1733 | __field(enum nl80211_channel_type, type) | 1746 | CHAN_DEF_ENTRY |
| 1734 | ), | 1747 | ), |
| 1735 | TP_fast_assign( | 1748 | TP_fast_assign( |
| 1736 | WIPHY_ASSIGN; | 1749 | WIPHY_ASSIGN; |
| 1737 | CHAN_ASSIGN(chan); | 1750 | if (ret == 0) |
| 1738 | __entry->type = type; | 1751 | CHAN_DEF_ASSIGN(chandef); |
| 1752 | else | ||
| 1753 | CHAN_DEF_ASSIGN((struct cfg80211_chan_def *)NULL); | ||
| 1754 | __entry->ret = ret; | ||
| 1739 | ), | 1755 | ), |
| 1740 | TP_printk(WIPHY_PR_FMT CHAN_PR_FMT ", channel type: %d", | 1756 | TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT ", ret: %d", |
| 1741 | WIPHY_PR_ARG, CHAN_PR_ARG, __entry->type) | 1757 | WIPHY_PR_ARG, CHAN_DEF_PR_ARG, __entry->ret) |
| 1742 | ); | 1758 | ); |
| 1743 | 1759 | ||
| 1744 | DEFINE_EVENT(wiphy_wdev_evt, rdev_start_p2p_device, | 1760 | DEFINE_EVENT(wiphy_wdev_evt, rdev_start_p2p_device, |
| @@ -1817,7 +1833,7 @@ TRACE_EVENT(cfg80211_send_rx_assoc, | |||
| 1817 | MAC_ASSIGN(bssid, bss->bssid); | 1833 | MAC_ASSIGN(bssid, bss->bssid); |
| 1818 | CHAN_ASSIGN(bss->channel); | 1834 | CHAN_ASSIGN(bss->channel); |
| 1819 | ), | 1835 | ), |
| 1820 | TP_printk(NETDEV_PR_FMT MAC_PR_FMT CHAN_PR_FMT, | 1836 | TP_printk(NETDEV_PR_FMT ", " MAC_PR_FMT ", " CHAN_PR_FMT, |
| 1821 | NETDEV_PR_ARG, MAC_PR_ARG(bssid), CHAN_PR_ARG) | 1837 | NETDEV_PR_ARG, MAC_PR_ARG(bssid), CHAN_PR_ARG) |
| 1822 | ); | 1838 | ); |
| 1823 | 1839 | ||
| @@ -1884,7 +1900,7 @@ TRACE_EVENT(cfg80211_michael_mic_failure, | |||
| 1884 | __entry->key_id = key_id; | 1900 | __entry->key_id = key_id; |
| 1885 | memcpy(__entry->tsc, tsc, 6); | 1901 | memcpy(__entry->tsc, tsc, 6); |
| 1886 | ), | 1902 | ), |
| 1887 | TP_printk(NETDEV_PR_FMT MAC_PR_FMT ", key type: %d, key id: %d, tsc: %pm", | 1903 | TP_printk(NETDEV_PR_FMT ", " MAC_PR_FMT ", key type: %d, key id: %d, tsc: %pm", |
| 1888 | NETDEV_PR_ARG, MAC_PR_ARG(addr), __entry->key_type, | 1904 | NETDEV_PR_ARG, MAC_PR_ARG(addr), __entry->key_type, |
| 1889 | __entry->key_id, __entry->tsc) | 1905 | __entry->key_id, __entry->tsc) |
| 1890 | ); | 1906 | ); |
| @@ -1892,47 +1908,41 @@ TRACE_EVENT(cfg80211_michael_mic_failure, | |||
| 1892 | TRACE_EVENT(cfg80211_ready_on_channel, | 1908 | TRACE_EVENT(cfg80211_ready_on_channel, |
| 1893 | TP_PROTO(struct wireless_dev *wdev, u64 cookie, | 1909 | TP_PROTO(struct wireless_dev *wdev, u64 cookie, |
| 1894 | struct ieee80211_channel *chan, | 1910 | struct ieee80211_channel *chan, |
| 1895 | enum nl80211_channel_type channel_type, unsigned int duration), | 1911 | unsigned int duration), |
| 1896 | TP_ARGS(wdev, cookie, chan, channel_type, duration), | 1912 | TP_ARGS(wdev, cookie, chan, duration), |
| 1897 | TP_STRUCT__entry( | 1913 | TP_STRUCT__entry( |
| 1898 | WDEV_ENTRY | 1914 | WDEV_ENTRY |
| 1899 | __field(u64, cookie) | 1915 | __field(u64, cookie) |
| 1900 | CHAN_ENTRY | 1916 | CHAN_ENTRY |
| 1901 | __field(enum nl80211_channel_type, channel_type) | ||
| 1902 | __field(unsigned int, duration) | 1917 | __field(unsigned int, duration) |
| 1903 | ), | 1918 | ), |
| 1904 | TP_fast_assign( | 1919 | TP_fast_assign( |
| 1905 | WDEV_ASSIGN; | 1920 | WDEV_ASSIGN; |
| 1906 | __entry->cookie = cookie; | 1921 | __entry->cookie = cookie; |
| 1907 | CHAN_ASSIGN(chan); | 1922 | CHAN_ASSIGN(chan); |
| 1908 | __entry->channel_type = channel_type; | ||
| 1909 | __entry->duration = duration; | 1923 | __entry->duration = duration; |
| 1910 | ), | 1924 | ), |
| 1911 | TP_printk(WDEV_PR_FMT ", cookie: %llu, " CHAN_PR_FMT ", channel type: %d, duration: %u", | 1925 | TP_printk(WDEV_PR_FMT ", cookie: %llu, " CHAN_PR_FMT ", duration: %u", |
| 1912 | WDEV_PR_ARG, __entry->cookie, CHAN_PR_ARG, | 1926 | WDEV_PR_ARG, __entry->cookie, CHAN_PR_ARG, |
| 1913 | __entry->channel_type, __entry->duration) | 1927 | __entry->duration) |
| 1914 | ); | 1928 | ); |
| 1915 | 1929 | ||
| 1916 | TRACE_EVENT(cfg80211_ready_on_channel_expired, | 1930 | TRACE_EVENT(cfg80211_ready_on_channel_expired, |
| 1917 | TP_PROTO(struct wireless_dev *wdev, u64 cookie, | 1931 | TP_PROTO(struct wireless_dev *wdev, u64 cookie, |
| 1918 | struct ieee80211_channel *chan, | 1932 | struct ieee80211_channel *chan), |
| 1919 | enum nl80211_channel_type channel_type), | 1933 | TP_ARGS(wdev, cookie, chan), |
| 1920 | TP_ARGS(wdev, cookie, chan, channel_type), | ||
| 1921 | TP_STRUCT__entry( | 1934 | TP_STRUCT__entry( |
| 1922 | WDEV_ENTRY | 1935 | WDEV_ENTRY |
| 1923 | __field(u64, cookie) | 1936 | __field(u64, cookie) |
| 1924 | CHAN_ENTRY | 1937 | CHAN_ENTRY |
| 1925 | __field(enum nl80211_channel_type, channel_type) | ||
| 1926 | ), | 1938 | ), |
| 1927 | TP_fast_assign( | 1939 | TP_fast_assign( |
| 1928 | WDEV_ASSIGN; | 1940 | WDEV_ASSIGN; |
| 1929 | __entry->cookie = cookie; | 1941 | __entry->cookie = cookie; |
| 1930 | CHAN_ASSIGN(chan); | 1942 | CHAN_ASSIGN(chan); |
| 1931 | __entry->channel_type = channel_type; | ||
| 1932 | ), | 1943 | ), |
| 1933 | TP_printk(WDEV_PR_FMT ", cookie: %llu, " CHAN_PR_FMT ", channel type: %d", | 1944 | TP_printk(WDEV_PR_FMT ", cookie: %llu, " CHAN_PR_FMT, |
| 1934 | WDEV_PR_ARG, __entry->cookie, CHAN_PR_ARG, | 1945 | WDEV_PR_ARG, __entry->cookie, CHAN_PR_ARG) |
| 1935 | __entry->channel_type) | ||
| 1936 | ); | 1946 | ); |
| 1937 | 1947 | ||
| 1938 | TRACE_EVENT(cfg80211_new_sta, | 1948 | TRACE_EVENT(cfg80211_new_sta, |
| @@ -1949,7 +1959,7 @@ TRACE_EVENT(cfg80211_new_sta, | |||
| 1949 | MAC_ASSIGN(mac_addr, mac_addr); | 1959 | MAC_ASSIGN(mac_addr, mac_addr); |
| 1950 | SINFO_ASSIGN; | 1960 | SINFO_ASSIGN; |
| 1951 | ), | 1961 | ), |
| 1952 | TP_printk(NETDEV_PR_FMT MAC_PR_FMT, | 1962 | TP_printk(NETDEV_PR_FMT ", " MAC_PR_FMT, |
| 1953 | NETDEV_PR_ARG, MAC_PR_ARG(mac_addr)) | 1963 | NETDEV_PR_ARG, MAC_PR_ARG(mac_addr)) |
| 1954 | ); | 1964 | ); |
| 1955 | 1965 | ||
| @@ -2008,40 +2018,35 @@ TRACE_EVENT(cfg80211_cqm_rssi_notify, | |||
| 2008 | NETDEV_PR_ARG, __entry->rssi_event) | 2018 | NETDEV_PR_ARG, __entry->rssi_event) |
| 2009 | ); | 2019 | ); |
| 2010 | 2020 | ||
| 2011 | TRACE_EVENT(cfg80211_can_beacon_sec_chan, | 2021 | TRACE_EVENT(cfg80211_reg_can_beacon, |
| 2012 | TP_PROTO(struct wiphy *wiphy, struct ieee80211_channel *channel, | 2022 | TP_PROTO(struct wiphy *wiphy, struct cfg80211_chan_def *chandef), |
| 2013 | enum nl80211_channel_type channel_type), | 2023 | TP_ARGS(wiphy, chandef), |
| 2014 | TP_ARGS(wiphy, channel, channel_type), | ||
| 2015 | TP_STRUCT__entry( | 2024 | TP_STRUCT__entry( |
| 2016 | WIPHY_ENTRY | 2025 | WIPHY_ENTRY |
| 2017 | CHAN_ENTRY | 2026 | CHAN_DEF_ENTRY |
| 2018 | __field(enum nl80211_channel_type, channel_type) | ||
| 2019 | ), | 2027 | ), |
| 2020 | TP_fast_assign( | 2028 | TP_fast_assign( |
| 2021 | WIPHY_ASSIGN; | 2029 | WIPHY_ASSIGN; |
| 2022 | CHAN_ASSIGN(channel); | 2030 | CHAN_DEF_ASSIGN(chandef); |
| 2023 | __entry->channel_type = channel_type; | ||
| 2024 | ), | 2031 | ), |
| 2025 | TP_printk(WIPHY_PR_FMT CHAN_PR_FMT ", channel_type: %d", | 2032 | TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT, |
| 2026 | WIPHY_PR_ARG, CHAN_PR_ARG, __entry->channel_type) | 2033 | WIPHY_PR_ARG, CHAN_DEF_PR_ARG) |
| 2027 | ); | 2034 | ); |
| 2028 | 2035 | ||
| 2029 | TRACE_EVENT(cfg80211_ch_switch_notify, | 2036 | TRACE_EVENT(cfg80211_ch_switch_notify, |
| 2030 | TP_PROTO(struct net_device *netdev, int freq, | 2037 | TP_PROTO(struct net_device *netdev, |
| 2031 | enum nl80211_channel_type type), | 2038 | struct cfg80211_chan_def *chandef), |
| 2032 | TP_ARGS(netdev, freq, type), | 2039 | TP_ARGS(netdev, chandef), |
| 2033 | TP_STRUCT__entry( | 2040 | TP_STRUCT__entry( |
| 2034 | NETDEV_ENTRY | 2041 | NETDEV_ENTRY |
| 2035 | __field(int, freq) | 2042 | CHAN_DEF_ENTRY |
| 2036 | __field(enum nl80211_channel_type, type) | ||
| 2037 | ), | 2043 | ), |
| 2038 | TP_fast_assign( | 2044 | TP_fast_assign( |
| 2039 | NETDEV_ASSIGN; | 2045 | NETDEV_ASSIGN; |
| 2040 | __entry->freq = freq; | 2046 | CHAN_DEF_ASSIGN(chandef); |
| 2041 | __entry->type = type; | ||
| 2042 | ), | 2047 | ), |
| 2043 | TP_printk(NETDEV_PR_FMT ", freq: %d, type: %d", NETDEV_PR_ARG, | 2048 | TP_printk(NETDEV_PR_FMT ", " CHAN_DEF_PR_FMT, |
| 2044 | __entry->freq, __entry->type) | 2049 | NETDEV_PR_ARG, CHAN_DEF_PR_ARG) |
| 2045 | ); | 2050 | ); |
| 2046 | 2051 | ||
| 2047 | DECLARE_EVENT_CLASS(cfg80211_rx_evt, | 2052 | DECLARE_EVENT_CLASS(cfg80211_rx_evt, |
| @@ -2055,7 +2060,7 @@ DECLARE_EVENT_CLASS(cfg80211_rx_evt, | |||
| 2055 | NETDEV_ASSIGN; | 2060 | NETDEV_ASSIGN; |
| 2056 | MAC_ASSIGN(addr, addr); | 2061 | MAC_ASSIGN(addr, addr); |
| 2057 | ), | 2062 | ), |
| 2058 | TP_printk(NETDEV_PR_FMT MAC_PR_FMT, NETDEV_PR_ARG, MAC_PR_ARG(addr)) | 2063 | TP_printk(NETDEV_PR_FMT ", " MAC_PR_FMT, NETDEV_PR_ARG, MAC_PR_ARG(addr)) |
| 2059 | ); | 2064 | ); |
| 2060 | 2065 | ||
| 2061 | DEFINE_EVENT(cfg80211_rx_evt, cfg80211_ibss_joined, | 2066 | DEFINE_EVENT(cfg80211_rx_evt, cfg80211_ibss_joined, |
| @@ -2089,7 +2094,7 @@ TRACE_EVENT(cfg80211_probe_status, | |||
| 2089 | __entry->cookie = cookie; | 2094 | __entry->cookie = cookie; |
| 2090 | __entry->acked = acked; | 2095 | __entry->acked = acked; |
| 2091 | ), | 2096 | ), |
| 2092 | TP_printk(NETDEV_PR_FMT MAC_PR_FMT ", cookie: %llu, acked: %s", | 2097 | TP_printk(NETDEV_PR_FMT " addr:" MAC_PR_FMT ", cookie: %llu, acked: %s", |
| 2093 | NETDEV_PR_ARG, MAC_PR_ARG(addr), __entry->cookie, | 2098 | NETDEV_PR_ARG, MAC_PR_ARG(addr), __entry->cookie, |
| 2094 | BOOL_TO_STR(__entry->acked)) | 2099 | BOOL_TO_STR(__entry->acked)) |
| 2095 | ); | 2100 | ); |
| @@ -2155,6 +2160,29 @@ TRACE_EVENT(cfg80211_report_obss_beacon, | |||
| 2155 | WIPHY_PR_ARG, __entry->freq, __entry->sig_dbm) | 2160 | WIPHY_PR_ARG, __entry->freq, __entry->sig_dbm) |
| 2156 | ); | 2161 | ); |
| 2157 | 2162 | ||
| 2163 | TRACE_EVENT(cfg80211_tdls_oper_request, | ||
| 2164 | TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, const u8 *peer, | ||
| 2165 | enum nl80211_tdls_operation oper, u16 reason_code), | ||
| 2166 | TP_ARGS(wiphy, netdev, peer, oper, reason_code), | ||
| 2167 | TP_STRUCT__entry( | ||
| 2168 | WIPHY_ENTRY | ||
| 2169 | NETDEV_ENTRY | ||
| 2170 | MAC_ENTRY(peer) | ||
| 2171 | __field(enum nl80211_tdls_operation, oper) | ||
| 2172 | __field(u16, reason_code) | ||
| 2173 | ), | ||
| 2174 | TP_fast_assign( | ||
| 2175 | WIPHY_ASSIGN; | ||
| 2176 | NETDEV_ASSIGN; | ||
| 2177 | MAC_ASSIGN(peer, peer); | ||
| 2178 | __entry->oper = oper; | ||
| 2179 | __entry->reason_code = reason_code; | ||
| 2180 | ), | ||
| 2181 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", peer: " MAC_PR_FMT ", oper: %d, reason_code %u", | ||
| 2182 | WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(peer), __entry->oper, | ||
| 2183 | __entry->reason_code) | ||
| 2184 | ); | ||
| 2185 | |||
| 2158 | TRACE_EVENT(cfg80211_scan_done, | 2186 | TRACE_EVENT(cfg80211_scan_done, |
| 2159 | TP_PROTO(struct cfg80211_scan_request *request, bool aborted), | 2187 | TP_PROTO(struct cfg80211_scan_request *request, bool aborted), |
| 2160 | TP_ARGS(request, aborted), | 2188 | TP_ARGS(request, aborted), |
| @@ -2216,7 +2244,7 @@ TRACE_EVENT(cfg80211_get_bss, | |||
| 2216 | __entry->capa_mask = capa_mask; | 2244 | __entry->capa_mask = capa_mask; |
| 2217 | __entry->capa_val = capa_val; | 2245 | __entry->capa_val = capa_val; |
| 2218 | ), | 2246 | ), |
| 2219 | TP_printk(WIPHY_PR_FMT CHAN_PR_FMT MAC_PR_FMT ", buf: %#.2x, " | 2247 | TP_printk(WIPHY_PR_FMT ", " CHAN_PR_FMT ", " MAC_PR_FMT ", buf: %#.2x, " |
| 2220 | "capa_mask: %d, capa_val: %u", WIPHY_PR_ARG, CHAN_PR_ARG, | 2248 | "capa_mask: %d, capa_val: %u", WIPHY_PR_ARG, CHAN_PR_ARG, |
| 2221 | MAC_PR_ARG(bssid), ((u8 *)__get_dynamic_array(ssid))[0], | 2249 | MAC_PR_ARG(bssid), ((u8 *)__get_dynamic_array(ssid))[0], |
| 2222 | __entry->capa_mask, __entry->capa_val) | 2250 | __entry->capa_mask, __entry->capa_val) |
| @@ -2240,7 +2268,7 @@ TRACE_EVENT(cfg80211_inform_bss_frame, | |||
| 2240 | memcpy(__get_dynamic_array(mgmt), mgmt, len); | 2268 | memcpy(__get_dynamic_array(mgmt), mgmt, len); |
| 2241 | __entry->signal = signal; | 2269 | __entry->signal = signal; |
| 2242 | ), | 2270 | ), |
| 2243 | TP_printk(WIPHY_PR_FMT CHAN_PR_FMT "signal: %d", | 2271 | TP_printk(WIPHY_PR_FMT ", " CHAN_PR_FMT "signal: %d", |
| 2244 | WIPHY_PR_ARG, CHAN_PR_ARG, __entry->signal) | 2272 | WIPHY_PR_ARG, CHAN_PR_ARG, __entry->signal) |
| 2245 | ); | 2273 | ); |
| 2246 | 2274 | ||
| @@ -2255,7 +2283,7 @@ DECLARE_EVENT_CLASS(cfg80211_bss_evt, | |||
| 2255 | MAC_ASSIGN(bssid, pub->bssid); | 2283 | MAC_ASSIGN(bssid, pub->bssid); |
| 2256 | CHAN_ASSIGN(pub->channel); | 2284 | CHAN_ASSIGN(pub->channel); |
| 2257 | ), | 2285 | ), |
| 2258 | TP_printk(MAC_PR_FMT CHAN_PR_FMT, MAC_PR_ARG(bssid), CHAN_PR_ARG) | 2286 | TP_printk(MAC_PR_FMT ", " CHAN_PR_FMT, MAC_PR_ARG(bssid), CHAN_PR_ARG) |
| 2259 | ); | 2287 | ); |
| 2260 | 2288 | ||
| 2261 | DEFINE_EVENT(cfg80211_bss_evt, cfg80211_return_bss, | 2289 | DEFINE_EVENT(cfg80211_bss_evt, cfg80211_return_bss, |
diff --git a/net/wireless/util.c b/net/wireless/util.c index 5b6c1df72f31..3cce6e486219 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c | |||
| @@ -944,14 +944,86 @@ static u32 cfg80211_calculate_bitrate_60g(struct rate_info *rate) | |||
| 944 | return __mcs2bitrate[rate->mcs]; | 944 | return __mcs2bitrate[rate->mcs]; |
| 945 | } | 945 | } |
| 946 | 946 | ||
| 947 | static u32 cfg80211_calculate_bitrate_vht(struct rate_info *rate) | ||
| 948 | { | ||
| 949 | static const u32 base[4][10] = { | ||
| 950 | { 6500000, | ||
| 951 | 13000000, | ||
| 952 | 19500000, | ||
| 953 | 26000000, | ||
| 954 | 39000000, | ||
| 955 | 52000000, | ||
| 956 | 58500000, | ||
| 957 | 65000000, | ||
| 958 | 78000000, | ||
| 959 | 0, | ||
| 960 | }, | ||
| 961 | { 13500000, | ||
| 962 | 27000000, | ||
| 963 | 40500000, | ||
| 964 | 54000000, | ||
| 965 | 81000000, | ||
| 966 | 108000000, | ||
| 967 | 121500000, | ||
| 968 | 135000000, | ||
| 969 | 162000000, | ||
| 970 | 180000000, | ||
| 971 | }, | ||
| 972 | { 29300000, | ||
| 973 | 58500000, | ||
| 974 | 87800000, | ||
| 975 | 117000000, | ||
| 976 | 175500000, | ||
| 977 | 234000000, | ||
| 978 | 263300000, | ||
| 979 | 292500000, | ||
| 980 | 351000000, | ||
| 981 | 390000000, | ||
| 982 | }, | ||
| 983 | { 58500000, | ||
| 984 | 117000000, | ||
| 985 | 175500000, | ||
| 986 | 234000000, | ||
| 987 | 351000000, | ||
| 988 | 468000000, | ||
| 989 | 526500000, | ||
| 990 | 585000000, | ||
| 991 | 702000000, | ||
| 992 | 780000000, | ||
| 993 | }, | ||
| 994 | }; | ||
| 995 | u32 bitrate; | ||
| 996 | int idx; | ||
| 997 | |||
| 998 | if (WARN_ON_ONCE(rate->mcs > 9)) | ||
| 999 | return 0; | ||
| 1000 | |||
| 1001 | idx = rate->flags & (RATE_INFO_FLAGS_160_MHZ_WIDTH | | ||
| 1002 | RATE_INFO_FLAGS_80P80_MHZ_WIDTH) ? 3 : | ||
| 1003 | rate->flags & RATE_INFO_FLAGS_80_MHZ_WIDTH ? 2 : | ||
| 1004 | rate->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH ? 1 : 0; | ||
| 1005 | |||
| 1006 | bitrate = base[idx][rate->mcs]; | ||
| 1007 | bitrate *= rate->nss; | ||
| 1008 | |||
| 1009 | if (rate->flags & RATE_INFO_FLAGS_SHORT_GI) | ||
| 1010 | bitrate = (bitrate / 9) * 10; | ||
| 1011 | |||
| 1012 | /* do NOT round down here */ | ||
| 1013 | return (bitrate + 50000) / 100000; | ||
| 1014 | } | ||
| 1015 | |||
| 947 | u32 cfg80211_calculate_bitrate(struct rate_info *rate) | 1016 | u32 cfg80211_calculate_bitrate(struct rate_info *rate) |
| 948 | { | 1017 | { |
| 949 | int modulation, streams, bitrate; | 1018 | int modulation, streams, bitrate; |
| 950 | 1019 | ||
| 951 | if (!(rate->flags & RATE_INFO_FLAGS_MCS)) | 1020 | if (!(rate->flags & RATE_INFO_FLAGS_MCS) && |
| 1021 | !(rate->flags & RATE_INFO_FLAGS_VHT_MCS)) | ||
| 952 | return rate->legacy; | 1022 | return rate->legacy; |
| 953 | if (rate->flags & RATE_INFO_FLAGS_60G) | 1023 | if (rate->flags & RATE_INFO_FLAGS_60G) |
| 954 | return cfg80211_calculate_bitrate_60g(rate); | 1024 | return cfg80211_calculate_bitrate_60g(rate); |
| 1025 | if (rate->flags & RATE_INFO_FLAGS_VHT_MCS) | ||
| 1026 | return cfg80211_calculate_bitrate_vht(rate); | ||
| 955 | 1027 | ||
| 956 | /* the formula below does only work for MCS values smaller than 32 */ | 1028 | /* the formula below does only work for MCS values smaller than 32 */ |
| 957 | if (WARN_ON_ONCE(rate->mcs >= 32)) | 1029 | if (WARN_ON_ONCE(rate->mcs >= 32)) |
| @@ -980,6 +1052,106 @@ u32 cfg80211_calculate_bitrate(struct rate_info *rate) | |||
| 980 | } | 1052 | } |
| 981 | EXPORT_SYMBOL(cfg80211_calculate_bitrate); | 1053 | EXPORT_SYMBOL(cfg80211_calculate_bitrate); |
| 982 | 1054 | ||
| 1055 | int cfg80211_get_p2p_attr(const u8 *ies, unsigned int len, | ||
| 1056 | enum ieee80211_p2p_attr_id attr, | ||
| 1057 | u8 *buf, unsigned int bufsize) | ||
| 1058 | { | ||
| 1059 | u8 *out = buf; | ||
| 1060 | u16 attr_remaining = 0; | ||
| 1061 | bool desired_attr = false; | ||
| 1062 | u16 desired_len = 0; | ||
| 1063 | |||
| 1064 | while (len > 0) { | ||
| 1065 | unsigned int iedatalen; | ||
| 1066 | unsigned int copy; | ||
| 1067 | const u8 *iedata; | ||
| 1068 | |||
| 1069 | if (len < 2) | ||
| 1070 | return -EILSEQ; | ||
| 1071 | iedatalen = ies[1]; | ||
| 1072 | if (iedatalen + 2 > len) | ||
| 1073 | return -EILSEQ; | ||
| 1074 | |||
| 1075 | if (ies[0] != WLAN_EID_VENDOR_SPECIFIC) | ||
| 1076 | goto cont; | ||
| 1077 | |||
| 1078 | if (iedatalen < 4) | ||
| 1079 | goto cont; | ||
| 1080 | |||
| 1081 | iedata = ies + 2; | ||
| 1082 | |||
| 1083 | /* check WFA OUI, P2P subtype */ | ||
| 1084 | if (iedata[0] != 0x50 || iedata[1] != 0x6f || | ||
| 1085 | iedata[2] != 0x9a || iedata[3] != 0x09) | ||
| 1086 | goto cont; | ||
| 1087 | |||
| 1088 | iedatalen -= 4; | ||
| 1089 | iedata += 4; | ||
| 1090 | |||
| 1091 | /* check attribute continuation into this IE */ | ||
| 1092 | copy = min_t(unsigned int, attr_remaining, iedatalen); | ||
| 1093 | if (copy && desired_attr) { | ||
| 1094 | desired_len += copy; | ||
| 1095 | if (out) { | ||
| 1096 | memcpy(out, iedata, min(bufsize, copy)); | ||
| 1097 | out += min(bufsize, copy); | ||
| 1098 | bufsize -= min(bufsize, copy); | ||
| 1099 | } | ||
| 1100 | |||
| 1101 | |||
| 1102 | if (copy == attr_remaining) | ||
| 1103 | return desired_len; | ||
| 1104 | } | ||
| 1105 | |||
| 1106 | attr_remaining -= copy; | ||
| 1107 | if (attr_remaining) | ||
| 1108 | goto cont; | ||
| 1109 | |||
| 1110 | iedatalen -= copy; | ||
| 1111 | iedata += copy; | ||
| 1112 | |||
| 1113 | while (iedatalen > 0) { | ||
| 1114 | u16 attr_len; | ||
| 1115 | |||
| 1116 | /* P2P attribute ID & size must fit */ | ||
| 1117 | if (iedatalen < 3) | ||
| 1118 | return -EILSEQ; | ||
| 1119 | desired_attr = iedata[0] == attr; | ||
| 1120 | attr_len = get_unaligned_le16(iedata + 1); | ||
| 1121 | iedatalen -= 3; | ||
| 1122 | iedata += 3; | ||
| 1123 | |||
| 1124 | copy = min_t(unsigned int, attr_len, iedatalen); | ||
| 1125 | |||
| 1126 | if (desired_attr) { | ||
| 1127 | desired_len += copy; | ||
| 1128 | if (out) { | ||
| 1129 | memcpy(out, iedata, min(bufsize, copy)); | ||
| 1130 | out += min(bufsize, copy); | ||
| 1131 | bufsize -= min(bufsize, copy); | ||
| 1132 | } | ||
| 1133 | |||
| 1134 | if (copy == attr_len) | ||
| 1135 | return desired_len; | ||
| 1136 | } | ||
| 1137 | |||
| 1138 | iedata += copy; | ||
| 1139 | iedatalen -= copy; | ||
| 1140 | attr_remaining = attr_len - copy; | ||
| 1141 | } | ||
| 1142 | |||
| 1143 | cont: | ||
| 1144 | len -= ies[1] + 2; | ||
| 1145 | ies += ies[1] + 2; | ||
| 1146 | } | ||
| 1147 | |||
| 1148 | if (attr_remaining && desired_attr) | ||
| 1149 | return -EILSEQ; | ||
| 1150 | |||
| 1151 | return -ENOENT; | ||
| 1152 | } | ||
| 1153 | EXPORT_SYMBOL(cfg80211_get_p2p_attr); | ||
| 1154 | |||
| 983 | int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, | 1155 | int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, |
| 984 | u32 beacon_int) | 1156 | u32 beacon_int) |
| 985 | { | 1157 | { |
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index 6488d2dbc1d7..f9680c9cf9b3 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c | |||
| @@ -784,6 +784,9 @@ static int cfg80211_wext_siwfreq(struct net_device *dev, | |||
| 784 | { | 784 | { |
| 785 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 785 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
| 786 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | 786 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
| 787 | struct cfg80211_chan_def chandef = { | ||
| 788 | .width = NL80211_CHAN_WIDTH_20_NOHT, | ||
| 789 | }; | ||
| 787 | int freq, err; | 790 | int freq, err; |
| 788 | 791 | ||
| 789 | switch (wdev->iftype) { | 792 | switch (wdev->iftype) { |
| @@ -797,8 +800,12 @@ static int cfg80211_wext_siwfreq(struct net_device *dev, | |||
| 797 | return freq; | 800 | return freq; |
| 798 | if (freq == 0) | 801 | if (freq == 0) |
| 799 | return -EINVAL; | 802 | return -EINVAL; |
| 803 | chandef.center_freq1 = freq; | ||
| 804 | chandef.chan = ieee80211_get_channel(&rdev->wiphy, freq); | ||
| 805 | if (!chandef.chan) | ||
| 806 | return -EINVAL; | ||
| 800 | mutex_lock(&rdev->devlist_mtx); | 807 | mutex_lock(&rdev->devlist_mtx); |
| 801 | err = cfg80211_set_monitor_channel(rdev, freq, NL80211_CHAN_NO_HT); | 808 | err = cfg80211_set_monitor_channel(rdev, &chandef); |
| 802 | mutex_unlock(&rdev->devlist_mtx); | 809 | mutex_unlock(&rdev->devlist_mtx); |
| 803 | return err; | 810 | return err; |
| 804 | case NL80211_IFTYPE_MESH_POINT: | 811 | case NL80211_IFTYPE_MESH_POINT: |
| @@ -807,9 +814,12 @@ static int cfg80211_wext_siwfreq(struct net_device *dev, | |||
| 807 | return freq; | 814 | return freq; |
| 808 | if (freq == 0) | 815 | if (freq == 0) |
| 809 | return -EINVAL; | 816 | return -EINVAL; |
| 817 | chandef.center_freq1 = freq; | ||
| 818 | chandef.chan = ieee80211_get_channel(&rdev->wiphy, freq); | ||
| 819 | if (!chandef.chan) | ||
| 820 | return -EINVAL; | ||
| 810 | mutex_lock(&rdev->devlist_mtx); | 821 | mutex_lock(&rdev->devlist_mtx); |
| 811 | err = cfg80211_set_mesh_freq(rdev, wdev, freq, | 822 | err = cfg80211_set_mesh_channel(rdev, wdev, &chandef); |
| 812 | NL80211_CHAN_NO_HT); | ||
| 813 | mutex_unlock(&rdev->devlist_mtx); | 823 | mutex_unlock(&rdev->devlist_mtx); |
| 814 | return err; | 824 | return err; |
| 815 | default: | 825 | default: |
| @@ -823,8 +833,8 @@ static int cfg80211_wext_giwfreq(struct net_device *dev, | |||
| 823 | { | 833 | { |
| 824 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 834 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
| 825 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | 835 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
| 826 | struct ieee80211_channel *chan; | 836 | struct cfg80211_chan_def chandef; |
| 827 | enum nl80211_channel_type channel_type; | 837 | int ret; |
| 828 | 838 | ||
| 829 | switch (wdev->iftype) { | 839 | switch (wdev->iftype) { |
| 830 | case NL80211_IFTYPE_STATION: | 840 | case NL80211_IFTYPE_STATION: |
| @@ -835,10 +845,10 @@ static int cfg80211_wext_giwfreq(struct net_device *dev, | |||
| 835 | if (!rdev->ops->get_channel) | 845 | if (!rdev->ops->get_channel) |
| 836 | return -EINVAL; | 846 | return -EINVAL; |
| 837 | 847 | ||
| 838 | chan = rdev_get_channel(rdev, wdev, &channel_type); | 848 | ret = rdev_get_channel(rdev, wdev, &chandef); |
| 839 | if (!chan) | 849 | if (ret) |
| 840 | return -EINVAL; | 850 | return ret; |
| 841 | freq->m = chan->center_freq; | 851 | freq->m = chandef.chan->center_freq; |
| 842 | freq->e = 6; | 852 | freq->e = 6; |
| 843 | return 0; | 853 | return 0; |
| 844 | default: | 854 | default: |
| @@ -895,7 +905,7 @@ static int cfg80211_wext_siwtxpower(struct net_device *dev, | |||
| 895 | return 0; | 905 | return 0; |
| 896 | } | 906 | } |
| 897 | 907 | ||
| 898 | return rdev_set_tx_power(rdev, type, DBM_TO_MBM(dbm)); | 908 | return rdev_set_tx_power(rdev, wdev, type, DBM_TO_MBM(dbm)); |
| 899 | } | 909 | } |
| 900 | 910 | ||
| 901 | static int cfg80211_wext_giwtxpower(struct net_device *dev, | 911 | static int cfg80211_wext_giwtxpower(struct net_device *dev, |
| @@ -914,7 +924,7 @@ static int cfg80211_wext_giwtxpower(struct net_device *dev, | |||
| 914 | if (!rdev->ops->get_tx_power) | 924 | if (!rdev->ops->get_tx_power) |
| 915 | return -EOPNOTSUPP; | 925 | return -EOPNOTSUPP; |
| 916 | 926 | ||
| 917 | err = rdev_get_tx_power(rdev, &val); | 927 | err = rdev_get_tx_power(rdev, wdev, &val); |
| 918 | if (err) | 928 | if (err) |
| 919 | return err; | 929 | return err; |
| 920 | 930 | ||
diff --git a/net/wireless/wext-sme.c b/net/wireless/wext-sme.c index 1f773f668d1a..873af63187c0 100644 --- a/net/wireless/wext-sme.c +++ b/net/wireless/wext-sme.c | |||
| @@ -119,7 +119,16 @@ int cfg80211_mgd_wext_siwfreq(struct net_device *dev, | |||
| 119 | * channel we disconnected above and reconnect below. | 119 | * channel we disconnected above and reconnect below. |
| 120 | */ | 120 | */ |
| 121 | if (chan && !wdev->wext.connect.ssid_len) { | 121 | if (chan && !wdev->wext.connect.ssid_len) { |
| 122 | err = cfg80211_set_monitor_channel(rdev, freq, NL80211_CHAN_NO_HT); | 122 | struct cfg80211_chan_def chandef = { |
| 123 | .width = NL80211_CHAN_WIDTH_20_NOHT, | ||
| 124 | .center_freq1 = freq, | ||
| 125 | }; | ||
| 126 | |||
| 127 | chandef.chan = ieee80211_get_channel(&rdev->wiphy, freq); | ||
| 128 | if (chandef.chan) | ||
| 129 | err = cfg80211_set_monitor_channel(rdev, &chandef); | ||
| 130 | else | ||
| 131 | err = -EINVAL; | ||
| 123 | goto out; | 132 | goto out; |
| 124 | } | 133 | } |
| 125 | 134 | ||
