diff options
Diffstat (limited to 'net')
32 files changed, 236 insertions, 117 deletions
diff --git a/net/Kconfig b/net/Kconfig index 2ddc9046868e..6dfe1c636a80 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -5,6 +5,7 @@ menuconfig NET bool "Networking support" select NLATTR + select GENERIC_NET_UTILS ---help--- Unless you really know what you are doing, you should say Y here. The reason is that some programs need kernel networking support even diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index d817c932d634..ace5e55fe5a3 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -341,7 +341,6 @@ static void hci_init1_req(struct hci_request *req, unsigned long opt) static void bredr_setup(struct hci_request *req) { - struct hci_cp_delete_stored_link_key cp; __le16 param; __u8 flt_type; @@ -365,10 +364,6 @@ static void bredr_setup(struct hci_request *req) param = __constant_cpu_to_le16(0x7d00); hci_req_add(req, HCI_OP_WRITE_CA_TIMEOUT, 2, ¶m); - bacpy(&cp.bdaddr, BDADDR_ANY); - cp.delete_all = 0x01; - hci_req_add(req, HCI_OP_DELETE_STORED_LINK_KEY, sizeof(cp), &cp); - /* Read page scan parameters */ if (req->hdev->hci_ver > BLUETOOTH_VER_1_1) { hci_req_add(req, HCI_OP_READ_PAGE_SCAN_ACTIVITY, 0, NULL); @@ -602,6 +597,16 @@ static void hci_init3_req(struct hci_request *req, unsigned long opt) struct hci_dev *hdev = req->hdev; u8 p; + /* Only send HCI_Delete_Stored_Link_Key if it is supported */ + if (hdev->commands[6] & 0x80) { + struct hci_cp_delete_stored_link_key cp; + + bacpy(&cp.bdaddr, BDADDR_ANY); + cp.delete_all = 0x01; + hci_req_add(req, HCI_OP_DELETE_STORED_LINK_KEY, + sizeof(cp), &cp); + } + if (hdev->commands[5] & 0x10) hci_setup_link_policy(req); diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 24bee07ee4ce..68843a28a7af 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -2852,6 +2852,9 @@ static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn, u8 code, BT_DBG("conn %p, code 0x%2.2x, ident 0x%2.2x, len %u", conn, code, ident, dlen); + if (conn->mtu < L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE) + return NULL; + len = L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE + dlen; count = min_t(unsigned int, conn->mtu, len); @@ -4330,7 +4333,7 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) data; u16 type, result; - if (cmd_len != sizeof(*rsp)) + if (cmd_len < sizeof(*rsp)) return -EPROTO; type = __le16_to_cpu(rsp->type); diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c index 81f2389f78eb..d6448e35e027 100644 --- a/net/bridge/br_multicast.c +++ b/net/bridge/br_multicast.c @@ -465,8 +465,9 @@ static struct sk_buff *br_ip6_multicast_alloc_query(struct net_bridge *br, skb_set_transport_header(skb, skb->len); mldq = (struct mld_msg *) icmp6_hdr(skb); - interval = ipv6_addr_any(group) ? br->multicast_last_member_interval : - br->multicast_query_response_interval; + interval = ipv6_addr_any(group) ? + br->multicast_query_response_interval : + br->multicast_last_member_interval; mldq->mld_type = ICMPV6_MGM_QUERY; mldq->mld_code = 0; diff --git a/net/core/dev.c b/net/core/dev.c index fc1e289397f5..faebb398fb46 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -792,6 +792,40 @@ struct net_device *dev_get_by_index(struct net *net, int ifindex) EXPORT_SYMBOL(dev_get_by_index); /** + * netdev_get_name - get a netdevice name, knowing its ifindex. + * @net: network namespace + * @name: a pointer to the buffer where the name will be stored. + * @ifindex: the ifindex of the interface to get the name from. + * + * The use of raw_seqcount_begin() and cond_resched() before + * retrying is required as we want to give the writers a chance + * to complete when CONFIG_PREEMPT is not set. + */ +int netdev_get_name(struct net *net, char *name, int ifindex) +{ + struct net_device *dev; + unsigned int seq; + +retry: + seq = raw_seqcount_begin(&devnet_rename_seq); + rcu_read_lock(); + dev = dev_get_by_index_rcu(net, ifindex); + if (!dev) { + rcu_read_unlock(); + return -ENODEV; + } + + strcpy(name, dev->name); + rcu_read_unlock(); + if (read_seqcount_retry(&devnet_rename_seq, seq)) { + cond_resched(); + goto retry; + } + + return 0; +} + +/** * dev_getbyhwaddr_rcu - find a device by its hardware address * @net: the applicable net namespace * @type: media type of device diff --git a/net/core/dev_ioctl.c b/net/core/dev_ioctl.c index 6cc0481faade..5b7d0e1d0664 100644 --- a/net/core/dev_ioctl.c +++ b/net/core/dev_ioctl.c @@ -19,9 +19,8 @@ static int dev_ifname(struct net *net, struct ifreq __user *arg) { - struct net_device *dev; struct ifreq ifr; - unsigned seq; + int error; /* * Fetch the caller's info block. @@ -30,19 +29,9 @@ static int dev_ifname(struct net *net, struct ifreq __user *arg) if (copy_from_user(&ifr, arg, sizeof(struct ifreq))) return -EFAULT; -retry: - seq = read_seqcount_begin(&devnet_rename_seq); - rcu_read_lock(); - dev = dev_get_by_index_rcu(net, ifr.ifr_ifindex); - if (!dev) { - rcu_read_unlock(); - return -ENODEV; - } - - strcpy(ifr.ifr_name, dev->name); - rcu_read_unlock(); - if (read_seqcount_retry(&devnet_rename_seq, seq)) - goto retry; + error = netdev_get_name(net, ifr.ifr_name, ifr.ifr_ifindex); + if (error) + return error; if (copy_to_user(arg, &ifr, sizeof(struct ifreq))) return -EFAULT; diff --git a/net/core/ethtool.c b/net/core/ethtool.c index 22efdaa76ebf..ce91766eeca9 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -60,10 +60,10 @@ static const char netdev_features_strings[NETDEV_FEATURE_COUNT][ETH_GSTRING_LEN] [NETIF_F_IPV6_CSUM_BIT] = "tx-checksum-ipv6", [NETIF_F_HIGHDMA_BIT] = "highdma", [NETIF_F_FRAGLIST_BIT] = "tx-scatter-gather-fraglist", - [NETIF_F_HW_VLAN_CTAG_TX_BIT] = "tx-vlan-ctag-hw-insert", + [NETIF_F_HW_VLAN_CTAG_TX_BIT] = "tx-vlan-hw-insert", - [NETIF_F_HW_VLAN_CTAG_RX_BIT] = "rx-vlan-ctag-hw-parse", - [NETIF_F_HW_VLAN_CTAG_FILTER_BIT] = "rx-vlan-ctag-filter", + [NETIF_F_HW_VLAN_CTAG_RX_BIT] = "rx-vlan-hw-parse", + [NETIF_F_HW_VLAN_CTAG_FILTER_BIT] = "rx-vlan-filter", [NETIF_F_HW_VLAN_STAG_TX_BIT] = "tx-vlan-stag-hw-insert", [NETIF_F_HW_VLAN_STAG_RX_BIT] = "rx-vlan-stag-hw-parse", [NETIF_F_HW_VLAN_STAG_FILTER_BIT] = "rx-vlan-stag-filter", diff --git a/net/core/netpoll.c b/net/core/netpoll.c index cec074be8c43..35a9f0804b6f 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c @@ -12,6 +12,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/moduleparam.h> +#include <linux/kernel.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/string.h> diff --git a/net/core/skbuff.c b/net/core/skbuff.c index cfd777bd6bd0..1c1738cc4538 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -483,15 +483,8 @@ EXPORT_SYMBOL(skb_add_rx_frag); static void skb_drop_list(struct sk_buff **listp) { - struct sk_buff *list = *listp; - + kfree_skb_list(*listp); *listp = NULL; - - do { - struct sk_buff *this = list; - list = list->next; - kfree_skb(this); - } while (list); } static inline void skb_drop_fraglist(struct sk_buff *skb) @@ -651,6 +644,17 @@ void kfree_skb(struct sk_buff *skb) } EXPORT_SYMBOL(kfree_skb); +void kfree_skb_list(struct sk_buff *segs) +{ + while (segs) { + struct sk_buff *next = segs->next; + + kfree_skb(segs); + segs = next; + } +} +EXPORT_SYMBOL(kfree_skb_list); + /** * skb_tx_error - report an sk_buff xmit error * @skb: buffer that triggered an error diff --git a/net/core/sock.c b/net/core/sock.c index 88868a9d21da..d6d024cfaaaf 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -571,9 +571,7 @@ static int sock_getbindtodevice(struct sock *sk, char __user *optval, int ret = -ENOPROTOOPT; #ifdef CONFIG_NETDEVICES struct net *net = sock_net(sk); - struct net_device *dev; char devname[IFNAMSIZ]; - unsigned seq; if (sk->sk_bound_dev_if == 0) { len = 0; @@ -584,20 +582,9 @@ static int sock_getbindtodevice(struct sock *sk, char __user *optval, if (len < IFNAMSIZ) goto out; -retry: - seq = read_seqcount_begin(&devnet_rename_seq); - rcu_read_lock(); - dev = dev_get_by_index_rcu(net, sk->sk_bound_dev_if); - ret = -ENODEV; - if (!dev) { - rcu_read_unlock(); + ret = netdev_get_name(net, devname, sk->sk_bound_dev_if); + if (ret) goto out; - } - - strcpy(devname, dev->name); - rcu_read_unlock(); - if (read_seqcount_retry(&devnet_rename_seq, seq)) - goto retry; len = strlen(devname) + 1; diff --git a/net/core/utils.c b/net/core/utils.c index 3c7f5b51b979..aa88e23fc87a 100644 --- a/net/core/utils.c +++ b/net/core/utils.c @@ -338,25 +338,3 @@ void inet_proto_csum_replace16(__sum16 *sum, struct sk_buff *skb, csum_unfold(*sum))); } EXPORT_SYMBOL(inet_proto_csum_replace16); - -int mac_pton(const char *s, u8 *mac) -{ - int i; - - /* XX:XX:XX:XX:XX:XX */ - if (strlen(s) < 3 * ETH_ALEN - 1) - return 0; - - /* Don't dirty result unless string is valid MAC. */ - for (i = 0; i < ETH_ALEN; i++) { - if (!isxdigit(s[i * 3]) || !isxdigit(s[i * 3 + 1])) - return 0; - if (i != ETH_ALEN - 1 && s[i * 3 + 2] != ':') - return 0; - } - for (i = 0; i < ETH_ALEN; i++) { - mac[i] = (hex_to_bin(s[i * 3]) << 4) | hex_to_bin(s[i * 3 + 1]); - } - return 1; -} -EXPORT_SYMBOL(mac_pton); diff --git a/net/ipv4/gre.c b/net/ipv4/gre.c index b2e805af9b87..7856d1651d05 100644 --- a/net/ipv4/gre.c +++ b/net/ipv4/gre.c @@ -178,7 +178,7 @@ static struct sk_buff *gre_gso_segment(struct sk_buff *skb, err = __skb_linearize(skb); if (err) { - kfree_skb(segs); + kfree_skb_list(segs); segs = ERR_PTR(err); goto out; } diff --git a/net/ipv4/netfilter/ipt_ULOG.c b/net/ipv4/netfilter/ipt_ULOG.c index ff4b781b1056..32b0e978c8e0 100644 --- a/net/ipv4/netfilter/ipt_ULOG.c +++ b/net/ipv4/netfilter/ipt_ULOG.c @@ -125,15 +125,16 @@ static void ulog_send(struct ulog_net *ulog, unsigned int nlgroupnum) /* timer function to flush queue in flushtimeout time */ static void ulog_timer(unsigned long data) { + unsigned int groupnum = *((unsigned int *)data); struct ulog_net *ulog = container_of((void *)data, struct ulog_net, - nlgroup[*(unsigned int *)data]); + nlgroup[groupnum]); pr_debug("timer function called, calling ulog_send\n"); /* lock to protect against somebody modifying our structure * from ipt_ulog_target at the same time */ spin_lock_bh(&ulog->lock); - ulog_send(ulog, data); + ulog_send(ulog, groupnum); spin_unlock_bh(&ulog->lock); } @@ -407,8 +408,11 @@ static int __net_init ulog_tg_net_init(struct net *net) spin_lock_init(&ulog->lock); /* initialize ulog_buffers */ - for (i = 0; i < ULOG_MAXNLGROUPS; i++) - setup_timer(&ulog->ulog_buffers[i].timer, ulog_timer, i); + for (i = 0; i < ULOG_MAXNLGROUPS; i++) { + ulog->nlgroup[i] = i; + setup_timer(&ulog->ulog_buffers[i].timer, ulog_timer, + (unsigned long)&ulog->nlgroup[i]); + } ulog->nflognl = netlink_kernel_create(net, NETLINK_NFLOG, &cfg); if (!ulog->nflognl) diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 719652305a29..7999fc55c83b 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1003,7 +1003,7 @@ int tcp_md5_do_add(struct sock *sk, const union tcp_md5_addr *addr, struct tcp_sock *tp = tcp_sk(sk); struct tcp_md5sig_info *md5sig; - key = tcp_md5_do_lookup(sk, (union tcp_md5_addr *)&addr, AF_INET); + key = tcp_md5_do_lookup(sk, addr, family); if (key) { /* Pre-existing entry - just update that one. */ memcpy(key->key, newkey, newkeylen); @@ -1048,7 +1048,7 @@ int tcp_md5_do_del(struct sock *sk, const union tcp_md5_addr *addr, int family) struct tcp_md5sig_key *key; struct tcp_md5sig_info *md5sig; - key = tcp_md5_do_lookup(sk, (union tcp_md5_addr *)&addr, AF_INET); + key = tcp_md5_do_lookup(sk, addr, family); if (!key) return -ENOENT; hlist_del_rcu(&key->node); diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 1bbf744c2cc3..4ab4c38958c6 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -2655,6 +2655,9 @@ static void init_loopback(struct net_device *dev) if (sp_ifa->flags & (IFA_F_DADFAILED | IFA_F_TENTATIVE)) continue; + if (sp_ifa->rt) + continue; + sp_rt = addrconf_dst_alloc(idev, &sp_ifa->addr, 0); /* Failure cases are ignored */ @@ -4303,6 +4306,7 @@ static int inet6_set_iftoken(struct inet6_dev *idev, struct in6_addr *token) struct inet6_ifaddr *ifp; struct net_device *dev = idev->dev; bool update_rs = false; + struct in6_addr ll_addr; if (token == NULL) return -EINVAL; @@ -4322,11 +4326,9 @@ static int inet6_set_iftoken(struct inet6_dev *idev, struct in6_addr *token) write_unlock_bh(&idev->lock); - if (!idev->dead && (idev->if_flags & IF_READY)) { - struct in6_addr ll_addr; - - ipv6_get_lladdr(dev, &ll_addr, IFA_F_TENTATIVE | - IFA_F_OPTIMISTIC); + if (!idev->dead && (idev->if_flags & IF_READY) && + !ipv6_get_lladdr(dev, &ll_addr, IFA_F_TENTATIVE | + IFA_F_OPTIMISTIC)) { /* If we're not ready, then normal ifup will take care * of this. Otherwise, we need to request our rs here. diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index dae1949019d7..d5d20cde8d92 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -381,9 +381,8 @@ int ip6_forward(struct sk_buff *skb) * cannot be fragmented, because there is no warranty * that different fragments will go along one path. --ANK */ - if (opt->ra) { - u8 *ptr = skb_network_header(skb) + opt->ra; - if (ip6_call_ra_chain(skb, (ptr[2]<<8) + ptr[3])) + if (unlikely(opt->flags & IP6SKB_ROUTERALERT)) { + if (ip6_call_ra_chain(skb, ntohs(opt->ra))) return 0; } @@ -822,11 +821,17 @@ static struct dst_entry *ip6_sk_dst_check(struct sock *sk, const struct flowi6 *fl6) { struct ipv6_pinfo *np = inet6_sk(sk); - struct rt6_info *rt = (struct rt6_info *)dst; + struct rt6_info *rt; if (!dst) goto out; + if (dst->ops->family != AF_INET6) { + dst_release(dst); + return NULL; + } + + rt = (struct rt6_info *)dst; /* Yes, checking route validity in not connected * case is not very simple. Take into account, * that we do not support routing by source, TOS, diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 2712ab22a174..ca4ffcc287f1 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -1493,7 +1493,7 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target) */ if (ha) - ndisc_fill_addr_option(skb, ND_OPT_TARGET_LL_ADDR, ha); + ndisc_fill_addr_option(buff, ND_OPT_TARGET_LL_ADDR, ha); /* * build redirect option and copy skb over to the new packet. diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c index 97bcf2bae857..c9b6a6e6a1e8 100644 --- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c +++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c @@ -204,7 +204,7 @@ static unsigned int __ipv6_conntrack_in(struct net *net, if (ct != NULL && !nf_ct_is_untracked(ct)) { help = nfct_help(ct); if ((help && help->helper) || !nf_ct_is_confirmed(ct)) { - nf_conntrack_get_reasm(skb); + nf_conntrack_get_reasm(reasm); NF_HOOK_THRESH(NFPROTO_IPV6, hooknum, reasm, (struct net_device *)in, (struct net_device *)out, diff --git a/net/key/af_key.c b/net/key/af_key.c index c5fbd7589681..9da862070dd8 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -1710,6 +1710,7 @@ static int key_notify_sa_flush(const struct km_event *c) hdr->sadb_msg_version = PF_KEY_V2; hdr->sadb_msg_errno = (uint8_t) 0; hdr->sadb_msg_len = (sizeof(struct sadb_msg) / sizeof(uint64_t)); + hdr->sadb_msg_reserved = 0; pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_ALL, NULL, c->net); @@ -2699,6 +2700,7 @@ static int key_notify_policy_flush(const struct km_event *c) hdr->sadb_msg_errno = (uint8_t) 0; hdr->sadb_msg_satype = SADB_SATYPE_UNSPEC; hdr->sadb_msg_len = (sizeof(struct sadb_msg) / sizeof(uint64_t)); + hdr->sadb_msg_reserved = 0; pfkey_broadcast(skb_out, GFP_ATOMIC, BROADCAST_ALL, NULL, c->net); return 0; diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 1a89c80e6407..4fdb306e42e0 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1057,6 +1057,12 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state); ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED); + if (sdata->wdev.cac_started) { + cancel_delayed_work_sync(&sdata->dfs_cac_timer_work); + cfg80211_cac_event(sdata->dev, NL80211_RADAR_CAC_ABORTED, + GFP_KERNEL); + } + drv_stop_ap(sdata->local, sdata); /* free all potentially still buffered bcast frames */ diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 44be28cfc6c4..9ca8e3278cc0 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1497,10 +1497,11 @@ static inline void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, ieee80211_tx_skb_tid(sdata, skb, 7); } -u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, bool action, +u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action, struct ieee802_11_elems *elems, u64 filter, u32 crc); -static inline void ieee802_11_parse_elems(u8 *start, size_t len, bool action, +static inline void ieee802_11_parse_elems(const u8 *start, size_t len, + bool action, struct ieee802_11_elems *elems) { ieee802_11_parse_elems_crc(start, len, action, elems, 0, 0); diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index a8c2130c8ba4..741448b30825 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2522,8 +2522,11 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, u16 capab_info, aid; struct ieee802_11_elems elems; struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; + const struct cfg80211_bss_ies *bss_ies = NULL; + struct ieee80211_mgd_assoc_data *assoc_data = ifmgd->assoc_data; u32 changed = 0; int err; + bool ret; /* AssocResp and ReassocResp have identical structure */ @@ -2555,21 +2558,86 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, ifmgd->aid = aid; /* + * Some APs are erroneously not including some information in their + * (re)association response frames. Try to recover by using the data + * from the beacon or probe response. This seems to afflict mobile + * 2G/3G/4G wifi routers, reported models include the "Onda PN51T", + * "Vodafone PocketWiFi 2", "ZTE MF60" and a similar T-Mobile device. + */ + if ((assoc_data->wmm && !elems.wmm_param) || + (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT) && + (!elems.ht_cap_elem || !elems.ht_operation)) || + (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT) && + (!elems.vht_cap_elem || !elems.vht_operation))) { + const struct cfg80211_bss_ies *ies; + struct ieee802_11_elems bss_elems; + + rcu_read_lock(); + ies = rcu_dereference(cbss->ies); + if (ies) + bss_ies = kmemdup(ies, sizeof(*ies) + ies->len, + GFP_ATOMIC); + rcu_read_unlock(); + if (!bss_ies) + return false; + + ieee802_11_parse_elems(bss_ies->data, bss_ies->len, + false, &bss_elems); + if (assoc_data->wmm && + !elems.wmm_param && bss_elems.wmm_param) { + elems.wmm_param = bss_elems.wmm_param; + sdata_info(sdata, + "AP bug: WMM param missing from AssocResp\n"); + } + + /* + * Also check if we requested HT/VHT, otherwise the AP doesn't + * have to include the IEs in the (re)association response. + */ + if (!elems.ht_cap_elem && bss_elems.ht_cap_elem && + !(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) { + elems.ht_cap_elem = bss_elems.ht_cap_elem; + sdata_info(sdata, + "AP bug: HT capability missing from AssocResp\n"); + } + if (!elems.ht_operation && bss_elems.ht_operation && + !(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) { + elems.ht_operation = bss_elems.ht_operation; + sdata_info(sdata, + "AP bug: HT operation missing from AssocResp\n"); + } + if (!elems.vht_cap_elem && bss_elems.vht_cap_elem && + !(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) { + elems.vht_cap_elem = bss_elems.vht_cap_elem; + sdata_info(sdata, + "AP bug: VHT capa missing from AssocResp\n"); + } + if (!elems.vht_operation && bss_elems.vht_operation && + !(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) { + elems.vht_operation = bss_elems.vht_operation; + sdata_info(sdata, + "AP bug: VHT operation missing from AssocResp\n"); + } + } + + /* * We previously checked these in the beacon/probe response, so * they should be present here. This is just a safety net. */ if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT) && (!elems.wmm_param || !elems.ht_cap_elem || !elems.ht_operation)) { sdata_info(sdata, - "HT AP is missing WMM params or HT capability/operation in AssocResp\n"); - return false; + "HT AP is missing WMM params or HT capability/operation\n"); + ret = false; + goto out; } if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT) && (!elems.vht_cap_elem || !elems.vht_operation)) { sdata_info(sdata, - "VHT AP is missing VHT capability/operation in AssocResp\n"); - return false; + "VHT AP is missing VHT capability/operation\n"); + ret = false; + goto out; } mutex_lock(&sdata->local->sta_mtx); @@ -2580,7 +2648,8 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, sta = sta_info_get(sdata, cbss->bssid); if (WARN_ON(!sta)) { mutex_unlock(&sdata->local->sta_mtx); - return false; + ret = false; + goto out; } sband = local->hw.wiphy->bands[ieee80211_get_sdata_band(sdata)]; @@ -2633,7 +2702,8 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, sta->sta.addr); WARN_ON(__sta_info_destroy(sta)); mutex_unlock(&sdata->local->sta_mtx); - return false; + ret = false; + goto out; } mutex_unlock(&sdata->local->sta_mtx); @@ -2673,7 +2743,10 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, ieee80211_sta_rx_notify(sdata, (struct ieee80211_hdr *)mgmt); ieee80211_sta_reset_beacon_monitor(sdata); - return true; + ret = true; + out: + kfree(bss_ies); + return ret; } static enum rx_mgmt_action __must_check diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c index d3f414fe67e0..a02bef35b134 100644 --- a/net/mac80211/rate.c +++ b/net/mac80211/rate.c @@ -615,7 +615,7 @@ static void rate_control_apply_mask(struct ieee80211_sub_if_data *sdata, if (rates[i].idx < 0) break; - rate_idx_match_mask(&rates[i], sband, mask, chan_width, + rate_idx_match_mask(&rates[i], sband, chan_width, mask, mcs_mask); } } diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 27e07150eb46..72e6292955bb 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -661,12 +661,12 @@ void ieee80211_queue_delayed_work(struct ieee80211_hw *hw, } EXPORT_SYMBOL(ieee80211_queue_delayed_work); -u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, bool action, +u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action, struct ieee802_11_elems *elems, u64 filter, u32 crc) { size_t left = len; - u8 *pos = start; + const u8 *pos = start; bool calc_crc = filter != 0; DECLARE_BITMAP(seen_elems, 256); const u8 *ie; diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c index 05565d2b3a61..23b8eb53a569 100644 --- a/net/netfilter/ipvs/ip_vs_core.c +++ b/net/netfilter/ipvs/ip_vs_core.c @@ -1442,7 +1442,8 @@ ignore_ipip: /* do the statistics and put it back */ ip_vs_in_stats(cp, skb); - if (IPPROTO_TCP == cih->protocol || IPPROTO_UDP == cih->protocol) + if (IPPROTO_TCP == cih->protocol || IPPROTO_UDP == cih->protocol || + IPPROTO_SCTP == cih->protocol) offset += 2 * sizeof(__u16); verdict = ip_vs_icmp_xmit(skb, cp, pp, offset, hooknum, &ciph); diff --git a/net/netfilter/nf_conntrack_labels.c b/net/netfilter/nf_conntrack_labels.c index 8fe2e99428b7..355d2ef08094 100644 --- a/net/netfilter/nf_conntrack_labels.c +++ b/net/netfilter/nf_conntrack_labels.c @@ -45,7 +45,7 @@ int nf_connlabel_set(struct nf_conn *ct, u16 bit) if (test_bit(bit, labels->bits)) return 0; - if (test_and_set_bit(bit, labels->bits)) + if (!test_and_set_bit(bit, labels->bits)) nf_conntrack_event_cache(IPCT_LABEL, ct); return 0; diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 6d0f8a17c5b7..ecf065f94032 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -1825,6 +1825,7 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb, nf_conntrack_eventmask_report((1 << IPCT_REPLY) | (1 << IPCT_ASSURED) | (1 << IPCT_HELPER) | + (1 << IPCT_LABEL) | (1 << IPCT_PROTOINFO) | (1 << IPCT_NATSEQADJ) | (1 << IPCT_MARK), diff --git a/net/netfilter/nf_nat_sip.c b/net/netfilter/nf_nat_sip.c index 96ccdf78a29f..dac11f73868e 100644 --- a/net/netfilter/nf_nat_sip.c +++ b/net/netfilter/nf_nat_sip.c @@ -230,9 +230,10 @@ static unsigned int nf_nat_sip(struct sk_buff *skb, unsigned int protoff, &ct->tuplehash[!dir].tuple.src.u3, false); if (!mangle_packet(skb, protoff, dataoff, dptr, datalen, - poff, plen, buffer, buflen)) + poff, plen, buffer, buflen)) { nf_ct_helper_log(skb, ct, "cannot mangle received"); return NF_DROP; + } } /* The rport= parameter (RFC 3581) contains the port number diff --git a/net/netfilter/xt_TCPMSS.c b/net/netfilter/xt_TCPMSS.c index afaebc766933..7011c71646f0 100644 --- a/net/netfilter/xt_TCPMSS.c +++ b/net/netfilter/xt_TCPMSS.c @@ -45,17 +45,22 @@ optlen(const u_int8_t *opt, unsigned int offset) static int tcpmss_mangle_packet(struct sk_buff *skb, - const struct xt_tcpmss_info *info, + const struct xt_action_param *par, unsigned int in_mtu, unsigned int tcphoff, unsigned int minlen) { + const struct xt_tcpmss_info *info = par->targinfo; struct tcphdr *tcph; unsigned int tcplen, i; __be16 oldval; u16 newmss; u8 *opt; + /* This is a fragment, no TCP header is available */ + if (par->fragoff != 0) + return XT_CONTINUE; + if (!skb_make_writable(skb, skb->len)) return -1; @@ -125,11 +130,17 @@ tcpmss_mangle_packet(struct sk_buff *skb, skb_put(skb, TCPOLEN_MSS); - /* RFC 879 states that the default MSS is 536 without specific - * knowledge that the destination host is prepared to accept larger. - * Since no MSS was provided, we MUST NOT set a value > 536. + /* + * IPv4: RFC 1122 states "If an MSS option is not received at + * connection setup, TCP MUST assume a default send MSS of 536". + * IPv6: RFC 2460 states IPv6 has a minimum MTU of 1280 and a minimum + * length IPv6 header of 60, ergo the default MSS value is 1220 + * Since no MSS was provided, we must use the default values */ - newmss = min(newmss, (u16)536); + if (par->family == NFPROTO_IPV4) + newmss = min(newmss, (u16)536); + else + newmss = min(newmss, (u16)1220); opt = (u_int8_t *)tcph + sizeof(struct tcphdr); memmove(opt + TCPOLEN_MSS, opt, tcplen - sizeof(struct tcphdr)); @@ -188,7 +199,7 @@ tcpmss_tg4(struct sk_buff *skb, const struct xt_action_param *par) __be16 newlen; int ret; - ret = tcpmss_mangle_packet(skb, par->targinfo, + ret = tcpmss_mangle_packet(skb, par, tcpmss_reverse_mtu(skb, PF_INET), iph->ihl * 4, sizeof(*iph) + sizeof(struct tcphdr)); @@ -217,7 +228,7 @@ tcpmss_tg6(struct sk_buff *skb, const struct xt_action_param *par) tcphoff = ipv6_skip_exthdr(skb, sizeof(*ipv6h), &nexthdr, &frag_off); if (tcphoff < 0) return NF_DROP; - ret = tcpmss_mangle_packet(skb, par->targinfo, + ret = tcpmss_mangle_packet(skb, par, tcpmss_reverse_mtu(skb, PF_INET6), tcphoff, sizeof(*ipv6h) + sizeof(struct tcphdr)); diff --git a/net/netfilter/xt_TCPOPTSTRIP.c b/net/netfilter/xt_TCPOPTSTRIP.c index 1eb1a44bfd3d..b68fa191710f 100644 --- a/net/netfilter/xt_TCPOPTSTRIP.c +++ b/net/netfilter/xt_TCPOPTSTRIP.c @@ -48,11 +48,13 @@ tcpoptstrip_mangle_packet(struct sk_buff *skb, return NF_DROP; len = skb->len - tcphoff; - if (len < (int)sizeof(struct tcphdr) || - tcp_hdr(skb)->doff * 4 > len) + if (len < (int)sizeof(struct tcphdr)) return NF_DROP; tcph = (struct tcphdr *)(skb_network_header(skb) + tcphoff); + if (tcph->doff * 4 > len) + return NF_DROP; + opt = (u_int8_t *)tcph; /* diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c index 29b4ba93ab3c..b05ace4c5f12 100644 --- a/net/sunrpc/auth_gss/svcauth_gss.c +++ b/net/sunrpc/auth_gss/svcauth_gss.c @@ -1330,7 +1330,7 @@ static int wait_for_gss_proxy(struct net *net, struct file *file) static ssize_t write_gssp(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { - struct net *net = PDE_DATA(file->f_path.dentry->d_inode); + struct net *net = PDE_DATA(file_inode(file)); char tbuf[20]; unsigned long i; int res; @@ -1358,7 +1358,7 @@ static ssize_t write_gssp(struct file *file, const char __user *buf, static ssize_t read_gssp(struct file *file, char __user *buf, size_t count, loff_t *ppos) { - struct net *net = PDE_DATA(file->f_path.dentry->d_inode); + struct net *net = PDE_DATA(file_inode(file)); unsigned long p = *ppos; char tbuf[10]; size_t len; diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index d5aed3bb3945..b14b7e3cb6e6 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -1564,12 +1564,17 @@ static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb) struct cfg80211_registered_device *dev; s64 filter_wiphy = -1; bool split = false; - struct nlattr **tb = nl80211_fam.attrbuf; + struct nlattr **tb; int res; + /* will be zeroed in nlmsg_parse() */ + tb = kmalloc(sizeof(*tb) * (NL80211_ATTR_MAX + 1), GFP_KERNEL); + if (!tb) + return -ENOMEM; + mutex_lock(&cfg80211_mutex); res = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize, - tb, nl80211_fam.maxattr, nl80211_policy); + tb, NL80211_ATTR_MAX, nl80211_policy); if (res == 0) { split = tb[NL80211_ATTR_SPLIT_WIPHY_DUMP]; if (tb[NL80211_ATTR_WIPHY]) @@ -1583,6 +1588,7 @@ static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb) netdev = dev_get_by_index(sock_net(skb->sk), ifidx); if (!netdev) { mutex_unlock(&cfg80211_mutex); + kfree(tb); return -ENODEV; } if (netdev->ieee80211_ptr) { @@ -1593,6 +1599,7 @@ static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb) dev_put(netdev); } } + kfree(tb); list_for_each_entry(dev, &cfg80211_rdev_list, list) { if (!net_eq(wiphy_net(&dev->wiphy), sock_net(skb->sk))) |