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; |