aboutsummaryrefslogtreecommitdiffstats
path: root/net/rxrpc/ar-connevent.c
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2007-04-26 18:48:28 -0400
committerDavid S. Miller <davem@davemloft.net>2007-04-26 18:48:28 -0400
commit17926a79320afa9b95df6b977b40cca6d8713cea (patch)
tree5cedff43b69520ad17b86783d3752053686ec99c /net/rxrpc/ar-connevent.c
parente19dff1fdd99a25819af74cf0710e147fff4fd3a (diff)
[AF_RXRPC]: Provide secure RxRPC sockets for use by userspace and kernel both
Provide AF_RXRPC sockets that can be used to talk to AFS servers, or serve answers to AFS clients. KerberosIV security is fully supported. The patches and some example test programs can be found in: http://people.redhat.com/~dhowells/rxrpc/ This will eventually replace the old implementation of kernel-only RxRPC currently resident in net/rxrpc/. Signed-off-by: David Howells <dhowells@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/rxrpc/ar-connevent.c')
-rw-r--r--net/rxrpc/ar-connevent.c387
1 files changed, 387 insertions, 0 deletions
diff --git a/net/rxrpc/ar-connevent.c b/net/rxrpc/ar-connevent.c
new file mode 100644
index 000000000000..4b02815c1ded
--- /dev/null
+++ b/net/rxrpc/ar-connevent.c
@@ -0,0 +1,387 @@
1/* connection-level event handling
2 *
3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 */
11
12#include <linux/module.h>
13#include <linux/net.h>
14#include <linux/skbuff.h>
15#include <linux/errqueue.h>
16#include <linux/udp.h>
17#include <linux/in.h>
18#include <linux/in6.h>
19#include <linux/icmp.h>
20#include <net/sock.h>
21#include <net/af_rxrpc.h>
22#include <net/ip.h>
23#include "ar-internal.h"
24
25/*
26 * pass a connection-level abort onto all calls on that connection
27 */
28static void rxrpc_abort_calls(struct rxrpc_connection *conn, int state,
29 u32 abort_code)
30{
31 struct rxrpc_call *call;
32 struct rb_node *p;
33
34 _enter("{%d},%x", conn->debug_id, abort_code);
35
36 read_lock_bh(&conn->lock);
37
38 for (p = rb_first(&conn->calls); p; p = rb_next(p)) {
39 call = rb_entry(p, struct rxrpc_call, conn_node);
40 write_lock(&call->state_lock);
41 if (call->state <= RXRPC_CALL_COMPLETE) {
42 call->state = state;
43 call->abort_code = abort_code;
44 if (state == RXRPC_CALL_LOCALLY_ABORTED)
45 set_bit(RXRPC_CALL_CONN_ABORT, &call->events);
46 else
47 set_bit(RXRPC_CALL_RCVD_ABORT, &call->events);
48 schedule_work(&call->processor);
49 }
50 write_unlock(&call->state_lock);
51 }
52
53 read_unlock_bh(&conn->lock);
54 _leave("");
55}
56
57/*
58 * generate a connection-level abort
59 */
60static int rxrpc_abort_connection(struct rxrpc_connection *conn,
61 u32 error, u32 abort_code)
62{
63 struct rxrpc_header hdr;
64 struct msghdr msg;
65 struct kvec iov[2];
66 __be32 word;
67 size_t len;
68 int ret;
69
70 _enter("%d,,%u,%u", conn->debug_id, error, abort_code);
71
72 /* generate a connection-level abort */
73 spin_lock_bh(&conn->state_lock);
74 if (conn->state < RXRPC_CONN_REMOTELY_ABORTED) {
75 conn->state = RXRPC_CONN_LOCALLY_ABORTED;
76 conn->error = error;
77 spin_unlock_bh(&conn->state_lock);
78 } else {
79 spin_unlock_bh(&conn->state_lock);
80 _leave(" = 0 [already dead]");
81 return 0;
82 }
83
84 rxrpc_abort_calls(conn, RXRPC_CALL_LOCALLY_ABORTED, abort_code);
85
86 msg.msg_name = &conn->trans->peer->srx.transport.sin;
87 msg.msg_namelen = sizeof(conn->trans->peer->srx.transport.sin);
88 msg.msg_control = NULL;
89 msg.msg_controllen = 0;
90 msg.msg_flags = 0;
91
92 hdr.epoch = conn->epoch;
93 hdr.cid = conn->cid;
94 hdr.callNumber = 0;
95 hdr.seq = 0;
96 hdr.type = RXRPC_PACKET_TYPE_ABORT;
97 hdr.flags = conn->out_clientflag;
98 hdr.userStatus = 0;
99 hdr.securityIndex = conn->security_ix;
100 hdr._rsvd = 0;
101 hdr.serviceId = conn->service_id;
102
103 word = htonl(abort_code);
104
105 iov[0].iov_base = &hdr;
106 iov[0].iov_len = sizeof(hdr);
107 iov[1].iov_base = &word;
108 iov[1].iov_len = sizeof(word);
109
110 len = iov[0].iov_len + iov[1].iov_len;
111
112 hdr.serial = htonl(atomic_inc_return(&conn->serial));
113 _proto("Tx CONN ABORT %%%u { %d }", ntohl(hdr.serial), abort_code);
114
115 ret = kernel_sendmsg(conn->trans->local->socket, &msg, iov, 2, len);
116 if (ret < 0) {
117 _debug("sendmsg failed: %d", ret);
118 return -EAGAIN;
119 }
120
121 _leave(" = 0");
122 return 0;
123}
124
125/*
126 * mark a call as being on a now-secured channel
127 * - must be called with softirqs disabled
128 */
129void rxrpc_call_is_secure(struct rxrpc_call *call)
130{
131 _enter("%p", call);
132 if (call) {
133 read_lock(&call->state_lock);
134 if (call->state < RXRPC_CALL_COMPLETE &&
135 !test_and_set_bit(RXRPC_CALL_SECURED, &call->events))
136 schedule_work(&call->processor);
137 read_unlock(&call->state_lock);
138 }
139}
140
141/*
142 * connection-level Rx packet processor
143 */
144static int rxrpc_process_event(struct rxrpc_connection *conn,
145 struct sk_buff *skb,
146 u32 *_abort_code)
147{
148 struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
149 __be32 tmp;
150 u32 serial;
151 int loop, ret;
152
153 if (conn->state >= RXRPC_CONN_REMOTELY_ABORTED)
154 return -ECONNABORTED;
155
156 serial = ntohl(sp->hdr.serial);
157
158 switch (sp->hdr.type) {
159 case RXRPC_PACKET_TYPE_ABORT:
160 if (skb_copy_bits(skb, 0, &tmp, sizeof(tmp)) < 0)
161 return -EPROTO;
162 _proto("Rx ABORT %%%u { ac=%d }", serial, ntohl(tmp));
163
164 conn->state = RXRPC_CONN_REMOTELY_ABORTED;
165 rxrpc_abort_calls(conn, RXRPC_CALL_REMOTELY_ABORTED,
166 ntohl(tmp));
167 return -ECONNABORTED;
168
169 case RXRPC_PACKET_TYPE_CHALLENGE:
170 if (conn->security)
171 return conn->security->respond_to_challenge(
172 conn, skb, _abort_code);
173 return -EPROTO;
174
175 case RXRPC_PACKET_TYPE_RESPONSE:
176 if (!conn->security)
177 return -EPROTO;
178
179 ret = conn->security->verify_response(conn, skb, _abort_code);
180 if (ret < 0)
181 return ret;
182
183 ret = conn->security->init_connection_security(conn);
184 if (ret < 0)
185 return ret;
186
187 conn->security->prime_packet_security(conn);
188 read_lock_bh(&conn->lock);
189 spin_lock(&conn->state_lock);
190
191 if (conn->state == RXRPC_CONN_SERVER_CHALLENGING) {
192 conn->state = RXRPC_CONN_SERVER;
193 for (loop = 0; loop < RXRPC_MAXCALLS; loop++)
194 rxrpc_call_is_secure(conn->channels[loop]);
195 }
196
197 spin_unlock(&conn->state_lock);
198 read_unlock_bh(&conn->lock);
199 return 0;
200
201 default:
202 return -EPROTO;
203 }
204}
205
206/*
207 * set up security and issue a challenge
208 */
209static void rxrpc_secure_connection(struct rxrpc_connection *conn)
210{
211 u32 abort_code;
212 int ret;
213
214 _enter("{%d}", conn->debug_id);
215
216 ASSERT(conn->security_ix != 0);
217
218 if (!conn->key) {
219 _debug("set up security");
220 ret = rxrpc_init_server_conn_security(conn);
221 switch (ret) {
222 case 0:
223 break;
224 case -ENOENT:
225 abort_code = RX_CALL_DEAD;
226 goto abort;
227 default:
228 abort_code = RXKADNOAUTH;
229 goto abort;
230 }
231 }
232
233 ASSERT(conn->security != NULL);
234
235 if (conn->security->issue_challenge(conn) < 0) {
236 abort_code = RX_CALL_DEAD;
237 ret = -ENOMEM;
238 goto abort;
239 }
240
241 _leave("");
242 return;
243
244abort:
245 _debug("abort %d, %d", ret, abort_code);
246 rxrpc_abort_connection(conn, -ret, abort_code);
247 _leave(" [aborted]");
248}
249
250/*
251 * connection-level event processor
252 */
253void rxrpc_process_connection(struct work_struct *work)
254{
255 struct rxrpc_connection *conn =
256 container_of(work, struct rxrpc_connection, processor);
257 struct rxrpc_skb_priv *sp;
258 struct sk_buff *skb;
259 u32 abort_code = RX_PROTOCOL_ERROR;
260 int ret;
261
262 _enter("{%d}", conn->debug_id);
263
264 atomic_inc(&conn->usage);
265
266 if (test_and_clear_bit(RXRPC_CONN_CHALLENGE, &conn->events)) {
267 rxrpc_secure_connection(conn);
268 rxrpc_put_connection(conn);
269 }
270
271 /* go through the conn-level event packets, releasing the ref on this
272 * connection that each one has when we've finished with it */
273 while ((skb = skb_dequeue(&conn->rx_queue))) {
274 sp = rxrpc_skb(skb);
275
276 ret = rxrpc_process_event(conn, skb, &abort_code);
277 switch (ret) {
278 case -EPROTO:
279 case -EKEYEXPIRED:
280 case -EKEYREJECTED:
281 goto protocol_error;
282 case -EAGAIN:
283 goto requeue_and_leave;
284 case -ECONNABORTED:
285 default:
286 rxrpc_put_connection(conn);
287 rxrpc_free_skb(skb);
288 break;
289 }
290 }
291
292out:
293 rxrpc_put_connection(conn);
294 _leave("");
295 return;
296
297requeue_and_leave:
298 skb_queue_head(&conn->rx_queue, skb);
299 goto out;
300
301protocol_error:
302 if (rxrpc_abort_connection(conn, -ret, abort_code) < 0)
303 goto requeue_and_leave;
304 rxrpc_put_connection(conn);
305 rxrpc_free_skb(skb);
306 _leave(" [EPROTO]");
307 goto out;
308}
309
310/*
311 * reject packets through the local endpoint
312 */
313void rxrpc_reject_packets(struct work_struct *work)
314{
315 union {
316 struct sockaddr sa;
317 struct sockaddr_in sin;
318 } sa;
319 struct rxrpc_skb_priv *sp;
320 struct rxrpc_header hdr;
321 struct rxrpc_local *local;
322 struct sk_buff *skb;
323 struct msghdr msg;
324 struct kvec iov[2];
325 size_t size;
326 __be32 code;
327
328 local = container_of(work, struct rxrpc_local, rejecter);
329 rxrpc_get_local(local);
330
331 _enter("%d", local->debug_id);
332
333 iov[0].iov_base = &hdr;
334 iov[0].iov_len = sizeof(hdr);
335 iov[1].iov_base = &code;
336 iov[1].iov_len = sizeof(code);
337 size = sizeof(hdr) + sizeof(code);
338
339 msg.msg_name = &sa;
340 msg.msg_control = NULL;
341 msg.msg_controllen = 0;
342 msg.msg_flags = 0;
343
344 memset(&sa, 0, sizeof(sa));
345 sa.sa.sa_family = local->srx.transport.family;
346 switch (sa.sa.sa_family) {
347 case AF_INET:
348 msg.msg_namelen = sizeof(sa.sin);
349 break;
350 default:
351 msg.msg_namelen = 0;
352 break;
353 }
354
355 memset(&hdr, 0, sizeof(hdr));
356 hdr.type = RXRPC_PACKET_TYPE_ABORT;
357
358 while ((skb = skb_dequeue(&local->reject_queue))) {
359 sp = rxrpc_skb(skb);
360 switch (sa.sa.sa_family) {
361 case AF_INET:
362 sa.sin.sin_port = udp_hdr(skb)->source;
363 sa.sin.sin_addr.s_addr = ip_hdr(skb)->saddr;
364 code = htonl(skb->priority);
365
366 hdr.epoch = sp->hdr.epoch;
367 hdr.cid = sp->hdr.cid;
368 hdr.callNumber = sp->hdr.callNumber;
369 hdr.serviceId = sp->hdr.serviceId;
370 hdr.flags = sp->hdr.flags;
371 hdr.flags ^= RXRPC_CLIENT_INITIATED;
372 hdr.flags &= RXRPC_CLIENT_INITIATED;
373
374 kernel_sendmsg(local->socket, &msg, iov, 2, size);
375 break;
376
377 default:
378 break;
379 }
380
381 rxrpc_free_skb(skb);
382 rxrpc_put_local(local);
383 }
384
385 rxrpc_put_local(local);
386 _leave("");
387}