diff options
Diffstat (limited to 'net/rxrpc/ar-connevent.c')
-rw-r--r-- | net/rxrpc/ar-connevent.c | 387 |
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 | */ | ||
28 | static 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 | */ | ||
60 | static 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 | */ | ||
129 | void 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 | */ | ||
144 | static 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 | */ | ||
209 | static 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 | |||
244 | abort: | ||
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 | */ | ||
253 | void 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 | |||
292 | out: | ||
293 | rxrpc_put_connection(conn); | ||
294 | _leave(""); | ||
295 | return; | ||
296 | |||
297 | requeue_and_leave: | ||
298 | skb_queue_head(&conn->rx_queue, skb); | ||
299 | goto out; | ||
300 | |||
301 | protocol_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 | */ | ||
313 | void 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 | } | ||