diff options
Diffstat (limited to 'net/tipc/socket.c')
-rw-r--r-- | net/tipc/socket.c | 99 |
1 files changed, 92 insertions, 7 deletions
diff --git a/net/tipc/socket.c b/net/tipc/socket.c index d5fa708f037d..bd8e2cdeceef 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * net/tipc/socket.c: TIPC socket API | 2 | * net/tipc/socket.c: TIPC socket API |
3 | * | 3 | * |
4 | * Copyright (c) 2001-2007, 2012 Ericsson AB | 4 | * Copyright (c) 2001-2007, 2012 Ericsson AB |
5 | * Copyright (c) 2004-2008, 2010-2012, Wind River Systems | 5 | * Copyright (c) 2004-2008, 2010-2013, Wind River Systems |
6 | * All rights reserved. | 6 | * All rights reserved. |
7 | * | 7 | * |
8 | * Redistribution and use in source and binary forms, with or without | 8 | * Redistribution and use in source and binary forms, with or without |
@@ -63,12 +63,15 @@ static u32 dispatch(struct tipc_port *tport, struct sk_buff *buf); | |||
63 | static void wakeupdispatch(struct tipc_port *tport); | 63 | static void wakeupdispatch(struct tipc_port *tport); |
64 | static void tipc_data_ready(struct sock *sk, int len); | 64 | static void tipc_data_ready(struct sock *sk, int len); |
65 | static void tipc_write_space(struct sock *sk); | 65 | static void tipc_write_space(struct sock *sk); |
66 | static int release(struct socket *sock); | ||
67 | static int accept(struct socket *sock, struct socket *new_sock, int flags); | ||
66 | 68 | ||
67 | static const struct proto_ops packet_ops; | 69 | static const struct proto_ops packet_ops; |
68 | static const struct proto_ops stream_ops; | 70 | static const struct proto_ops stream_ops; |
69 | static const struct proto_ops msg_ops; | 71 | static const struct proto_ops msg_ops; |
70 | 72 | ||
71 | static struct proto tipc_proto; | 73 | static struct proto tipc_proto; |
74 | static struct proto tipc_proto_kern; | ||
72 | 75 | ||
73 | static int sockets_enabled; | 76 | static int sockets_enabled; |
74 | 77 | ||
@@ -141,7 +144,7 @@ static void reject_rx_queue(struct sock *sk) | |||
141 | } | 144 | } |
142 | 145 | ||
143 | /** | 146 | /** |
144 | * tipc_create - create a TIPC socket | 147 | * tipc_sk_create - create a TIPC socket |
145 | * @net: network namespace (must be default network) | 148 | * @net: network namespace (must be default network) |
146 | * @sock: pre-allocated socket structure | 149 | * @sock: pre-allocated socket structure |
147 | * @protocol: protocol indicator (must be 0) | 150 | * @protocol: protocol indicator (must be 0) |
@@ -152,8 +155,8 @@ static void reject_rx_queue(struct sock *sk) | |||
152 | * | 155 | * |
153 | * Returns 0 on success, errno otherwise | 156 | * Returns 0 on success, errno otherwise |
154 | */ | 157 | */ |
155 | static int tipc_create(struct net *net, struct socket *sock, int protocol, | 158 | static int tipc_sk_create(struct net *net, struct socket *sock, int protocol, |
156 | int kern) | 159 | int kern) |
157 | { | 160 | { |
158 | const struct proto_ops *ops; | 161 | const struct proto_ops *ops; |
159 | socket_state state; | 162 | socket_state state; |
@@ -183,7 +186,11 @@ static int tipc_create(struct net *net, struct socket *sock, int protocol, | |||
183 | } | 186 | } |
184 | 187 | ||
185 | /* Allocate socket's protocol area */ | 188 | /* Allocate socket's protocol area */ |
186 | sk = sk_alloc(net, AF_TIPC, GFP_KERNEL, &tipc_proto); | 189 | if (!kern) |
190 | sk = sk_alloc(net, AF_TIPC, GFP_KERNEL, &tipc_proto); | ||
191 | else | ||
192 | sk = sk_alloc(net, AF_TIPC, GFP_KERNEL, &tipc_proto_kern); | ||
193 | |||
187 | if (sk == NULL) | 194 | if (sk == NULL) |
188 | return -ENOMEM; | 195 | return -ENOMEM; |
189 | 196 | ||
@@ -219,6 +226,78 @@ static int tipc_create(struct net *net, struct socket *sock, int protocol, | |||
219 | } | 226 | } |
220 | 227 | ||
221 | /** | 228 | /** |
229 | * tipc_sock_create_local - create TIPC socket from inside TIPC module | ||
230 | * @type: socket type - SOCK_RDM or SOCK_SEQPACKET | ||
231 | * | ||
232 | * We cannot use sock_creat_kern here because it bumps module user count. | ||
233 | * Since socket owner and creator is the same module we must make sure | ||
234 | * that module count remains zero for module local sockets, otherwise | ||
235 | * we cannot do rmmod. | ||
236 | * | ||
237 | * Returns 0 on success, errno otherwise | ||
238 | */ | ||
239 | int tipc_sock_create_local(int type, struct socket **res) | ||
240 | { | ||
241 | int rc; | ||
242 | struct sock *sk; | ||
243 | |||
244 | rc = sock_create_lite(AF_TIPC, type, 0, res); | ||
245 | if (rc < 0) { | ||
246 | pr_err("Failed to create kernel socket\n"); | ||
247 | return rc; | ||
248 | } | ||
249 | tipc_sk_create(&init_net, *res, 0, 1); | ||
250 | |||
251 | sk = (*res)->sk; | ||
252 | |||
253 | return 0; | ||
254 | } | ||
255 | |||
256 | /** | ||
257 | * tipc_sock_release_local - release socket created by tipc_sock_create_local | ||
258 | * @sock: the socket to be released. | ||
259 | * | ||
260 | * Module reference count is not incremented when such sockets are created, | ||
261 | * so we must keep it from being decremented when they are released. | ||
262 | */ | ||
263 | void tipc_sock_release_local(struct socket *sock) | ||
264 | { | ||
265 | release(sock); | ||
266 | sock->ops = NULL; | ||
267 | sock_release(sock); | ||
268 | } | ||
269 | |||
270 | /** | ||
271 | * tipc_sock_accept_local - accept a connection on a socket created | ||
272 | * with tipc_sock_create_local. Use this function to avoid that | ||
273 | * module reference count is inadvertently incremented. | ||
274 | * | ||
275 | * @sock: the accepting socket | ||
276 | * @newsock: reference to the new socket to be created | ||
277 | * @flags: socket flags | ||
278 | */ | ||
279 | |||
280 | int tipc_sock_accept_local(struct socket *sock, struct socket **newsock, | ||
281 | int flags) | ||
282 | { | ||
283 | struct sock *sk = sock->sk; | ||
284 | int ret; | ||
285 | |||
286 | ret = sock_create_lite(sk->sk_family, sk->sk_type, | ||
287 | sk->sk_protocol, newsock); | ||
288 | if (ret < 0) | ||
289 | return ret; | ||
290 | |||
291 | ret = accept(sock, *newsock, flags); | ||
292 | if (ret < 0) { | ||
293 | sock_release(*newsock); | ||
294 | return ret; | ||
295 | } | ||
296 | (*newsock)->ops = sock->ops; | ||
297 | return ret; | ||
298 | } | ||
299 | |||
300 | /** | ||
222 | * release - destroy a TIPC socket | 301 | * release - destroy a TIPC socket |
223 | * @sock: socket to destroy | 302 | * @sock: socket to destroy |
224 | * | 303 | * |
@@ -1529,7 +1608,7 @@ static int accept(struct socket *sock, struct socket *new_sock, int flags) | |||
1529 | 1608 | ||
1530 | buf = skb_peek(&sk->sk_receive_queue); | 1609 | buf = skb_peek(&sk->sk_receive_queue); |
1531 | 1610 | ||
1532 | res = tipc_create(sock_net(sock->sk), new_sock, 0, 0); | 1611 | res = tipc_sk_create(sock_net(sock->sk), new_sock, 0, 1); |
1533 | if (res) | 1612 | if (res) |
1534 | goto exit; | 1613 | goto exit; |
1535 | 1614 | ||
@@ -1839,7 +1918,7 @@ static const struct proto_ops stream_ops = { | |||
1839 | static const struct net_proto_family tipc_family_ops = { | 1918 | static const struct net_proto_family tipc_family_ops = { |
1840 | .owner = THIS_MODULE, | 1919 | .owner = THIS_MODULE, |
1841 | .family = AF_TIPC, | 1920 | .family = AF_TIPC, |
1842 | .create = tipc_create | 1921 | .create = tipc_sk_create |
1843 | }; | 1922 | }; |
1844 | 1923 | ||
1845 | static struct proto tipc_proto = { | 1924 | static struct proto tipc_proto = { |
@@ -1849,6 +1928,12 @@ static struct proto tipc_proto = { | |||
1849 | .sysctl_rmem = sysctl_tipc_rmem | 1928 | .sysctl_rmem = sysctl_tipc_rmem |
1850 | }; | 1929 | }; |
1851 | 1930 | ||
1931 | static struct proto tipc_proto_kern = { | ||
1932 | .name = "TIPC", | ||
1933 | .obj_size = sizeof(struct tipc_sock), | ||
1934 | .sysctl_rmem = sysctl_tipc_rmem | ||
1935 | }; | ||
1936 | |||
1852 | /** | 1937 | /** |
1853 | * tipc_socket_init - initialize TIPC socket interface | 1938 | * tipc_socket_init - initialize TIPC socket interface |
1854 | * | 1939 | * |