blob: e37df8d5fe707968d0720de94b45c6a4bf5d8f2e [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/fs/ncpfs/sock.c
3 *
4 * Copyright (C) 1992, 1993 Rick Sladkey
5 *
6 * Modified 1995, 1996 by Volker Lendecke to be usable for ncp
7 * Modified 1997 Peter Waltenberg, Bill Hawes, David Woodhouse for 2.1 dcache
8 *
9 */
10
Linus Torvalds1da177e2005-04-16 15:20:36 -070011
12#include <linux/time.h>
13#include <linux/errno.h>
14#include <linux/socket.h>
15#include <linux/fcntl.h>
16#include <linux/stat.h>
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +010017#include <linux/string.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070018#include <asm/uaccess.h>
19#include <linux/in.h>
20#include <linux/net.h>
21#include <linux/mm.h>
22#include <linux/netdevice.h>
23#include <linux/signal.h>
24#include <net/scm.h>
25#include <net/sock.h>
26#include <linux/ipx.h>
27#include <linux/poll.h>
28#include <linux/file.h>
29
30#include <linux/ncp_fs.h>
31
32#include "ncpsign_kernel.h"
33
34static int _recv(struct socket *sock, void *buf, int size, unsigned flags)
35{
36 struct msghdr msg = {NULL, };
37 struct kvec iov = {buf, size};
38 return kernel_recvmsg(sock, &msg, &iov, 1, size, flags);
39}
40
41static inline int do_send(struct socket *sock, struct kvec *vec, int count,
42 int len, unsigned flags)
43{
44 struct msghdr msg = { .msg_flags = flags };
45 return kernel_sendmsg(sock, &msg, vec, count, len);
46}
47
48static int _send(struct socket *sock, const void *buff, int len)
49{
50 struct kvec vec;
51 vec.iov_base = (void *) buff;
52 vec.iov_len = len;
53 return do_send(sock, &vec, 1, len, 0);
54}
55
56struct ncp_request_reply {
57 struct list_head req;
58 wait_queue_head_t wq;
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +010059 atomic_t refs;
60 unsigned char* reply_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -070061 size_t datalen;
62 int result;
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +010063 enum { RQ_DONE, RQ_INPROGRESS, RQ_QUEUED, RQ_IDLE, RQ_ABANDONED } status;
Linus Torvalds1da177e2005-04-16 15:20:36 -070064 struct kvec* tx_ciov;
65 size_t tx_totallen;
66 size_t tx_iovlen;
67 struct kvec tx_iov[3];
68 u_int16_t tx_type;
69 u_int32_t sign[6];
70};
71
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +010072static inline struct ncp_request_reply* ncp_alloc_req(void)
73{
74 struct ncp_request_reply *req;
75
76 req = kmalloc(sizeof(struct ncp_request_reply), GFP_KERNEL);
77 if (!req)
78 return NULL;
79
80 init_waitqueue_head(&req->wq);
81 atomic_set(&req->refs, (1));
82 req->status = RQ_IDLE;
83
84 return req;
85}
86
87static void ncp_req_get(struct ncp_request_reply *req)
88{
89 atomic_inc(&req->refs);
90}
91
92static void ncp_req_put(struct ncp_request_reply *req)
93{
94 if (atomic_dec_and_test(&req->refs))
95 kfree(req);
96}
97
Linus Torvalds1da177e2005-04-16 15:20:36 -070098void ncp_tcp_data_ready(struct sock *sk, int len)
99{
100 struct ncp_server *server = sk->sk_user_data;
101
102 server->data_ready(sk, len);
103 schedule_work(&server->rcv.tq);
104}
105
106void ncp_tcp_error_report(struct sock *sk)
107{
108 struct ncp_server *server = sk->sk_user_data;
109
110 server->error_report(sk);
111 schedule_work(&server->rcv.tq);
112}
113
114void ncp_tcp_write_space(struct sock *sk)
115{
116 struct ncp_server *server = sk->sk_user_data;
117
118 /* We do not need any locking: we first set tx.creq, and then we do sendmsg,
119 not vice versa... */
120 server->write_space(sk);
121 if (server->tx.creq)
122 schedule_work(&server->tx.tq);
123}
124
125void ncpdgram_timeout_call(unsigned long v)
126{
127 struct ncp_server *server = (void*)v;
128
129 schedule_work(&server->timeout_tq);
130}
131
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100132static inline void ncp_finish_request(struct ncp_server *server, struct ncp_request_reply *req, int result)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133{
134 req->result = result;
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100135 if (req->status != RQ_ABANDONED)
136 memcpy(req->reply_buf, server->rxbuf, req->datalen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137 req->status = RQ_DONE;
138 wake_up_all(&req->wq);
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100139 ncp_req_put(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140}
141
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100142static void __abort_ncp_connection(struct ncp_server *server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143{
144 struct ncp_request_reply *req;
145
146 ncp_invalidate_conn(server);
147 del_timer(&server->timeout_tm);
148 while (!list_empty(&server->tx.requests)) {
149 req = list_entry(server->tx.requests.next, struct ncp_request_reply, req);
150
151 list_del_init(&req->req);
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100152 ncp_finish_request(server, req, -EIO);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153 }
154 req = server->rcv.creq;
155 if (req) {
156 server->rcv.creq = NULL;
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100157 ncp_finish_request(server, req, -EIO);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158 server->rcv.ptr = NULL;
159 server->rcv.state = 0;
160 }
161 req = server->tx.creq;
162 if (req) {
163 server->tx.creq = NULL;
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100164 ncp_finish_request(server, req, -EIO);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165 }
166}
167
168static inline int get_conn_number(struct ncp_reply_header *rp)
169{
170 return rp->conn_low | (rp->conn_high << 8);
171}
172
173static inline void __ncp_abort_request(struct ncp_server *server, struct ncp_request_reply *req, int err)
174{
175 /* If req is done, we got signal, but we also received answer... */
176 switch (req->status) {
177 case RQ_IDLE:
178 case RQ_DONE:
179 break;
180 case RQ_QUEUED:
181 list_del_init(&req->req);
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100182 ncp_finish_request(server, req, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183 break;
184 case RQ_INPROGRESS:
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100185 req->status = RQ_ABANDONED;
186 break;
187 case RQ_ABANDONED:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188 break;
189 }
190}
191
192static inline void ncp_abort_request(struct ncp_server *server, struct ncp_request_reply *req, int err)
193{
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800194 mutex_lock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195 __ncp_abort_request(server, req, err);
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800196 mutex_unlock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197}
198
199static inline void __ncptcp_abort(struct ncp_server *server)
200{
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100201 __abort_ncp_connection(server);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202}
203
204static int ncpdgram_send(struct socket *sock, struct ncp_request_reply *req)
205{
206 struct kvec vec[3];
207 /* sock_sendmsg updates iov pointers for us :-( */
208 memcpy(vec, req->tx_ciov, req->tx_iovlen * sizeof(vec[0]));
209 return do_send(sock, vec, req->tx_iovlen,
210 req->tx_totallen, MSG_DONTWAIT);
211}
212
213static void __ncptcp_try_send(struct ncp_server *server)
214{
215 struct ncp_request_reply *rq;
216 struct kvec *iov;
217 struct kvec iovc[3];
218 int result;
219
220 rq = server->tx.creq;
221 if (!rq)
222 return;
223
224 /* sock_sendmsg updates iov pointers for us :-( */
225 memcpy(iovc, rq->tx_ciov, rq->tx_iovlen * sizeof(iov[0]));
226 result = do_send(server->ncp_sock, iovc, rq->tx_iovlen,
227 rq->tx_totallen, MSG_NOSIGNAL | MSG_DONTWAIT);
228
229 if (result == -EAGAIN)
230 return;
231
232 if (result < 0) {
233 printk(KERN_ERR "ncpfs: tcp: Send failed: %d\n", result);
234 __ncp_abort_request(server, rq, result);
235 return;
236 }
237 if (result >= rq->tx_totallen) {
238 server->rcv.creq = rq;
239 server->tx.creq = NULL;
240 return;
241 }
242 rq->tx_totallen -= result;
243 iov = rq->tx_ciov;
244 while (iov->iov_len <= result) {
245 result -= iov->iov_len;
246 iov++;
247 rq->tx_iovlen--;
248 }
249 iov->iov_base += result;
250 iov->iov_len -= result;
251 rq->tx_ciov = iov;
252}
253
254static inline void ncp_init_header(struct ncp_server *server, struct ncp_request_reply *req, struct ncp_request_header *h)
255{
256 req->status = RQ_INPROGRESS;
257 h->conn_low = server->connection;
258 h->conn_high = server->connection >> 8;
259 h->sequence = ++server->sequence;
260}
261
262static void ncpdgram_start_request(struct ncp_server *server, struct ncp_request_reply *req)
263{
264 size_t signlen;
265 struct ncp_request_header* h;
266
267 req->tx_ciov = req->tx_iov + 1;
268
269 h = req->tx_iov[1].iov_base;
270 ncp_init_header(server, req, h);
271 signlen = sign_packet(server, req->tx_iov[1].iov_base + sizeof(struct ncp_request_header) - 1,
272 req->tx_iov[1].iov_len - sizeof(struct ncp_request_header) + 1,
273 cpu_to_le32(req->tx_totallen), req->sign);
274 if (signlen) {
275 req->tx_ciov[1].iov_base = req->sign;
276 req->tx_ciov[1].iov_len = signlen;
277 req->tx_iovlen += 1;
278 req->tx_totallen += signlen;
279 }
280 server->rcv.creq = req;
281 server->timeout_last = server->m.time_out;
282 server->timeout_retries = server->m.retry_count;
283 ncpdgram_send(server->ncp_sock, req);
284 mod_timer(&server->timeout_tm, jiffies + server->m.time_out);
285}
286
287#define NCP_TCP_XMIT_MAGIC (0x446D6454)
288#define NCP_TCP_XMIT_VERSION (1)
289#define NCP_TCP_RCVD_MAGIC (0x744E6350)
290
291static void ncptcp_start_request(struct ncp_server *server, struct ncp_request_reply *req)
292{
293 size_t signlen;
294 struct ncp_request_header* h;
295
296 req->tx_ciov = req->tx_iov;
297 h = req->tx_iov[1].iov_base;
298 ncp_init_header(server, req, h);
299 signlen = sign_packet(server, req->tx_iov[1].iov_base + sizeof(struct ncp_request_header) - 1,
300 req->tx_iov[1].iov_len - sizeof(struct ncp_request_header) + 1,
301 cpu_to_be32(req->tx_totallen + 24), req->sign + 4) + 16;
302
303 req->sign[0] = htonl(NCP_TCP_XMIT_MAGIC);
304 req->sign[1] = htonl(req->tx_totallen + signlen);
305 req->sign[2] = htonl(NCP_TCP_XMIT_VERSION);
306 req->sign[3] = htonl(req->datalen + 8);
307 req->tx_iov[0].iov_base = req->sign;
308 req->tx_iov[0].iov_len = signlen;
309 req->tx_iovlen += 1;
310 req->tx_totallen += signlen;
311
312 server->tx.creq = req;
313 __ncptcp_try_send(server);
314}
315
316static inline void __ncp_start_request(struct ncp_server *server, struct ncp_request_reply *req)
317{
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100318 /* we copy the data so that we do not depend on the caller
319 staying alive */
320 memcpy(server->txbuf, req->tx_iov[1].iov_base, req->tx_iov[1].iov_len);
321 req->tx_iov[1].iov_base = server->txbuf;
322
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323 if (server->ncp_sock->type == SOCK_STREAM)
324 ncptcp_start_request(server, req);
325 else
326 ncpdgram_start_request(server, req);
327}
328
329static int ncp_add_request(struct ncp_server *server, struct ncp_request_reply *req)
330{
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800331 mutex_lock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332 if (!ncp_conn_valid(server)) {
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800333 mutex_unlock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334 printk(KERN_ERR "ncpfs: tcp: Server died\n");
335 return -EIO;
336 }
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100337 ncp_req_get(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338 if (server->tx.creq || server->rcv.creq) {
339 req->status = RQ_QUEUED;
340 list_add_tail(&req->req, &server->tx.requests);
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800341 mutex_unlock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342 return 0;
343 }
344 __ncp_start_request(server, req);
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800345 mutex_unlock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346 return 0;
347}
348
349static void __ncp_next_request(struct ncp_server *server)
350{
351 struct ncp_request_reply *req;
352
353 server->rcv.creq = NULL;
354 if (list_empty(&server->tx.requests)) {
355 return;
356 }
357 req = list_entry(server->tx.requests.next, struct ncp_request_reply, req);
358 list_del_init(&req->req);
359 __ncp_start_request(server, req);
360}
361
362static void info_server(struct ncp_server *server, unsigned int id, const void * data, size_t len)
363{
364 if (server->info_sock) {
365 struct kvec iov[2];
366 __be32 hdr[2];
367
368 hdr[0] = cpu_to_be32(len + 8);
369 hdr[1] = cpu_to_be32(id);
370
371 iov[0].iov_base = hdr;
372 iov[0].iov_len = 8;
373 iov[1].iov_base = (void *) data;
374 iov[1].iov_len = len;
375
376 do_send(server->info_sock, iov, 2, len + 8, MSG_NOSIGNAL);
377 }
378}
379
David Howellsc4028952006-11-22 14:57:56 +0000380void ncpdgram_rcv_proc(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381{
David Howellsc4028952006-11-22 14:57:56 +0000382 struct ncp_server *server =
383 container_of(work, struct ncp_server, rcv.tq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384 struct socket* sock;
385
386 sock = server->ncp_sock;
387
388 while (1) {
389 struct ncp_reply_header reply;
390 int result;
391
392 result = _recv(sock, &reply, sizeof(reply), MSG_PEEK | MSG_DONTWAIT);
393 if (result < 0) {
394 break;
395 }
396 if (result >= sizeof(reply)) {
397 struct ncp_request_reply *req;
398
399 if (reply.type == NCP_WATCHDOG) {
400 unsigned char buf[10];
401
402 if (server->connection != get_conn_number(&reply)) {
403 goto drop;
404 }
405 result = _recv(sock, buf, sizeof(buf), MSG_DONTWAIT);
406 if (result < 0) {
407 DPRINTK("recv failed with %d\n", result);
408 continue;
409 }
410 if (result < 10) {
411 DPRINTK("too short (%u) watchdog packet\n", result);
412 continue;
413 }
414 if (buf[9] != '?') {
415 DPRINTK("bad signature (%02X) in watchdog packet\n", buf[9]);
416 continue;
417 }
418 buf[9] = 'Y';
419 _send(sock, buf, sizeof(buf));
420 continue;
421 }
422 if (reply.type != NCP_POSITIVE_ACK && reply.type != NCP_REPLY) {
423 result = _recv(sock, server->unexpected_packet.data, sizeof(server->unexpected_packet.data), MSG_DONTWAIT);
424 if (result < 0) {
425 continue;
426 }
427 info_server(server, 0, server->unexpected_packet.data, result);
428 continue;
429 }
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800430 mutex_lock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431 req = server->rcv.creq;
432 if (req && (req->tx_type == NCP_ALLOC_SLOT_REQUEST || (server->sequence == reply.sequence &&
433 server->connection == get_conn_number(&reply)))) {
434 if (reply.type == NCP_POSITIVE_ACK) {
435 server->timeout_retries = server->m.retry_count;
436 server->timeout_last = NCP_MAX_RPC_TIMEOUT;
437 mod_timer(&server->timeout_tm, jiffies + NCP_MAX_RPC_TIMEOUT);
438 } else if (reply.type == NCP_REPLY) {
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100439 result = _recv(sock, server->rxbuf, req->datalen, MSG_DONTWAIT);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440#ifdef CONFIG_NCPFS_PACKET_SIGNING
441 if (result >= 0 && server->sign_active && req->tx_type != NCP_DEALLOC_SLOT_REQUEST) {
442 if (result < 8 + 8) {
443 result = -EIO;
444 } else {
445 unsigned int hdrl;
446
447 result -= 8;
448 hdrl = sock->sk->sk_family == AF_INET ? 8 : 6;
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100449 if (sign_verify_reply(server, server->rxbuf + hdrl, result - hdrl, cpu_to_le32(result), server->rxbuf + result)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450 printk(KERN_INFO "ncpfs: Signature violation\n");
451 result = -EIO;
452 }
453 }
454 }
455#endif
456 del_timer(&server->timeout_tm);
457 server->rcv.creq = NULL;
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100458 ncp_finish_request(server, req, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459 __ncp_next_request(server);
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800460 mutex_unlock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461 continue;
462 }
463 }
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800464 mutex_unlock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465 }
466drop:;
467 _recv(sock, &reply, sizeof(reply), MSG_DONTWAIT);
468 }
469}
470
471static void __ncpdgram_timeout_proc(struct ncp_server *server)
472{
473 /* If timer is pending, we are processing another request... */
474 if (!timer_pending(&server->timeout_tm)) {
475 struct ncp_request_reply* req;
476
477 req = server->rcv.creq;
478 if (req) {
479 int timeout;
480
481 if (server->m.flags & NCP_MOUNT_SOFT) {
482 if (server->timeout_retries-- == 0) {
483 __ncp_abort_request(server, req, -ETIMEDOUT);
484 return;
485 }
486 }
487 /* Ignore errors */
488 ncpdgram_send(server->ncp_sock, req);
489 timeout = server->timeout_last << 1;
490 if (timeout > NCP_MAX_RPC_TIMEOUT) {
491 timeout = NCP_MAX_RPC_TIMEOUT;
492 }
493 server->timeout_last = timeout;
494 mod_timer(&server->timeout_tm, jiffies + timeout);
495 }
496 }
497}
498
David Howellsc4028952006-11-22 14:57:56 +0000499void ncpdgram_timeout_proc(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500{
David Howellsc4028952006-11-22 14:57:56 +0000501 struct ncp_server *server =
502 container_of(work, struct ncp_server, timeout_tq);
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800503 mutex_lock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504 __ncpdgram_timeout_proc(server);
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800505 mutex_unlock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506}
507
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508static int do_tcp_rcv(struct ncp_server *server, void *buffer, size_t len)
509{
510 int result;
511
512 if (buffer) {
513 result = _recv(server->ncp_sock, buffer, len, MSG_DONTWAIT);
514 } else {
515 static unsigned char dummy[1024];
516
517 if (len > sizeof(dummy)) {
518 len = sizeof(dummy);
519 }
520 result = _recv(server->ncp_sock, dummy, len, MSG_DONTWAIT);
521 }
522 if (result < 0) {
523 return result;
524 }
525 if (result > len) {
526 printk(KERN_ERR "ncpfs: tcp: bug in recvmsg (%u > %Zu)\n", result, len);
527 return -EIO;
528 }
529 return result;
530}
531
532static int __ncptcp_rcv_proc(struct ncp_server *server)
533{
534 /* We have to check the result, so store the complete header */
535 while (1) {
536 int result;
537 struct ncp_request_reply *req;
538 int datalen;
539 int type;
540
541 while (server->rcv.len) {
542 result = do_tcp_rcv(server, server->rcv.ptr, server->rcv.len);
543 if (result == -EAGAIN) {
544 return 0;
545 }
546 if (result <= 0) {
547 req = server->rcv.creq;
548 if (req) {
549 __ncp_abort_request(server, req, -EIO);
550 } else {
551 __ncptcp_abort(server);
552 }
553 if (result < 0) {
554 printk(KERN_ERR "ncpfs: tcp: error in recvmsg: %d\n", result);
555 } else {
556 DPRINTK(KERN_ERR "ncpfs: tcp: EOF\n");
557 }
558 return -EIO;
559 }
560 if (server->rcv.ptr) {
561 server->rcv.ptr += result;
562 }
563 server->rcv.len -= result;
564 }
565 switch (server->rcv.state) {
566 case 0:
567 if (server->rcv.buf.magic != htonl(NCP_TCP_RCVD_MAGIC)) {
568 printk(KERN_ERR "ncpfs: tcp: Unexpected reply type %08X\n", ntohl(server->rcv.buf.magic));
569 __ncptcp_abort(server);
570 return -EIO;
571 }
572 datalen = ntohl(server->rcv.buf.len) & 0x0FFFFFFF;
573 if (datalen < 10) {
574 printk(KERN_ERR "ncpfs: tcp: Unexpected reply len %d\n", datalen);
575 __ncptcp_abort(server);
576 return -EIO;
577 }
578#ifdef CONFIG_NCPFS_PACKET_SIGNING
579 if (server->sign_active) {
580 if (datalen < 18) {
581 printk(KERN_ERR "ncpfs: tcp: Unexpected reply len %d\n", datalen);
582 __ncptcp_abort(server);
583 return -EIO;
584 }
585 server->rcv.buf.len = datalen - 8;
586 server->rcv.ptr = (unsigned char*)&server->rcv.buf.p1;
587 server->rcv.len = 8;
588 server->rcv.state = 4;
589 break;
590 }
591#endif
592 type = ntohs(server->rcv.buf.type);
593#ifdef CONFIG_NCPFS_PACKET_SIGNING
594cont:;
595#endif
596 if (type != NCP_REPLY) {
597 if (datalen - 8 <= sizeof(server->unexpected_packet.data)) {
598 *(__u16*)(server->unexpected_packet.data) = htons(type);
599 server->unexpected_packet.len = datalen - 8;
600
601 server->rcv.state = 5;
602 server->rcv.ptr = server->unexpected_packet.data + 2;
603 server->rcv.len = datalen - 10;
604 break;
605 }
606 DPRINTK("ncpfs: tcp: Unexpected NCP type %02X\n", type);
607skipdata2:;
608 server->rcv.state = 2;
609skipdata:;
610 server->rcv.ptr = NULL;
611 server->rcv.len = datalen - 10;
612 break;
613 }
614 req = server->rcv.creq;
615 if (!req) {
616 DPRINTK(KERN_ERR "ncpfs: Reply without appropriate request\n");
617 goto skipdata2;
618 }
619 if (datalen > req->datalen + 8) {
620 printk(KERN_ERR "ncpfs: tcp: Unexpected reply len %d (expected at most %Zd)\n", datalen, req->datalen + 8);
621 server->rcv.state = 3;
622 goto skipdata;
623 }
624 req->datalen = datalen - 8;
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100625 ((struct ncp_reply_header*)server->rxbuf)->type = NCP_REPLY;
626 server->rcv.ptr = server->rxbuf + 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627 server->rcv.len = datalen - 10;
628 server->rcv.state = 1;
629 break;
630#ifdef CONFIG_NCPFS_PACKET_SIGNING
631 case 4:
632 datalen = server->rcv.buf.len;
633 type = ntohs(server->rcv.buf.type2);
634 goto cont;
635#endif
636 case 1:
637 req = server->rcv.creq;
638 if (req->tx_type != NCP_ALLOC_SLOT_REQUEST) {
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100639 if (((struct ncp_reply_header*)server->rxbuf)->sequence != server->sequence) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640 printk(KERN_ERR "ncpfs: tcp: Bad sequence number\n");
641 __ncp_abort_request(server, req, -EIO);
642 return -EIO;
643 }
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100644 if ((((struct ncp_reply_header*)server->rxbuf)->conn_low | (((struct ncp_reply_header*)server->rxbuf)->conn_high << 8)) != server->connection) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 printk(KERN_ERR "ncpfs: tcp: Connection number mismatch\n");
646 __ncp_abort_request(server, req, -EIO);
647 return -EIO;
648 }
649 }
650#ifdef CONFIG_NCPFS_PACKET_SIGNING
651 if (server->sign_active && req->tx_type != NCP_DEALLOC_SLOT_REQUEST) {
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100652 if (sign_verify_reply(server, server->rxbuf + 6, req->datalen - 6, cpu_to_be32(req->datalen + 16), &server->rcv.buf.type)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653 printk(KERN_ERR "ncpfs: tcp: Signature violation\n");
654 __ncp_abort_request(server, req, -EIO);
655 return -EIO;
656 }
657 }
658#endif
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100659 ncp_finish_request(server, req, req->datalen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660 nextreq:;
661 __ncp_next_request(server);
662 case 2:
663 next:;
664 server->rcv.ptr = (unsigned char*)&server->rcv.buf;
665 server->rcv.len = 10;
666 server->rcv.state = 0;
667 break;
668 case 3:
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100669 ncp_finish_request(server, server->rcv.creq, -EIO);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 goto nextreq;
671 case 5:
672 info_server(server, 0, server->unexpected_packet.data, server->unexpected_packet.len);
673 goto next;
674 }
675 }
676}
677
David Howellsc4028952006-11-22 14:57:56 +0000678void ncp_tcp_rcv_proc(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679{
David Howellsc4028952006-11-22 14:57:56 +0000680 struct ncp_server *server =
681 container_of(work, struct ncp_server, rcv.tq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800683 mutex_lock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 __ncptcp_rcv_proc(server);
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800685 mutex_unlock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686}
687
David Howellsc4028952006-11-22 14:57:56 +0000688void ncp_tcp_tx_proc(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689{
David Howellsc4028952006-11-22 14:57:56 +0000690 struct ncp_server *server =
691 container_of(work, struct ncp_server, tx.tq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800693 mutex_lock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694 __ncptcp_try_send(server);
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800695 mutex_unlock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696}
697
698static int do_ncp_rpc_call(struct ncp_server *server, int size,
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100699 unsigned char* reply_buf, int max_reply_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700{
701 int result;
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100702 struct ncp_request_reply *req;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100704 req = ncp_alloc_req();
705 if (!req)
706 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100708 req->reply_buf = reply_buf;
709 req->datalen = max_reply_size;
710 req->tx_iov[1].iov_base = server->packet;
711 req->tx_iov[1].iov_len = size;
712 req->tx_iovlen = 1;
713 req->tx_totallen = size;
714 req->tx_type = *(u_int16_t*)server->packet;
715
716 result = ncp_add_request(server, req);
717 if (result < 0)
718 goto out;
719
720 if (wait_event_interruptible(req->wq, req->status == RQ_DONE)) {
721 ncp_abort_request(server, req, -EINTR);
722 result = -EINTR;
723 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 }
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100725
726 result = req->result;
727
728out:
729 ncp_req_put(req);
730
731 return result;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732}
733
734/*
735 * We need the server to be locked here, so check!
736 */
737
738static int ncp_do_request(struct ncp_server *server, int size,
739 void* reply, int max_reply_size)
740{
741 int result;
742
743 if (server->lock == 0) {
744 printk(KERN_ERR "ncpfs: Server not locked!\n");
745 return -EIO;
746 }
747 if (!ncp_conn_valid(server)) {
748 printk(KERN_ERR "ncpfs: Connection invalid!\n");
749 return -EIO;
750 }
751 {
752 sigset_t old_set;
753 unsigned long mask, flags;
754
755 spin_lock_irqsave(&current->sighand->siglock, flags);
756 old_set = current->blocked;
757 if (current->flags & PF_EXITING)
758 mask = 0;
759 else
760 mask = sigmask(SIGKILL);
761 if (server->m.flags & NCP_MOUNT_INTR) {
762 /* FIXME: This doesn't seem right at all. So, like,
763 we can't handle SIGINT and get whatever to stop?
764 What if we've blocked it ourselves? What about
765 alarms? Why, in fact, are we mucking with the
766 sigmask at all? -- r~ */
767 if (current->sighand->action[SIGINT - 1].sa.sa_handler == SIG_DFL)
768 mask |= sigmask(SIGINT);
769 if (current->sighand->action[SIGQUIT - 1].sa.sa_handler == SIG_DFL)
770 mask |= sigmask(SIGQUIT);
771 }
772 siginitsetinv(&current->blocked, mask);
773 recalc_sigpending();
774 spin_unlock_irqrestore(&current->sighand->siglock, flags);
775
776 result = do_ncp_rpc_call(server, size, reply, max_reply_size);
777
778 spin_lock_irqsave(&current->sighand->siglock, flags);
779 current->blocked = old_set;
780 recalc_sigpending();
781 spin_unlock_irqrestore(&current->sighand->siglock, flags);
782 }
783
784 DDPRINTK("do_ncp_rpc_call returned %d\n", result);
785
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786 return result;
787}
788
789/* ncp_do_request assures that at least a complete reply header is
790 * received. It assumes that server->current_size contains the ncp
791 * request size
792 */
793int ncp_request2(struct ncp_server *server, int function,
794 void* rpl, int size)
795{
796 struct ncp_request_header *h;
797 struct ncp_reply_header* reply = rpl;
798 int result;
799
800 h = (struct ncp_request_header *) (server->packet);
801 if (server->has_subfunction != 0) {
802 *(__u16 *) & (h->data[0]) = htons(server->current_size - sizeof(*h) - 2);
803 }
804 h->type = NCP_REQUEST;
805 /*
806 * The server shouldn't know or care what task is making a
807 * request, so we always use the same task number.
808 */
809 h->task = 2; /* (current->pid) & 0xff; */
810 h->function = function;
811
812 result = ncp_do_request(server, server->current_size, reply, size);
813 if (result < 0) {
814 DPRINTK("ncp_request_error: %d\n", result);
815 goto out;
816 }
817 server->completion = reply->completion_code;
818 server->conn_status = reply->connection_state;
819 server->reply_size = result;
820 server->ncp_reply_size = result - sizeof(struct ncp_reply_header);
821
822 result = reply->completion_code;
823
824 if (result != 0)
825 PPRINTK("ncp_request: completion code=%x\n", result);
826out:
827 return result;
828}
829
830int ncp_connect(struct ncp_server *server)
831{
832 struct ncp_request_header *h;
833 int result;
834
835 server->connection = 0xFFFF;
836 server->sequence = 255;
837
838 h = (struct ncp_request_header *) (server->packet);
839 h->type = NCP_ALLOC_SLOT_REQUEST;
840 h->task = 2; /* see above */
841 h->function = 0;
842
843 result = ncp_do_request(server, sizeof(*h), server->packet, server->packet_size);
844 if (result < 0)
845 goto out;
846 server->connection = h->conn_low + (h->conn_high * 256);
847 result = 0;
848out:
849 return result;
850}
851
852int ncp_disconnect(struct ncp_server *server)
853{
854 struct ncp_request_header *h;
855
856 h = (struct ncp_request_header *) (server->packet);
857 h->type = NCP_DEALLOC_SLOT_REQUEST;
858 h->task = 2; /* see above */
859 h->function = 0;
860
861 return ncp_do_request(server, sizeof(*h), server->packet, server->packet_size);
862}
863
864void ncp_lock_server(struct ncp_server *server)
865{
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800866 mutex_lock(&server->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867 if (server->lock)
868 printk(KERN_WARNING "ncp_lock_server: was locked!\n");
869 server->lock = 1;
870}
871
872void ncp_unlock_server(struct ncp_server *server)
873{
874 if (!server->lock) {
875 printk(KERN_WARNING "ncp_unlock_server: was not locked!\n");
876 return;
877 }
878 server->lock = 0;
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800879 mutex_unlock(&server->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880}