2 changes: 1 addition & 1 deletion include/linux/if_vlan.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ struct vlan_hdr {
* struct vlan_ethhdr - vlan ethernet header (ethhdr + vlan_hdr)
* @h_dest: destination ethernet address
* @h_source: source ethernet address
* @h_vlan_proto: ethernet protocol (always 0x8100)
* @h_vlan_proto: ethernet protocol
* @h_vlan_TCI: priority and VLAN ID
* @h_vlan_encapsulated_proto: packet type ID or len
*/
Expand Down
1 change: 1 addition & 0 deletions include/linux/netdevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -1695,6 +1695,7 @@ extern int init_dummy_netdev(struct net_device *dev);
extern struct net_device *dev_get_by_index(struct net *net, int ifindex);
extern struct net_device *__dev_get_by_index(struct net *net, int ifindex);
extern struct net_device *dev_get_by_index_rcu(struct net *net, int ifindex);
extern int netdev_get_name(struct net *net, char *name, int ifindex);
extern int dev_restart(struct net_device *dev);
#ifdef CONFIG_NETPOLL_TRAP
extern int netpoll_trap(void);
Expand Down
1 change: 1 addition & 0 deletions include/linux/skbuff.h
Original file line number Diff line number Diff line change
Expand Up @@ -627,6 +627,7 @@ static inline struct rtable *skb_rtable(const struct sk_buff *skb)
}

extern void kfree_skb(struct sk_buff *skb);
extern void kfree_skb_list(struct sk_buff *segs);
extern void skb_tx_error(struct sk_buff *skb);
extern void consume_skb(struct sk_buff *skb);
extern void __kfree_skb(struct sk_buff *skb);
Expand Down
1 change: 1 addition & 0 deletions include/uapi/linux/Kbuild
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,7 @@ header-y += net_dropmon.h
header-y += net_tstamp.h
header-y += netconf.h
header-y += netdevice.h
header-y += netlink_diag.h
header-y += netfilter.h
header-y += netfilter_arp.h
header-y += netfilter_bridge.h
Expand Down
6 changes: 3 additions & 3 deletions kernel/events/hw_breakpoint.c
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ static int task_bp_pinned(int cpu, struct perf_event *bp, enum bp_type_idx type)
list_for_each_entry(iter, &bp_task_head, hw.bp_list) {
if (iter->hw.bp_target == tsk &&
find_slot_idx(iter) == type &&
cpu == iter->cpu)
(iter->cpu < 0 || cpu == iter->cpu))
count += hw_breakpoint_weight(iter);
}

Expand Down Expand Up @@ -149,7 +149,7 @@ fetch_bp_busy_slots(struct bp_busy_slots *slots, struct perf_event *bp,
return;
}

for_each_online_cpu(cpu) {
for_each_possible_cpu(cpu) {
unsigned int nr;

nr = per_cpu(nr_cpu_bp_pinned[type], cpu);
Expand Down Expand Up @@ -235,7 +235,7 @@ toggle_bp_slot(struct perf_event *bp, bool enable, enum bp_type_idx type,
if (cpu >= 0) {
toggle_bp_task_slot(bp, cpu, enable, type, weight);
} else {
for_each_online_cpu(cpu)
for_each_possible_cpu(cpu)
toggle_bp_task_slot(bp, cpu, enable, type, weight);
}

Expand Down
20 changes: 11 additions & 9 deletions kernel/ptrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -665,20 +665,22 @@ static int ptrace_peek_siginfo(struct task_struct *child,
if (unlikely(is_compat_task())) {
compat_siginfo_t __user *uinfo = compat_ptr(data);

ret = copy_siginfo_to_user32(uinfo, &info);
ret |= __put_user(info.si_code, &uinfo->si_code);
if (copy_siginfo_to_user32(uinfo, &info) ||
__put_user(info.si_code, &uinfo->si_code)) {
ret = -EFAULT;
break;
}

} else
#endif
{
siginfo_t __user *uinfo = (siginfo_t __user *) data;

ret = copy_siginfo_to_user(uinfo, &info);
ret |= __put_user(info.si_code, &uinfo->si_code);
}

if (ret) {
ret = -EFAULT;
break;
if (copy_siginfo_to_user(uinfo, &info) ||
__put_user(info.si_code, &uinfo->si_code)) {
ret = -EFAULT;
break;
}
}

data += sizeof(siginfo_t);
Expand Down
7 changes: 5 additions & 2 deletions kernel/time/tick-broadcast.c
Original file line number Diff line number Diff line change
Expand Up @@ -599,8 +599,6 @@ void tick_broadcast_oneshot_control(unsigned long reason)
} else {
if (cpumask_test_and_clear_cpu(cpu, tick_broadcast_oneshot_mask)) {
clockevents_set_mode(dev, CLOCK_EVT_MODE_ONESHOT);
if (dev->next_event.tv64 == KTIME_MAX)
goto out;
/*
* The cpu which was handling the broadcast
* timer marked this cpu in the broadcast
Expand All @@ -614,6 +612,11 @@ void tick_broadcast_oneshot_control(unsigned long reason)
tick_broadcast_pending_mask))
goto out;

/*
* Bail out if there is no next event.
*/
if (dev->next_event.tv64 == KTIME_MAX)
goto out;
/*
* If the pending bit is not set, then we are
* either the CPU handling the broadcast
Expand Down
15 changes: 10 additions & 5 deletions net/bluetooth/hci_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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, &param);

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);
Expand Down Expand Up @@ -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);

Expand Down
5 changes: 4 additions & 1 deletion net/bluetooth/l2cap_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -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);
Expand Down
5 changes: 3 additions & 2 deletions net/bridge/br_multicast.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
34 changes: 34 additions & 0 deletions net/core/dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -791,6 +791,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
Expand Down
19 changes: 4 additions & 15 deletions net/core/dev_ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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;
Expand Down
6 changes: 3 additions & 3 deletions net/core/ethtool.c
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
20 changes: 12 additions & 8 deletions net/core/skbuff.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand Down
17 changes: 2 additions & 15 deletions net/core/sock.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;

Expand Down
2 changes: 1 addition & 1 deletion net/ipv4/gre.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
12 changes: 8 additions & 4 deletions net/ipv4/netfilter/ipt_ULOG.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down Expand Up @@ -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)
Expand Down
4 changes: 2 additions & 2 deletions net/ipv4/tcp_ipv4.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
12 changes: 7 additions & 5 deletions net/ipv6/addrconf.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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;
Expand All @@ -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.
Expand Down
13 changes: 9 additions & 4 deletions net/ipv6/ip6_output.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion net/ipv6/ndisc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
2 changes: 1 addition & 1 deletion net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 2 additions & 0 deletions net/key/af_key.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -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;

Expand Down
6 changes: 6 additions & 0 deletions net/mac80211/cfg.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
5 changes: 3 additions & 2 deletions net/mac80211/ieee80211_i.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
87 changes: 80 additions & 7 deletions net/mac80211/mlme.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */

Expand Down Expand Up @@ -2554,22 +2557,87 @@ 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);
Expand All @@ -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)];
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion net/mac80211/rate.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
Expand Down
4 changes: 2 additions & 2 deletions net/mac80211/util.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
3 changes: 2 additions & 1 deletion net/netfilter/ipvs/ip_vs_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -1442,7 +1442,8 @@ ip_vs_in_icmp(struct sk_buff *skb, int *related, unsigned int hooknum)

/* 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);

Expand Down
2 changes: 1 addition & 1 deletion net/netfilter/nf_conntrack_labels.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions net/netfilter/nf_conntrack_netlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down
3 changes: 2 additions & 1 deletion net/netfilter/nf_nat_sip.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
25 changes: 18 additions & 7 deletions net/netfilter/xt_TCPMSS.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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));
Expand Down Expand Up @@ -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));
Expand Down Expand Up @@ -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));
Expand Down
6 changes: 4 additions & 2 deletions net/netfilter/xt_TCPOPTSTRIP.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

/*
Expand Down
11 changes: 9 additions & 2 deletions net/wireless/nl80211.c
Original file line number Diff line number Diff line change
Expand Up @@ -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])
Expand All @@ -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) {
Expand All @@ -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)))
Expand Down