diff options
Diffstat (limited to 'net')
37 files changed, 279 insertions, 161 deletions
diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c index 1f1de715197c..e2aa7be3a847 100644 --- a/net/bridge/br_input.c +++ b/net/bridge/br_input.c | |||
| @@ -154,7 +154,8 @@ int br_handle_frame_finish(struct sk_buff *skb) | |||
| 154 | dst = NULL; | 154 | dst = NULL; |
| 155 | 155 | ||
| 156 | if (is_broadcast_ether_addr(dest)) { | 156 | if (is_broadcast_ether_addr(dest)) { |
| 157 | if (p->flags & BR_PROXYARP && | 157 | if (IS_ENABLED(CONFIG_INET) && |
| 158 | p->flags & BR_PROXYARP && | ||
| 158 | skb->protocol == htons(ETH_P_ARP)) | 159 | skb->protocol == htons(ETH_P_ARP)) |
| 159 | br_do_proxy_arp(skb, br, vid); | 160 | br_do_proxy_arp(skb, br, vid); |
| 160 | 161 | ||
diff --git a/net/core/dev.c b/net/core/dev.c index 683d493aa1bf..171420e75b03 100644 --- a/net/core/dev.c +++ b/net/core/dev.c | |||
| @@ -7072,10 +7072,20 @@ static int dev_cpu_callback(struct notifier_block *nfb, | |||
| 7072 | oldsd->output_queue = NULL; | 7072 | oldsd->output_queue = NULL; |
| 7073 | oldsd->output_queue_tailp = &oldsd->output_queue; | 7073 | oldsd->output_queue_tailp = &oldsd->output_queue; |
| 7074 | } | 7074 | } |
| 7075 | /* Append NAPI poll list from offline CPU. */ | 7075 | /* Append NAPI poll list from offline CPU, with one exception : |
| 7076 | if (!list_empty(&oldsd->poll_list)) { | 7076 | * process_backlog() must be called by cpu owning percpu backlog. |
| 7077 | list_splice_init(&oldsd->poll_list, &sd->poll_list); | 7077 | * We properly handle process_queue & input_pkt_queue later. |
| 7078 | raise_softirq_irqoff(NET_RX_SOFTIRQ); | 7078 | */ |
| 7079 | while (!list_empty(&oldsd->poll_list)) { | ||
| 7080 | struct napi_struct *napi = list_first_entry(&oldsd->poll_list, | ||
| 7081 | struct napi_struct, | ||
| 7082 | poll_list); | ||
| 7083 | |||
| 7084 | list_del_init(&napi->poll_list); | ||
| 7085 | if (napi->poll == process_backlog) | ||
| 7086 | napi->state = 0; | ||
| 7087 | else | ||
| 7088 | ____napi_schedule(sd, napi); | ||
| 7079 | } | 7089 | } |
| 7080 | 7090 | ||
| 7081 | raise_softirq_irqoff(NET_TX_SOFTIRQ); | 7091 | raise_softirq_irqoff(NET_TX_SOFTIRQ); |
| @@ -7086,7 +7096,7 @@ static int dev_cpu_callback(struct notifier_block *nfb, | |||
| 7086 | netif_rx_internal(skb); | 7096 | netif_rx_internal(skb); |
| 7087 | input_queue_head_incr(oldsd); | 7097 | input_queue_head_incr(oldsd); |
| 7088 | } | 7098 | } |
| 7089 | while ((skb = __skb_dequeue(&oldsd->input_pkt_queue))) { | 7099 | while ((skb = skb_dequeue(&oldsd->input_pkt_queue))) { |
| 7090 | netif_rx_internal(skb); | 7100 | netif_rx_internal(skb); |
| 7091 | input_queue_head_incr(oldsd); | 7101 | input_queue_head_incr(oldsd); |
| 7092 | } | 7102 | } |
diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 8e38f17288d3..8d614c93f86a 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c | |||
| @@ -2043,6 +2043,12 @@ static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
| 2043 | case NDTPA_BASE_REACHABLE_TIME: | 2043 | case NDTPA_BASE_REACHABLE_TIME: |
| 2044 | NEIGH_VAR_SET(p, BASE_REACHABLE_TIME, | 2044 | NEIGH_VAR_SET(p, BASE_REACHABLE_TIME, |
| 2045 | nla_get_msecs(tbp[i])); | 2045 | nla_get_msecs(tbp[i])); |
| 2046 | /* update reachable_time as well, otherwise, the change will | ||
| 2047 | * only be effective after the next time neigh_periodic_work | ||
| 2048 | * decides to recompute it (can be multiple minutes) | ||
| 2049 | */ | ||
| 2050 | p->reachable_time = | ||
| 2051 | neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME)); | ||
| 2046 | break; | 2052 | break; |
| 2047 | case NDTPA_GC_STALETIME: | 2053 | case NDTPA_GC_STALETIME: |
| 2048 | NEIGH_VAR_SET(p, GC_STALETIME, | 2054 | NEIGH_VAR_SET(p, GC_STALETIME, |
| @@ -2921,6 +2927,31 @@ static int neigh_proc_dointvec_unres_qlen(struct ctl_table *ctl, int write, | |||
| 2921 | return ret; | 2927 | return ret; |
| 2922 | } | 2928 | } |
| 2923 | 2929 | ||
| 2930 | static int neigh_proc_base_reachable_time(struct ctl_table *ctl, int write, | ||
| 2931 | void __user *buffer, | ||
| 2932 | size_t *lenp, loff_t *ppos) | ||
| 2933 | { | ||
| 2934 | struct neigh_parms *p = ctl->extra2; | ||
| 2935 | int ret; | ||
| 2936 | |||
| 2937 | if (strcmp(ctl->procname, "base_reachable_time") == 0) | ||
| 2938 | ret = neigh_proc_dointvec_jiffies(ctl, write, buffer, lenp, ppos); | ||
| 2939 | else if (strcmp(ctl->procname, "base_reachable_time_ms") == 0) | ||
| 2940 | ret = neigh_proc_dointvec_ms_jiffies(ctl, write, buffer, lenp, ppos); | ||
| 2941 | else | ||
| 2942 | ret = -1; | ||
| 2943 | |||
| 2944 | if (write && ret == 0) { | ||
| 2945 | /* update reachable_time as well, otherwise, the change will | ||
| 2946 | * only be effective after the next time neigh_periodic_work | ||
| 2947 | * decides to recompute it | ||
| 2948 | */ | ||
| 2949 | p->reachable_time = | ||
| 2950 | neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME)); | ||
| 2951 | } | ||
| 2952 | return ret; | ||
| 2953 | } | ||
| 2954 | |||
| 2924 | #define NEIGH_PARMS_DATA_OFFSET(index) \ | 2955 | #define NEIGH_PARMS_DATA_OFFSET(index) \ |
| 2925 | (&((struct neigh_parms *) 0)->data[index]) | 2956 | (&((struct neigh_parms *) 0)->data[index]) |
| 2926 | 2957 | ||
| @@ -3047,6 +3078,19 @@ int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p, | |||
| 3047 | t->neigh_vars[NEIGH_VAR_RETRANS_TIME_MS].proc_handler = handler; | 3078 | t->neigh_vars[NEIGH_VAR_RETRANS_TIME_MS].proc_handler = handler; |
| 3048 | /* ReachableTime (in milliseconds) */ | 3079 | /* ReachableTime (in milliseconds) */ |
| 3049 | t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME_MS].proc_handler = handler; | 3080 | t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME_MS].proc_handler = handler; |
| 3081 | } else { | ||
| 3082 | /* Those handlers will update p->reachable_time after | ||
| 3083 | * base_reachable_time(_ms) is set to ensure the new timer starts being | ||
| 3084 | * applied after the next neighbour update instead of waiting for | ||
| 3085 | * neigh_periodic_work to update its value (can be multiple minutes) | ||
| 3086 | * So any handler that replaces them should do this as well | ||
| 3087 | */ | ||
| 3088 | /* ReachableTime */ | ||
| 3089 | t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME].proc_handler = | ||
| 3090 | neigh_proc_base_reachable_time; | ||
| 3091 | /* ReachableTime (in milliseconds) */ | ||
| 3092 | t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME_MS].proc_handler = | ||
| 3093 | neigh_proc_base_reachable_time; | ||
| 3050 | } | 3094 | } |
| 3051 | 3095 | ||
| 3052 | /* Don't export sysctls to unprivileged users */ | 3096 | /* Don't export sysctls to unprivileged users */ |
diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 515569ffde8a..589aafd01fc5 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c | |||
| @@ -46,6 +46,7 @@ void dsa_slave_mii_bus_init(struct dsa_switch *ds) | |||
| 46 | snprintf(ds->slave_mii_bus->id, MII_BUS_ID_SIZE, "dsa-%d:%.2x", | 46 | snprintf(ds->slave_mii_bus->id, MII_BUS_ID_SIZE, "dsa-%d:%.2x", |
| 47 | ds->index, ds->pd->sw_addr); | 47 | ds->index, ds->pd->sw_addr); |
| 48 | ds->slave_mii_bus->parent = ds->master_dev; | 48 | ds->slave_mii_bus->parent = ds->master_dev; |
| 49 | ds->slave_mii_bus->phy_mask = ~ds->phys_mii_mask; | ||
| 49 | } | 50 | } |
| 50 | 51 | ||
| 51 | 52 | ||
diff --git a/net/ipv4/ip_forward.c b/net/ipv4/ip_forward.c index 3a83ce5efa80..787b3c294ce6 100644 --- a/net/ipv4/ip_forward.c +++ b/net/ipv4/ip_forward.c | |||
| @@ -129,7 +129,8 @@ int ip_forward(struct sk_buff *skb) | |||
| 129 | * We now generate an ICMP HOST REDIRECT giving the route | 129 | * We now generate an ICMP HOST REDIRECT giving the route |
| 130 | * we calculated. | 130 | * we calculated. |
| 131 | */ | 131 | */ |
| 132 | if (rt->rt_flags&RTCF_DOREDIRECT && !opt->srr && !skb_sec_path(skb)) | 132 | if (IPCB(skb)->flags & IPSKB_DOREDIRECT && !opt->srr && |
| 133 | !skb_sec_path(skb)) | ||
| 133 | ip_rt_send_redirect(skb); | 134 | ip_rt_send_redirect(skb); |
| 134 | 135 | ||
| 135 | skb->priority = rt_tos2priority(iph->tos); | 136 | skb->priority = rt_tos2priority(iph->tos); |
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index 8a89c738b7a3..6b85adb05003 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c | |||
| @@ -461,17 +461,13 @@ int ip_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len) | |||
| 461 | 461 | ||
| 462 | memcpy(&errhdr.ee, &serr->ee, sizeof(struct sock_extended_err)); | 462 | memcpy(&errhdr.ee, &serr->ee, sizeof(struct sock_extended_err)); |
| 463 | sin = &errhdr.offender; | 463 | sin = &errhdr.offender; |
| 464 | sin->sin_family = AF_UNSPEC; | 464 | memset(sin, 0, sizeof(*sin)); |
| 465 | 465 | ||
| 466 | if (serr->ee.ee_origin == SO_EE_ORIGIN_ICMP || | 466 | if (serr->ee.ee_origin == SO_EE_ORIGIN_ICMP || |
| 467 | ipv4_pktinfo_prepare_errqueue(sk, skb, serr->ee.ee_origin)) { | 467 | ipv4_pktinfo_prepare_errqueue(sk, skb, serr->ee.ee_origin)) { |
| 468 | struct inet_sock *inet = inet_sk(sk); | ||
| 469 | |||
| 470 | sin->sin_family = AF_INET; | 468 | sin->sin_family = AF_INET; |
| 471 | sin->sin_addr.s_addr = ip_hdr(skb)->saddr; | 469 | sin->sin_addr.s_addr = ip_hdr(skb)->saddr; |
| 472 | sin->sin_port = 0; | 470 | if (inet_sk(sk)->cmsg_flags) |
| 473 | memset(&sin->sin_zero, 0, sizeof(sin->sin_zero)); | ||
| 474 | if (inet->cmsg_flags) | ||
| 475 | ip_cmsg_recv(msg, skb); | 471 | ip_cmsg_recv(msg, skb); |
| 476 | } | 472 | } |
| 477 | 473 | ||
diff --git a/net/ipv4/netfilter/nft_redir_ipv4.c b/net/ipv4/netfilter/nft_redir_ipv4.c index ff2d23d8c87a..6ecfce63201a 100644 --- a/net/ipv4/netfilter/nft_redir_ipv4.c +++ b/net/ipv4/netfilter/nft_redir_ipv4.c | |||
| @@ -27,10 +27,10 @@ static void nft_redir_ipv4_eval(const struct nft_expr *expr, | |||
| 27 | 27 | ||
| 28 | memset(&mr, 0, sizeof(mr)); | 28 | memset(&mr, 0, sizeof(mr)); |
| 29 | if (priv->sreg_proto_min) { | 29 | if (priv->sreg_proto_min) { |
| 30 | mr.range[0].min.all = (__force __be16) | 30 | mr.range[0].min.all = |
| 31 | data[priv->sreg_proto_min].data[0]; | 31 | *(__be16 *)&data[priv->sreg_proto_min].data[0]; |
| 32 | mr.range[0].max.all = (__force __be16) | 32 | mr.range[0].max.all = |
| 33 | data[priv->sreg_proto_max].data[0]; | 33 | *(__be16 *)&data[priv->sreg_proto_max].data[0]; |
| 34 | mr.range[0].flags |= NF_NAT_RANGE_PROTO_SPECIFIED; | 34 | mr.range[0].flags |= NF_NAT_RANGE_PROTO_SPECIFIED; |
| 35 | } | 35 | } |
| 36 | 36 | ||
diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c index c0d82f78d364..2a3720fb5a5f 100644 --- a/net/ipv4/ping.c +++ b/net/ipv4/ping.c | |||
| @@ -966,8 +966,11 @@ bool ping_rcv(struct sk_buff *skb) | |||
| 966 | 966 | ||
| 967 | sk = ping_lookup(net, skb, ntohs(icmph->un.echo.id)); | 967 | sk = ping_lookup(net, skb, ntohs(icmph->un.echo.id)); |
| 968 | if (sk != NULL) { | 968 | if (sk != NULL) { |
| 969 | struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC); | ||
| 970 | |||
| 969 | pr_debug("rcv on socket %p\n", sk); | 971 | pr_debug("rcv on socket %p\n", sk); |
| 970 | ping_queue_rcv_skb(sk, skb_get(skb)); | 972 | if (skb2) |
| 973 | ping_queue_rcv_skb(sk, skb2); | ||
| 971 | sock_put(sk); | 974 | sock_put(sk); |
| 972 | return true; | 975 | return true; |
| 973 | } | 976 | } |
diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 6a2155b02602..d58dd0ec3e53 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c | |||
| @@ -1554,11 +1554,10 @@ static int __mkroute_input(struct sk_buff *skb, | |||
| 1554 | 1554 | ||
| 1555 | do_cache = res->fi && !itag; | 1555 | do_cache = res->fi && !itag; |
| 1556 | if (out_dev == in_dev && err && IN_DEV_TX_REDIRECTS(out_dev) && | 1556 | if (out_dev == in_dev && err && IN_DEV_TX_REDIRECTS(out_dev) && |
| 1557 | skb->protocol == htons(ETH_P_IP) && | ||
| 1557 | (IN_DEV_SHARED_MEDIA(out_dev) || | 1558 | (IN_DEV_SHARED_MEDIA(out_dev) || |
| 1558 | inet_addr_onlink(out_dev, saddr, FIB_RES_GW(*res)))) { | 1559 | inet_addr_onlink(out_dev, saddr, FIB_RES_GW(*res)))) |
| 1559 | flags |= RTCF_DOREDIRECT; | 1560 | IPCB(skb)->flags |= IPSKB_DOREDIRECT; |
| 1560 | do_cache = false; | ||
| 1561 | } | ||
| 1562 | 1561 | ||
| 1563 | if (skb->protocol != htons(ETH_P_IP)) { | 1562 | if (skb->protocol != htons(ETH_P_IP)) { |
| 1564 | /* Not IP (i.e. ARP). Do not create route, if it is | 1563 | /* Not IP (i.e. ARP). Do not create route, if it is |
| @@ -2303,6 +2302,8 @@ static int rt_fill_info(struct net *net, __be32 dst, __be32 src, | |||
| 2303 | r->rtm_flags = (rt->rt_flags & ~0xFFFF) | RTM_F_CLONED; | 2302 | r->rtm_flags = (rt->rt_flags & ~0xFFFF) | RTM_F_CLONED; |
| 2304 | if (rt->rt_flags & RTCF_NOTIFY) | 2303 | if (rt->rt_flags & RTCF_NOTIFY) |
| 2305 | r->rtm_flags |= RTM_F_NOTIFY; | 2304 | r->rtm_flags |= RTM_F_NOTIFY; |
| 2305 | if (IPCB(skb)->flags & IPSKB_DOREDIRECT) | ||
| 2306 | r->rtm_flags |= RTCF_DOREDIRECT; | ||
| 2306 | 2307 | ||
| 2307 | if (nla_put_be32(skb, RTA_DST, dst)) | 2308 | if (nla_put_be32(skb, RTA_DST, dst)) |
| 2308 | goto nla_put_failure; | 2309 | goto nla_put_failure; |
diff --git a/net/ipv4/udp_diag.c b/net/ipv4/udp_diag.c index 7927db0a9279..4a000f1dd757 100644 --- a/net/ipv4/udp_diag.c +++ b/net/ipv4/udp_diag.c | |||
| @@ -99,11 +99,13 @@ static void udp_dump(struct udp_table *table, struct sk_buff *skb, struct netlin | |||
| 99 | s_slot = cb->args[0]; | 99 | s_slot = cb->args[0]; |
| 100 | num = s_num = cb->args[1]; | 100 | num = s_num = cb->args[1]; |
| 101 | 101 | ||
| 102 | for (slot = s_slot; slot <= table->mask; num = s_num = 0, slot++) { | 102 | for (slot = s_slot; slot <= table->mask; s_num = 0, slot++) { |
| 103 | struct sock *sk; | 103 | struct sock *sk; |
| 104 | struct hlist_nulls_node *node; | 104 | struct hlist_nulls_node *node; |
| 105 | struct udp_hslot *hslot = &table->hash[slot]; | 105 | struct udp_hslot *hslot = &table->hash[slot]; |
| 106 | 106 | ||
| 107 | num = 0; | ||
| 108 | |||
| 107 | if (hlist_nulls_empty(&hslot->head)) | 109 | if (hlist_nulls_empty(&hslot->head)) |
| 108 | continue; | 110 | continue; |
| 109 | 111 | ||
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c index 100c589a2a6c..49f5e73db122 100644 --- a/net/ipv6/datagram.c +++ b/net/ipv6/datagram.c | |||
| @@ -393,11 +393,10 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len) | |||
| 393 | 393 | ||
| 394 | memcpy(&errhdr.ee, &serr->ee, sizeof(struct sock_extended_err)); | 394 | memcpy(&errhdr.ee, &serr->ee, sizeof(struct sock_extended_err)); |
| 395 | sin = &errhdr.offender; | 395 | sin = &errhdr.offender; |
| 396 | sin->sin6_family = AF_UNSPEC; | 396 | memset(sin, 0, sizeof(*sin)); |
| 397 | |||
| 397 | if (serr->ee.ee_origin != SO_EE_ORIGIN_LOCAL) { | 398 | if (serr->ee.ee_origin != SO_EE_ORIGIN_LOCAL) { |
| 398 | sin->sin6_family = AF_INET6; | 399 | sin->sin6_family = AF_INET6; |
| 399 | sin->sin6_flowinfo = 0; | ||
| 400 | sin->sin6_port = 0; | ||
| 401 | if (np->rxopt.all) { | 400 | if (np->rxopt.all) { |
| 402 | if (serr->ee.ee_origin != SO_EE_ORIGIN_ICMP && | 401 | if (serr->ee.ee_origin != SO_EE_ORIGIN_ICMP && |
| 403 | serr->ee.ee_origin != SO_EE_ORIGIN_ICMP6) | 402 | serr->ee.ee_origin != SO_EE_ORIGIN_ICMP6) |
| @@ -412,12 +411,9 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len) | |||
| 412 | ipv6_iface_scope_id(&sin->sin6_addr, | 411 | ipv6_iface_scope_id(&sin->sin6_addr, |
| 413 | IP6CB(skb)->iif); | 412 | IP6CB(skb)->iif); |
| 414 | } else { | 413 | } else { |
| 415 | struct inet_sock *inet = inet_sk(sk); | ||
| 416 | |||
| 417 | ipv6_addr_set_v4mapped(ip_hdr(skb)->saddr, | 414 | ipv6_addr_set_v4mapped(ip_hdr(skb)->saddr, |
| 418 | &sin->sin6_addr); | 415 | &sin->sin6_addr); |
| 419 | sin->sin6_scope_id = 0; | 416 | if (inet_sk(sk)->cmsg_flags) |
| 420 | if (inet->cmsg_flags) | ||
| 421 | ip_cmsg_recv(msg, skb); | 417 | ip_cmsg_recv(msg, skb); |
| 422 | } | 418 | } |
| 423 | } | 419 | } |
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index b2d1838897c9..f1c6d5e98322 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c | |||
| @@ -659,6 +659,29 @@ static int fib6_commit_metrics(struct dst_entry *dst, | |||
| 659 | return 0; | 659 | return 0; |
| 660 | } | 660 | } |
| 661 | 661 | ||
| 662 | static void fib6_purge_rt(struct rt6_info *rt, struct fib6_node *fn, | ||
| 663 | struct net *net) | ||
| 664 | { | ||
| 665 | if (atomic_read(&rt->rt6i_ref) != 1) { | ||
| 666 | /* This route is used as dummy address holder in some split | ||
| 667 | * nodes. It is not leaked, but it still holds other resources, | ||
| 668 | * which must be released in time. So, scan ascendant nodes | ||
| 669 | * and replace dummy references to this route with references | ||
| 670 | * to still alive ones. | ||
| 671 | */ | ||
| 672 | while (fn) { | ||
| 673 | if (!(fn->fn_flags & RTN_RTINFO) && fn->leaf == rt) { | ||
| 674 | fn->leaf = fib6_find_prefix(net, fn); | ||
| 675 | atomic_inc(&fn->leaf->rt6i_ref); | ||
| 676 | rt6_release(rt); | ||
| 677 | } | ||
| 678 | fn = fn->parent; | ||
| 679 | } | ||
| 680 | /* No more references are possible at this point. */ | ||
| 681 | BUG_ON(atomic_read(&rt->rt6i_ref) != 1); | ||
| 682 | } | ||
| 683 | } | ||
| 684 | |||
| 662 | /* | 685 | /* |
| 663 | * Insert routing information in a node. | 686 | * Insert routing information in a node. |
| 664 | */ | 687 | */ |
| @@ -807,11 +830,12 @@ add: | |||
| 807 | rt->dst.rt6_next = iter->dst.rt6_next; | 830 | rt->dst.rt6_next = iter->dst.rt6_next; |
| 808 | atomic_inc(&rt->rt6i_ref); | 831 | atomic_inc(&rt->rt6i_ref); |
| 809 | inet6_rt_notify(RTM_NEWROUTE, rt, info); | 832 | inet6_rt_notify(RTM_NEWROUTE, rt, info); |
| 810 | rt6_release(iter); | ||
| 811 | if (!(fn->fn_flags & RTN_RTINFO)) { | 833 | if (!(fn->fn_flags & RTN_RTINFO)) { |
| 812 | info->nl_net->ipv6.rt6_stats->fib_route_nodes++; | 834 | info->nl_net->ipv6.rt6_stats->fib_route_nodes++; |
| 813 | fn->fn_flags |= RTN_RTINFO; | 835 | fn->fn_flags |= RTN_RTINFO; |
| 814 | } | 836 | } |
| 837 | fib6_purge_rt(iter, fn, info->nl_net); | ||
| 838 | rt6_release(iter); | ||
| 815 | } | 839 | } |
| 816 | 840 | ||
| 817 | return 0; | 841 | return 0; |
| @@ -1322,24 +1346,7 @@ static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp, | |||
| 1322 | fn = fib6_repair_tree(net, fn); | 1346 | fn = fib6_repair_tree(net, fn); |
| 1323 | } | 1347 | } |
| 1324 | 1348 | ||
| 1325 | if (atomic_read(&rt->rt6i_ref) != 1) { | 1349 | fib6_purge_rt(rt, fn, net); |
| 1326 | /* This route is used as dummy address holder in some split | ||
| 1327 | * nodes. It is not leaked, but it still holds other resources, | ||
| 1328 | * which must be released in time. So, scan ascendant nodes | ||
| 1329 | * and replace dummy references to this route with references | ||
| 1330 | * to still alive ones. | ||
| 1331 | */ | ||
| 1332 | while (fn) { | ||
| 1333 | if (!(fn->fn_flags & RTN_RTINFO) && fn->leaf == rt) { | ||
| 1334 | fn->leaf = fib6_find_prefix(net, fn); | ||
| 1335 | atomic_inc(&fn->leaf->rt6i_ref); | ||
| 1336 | rt6_release(rt); | ||
| 1337 | } | ||
| 1338 | fn = fn->parent; | ||
| 1339 | } | ||
| 1340 | /* No more references are possible at this point. */ | ||
| 1341 | BUG_ON(atomic_read(&rt->rt6i_ref) != 1); | ||
| 1342 | } | ||
| 1343 | 1350 | ||
| 1344 | inet6_rt_notify(RTM_DELROUTE, rt, info); | 1351 | inet6_rt_notify(RTM_DELROUTE, rt, info); |
| 1345 | rt6_release(rt); | 1352 | rt6_release(rt); |
diff --git a/net/ipv6/netfilter/nft_redir_ipv6.c b/net/ipv6/netfilter/nft_redir_ipv6.c index 2433a6bfb191..11820b6b3613 100644 --- a/net/ipv6/netfilter/nft_redir_ipv6.c +++ b/net/ipv6/netfilter/nft_redir_ipv6.c | |||
| @@ -27,10 +27,10 @@ static void nft_redir_ipv6_eval(const struct nft_expr *expr, | |||
| 27 | 27 | ||
| 28 | memset(&range, 0, sizeof(range)); | 28 | memset(&range, 0, sizeof(range)); |
| 29 | if (priv->sreg_proto_min) { | 29 | if (priv->sreg_proto_min) { |
| 30 | range.min_proto.all = (__force __be16) | 30 | range.min_proto.all = |
| 31 | data[priv->sreg_proto_min].data[0]; | 31 | *(__be16 *)&data[priv->sreg_proto_min].data[0]; |
| 32 | range.max_proto.all = (__force __be16) | 32 | range.max_proto.all = |
| 33 | data[priv->sreg_proto_max].data[0]; | 33 | *(__be16 *)&data[priv->sreg_proto_max].data[0]; |
| 34 | range.flags |= NF_NAT_RANGE_PROTO_SPECIFIED; | 34 | range.flags |= NF_NAT_RANGE_PROTO_SPECIFIED; |
| 35 | } | 35 | } |
| 36 | 36 | ||
diff --git a/net/ipv6/route.c b/net/ipv6/route.c index c91083156edb..495965358d22 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c | |||
| @@ -1160,12 +1160,9 @@ static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk, | |||
| 1160 | struct net *net = dev_net(dst->dev); | 1160 | struct net *net = dev_net(dst->dev); |
| 1161 | 1161 | ||
| 1162 | rt6->rt6i_flags |= RTF_MODIFIED; | 1162 | rt6->rt6i_flags |= RTF_MODIFIED; |
| 1163 | if (mtu < IPV6_MIN_MTU) { | 1163 | if (mtu < IPV6_MIN_MTU) |
| 1164 | u32 features = dst_metric(dst, RTAX_FEATURES); | ||
| 1165 | mtu = IPV6_MIN_MTU; | 1164 | mtu = IPV6_MIN_MTU; |
| 1166 | features |= RTAX_FEATURE_ALLFRAG; | 1165 | |
| 1167 | dst_metric_set(dst, RTAX_FEATURES, features); | ||
| 1168 | } | ||
| 1169 | dst_metric_set(dst, RTAX_MTU, mtu); | 1166 | dst_metric_set(dst, RTAX_MTU, mtu); |
| 1170 | rt6_update_expires(rt6, net->ipv6.sysctl.ip6_rt_mtu_expires); | 1167 | rt6_update_expires(rt6, net->ipv6.sysctl.ip6_rt_mtu_expires); |
| 1171 | } | 1168 | } |
| @@ -1245,12 +1242,16 @@ restart: | |||
| 1245 | rt = net->ipv6.ip6_null_entry; | 1242 | rt = net->ipv6.ip6_null_entry; |
| 1246 | else if (rt->dst.error) { | 1243 | else if (rt->dst.error) { |
| 1247 | rt = net->ipv6.ip6_null_entry; | 1244 | rt = net->ipv6.ip6_null_entry; |
| 1248 | } else if (rt == net->ipv6.ip6_null_entry) { | 1245 | goto out; |
| 1246 | } | ||
| 1247 | |||
| 1248 | if (rt == net->ipv6.ip6_null_entry) { | ||
| 1249 | fn = fib6_backtrack(fn, &fl6->saddr); | 1249 | fn = fib6_backtrack(fn, &fl6->saddr); |
| 1250 | if (fn) | 1250 | if (fn) |
| 1251 | goto restart; | 1251 | goto restart; |
| 1252 | } | 1252 | } |
| 1253 | 1253 | ||
| 1254 | out: | ||
| 1254 | dst_hold(&rt->dst); | 1255 | dst_hold(&rt->dst); |
| 1255 | 1256 | ||
| 1256 | read_unlock_bh(&table->tb6_lock); | 1257 | read_unlock_bh(&table->tb6_lock); |
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c index 5f983644373a..48bf5a06847b 100644 --- a/net/ipv6/xfrm6_policy.c +++ b/net/ipv6/xfrm6_policy.c | |||
| @@ -130,12 +130,18 @@ _decode_session6(struct sk_buff *skb, struct flowi *fl, int reverse) | |||
| 130 | { | 130 | { |
| 131 | struct flowi6 *fl6 = &fl->u.ip6; | 131 | struct flowi6 *fl6 = &fl->u.ip6; |
| 132 | int onlyproto = 0; | 132 | int onlyproto = 0; |
| 133 | u16 offset = skb_network_header_len(skb); | ||
| 134 | const struct ipv6hdr *hdr = ipv6_hdr(skb); | 133 | const struct ipv6hdr *hdr = ipv6_hdr(skb); |
| 134 | u16 offset = sizeof(*hdr); | ||
| 135 | struct ipv6_opt_hdr *exthdr; | 135 | struct ipv6_opt_hdr *exthdr; |
| 136 | const unsigned char *nh = skb_network_header(skb); | 136 | const unsigned char *nh = skb_network_header(skb); |
| 137 | u8 nexthdr = nh[IP6CB(skb)->nhoff]; | 137 | u16 nhoff = IP6CB(skb)->nhoff; |
| 138 | int oif = 0; | 138 | int oif = 0; |
| 139 | u8 nexthdr; | ||
| 140 | |||
| 141 | if (!nhoff) | ||
| 142 | nhoff = offsetof(struct ipv6hdr, nexthdr); | ||
| 143 | |||
| 144 | nexthdr = nh[nhoff]; | ||
| 139 | 145 | ||
| 140 | if (skb_dst(skb)) | 146 | if (skb_dst(skb)) |
| 141 | oif = skb_dst(skb)->dev->ifindex; | 147 | oif = skb_dst(skb)->dev->ifindex; |
diff --git a/net/llc/sysctl_net_llc.c b/net/llc/sysctl_net_llc.c index 612a5ddaf93b..799bafc2af39 100644 --- a/net/llc/sysctl_net_llc.c +++ b/net/llc/sysctl_net_llc.c | |||
| @@ -18,28 +18,28 @@ static struct ctl_table llc2_timeout_table[] = { | |||
| 18 | { | 18 | { |
| 19 | .procname = "ack", | 19 | .procname = "ack", |
| 20 | .data = &sysctl_llc2_ack_timeout, | 20 | .data = &sysctl_llc2_ack_timeout, |
| 21 | .maxlen = sizeof(long), | 21 | .maxlen = sizeof(sysctl_llc2_ack_timeout), |
| 22 | .mode = 0644, | 22 | .mode = 0644, |
| 23 | .proc_handler = proc_dointvec_jiffies, | 23 | .proc_handler = proc_dointvec_jiffies, |
| 24 | }, | 24 | }, |
| 25 | { | 25 | { |
| 26 | .procname = "busy", | 26 | .procname = "busy", |
| 27 | .data = &sysctl_llc2_busy_timeout, | 27 | .data = &sysctl_llc2_busy_timeout, |
| 28 | .maxlen = sizeof(long), | 28 | .maxlen = sizeof(sysctl_llc2_busy_timeout), |
| 29 | .mode = 0644, | 29 | .mode = 0644, |
| 30 | .proc_handler = proc_dointvec_jiffies, | 30 | .proc_handler = proc_dointvec_jiffies, |
| 31 | }, | 31 | }, |
| 32 | { | 32 | { |
| 33 | .procname = "p", | 33 | .procname = "p", |
| 34 | .data = &sysctl_llc2_p_timeout, | 34 | .data = &sysctl_llc2_p_timeout, |
| 35 | .maxlen = sizeof(long), | 35 | .maxlen = sizeof(sysctl_llc2_p_timeout), |
| 36 | .mode = 0644, | 36 | .mode = 0644, |
| 37 | .proc_handler = proc_dointvec_jiffies, | 37 | .proc_handler = proc_dointvec_jiffies, |
| 38 | }, | 38 | }, |
| 39 | { | 39 | { |
| 40 | .procname = "rej", | 40 | .procname = "rej", |
| 41 | .data = &sysctl_llc2_rej_timeout, | 41 | .data = &sysctl_llc2_rej_timeout, |
| 42 | .maxlen = sizeof(long), | 42 | .maxlen = sizeof(sysctl_llc2_rej_timeout), |
| 43 | .mode = 0644, | 43 | .mode = 0644, |
| 44 | .proc_handler = proc_dointvec_jiffies, | 44 | .proc_handler = proc_dointvec_jiffies, |
| 45 | }, | 45 | }, |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 2c36c4765f47..837a406a9dd6 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
| @@ -1643,7 +1643,7 @@ __ieee80211_sta_handle_tspec_ac_params(struct ieee80211_sub_if_data *sdata) | |||
| 1643 | { | 1643 | { |
| 1644 | struct ieee80211_local *local = sdata->local; | 1644 | struct ieee80211_local *local = sdata->local; |
| 1645 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 1645 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
| 1646 | bool ret; | 1646 | bool ret = false; |
| 1647 | int ac; | 1647 | int ac; |
| 1648 | 1648 | ||
| 1649 | if (local->hw.queues < IEEE80211_NUM_ACS) | 1649 | if (local->hw.queues < IEEE80211_NUM_ACS) |
diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index 4c5192e0d66c..4a95fe3cffbc 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c | |||
| @@ -86,20 +86,6 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) | |||
| 86 | } | 86 | } |
| 87 | } | 87 | } |
| 88 | 88 | ||
| 89 | /* tear down aggregation sessions and remove STAs */ | ||
| 90 | mutex_lock(&local->sta_mtx); | ||
| 91 | list_for_each_entry(sta, &local->sta_list, list) { | ||
| 92 | if (sta->uploaded) { | ||
| 93 | enum ieee80211_sta_state state; | ||
| 94 | |||
| 95 | state = sta->sta_state; | ||
| 96 | for (; state > IEEE80211_STA_NOTEXIST; state--) | ||
| 97 | WARN_ON(drv_sta_state(local, sta->sdata, sta, | ||
| 98 | state, state - 1)); | ||
| 99 | } | ||
| 100 | } | ||
| 101 | mutex_unlock(&local->sta_mtx); | ||
| 102 | |||
| 103 | /* remove all interfaces that were created in the driver */ | 89 | /* remove all interfaces that were created in the driver */ |
| 104 | list_for_each_entry(sdata, &local->interfaces, list) { | 90 | list_for_each_entry(sdata, &local->interfaces, list) { |
| 105 | if (!ieee80211_sdata_running(sdata)) | 91 | if (!ieee80211_sdata_running(sdata)) |
| @@ -111,6 +97,21 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) | |||
| 111 | case NL80211_IFTYPE_STATION: | 97 | case NL80211_IFTYPE_STATION: |
| 112 | ieee80211_mgd_quiesce(sdata); | 98 | ieee80211_mgd_quiesce(sdata); |
| 113 | break; | 99 | break; |
| 100 | case NL80211_IFTYPE_WDS: | ||
| 101 | /* tear down aggregation sessions and remove STAs */ | ||
| 102 | mutex_lock(&local->sta_mtx); | ||
| 103 | sta = sdata->u.wds.sta; | ||
| 104 | if (sta && sta->uploaded) { | ||
| 105 | enum ieee80211_sta_state state; | ||
| 106 | |||
| 107 | state = sta->sta_state; | ||
| 108 | for (; state > IEEE80211_STA_NOTEXIST; state--) | ||
| 109 | WARN_ON(drv_sta_state(local, sta->sdata, | ||
| 110 | sta, state, | ||
| 111 | state - 1)); | ||
| 112 | } | ||
| 113 | mutex_unlock(&local->sta_mtx); | ||
| 114 | break; | ||
| 114 | default: | 115 | default: |
| 115 | break; | 116 | break; |
| 116 | } | 117 | } |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 683b10f46505..d69ca513848e 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
| @@ -272,7 +272,7 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, | |||
| 272 | else if (rate && rate->flags & IEEE80211_RATE_ERP_G) | 272 | else if (rate && rate->flags & IEEE80211_RATE_ERP_G) |
| 273 | channel_flags |= IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ; | 273 | channel_flags |= IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ; |
| 274 | else if (rate) | 274 | else if (rate) |
| 275 | channel_flags |= IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ; | 275 | channel_flags |= IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ; |
| 276 | else | 276 | else |
| 277 | channel_flags |= IEEE80211_CHAN_2GHZ; | 277 | channel_flags |= IEEE80211_CHAN_2GHZ; |
| 278 | put_unaligned_le16(channel_flags, pos); | 278 | put_unaligned_le16(channel_flags, pos); |
diff --git a/net/netfilter/ipvs/ip_vs_ftp.c b/net/netfilter/ipvs/ip_vs_ftp.c index 1d5341f3761d..5d3daae98bf0 100644 --- a/net/netfilter/ipvs/ip_vs_ftp.c +++ b/net/netfilter/ipvs/ip_vs_ftp.c | |||
| @@ -183,6 +183,8 @@ static int ip_vs_ftp_out(struct ip_vs_app *app, struct ip_vs_conn *cp, | |||
| 183 | struct nf_conn *ct; | 183 | struct nf_conn *ct; |
| 184 | struct net *net; | 184 | struct net *net; |
| 185 | 185 | ||
| 186 | *diff = 0; | ||
| 187 | |||
| 186 | #ifdef CONFIG_IP_VS_IPV6 | 188 | #ifdef CONFIG_IP_VS_IPV6 |
| 187 | /* This application helper doesn't work with IPv6 yet, | 189 | /* This application helper doesn't work with IPv6 yet, |
| 188 | * so turn this into a no-op for IPv6 packets | 190 | * so turn this into a no-op for IPv6 packets |
| @@ -191,8 +193,6 @@ static int ip_vs_ftp_out(struct ip_vs_app *app, struct ip_vs_conn *cp, | |||
| 191 | return 1; | 193 | return 1; |
| 192 | #endif | 194 | #endif |
| 193 | 195 | ||
| 194 | *diff = 0; | ||
| 195 | |||
| 196 | /* Only useful for established sessions */ | 196 | /* Only useful for established sessions */ |
| 197 | if (cp->state != IP_VS_TCP_S_ESTABLISHED) | 197 | if (cp->state != IP_VS_TCP_S_ESTABLISHED) |
| 198 | return 1; | 198 | return 1; |
| @@ -322,6 +322,9 @@ static int ip_vs_ftp_in(struct ip_vs_app *app, struct ip_vs_conn *cp, | |||
| 322 | struct ip_vs_conn *n_cp; | 322 | struct ip_vs_conn *n_cp; |
| 323 | struct net *net; | 323 | struct net *net; |
| 324 | 324 | ||
| 325 | /* no diff required for incoming packets */ | ||
| 326 | *diff = 0; | ||
| 327 | |||
| 325 | #ifdef CONFIG_IP_VS_IPV6 | 328 | #ifdef CONFIG_IP_VS_IPV6 |
| 326 | /* This application helper doesn't work with IPv6 yet, | 329 | /* This application helper doesn't work with IPv6 yet, |
| 327 | * so turn this into a no-op for IPv6 packets | 330 | * so turn this into a no-op for IPv6 packets |
| @@ -330,9 +333,6 @@ static int ip_vs_ftp_in(struct ip_vs_app *app, struct ip_vs_conn *cp, | |||
| 330 | return 1; | 333 | return 1; |
| 331 | #endif | 334 | #endif |
| 332 | 335 | ||
| 333 | /* no diff required for incoming packets */ | ||
| 334 | *diff = 0; | ||
| 335 | |||
| 336 | /* Only useful for established sessions */ | 336 | /* Only useful for established sessions */ |
| 337 | if (cp->state != IP_VS_TCP_S_ESTABLISHED) | 337 | if (cp->state != IP_VS_TCP_S_ESTABLISHED) |
| 338 | return 1; | 338 | return 1; |
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index a11674806707..46d1b26a468e 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c | |||
| @@ -611,16 +611,15 @@ __nf_conntrack_confirm(struct sk_buff *skb) | |||
| 611 | */ | 611 | */ |
| 612 | NF_CT_ASSERT(!nf_ct_is_confirmed(ct)); | 612 | NF_CT_ASSERT(!nf_ct_is_confirmed(ct)); |
| 613 | pr_debug("Confirming conntrack %p\n", ct); | 613 | pr_debug("Confirming conntrack %p\n", ct); |
| 614 | /* We have to check the DYING flag inside the lock to prevent | 614 | /* We have to check the DYING flag after unlink to prevent |
| 615 | a race against nf_ct_get_next_corpse() possibly called from | 615 | * a race against nf_ct_get_next_corpse() possibly called from |
| 616 | user context, else we insert an already 'dead' hash, blocking | 616 | * user context, else we insert an already 'dead' hash, blocking |
| 617 | further use of that particular connection -JM */ | 617 | * further use of that particular connection -JM. |
| 618 | */ | ||
| 619 | nf_ct_del_from_dying_or_unconfirmed_list(ct); | ||
| 618 | 620 | ||
| 619 | if (unlikely(nf_ct_is_dying(ct))) { | 621 | if (unlikely(nf_ct_is_dying(ct))) |
| 620 | nf_conntrack_double_unlock(hash, reply_hash); | 622 | goto out; |
| 621 | local_bh_enable(); | ||
| 622 | return NF_ACCEPT; | ||
| 623 | } | ||
| 624 | 623 | ||
| 625 | /* See if there's one in the list already, including reverse: | 624 | /* See if there's one in the list already, including reverse: |
| 626 | NAT could have grabbed it without realizing, since we're | 625 | NAT could have grabbed it without realizing, since we're |
| @@ -636,8 +635,6 @@ __nf_conntrack_confirm(struct sk_buff *skb) | |||
| 636 | zone == nf_ct_zone(nf_ct_tuplehash_to_ctrack(h))) | 635 | zone == nf_ct_zone(nf_ct_tuplehash_to_ctrack(h))) |
| 637 | goto out; | 636 | goto out; |
| 638 | 637 | ||
| 639 | nf_ct_del_from_dying_or_unconfirmed_list(ct); | ||
| 640 | |||
| 641 | /* Timer relative to confirmation time, not original | 638 | /* Timer relative to confirmation time, not original |
| 642 | setting time, otherwise we'd get timer wrap in | 639 | setting time, otherwise we'd get timer wrap in |
| 643 | weird delay cases. */ | 640 | weird delay cases. */ |
| @@ -673,6 +670,7 @@ __nf_conntrack_confirm(struct sk_buff *skb) | |||
| 673 | return NF_ACCEPT; | 670 | return NF_ACCEPT; |
| 674 | 671 | ||
| 675 | out: | 672 | out: |
| 673 | nf_ct_add_to_dying_list(ct); | ||
| 676 | nf_conntrack_double_unlock(hash, reply_hash); | 674 | nf_conntrack_double_unlock(hash, reply_hash); |
| 677 | NF_CT_STAT_INC(net, insert_failed); | 675 | NF_CT_STAT_INC(net, insert_failed); |
| 678 | local_bh_enable(); | 676 | local_bh_enable(); |
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index 129a8daa4abf..3b3ddb4fb9ee 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c | |||
| @@ -713,16 +713,12 @@ static int nft_flush_table(struct nft_ctx *ctx) | |||
| 713 | struct nft_chain *chain, *nc; | 713 | struct nft_chain *chain, *nc; |
| 714 | struct nft_set *set, *ns; | 714 | struct nft_set *set, *ns; |
| 715 | 715 | ||
| 716 | list_for_each_entry_safe(chain, nc, &ctx->table->chains, list) { | 716 | list_for_each_entry(chain, &ctx->table->chains, list) { |
| 717 | ctx->chain = chain; | 717 | ctx->chain = chain; |
| 718 | 718 | ||
| 719 | err = nft_delrule_by_chain(ctx); | 719 | err = nft_delrule_by_chain(ctx); |
| 720 | if (err < 0) | 720 | if (err < 0) |
| 721 | goto out; | 721 | goto out; |
| 722 | |||
| 723 | err = nft_delchain(ctx); | ||
| 724 | if (err < 0) | ||
| 725 | goto out; | ||
| 726 | } | 722 | } |
| 727 | 723 | ||
| 728 | list_for_each_entry_safe(set, ns, &ctx->table->sets, list) { | 724 | list_for_each_entry_safe(set, ns, &ctx->table->sets, list) { |
| @@ -735,6 +731,14 @@ static int nft_flush_table(struct nft_ctx *ctx) | |||
| 735 | goto out; | 731 | goto out; |
| 736 | } | 732 | } |
| 737 | 733 | ||
| 734 | list_for_each_entry_safe(chain, nc, &ctx->table->chains, list) { | ||
| 735 | ctx->chain = chain; | ||
| 736 | |||
| 737 | err = nft_delchain(ctx); | ||
| 738 | if (err < 0) | ||
| 739 | goto out; | ||
| 740 | } | ||
| 741 | |||
| 738 | err = nft_deltable(ctx); | 742 | err = nft_deltable(ctx); |
| 739 | out: | 743 | out: |
| 740 | return err; | 744 | return err; |
diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c index cde4a6702fa3..c421d94c4652 100644 --- a/net/netfilter/nfnetlink.c +++ b/net/netfilter/nfnetlink.c | |||
| @@ -321,7 +321,8 @@ replay: | |||
| 321 | nlh = nlmsg_hdr(skb); | 321 | nlh = nlmsg_hdr(skb); |
| 322 | err = 0; | 322 | err = 0; |
| 323 | 323 | ||
| 324 | if (nlh->nlmsg_len < NLMSG_HDRLEN) { | 324 | if (nlmsg_len(nlh) < sizeof(struct nfgenmsg) || |
| 325 | skb->len < nlh->nlmsg_len) { | ||
| 325 | err = -EINVAL; | 326 | err = -EINVAL; |
| 326 | goto ack; | 327 | goto ack; |
| 327 | } | 328 | } |
| @@ -469,7 +470,7 @@ static int nfnetlink_bind(struct net *net, int group) | |||
| 469 | int type; | 470 | int type; |
| 470 | 471 | ||
| 471 | if (group <= NFNLGRP_NONE || group > NFNLGRP_MAX) | 472 | if (group <= NFNLGRP_NONE || group > NFNLGRP_MAX) |
| 472 | return -EINVAL; | 473 | return 0; |
| 473 | 474 | ||
| 474 | type = nfnl_group2type[group]; | 475 | type = nfnl_group2type[group]; |
| 475 | 476 | ||
diff --git a/net/netfilter/nft_nat.c b/net/netfilter/nft_nat.c index afe2b0b45ec4..aff54fb1c8a0 100644 --- a/net/netfilter/nft_nat.c +++ b/net/netfilter/nft_nat.c | |||
| @@ -65,10 +65,10 @@ static void nft_nat_eval(const struct nft_expr *expr, | |||
| 65 | } | 65 | } |
| 66 | 66 | ||
| 67 | if (priv->sreg_proto_min) { | 67 | if (priv->sreg_proto_min) { |
| 68 | range.min_proto.all = (__force __be16) | 68 | range.min_proto.all = |
| 69 | data[priv->sreg_proto_min].data[0]; | 69 | *(__be16 *)&data[priv->sreg_proto_min].data[0]; |
| 70 | range.max_proto.all = (__force __be16) | 70 | range.max_proto.all = |
| 71 | data[priv->sreg_proto_max].data[0]; | 71 | *(__be16 *)&data[priv->sreg_proto_max].data[0]; |
| 72 | range.flags |= NF_NAT_RANGE_PROTO_SPECIFIED; | 72 | range.flags |= NF_NAT_RANGE_PROTO_SPECIFIED; |
| 73 | } | 73 | } |
| 74 | 74 | ||
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 84ea76ca3f1f..02fdde28dada 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c | |||
| @@ -61,6 +61,7 @@ | |||
| 61 | #include <linux/rhashtable.h> | 61 | #include <linux/rhashtable.h> |
| 62 | #include <asm/cacheflush.h> | 62 | #include <asm/cacheflush.h> |
| 63 | #include <linux/hash.h> | 63 | #include <linux/hash.h> |
| 64 | #include <linux/genetlink.h> | ||
| 64 | 65 | ||
| 65 | #include <net/net_namespace.h> | 66 | #include <net/net_namespace.h> |
| 66 | #include <net/sock.h> | 67 | #include <net/sock.h> |
| @@ -1095,6 +1096,8 @@ static void netlink_remove(struct sock *sk) | |||
| 1095 | __sk_del_bind_node(sk); | 1096 | __sk_del_bind_node(sk); |
| 1096 | netlink_update_listeners(sk); | 1097 | netlink_update_listeners(sk); |
| 1097 | } | 1098 | } |
| 1099 | if (sk->sk_protocol == NETLINK_GENERIC) | ||
| 1100 | atomic_inc(&genl_sk_destructing_cnt); | ||
| 1098 | netlink_table_ungrab(); | 1101 | netlink_table_ungrab(); |
| 1099 | } | 1102 | } |
| 1100 | 1103 | ||
| @@ -1211,6 +1214,20 @@ static int netlink_release(struct socket *sock) | |||
| 1211 | * will be purged. | 1214 | * will be purged. |
| 1212 | */ | 1215 | */ |
| 1213 | 1216 | ||
| 1217 | /* must not acquire netlink_table_lock in any way again before unbind | ||
| 1218 | * and notifying genetlink is done as otherwise it might deadlock | ||
| 1219 | */ | ||
| 1220 | if (nlk->netlink_unbind) { | ||
| 1221 | int i; | ||
| 1222 | |||
| 1223 | for (i = 0; i < nlk->ngroups; i++) | ||
| 1224 | if (test_bit(i, nlk->groups)) | ||
| 1225 | nlk->netlink_unbind(sock_net(sk), i + 1); | ||
| 1226 | } | ||
| 1227 | if (sk->sk_protocol == NETLINK_GENERIC && | ||
| 1228 | atomic_dec_return(&genl_sk_destructing_cnt) == 0) | ||
| 1229 | wake_up(&genl_sk_destructing_waitq); | ||
| 1230 | |||
| 1214 | sock->sk = NULL; | 1231 | sock->sk = NULL; |
| 1215 | wake_up_interruptible_all(&nlk->wait); | 1232 | wake_up_interruptible_all(&nlk->wait); |
| 1216 | 1233 | ||
| @@ -1246,13 +1263,6 @@ static int netlink_release(struct socket *sock) | |||
| 1246 | netlink_table_ungrab(); | 1263 | netlink_table_ungrab(); |
| 1247 | } | 1264 | } |
| 1248 | 1265 | ||
| 1249 | if (nlk->netlink_unbind) { | ||
| 1250 | int i; | ||
| 1251 | |||
| 1252 | for (i = 0; i < nlk->ngroups; i++) | ||
| 1253 | if (test_bit(i, nlk->groups)) | ||
| 1254 | nlk->netlink_unbind(sock_net(sk), i + 1); | ||
| 1255 | } | ||
| 1256 | kfree(nlk->groups); | 1266 | kfree(nlk->groups); |
| 1257 | nlk->groups = NULL; | 1267 | nlk->groups = NULL; |
| 1258 | 1268 | ||
diff --git a/net/netlink/af_netlink.h b/net/netlink/af_netlink.h index f123a88496f8..f1c31b39aa3e 100644 --- a/net/netlink/af_netlink.h +++ b/net/netlink/af_netlink.h | |||
| @@ -2,6 +2,7 @@ | |||
| 2 | #define _AF_NETLINK_H | 2 | #define _AF_NETLINK_H |
| 3 | 3 | ||
| 4 | #include <linux/rhashtable.h> | 4 | #include <linux/rhashtable.h> |
| 5 | #include <linux/atomic.h> | ||
| 5 | #include <net/sock.h> | 6 | #include <net/sock.h> |
| 6 | 7 | ||
| 7 | #define NLGRPSZ(x) (ALIGN(x, sizeof(unsigned long) * 8) / 8) | 8 | #define NLGRPSZ(x) (ALIGN(x, sizeof(unsigned long) * 8) / 8) |
diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c index 2e11061ef885..ee57459fc258 100644 --- a/net/netlink/genetlink.c +++ b/net/netlink/genetlink.c | |||
| @@ -23,6 +23,9 @@ | |||
| 23 | static DEFINE_MUTEX(genl_mutex); /* serialization of message processing */ | 23 | static DEFINE_MUTEX(genl_mutex); /* serialization of message processing */ |
| 24 | static DECLARE_RWSEM(cb_lock); | 24 | static DECLARE_RWSEM(cb_lock); |
| 25 | 25 | ||
| 26 | atomic_t genl_sk_destructing_cnt = ATOMIC_INIT(0); | ||
| 27 | DECLARE_WAIT_QUEUE_HEAD(genl_sk_destructing_waitq); | ||
| 28 | |||
| 26 | void genl_lock(void) | 29 | void genl_lock(void) |
| 27 | { | 30 | { |
| 28 | mutex_lock(&genl_mutex); | 31 | mutex_lock(&genl_mutex); |
| @@ -435,15 +438,18 @@ int genl_unregister_family(struct genl_family *family) | |||
| 435 | 438 | ||
| 436 | genl_lock_all(); | 439 | genl_lock_all(); |
| 437 | 440 | ||
| 438 | genl_unregister_mc_groups(family); | ||
| 439 | |||
| 440 | list_for_each_entry(rc, genl_family_chain(family->id), family_list) { | 441 | list_for_each_entry(rc, genl_family_chain(family->id), family_list) { |
| 441 | if (family->id != rc->id || strcmp(rc->name, family->name)) | 442 | if (family->id != rc->id || strcmp(rc->name, family->name)) |
| 442 | continue; | 443 | continue; |
| 443 | 444 | ||
| 445 | genl_unregister_mc_groups(family); | ||
| 446 | |||
| 444 | list_del(&rc->family_list); | 447 | list_del(&rc->family_list); |
| 445 | family->n_ops = 0; | 448 | family->n_ops = 0; |
| 446 | genl_unlock_all(); | 449 | up_write(&cb_lock); |
| 450 | wait_event(genl_sk_destructing_waitq, | ||
| 451 | atomic_read(&genl_sk_destructing_cnt) == 0); | ||
| 452 | genl_unlock(); | ||
| 447 | 453 | ||
| 448 | kfree(family->attrbuf); | 454 | kfree(family->attrbuf); |
| 449 | genl_ctrl_event(CTRL_CMD_DELFAMILY, family, NULL, 0); | 455 | genl_ctrl_event(CTRL_CMD_DELFAMILY, family, NULL, 0); |
| @@ -985,7 +991,7 @@ static struct genl_multicast_group genl_ctrl_groups[] = { | |||
| 985 | 991 | ||
| 986 | static int genl_bind(struct net *net, int group) | 992 | static int genl_bind(struct net *net, int group) |
| 987 | { | 993 | { |
| 988 | int i, err = 0; | 994 | int i, err = -ENOENT; |
| 989 | 995 | ||
| 990 | down_read(&cb_lock); | 996 | down_read(&cb_lock); |
| 991 | for (i = 0; i < GENL_FAM_TAB_SIZE; i++) { | 997 | for (i = 0; i < GENL_FAM_TAB_SIZE; i++) { |
| @@ -1014,7 +1020,6 @@ static int genl_bind(struct net *net, int group) | |||
| 1014 | static void genl_unbind(struct net *net, int group) | 1020 | static void genl_unbind(struct net *net, int group) |
| 1015 | { | 1021 | { |
| 1016 | int i; | 1022 | int i; |
| 1017 | bool found = false; | ||
| 1018 | 1023 | ||
| 1019 | down_read(&cb_lock); | 1024 | down_read(&cb_lock); |
| 1020 | for (i = 0; i < GENL_FAM_TAB_SIZE; i++) { | 1025 | for (i = 0; i < GENL_FAM_TAB_SIZE; i++) { |
| @@ -1027,14 +1032,11 @@ static void genl_unbind(struct net *net, int group) | |||
| 1027 | 1032 | ||
| 1028 | if (f->mcast_unbind) | 1033 | if (f->mcast_unbind) |
| 1029 | f->mcast_unbind(net, fam_grp); | 1034 | f->mcast_unbind(net, fam_grp); |
| 1030 | found = true; | ||
| 1031 | break; | 1035 | break; |
| 1032 | } | 1036 | } |
| 1033 | } | 1037 | } |
| 1034 | } | 1038 | } |
| 1035 | up_read(&cb_lock); | 1039 | up_read(&cb_lock); |
| 1036 | |||
| 1037 | WARN_ON(!found); | ||
| 1038 | } | 1040 | } |
| 1039 | 1041 | ||
| 1040 | static int __net_init genl_pernet_init(struct net *net) | 1042 | static int __net_init genl_pernet_init(struct net *net) |
diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c index 4e9a5f035cbc..b07349e82d78 100644 --- a/net/openvswitch/datapath.c +++ b/net/openvswitch/datapath.c | |||
| @@ -524,7 +524,7 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info) | |||
| 524 | struct vport *input_vport; | 524 | struct vport *input_vport; |
| 525 | int len; | 525 | int len; |
| 526 | int err; | 526 | int err; |
| 527 | bool log = !a[OVS_FLOW_ATTR_PROBE]; | 527 | bool log = !a[OVS_PACKET_ATTR_PROBE]; |
| 528 | 528 | ||
| 529 | err = -EINVAL; | 529 | err = -EINVAL; |
| 530 | if (!a[OVS_PACKET_ATTR_PACKET] || !a[OVS_PACKET_ATTR_KEY] || | 530 | if (!a[OVS_PACKET_ATTR_PACKET] || !a[OVS_PACKET_ATTR_KEY] || |
| @@ -610,6 +610,7 @@ static const struct nla_policy packet_policy[OVS_PACKET_ATTR_MAX + 1] = { | |||
| 610 | [OVS_PACKET_ATTR_PACKET] = { .len = ETH_HLEN }, | 610 | [OVS_PACKET_ATTR_PACKET] = { .len = ETH_HLEN }, |
| 611 | [OVS_PACKET_ATTR_KEY] = { .type = NLA_NESTED }, | 611 | [OVS_PACKET_ATTR_KEY] = { .type = NLA_NESTED }, |
| 612 | [OVS_PACKET_ATTR_ACTIONS] = { .type = NLA_NESTED }, | 612 | [OVS_PACKET_ATTR_ACTIONS] = { .type = NLA_NESTED }, |
| 613 | [OVS_PACKET_ATTR_PROBE] = { .type = NLA_FLAG }, | ||
| 613 | }; | 614 | }; |
| 614 | 615 | ||
| 615 | static const struct genl_ops dp_packet_genl_ops[] = { | 616 | static const struct genl_ops dp_packet_genl_ops[] = { |
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 6880f34a529a..9cfe2e1dd8b5 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c | |||
| @@ -2517,7 +2517,7 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len) | |||
| 2517 | err = -EINVAL; | 2517 | err = -EINVAL; |
| 2518 | if (sock->type == SOCK_DGRAM) { | 2518 | if (sock->type == SOCK_DGRAM) { |
| 2519 | offset = dev_hard_header(skb, dev, ntohs(proto), addr, NULL, len); | 2519 | offset = dev_hard_header(skb, dev, ntohs(proto), addr, NULL, len); |
| 2520 | if (unlikely(offset) < 0) | 2520 | if (unlikely(offset < 0)) |
| 2521 | goto out_free; | 2521 | goto out_free; |
| 2522 | } else { | 2522 | } else { |
| 2523 | if (ll_header_truncated(dev, len)) | 2523 | if (ll_header_truncated(dev, len)) |
diff --git a/net/sched/cls_bpf.c b/net/sched/cls_bpf.c index 84c8219c3e1c..f59adf8a4cd7 100644 --- a/net/sched/cls_bpf.c +++ b/net/sched/cls_bpf.c | |||
| @@ -180,6 +180,11 @@ static int cls_bpf_modify_existing(struct net *net, struct tcf_proto *tp, | |||
| 180 | } | 180 | } |
| 181 | 181 | ||
| 182 | bpf_size = bpf_len * sizeof(*bpf_ops); | 182 | bpf_size = bpf_len * sizeof(*bpf_ops); |
| 183 | if (bpf_size != nla_len(tb[TCA_BPF_OPS])) { | ||
| 184 | ret = -EINVAL; | ||
| 185 | goto errout; | ||
| 186 | } | ||
| 187 | |||
| 183 | bpf_ops = kzalloc(bpf_size, GFP_KERNEL); | 188 | bpf_ops = kzalloc(bpf_size, GFP_KERNEL); |
| 184 | if (bpf_ops == NULL) { | 189 | if (bpf_ops == NULL) { |
| 185 | ret = -ENOMEM; | 190 | ret = -ENOMEM; |
| @@ -215,15 +220,21 @@ static u32 cls_bpf_grab_new_handle(struct tcf_proto *tp, | |||
| 215 | struct cls_bpf_head *head) | 220 | struct cls_bpf_head *head) |
| 216 | { | 221 | { |
| 217 | unsigned int i = 0x80000000; | 222 | unsigned int i = 0x80000000; |
| 223 | u32 handle; | ||
| 218 | 224 | ||
| 219 | do { | 225 | do { |
| 220 | if (++head->hgen == 0x7FFFFFFF) | 226 | if (++head->hgen == 0x7FFFFFFF) |
| 221 | head->hgen = 1; | 227 | head->hgen = 1; |
| 222 | } while (--i > 0 && cls_bpf_get(tp, head->hgen)); | 228 | } while (--i > 0 && cls_bpf_get(tp, head->hgen)); |
| 223 | if (i == 0) | 229 | |
| 230 | if (unlikely(i == 0)) { | ||
| 224 | pr_err("Insufficient number of handles\n"); | 231 | pr_err("Insufficient number of handles\n"); |
| 232 | handle = 0; | ||
| 233 | } else { | ||
| 234 | handle = head->hgen; | ||
| 235 | } | ||
| 225 | 236 | ||
| 226 | return i; | 237 | return handle; |
| 227 | } | 238 | } |
| 228 | 239 | ||
| 229 | static int cls_bpf_change(struct net *net, struct sk_buff *in_skb, | 240 | static int cls_bpf_change(struct net *net, struct sk_buff *in_skb, |
diff --git a/net/sctp/associola.c b/net/sctp/associola.c index f791edd64d6c..26d06dbcc1c8 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c | |||
| @@ -1182,7 +1182,6 @@ void sctp_assoc_update(struct sctp_association *asoc, | |||
| 1182 | asoc->peer.peer_hmacs = new->peer.peer_hmacs; | 1182 | asoc->peer.peer_hmacs = new->peer.peer_hmacs; |
| 1183 | new->peer.peer_hmacs = NULL; | 1183 | new->peer.peer_hmacs = NULL; |
| 1184 | 1184 | ||
| 1185 | sctp_auth_key_put(asoc->asoc_shared_key); | ||
| 1186 | sctp_auth_asoc_init_active_key(asoc, GFP_ATOMIC); | 1185 | sctp_auth_asoc_init_active_key(asoc, GFP_ATOMIC); |
| 1187 | } | 1186 | } |
| 1188 | 1187 | ||
diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 2625eccb77d5..aafe94bf292e 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c | |||
| @@ -1603,7 +1603,7 @@ static int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
| 1603 | sctp_assoc_t associd = 0; | 1603 | sctp_assoc_t associd = 0; |
| 1604 | sctp_cmsgs_t cmsgs = { NULL }; | 1604 | sctp_cmsgs_t cmsgs = { NULL }; |
| 1605 | sctp_scope_t scope; | 1605 | sctp_scope_t scope; |
| 1606 | bool fill_sinfo_ttl = false; | 1606 | bool fill_sinfo_ttl = false, wait_connect = false; |
| 1607 | struct sctp_datamsg *datamsg; | 1607 | struct sctp_datamsg *datamsg; |
| 1608 | int msg_flags = msg->msg_flags; | 1608 | int msg_flags = msg->msg_flags; |
| 1609 | __u16 sinfo_flags = 0; | 1609 | __u16 sinfo_flags = 0; |
| @@ -1943,6 +1943,7 @@ static int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
| 1943 | if (err < 0) | 1943 | if (err < 0) |
| 1944 | goto out_free; | 1944 | goto out_free; |
| 1945 | 1945 | ||
| 1946 | wait_connect = true; | ||
| 1946 | pr_debug("%s: we associated primitively\n", __func__); | 1947 | pr_debug("%s: we associated primitively\n", __func__); |
| 1947 | } | 1948 | } |
| 1948 | 1949 | ||
| @@ -1980,6 +1981,11 @@ static int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
| 1980 | sctp_datamsg_put(datamsg); | 1981 | sctp_datamsg_put(datamsg); |
| 1981 | err = msg_len; | 1982 | err = msg_len; |
| 1982 | 1983 | ||
| 1984 | if (unlikely(wait_connect)) { | ||
| 1985 | timeo = sock_sndtimeo(sk, msg_flags & MSG_DONTWAIT); | ||
| 1986 | sctp_wait_for_connect(asoc, &timeo); | ||
| 1987 | } | ||
| 1988 | |||
| 1983 | /* If we are already past ASSOCIATE, the lower | 1989 | /* If we are already past ASSOCIATE, the lower |
| 1984 | * layers are responsible for association cleanup. | 1990 | * layers are responsible for association cleanup. |
| 1985 | */ | 1991 | */ |
diff --git a/net/socket.c b/net/socket.c index a2c33a4dc7ba..418795caa897 100644 --- a/net/socket.c +++ b/net/socket.c | |||
| @@ -869,9 +869,6 @@ static ssize_t sock_splice_read(struct file *file, loff_t *ppos, | |||
| 869 | static struct sock_iocb *alloc_sock_iocb(struct kiocb *iocb, | 869 | static struct sock_iocb *alloc_sock_iocb(struct kiocb *iocb, |
| 870 | struct sock_iocb *siocb) | 870 | struct sock_iocb *siocb) |
| 871 | { | 871 | { |
| 872 | if (!is_sync_kiocb(iocb)) | ||
| 873 | BUG(); | ||
| 874 | |||
| 875 | siocb->kiocb = iocb; | 872 | siocb->kiocb = iocb; |
| 876 | iocb->private = siocb; | 873 | iocb->private = siocb; |
| 877 | return siocb; | 874 | return siocb; |
diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c index 96ceefeb9daf..a9e174fc0f91 100644 --- a/net/tipc/bcast.c +++ b/net/tipc/bcast.c | |||
| @@ -220,10 +220,11 @@ static void bclink_retransmit_pkt(u32 after, u32 to) | |||
| 220 | struct sk_buff *skb; | 220 | struct sk_buff *skb; |
| 221 | 221 | ||
| 222 | skb_queue_walk(&bcl->outqueue, skb) { | 222 | skb_queue_walk(&bcl->outqueue, skb) { |
| 223 | if (more(buf_seqno(skb), after)) | 223 | if (more(buf_seqno(skb), after)) { |
| 224 | tipc_link_retransmit(bcl, skb, mod(to - after)); | ||
| 224 | break; | 225 | break; |
| 226 | } | ||
| 225 | } | 227 | } |
| 226 | tipc_link_retransmit(bcl, skb, mod(to - after)); | ||
| 227 | } | 228 | } |
| 228 | 229 | ||
| 229 | /** | 230 | /** |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 7ca4b5133123..8887c6e5fca8 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
| @@ -2854,6 +2854,9 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) | |||
| 2854 | if (!rdev->ops->get_key) | 2854 | if (!rdev->ops->get_key) |
| 2855 | return -EOPNOTSUPP; | 2855 | return -EOPNOTSUPP; |
| 2856 | 2856 | ||
| 2857 | if (!pairwise && mac_addr && !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN)) | ||
| 2858 | return -ENOENT; | ||
| 2859 | |||
| 2857 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 2860 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
| 2858 | if (!msg) | 2861 | if (!msg) |
| 2859 | return -ENOMEM; | 2862 | return -ENOMEM; |
| @@ -2873,10 +2876,6 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) | |||
| 2873 | nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr)) | 2876 | nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr)) |
| 2874 | goto nla_put_failure; | 2877 | goto nla_put_failure; |
| 2875 | 2878 | ||
| 2876 | if (pairwise && mac_addr && | ||
| 2877 | !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN)) | ||
| 2878 | return -ENOENT; | ||
| 2879 | |||
| 2880 | err = rdev_get_key(rdev, dev, key_idx, pairwise, mac_addr, &cookie, | 2879 | err = rdev_get_key(rdev, dev, key_idx, pairwise, mac_addr, &cookie, |
| 2881 | get_key_callback); | 2880 | get_key_callback); |
| 2882 | 2881 | ||
| @@ -3047,7 +3046,7 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info) | |||
| 3047 | wdev_lock(dev->ieee80211_ptr); | 3046 | wdev_lock(dev->ieee80211_ptr); |
| 3048 | err = nl80211_key_allowed(dev->ieee80211_ptr); | 3047 | err = nl80211_key_allowed(dev->ieee80211_ptr); |
| 3049 | 3048 | ||
| 3050 | if (key.type == NL80211_KEYTYPE_PAIRWISE && mac_addr && | 3049 | if (key.type == NL80211_KEYTYPE_GROUP && mac_addr && |
| 3051 | !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN)) | 3050 | !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN)) |
| 3052 | err = -ENOENT; | 3051 | err = -ENOENT; |
| 3053 | 3052 | ||
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 7b8309840d4e..d39d1cbc86b1 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c | |||
| @@ -1530,45 +1530,40 @@ static void reg_call_notifier(struct wiphy *wiphy, | |||
| 1530 | 1530 | ||
| 1531 | static bool reg_wdev_chan_valid(struct wiphy *wiphy, struct wireless_dev *wdev) | 1531 | static bool reg_wdev_chan_valid(struct wiphy *wiphy, struct wireless_dev *wdev) |
| 1532 | { | 1532 | { |
| 1533 | struct ieee80211_channel *ch; | ||
| 1534 | struct cfg80211_chan_def chandef; | 1533 | struct cfg80211_chan_def chandef; |
| 1535 | struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); | 1534 | struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); |
| 1536 | bool ret = true; | 1535 | enum nl80211_iftype iftype; |
| 1537 | 1536 | ||
| 1538 | wdev_lock(wdev); | 1537 | wdev_lock(wdev); |
| 1538 | iftype = wdev->iftype; | ||
| 1539 | 1539 | ||
| 1540 | /* make sure the interface is active */ | ||
| 1540 | if (!wdev->netdev || !netif_running(wdev->netdev)) | 1541 | if (!wdev->netdev || !netif_running(wdev->netdev)) |
| 1541 | goto out; | 1542 | goto wdev_inactive_unlock; |
| 1542 | 1543 | ||
| 1543 | switch (wdev->iftype) { | 1544 | switch (iftype) { |
| 1544 | case NL80211_IFTYPE_AP: | 1545 | case NL80211_IFTYPE_AP: |
| 1545 | case NL80211_IFTYPE_P2P_GO: | 1546 | case NL80211_IFTYPE_P2P_GO: |
| 1546 | if (!wdev->beacon_interval) | 1547 | if (!wdev->beacon_interval) |
| 1547 | goto out; | 1548 | goto wdev_inactive_unlock; |
| 1548 | 1549 | chandef = wdev->chandef; | |
| 1549 | ret = cfg80211_reg_can_beacon(wiphy, | ||
| 1550 | &wdev->chandef, wdev->iftype); | ||
| 1551 | break; | 1550 | break; |
| 1552 | case NL80211_IFTYPE_ADHOC: | 1551 | case NL80211_IFTYPE_ADHOC: |
| 1553 | if (!wdev->ssid_len) | 1552 | if (!wdev->ssid_len) |
| 1554 | goto out; | 1553 | goto wdev_inactive_unlock; |
| 1555 | 1554 | chandef = wdev->chandef; | |
| 1556 | ret = cfg80211_reg_can_beacon(wiphy, | ||
| 1557 | &wdev->chandef, wdev->iftype); | ||
| 1558 | break; | 1555 | break; |
| 1559 | case NL80211_IFTYPE_STATION: | 1556 | case NL80211_IFTYPE_STATION: |
| 1560 | case NL80211_IFTYPE_P2P_CLIENT: | 1557 | case NL80211_IFTYPE_P2P_CLIENT: |
| 1561 | if (!wdev->current_bss || | 1558 | if (!wdev->current_bss || |
| 1562 | !wdev->current_bss->pub.channel) | 1559 | !wdev->current_bss->pub.channel) |
| 1563 | goto out; | 1560 | goto wdev_inactive_unlock; |
| 1564 | 1561 | ||
| 1565 | ch = wdev->current_bss->pub.channel; | 1562 | if (!rdev->ops->get_channel || |
| 1566 | if (rdev->ops->get_channel && | 1563 | rdev_get_channel(rdev, wdev, &chandef)) |
| 1567 | !rdev_get_channel(rdev, wdev, &chandef)) | 1564 | cfg80211_chandef_create(&chandef, |
| 1568 | ret = cfg80211_chandef_usable(wiphy, &chandef, | 1565 | wdev->current_bss->pub.channel, |
| 1569 | IEEE80211_CHAN_DISABLED); | 1566 | NL80211_CHAN_NO_HT); |
| 1570 | else | ||
| 1571 | ret = !(ch->flags & IEEE80211_CHAN_DISABLED); | ||
| 1572 | break; | 1567 | break; |
| 1573 | case NL80211_IFTYPE_MONITOR: | 1568 | case NL80211_IFTYPE_MONITOR: |
| 1574 | case NL80211_IFTYPE_AP_VLAN: | 1569 | case NL80211_IFTYPE_AP_VLAN: |
| @@ -1581,9 +1576,26 @@ static bool reg_wdev_chan_valid(struct wiphy *wiphy, struct wireless_dev *wdev) | |||
| 1581 | break; | 1576 | break; |
| 1582 | } | 1577 | } |
| 1583 | 1578 | ||
| 1584 | out: | ||
| 1585 | wdev_unlock(wdev); | 1579 | wdev_unlock(wdev); |
| 1586 | return ret; | 1580 | |
| 1581 | switch (iftype) { | ||
| 1582 | case NL80211_IFTYPE_AP: | ||
| 1583 | case NL80211_IFTYPE_P2P_GO: | ||
| 1584 | case NL80211_IFTYPE_ADHOC: | ||
| 1585 | return cfg80211_reg_can_beacon(wiphy, &chandef, iftype); | ||
| 1586 | case NL80211_IFTYPE_STATION: | ||
| 1587 | case NL80211_IFTYPE_P2P_CLIENT: | ||
| 1588 | return cfg80211_chandef_usable(wiphy, &chandef, | ||
| 1589 | IEEE80211_CHAN_DISABLED); | ||
| 1590 | default: | ||
| 1591 | break; | ||
| 1592 | } | ||
| 1593 | |||
| 1594 | return true; | ||
| 1595 | |||
| 1596 | wdev_inactive_unlock: | ||
| 1597 | wdev_unlock(wdev); | ||
| 1598 | return true; | ||
| 1587 | } | 1599 | } |
| 1588 | 1600 | ||
| 1589 | static void reg_leave_invalid_chans(struct wiphy *wiphy) | 1601 | static void reg_leave_invalid_chans(struct wiphy *wiphy) |
diff --git a/net/wireless/util.c b/net/wireless/util.c index d0ac795445b7..5488c3662f7d 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c | |||
| @@ -308,6 +308,12 @@ unsigned int __attribute_const__ ieee80211_hdrlen(__le16 fc) | |||
| 308 | goto out; | 308 | goto out; |
| 309 | } | 309 | } |
| 310 | 310 | ||
| 311 | if (ieee80211_is_mgmt(fc)) { | ||
| 312 | if (ieee80211_has_order(fc)) | ||
| 313 | hdrlen += IEEE80211_HT_CTL_LEN; | ||
| 314 | goto out; | ||
| 315 | } | ||
| 316 | |||
| 311 | if (ieee80211_is_ctl(fc)) { | 317 | if (ieee80211_is_ctl(fc)) { |
| 312 | /* | 318 | /* |
| 313 | * ACK and CTS are 10 bytes, all others 16. To see how | 319 | * ACK and CTS are 10 bytes, all others 16. To see how |
