diff options
| author | David S. Miller <davem@davemloft.net> | 2015-09-26 19:08:27 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2015-09-26 19:08:27 -0400 |
| commit | 4963ed48f2c20196d51a447ee87dc2815584fee4 (patch) | |
| tree | a1902f466dafa00453889a4f1e66b00249ce0529 /net/netlink | |
| parent | 4d54d86546f62c7c4a0fe3b36a64c5e3b98ce1a9 (diff) | |
| parent | 518a7cb6980cd640c7f979d29021ad870f60d7d7 (diff) | |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
Conflicts:
net/ipv4/arp.c
The net/ipv4/arp.c conflict was one commit adding a new
local variable while another commit was deleting one.
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/netlink')
| -rw-r--r-- | net/netlink/af_netlink.c | 63 | ||||
| -rw-r--r-- | net/netlink/af_netlink.h | 10 |
2 files changed, 59 insertions, 14 deletions
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 7f86d3b55060..8f060d7f9a0e 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c | |||
| @@ -125,6 +125,24 @@ static inline u32 netlink_group_mask(u32 group) | |||
| 125 | return group ? 1 << (group - 1) : 0; | 125 | return group ? 1 << (group - 1) : 0; |
| 126 | } | 126 | } |
| 127 | 127 | ||
| 128 | static struct sk_buff *netlink_to_full_skb(const struct sk_buff *skb, | ||
| 129 | gfp_t gfp_mask) | ||
| 130 | { | ||
| 131 | unsigned int len = skb_end_offset(skb); | ||
| 132 | struct sk_buff *new; | ||
| 133 | |||
| 134 | new = alloc_skb(len, gfp_mask); | ||
| 135 | if (new == NULL) | ||
| 136 | return NULL; | ||
| 137 | |||
| 138 | NETLINK_CB(new).portid = NETLINK_CB(skb).portid; | ||
| 139 | NETLINK_CB(new).dst_group = NETLINK_CB(skb).dst_group; | ||
| 140 | NETLINK_CB(new).creds = NETLINK_CB(skb).creds; | ||
| 141 | |||
| 142 | memcpy(skb_put(new, len), skb->data, len); | ||
| 143 | return new; | ||
| 144 | } | ||
| 145 | |||
| 128 | int netlink_add_tap(struct netlink_tap *nt) | 146 | int netlink_add_tap(struct netlink_tap *nt) |
| 129 | { | 147 | { |
| 130 | if (unlikely(nt->dev->type != ARPHRD_NETLINK)) | 148 | if (unlikely(nt->dev->type != ARPHRD_NETLINK)) |
| @@ -206,7 +224,11 @@ static int __netlink_deliver_tap_skb(struct sk_buff *skb, | |||
| 206 | int ret = -ENOMEM; | 224 | int ret = -ENOMEM; |
| 207 | 225 | ||
| 208 | dev_hold(dev); | 226 | dev_hold(dev); |
| 209 | nskb = skb_clone(skb, GFP_ATOMIC); | 227 | |
| 228 | if (netlink_skb_is_mmaped(skb) || is_vmalloc_addr(skb->head)) | ||
| 229 | nskb = netlink_to_full_skb(skb, GFP_ATOMIC); | ||
| 230 | else | ||
| 231 | nskb = skb_clone(skb, GFP_ATOMIC); | ||
| 210 | if (nskb) { | 232 | if (nskb) { |
| 211 | nskb->dev = dev; | 233 | nskb->dev = dev; |
| 212 | nskb->protocol = htons((u16) sk->sk_protocol); | 234 | nskb->protocol = htons((u16) sk->sk_protocol); |
| @@ -279,11 +301,6 @@ static void netlink_rcv_wake(struct sock *sk) | |||
| 279 | } | 301 | } |
| 280 | 302 | ||
| 281 | #ifdef CONFIG_NETLINK_MMAP | 303 | #ifdef CONFIG_NETLINK_MMAP |
| 282 | static bool netlink_skb_is_mmaped(const struct sk_buff *skb) | ||
| 283 | { | ||
| 284 | return NETLINK_CB(skb).flags & NETLINK_SKB_MMAPED; | ||
| 285 | } | ||
| 286 | |||
| 287 | static bool netlink_rx_is_mmaped(struct sock *sk) | 304 | static bool netlink_rx_is_mmaped(struct sock *sk) |
| 288 | { | 305 | { |
| 289 | return nlk_sk(sk)->rx_ring.pg_vec != NULL; | 306 | return nlk_sk(sk)->rx_ring.pg_vec != NULL; |
| @@ -846,7 +863,6 @@ static void netlink_ring_set_copied(struct sock *sk, struct sk_buff *skb) | |||
| 846 | } | 863 | } |
| 847 | 864 | ||
| 848 | #else /* CONFIG_NETLINK_MMAP */ | 865 | #else /* CONFIG_NETLINK_MMAP */ |
| 849 | #define netlink_skb_is_mmaped(skb) false | ||
| 850 | #define netlink_rx_is_mmaped(sk) false | 866 | #define netlink_rx_is_mmaped(sk) false |
| 851 | #define netlink_tx_is_mmaped(sk) false | 867 | #define netlink_tx_is_mmaped(sk) false |
| 852 | #define netlink_mmap sock_no_mmap | 868 | #define netlink_mmap sock_no_mmap |
| @@ -1094,8 +1110,8 @@ static int netlink_insert(struct sock *sk, u32 portid) | |||
| 1094 | 1110 | ||
| 1095 | lock_sock(sk); | 1111 | lock_sock(sk); |
| 1096 | 1112 | ||
| 1097 | err = -EBUSY; | 1113 | err = nlk_sk(sk)->portid == portid ? 0 : -EBUSY; |
| 1098 | if (nlk_sk(sk)->portid) | 1114 | if (nlk_sk(sk)->bound) |
| 1099 | goto err; | 1115 | goto err; |
| 1100 | 1116 | ||
| 1101 | err = -ENOMEM; | 1117 | err = -ENOMEM; |
| @@ -1115,10 +1131,14 @@ static int netlink_insert(struct sock *sk, u32 portid) | |||
| 1115 | err = -EOVERFLOW; | 1131 | err = -EOVERFLOW; |
| 1116 | if (err == -EEXIST) | 1132 | if (err == -EEXIST) |
| 1117 | err = -EADDRINUSE; | 1133 | err = -EADDRINUSE; |
| 1118 | nlk_sk(sk)->portid = 0; | ||
| 1119 | sock_put(sk); | 1134 | sock_put(sk); |
| 1135 | goto err; | ||
| 1120 | } | 1136 | } |
| 1121 | 1137 | ||
| 1138 | /* We need to ensure that the socket is hashed and visible. */ | ||
| 1139 | smp_wmb(); | ||
| 1140 | nlk_sk(sk)->bound = portid; | ||
| 1141 | |||
| 1122 | err: | 1142 | err: |
| 1123 | release_sock(sk); | 1143 | release_sock(sk); |
| 1124 | return err; | 1144 | return err; |
| @@ -1503,6 +1523,7 @@ static int netlink_bind(struct socket *sock, struct sockaddr *addr, | |||
| 1503 | struct sockaddr_nl *nladdr = (struct sockaddr_nl *)addr; | 1523 | struct sockaddr_nl *nladdr = (struct sockaddr_nl *)addr; |
| 1504 | int err; | 1524 | int err; |
| 1505 | long unsigned int groups = nladdr->nl_groups; | 1525 | long unsigned int groups = nladdr->nl_groups; |
| 1526 | bool bound; | ||
| 1506 | 1527 | ||
| 1507 | if (addr_len < sizeof(struct sockaddr_nl)) | 1528 | if (addr_len < sizeof(struct sockaddr_nl)) |
| 1508 | return -EINVAL; | 1529 | return -EINVAL; |
| @@ -1519,9 +1540,14 @@ static int netlink_bind(struct socket *sock, struct sockaddr *addr, | |||
| 1519 | return err; | 1540 | return err; |
| 1520 | } | 1541 | } |
| 1521 | 1542 | ||
| 1522 | if (nlk->portid) | 1543 | bound = nlk->bound; |
| 1544 | if (bound) { | ||
| 1545 | /* Ensure nlk->portid is up-to-date. */ | ||
| 1546 | smp_rmb(); | ||
| 1547 | |||
| 1523 | if (nladdr->nl_pid != nlk->portid) | 1548 | if (nladdr->nl_pid != nlk->portid) |
| 1524 | return -EINVAL; | 1549 | return -EINVAL; |
| 1550 | } | ||
| 1525 | 1551 | ||
| 1526 | if (nlk->netlink_bind && groups) { | 1552 | if (nlk->netlink_bind && groups) { |
| 1527 | int group; | 1553 | int group; |
| @@ -1537,7 +1563,10 @@ static int netlink_bind(struct socket *sock, struct sockaddr *addr, | |||
| 1537 | } | 1563 | } |
| 1538 | } | 1564 | } |
| 1539 | 1565 | ||
| 1540 | if (!nlk->portid) { | 1566 | /* No need for barriers here as we return to user-space without |
| 1567 | * using any of the bound attributes. | ||
| 1568 | */ | ||
| 1569 | if (!bound) { | ||
| 1541 | err = nladdr->nl_pid ? | 1570 | err = nladdr->nl_pid ? |
| 1542 | netlink_insert(sk, nladdr->nl_pid) : | 1571 | netlink_insert(sk, nladdr->nl_pid) : |
| 1543 | netlink_autobind(sock); | 1572 | netlink_autobind(sock); |
| @@ -1585,7 +1614,10 @@ static int netlink_connect(struct socket *sock, struct sockaddr *addr, | |||
| 1585 | !netlink_allowed(sock, NL_CFG_F_NONROOT_SEND)) | 1614 | !netlink_allowed(sock, NL_CFG_F_NONROOT_SEND)) |
| 1586 | return -EPERM; | 1615 | return -EPERM; |
| 1587 | 1616 | ||
| 1588 | if (!nlk->portid) | 1617 | /* No need for barriers here as we return to user-space without |
| 1618 | * using any of the bound attributes. | ||
| 1619 | */ | ||
| 1620 | if (!nlk->bound) | ||
| 1589 | err = netlink_autobind(sock); | 1621 | err = netlink_autobind(sock); |
| 1590 | 1622 | ||
| 1591 | if (err == 0) { | 1623 | if (err == 0) { |
| @@ -2426,10 +2458,13 @@ static int netlink_sendmsg(struct socket *sock, struct msghdr *msg, size_t len) | |||
| 2426 | dst_group = nlk->dst_group; | 2458 | dst_group = nlk->dst_group; |
| 2427 | } | 2459 | } |
| 2428 | 2460 | ||
| 2429 | if (!nlk->portid) { | 2461 | if (!nlk->bound) { |
| 2430 | err = netlink_autobind(sock); | 2462 | err = netlink_autobind(sock); |
| 2431 | if (err) | 2463 | if (err) |
| 2432 | goto out; | 2464 | goto out; |
| 2465 | } else { | ||
| 2466 | /* Ensure nlk is hashed and visible. */ | ||
| 2467 | smp_rmb(); | ||
| 2433 | } | 2468 | } |
| 2434 | 2469 | ||
| 2435 | /* It's a really convoluted way for userland to ask for mmaped | 2470 | /* It's a really convoluted way for userland to ask for mmaped |
diff --git a/net/netlink/af_netlink.h b/net/netlink/af_netlink.h index 89008405d6b4..14437d9b1965 100644 --- a/net/netlink/af_netlink.h +++ b/net/netlink/af_netlink.h | |||
| @@ -35,6 +35,7 @@ struct netlink_sock { | |||
| 35 | unsigned long state; | 35 | unsigned long state; |
| 36 | size_t max_recvmsg_len; | 36 | size_t max_recvmsg_len; |
| 37 | wait_queue_head_t wait; | 37 | wait_queue_head_t wait; |
| 38 | bool bound; | ||
| 38 | bool cb_running; | 39 | bool cb_running; |
| 39 | struct netlink_callback cb; | 40 | struct netlink_callback cb; |
| 40 | struct mutex *cb_mutex; | 41 | struct mutex *cb_mutex; |
| @@ -59,6 +60,15 @@ static inline struct netlink_sock *nlk_sk(struct sock *sk) | |||
| 59 | return container_of(sk, struct netlink_sock, sk); | 60 | return container_of(sk, struct netlink_sock, sk); |
| 60 | } | 61 | } |
| 61 | 62 | ||
| 63 | static inline bool netlink_skb_is_mmaped(const struct sk_buff *skb) | ||
| 64 | { | ||
| 65 | #ifdef CONFIG_NETLINK_MMAP | ||
| 66 | return NETLINK_CB(skb).flags & NETLINK_SKB_MMAPED; | ||
| 67 | #else | ||
| 68 | return false; | ||
| 69 | #endif /* CONFIG_NETLINK_MMAP */ | ||
| 70 | } | ||
| 71 | |||
| 62 | struct netlink_table { | 72 | struct netlink_table { |
| 63 | struct rhashtable hash; | 73 | struct rhashtable hash; |
| 64 | struct hlist_head mc_list; | 74 | struct hlist_head mc_list; |
