]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blame - fs/ncpfs/sock.c
ncpfs: switch to sock_sendmsg()
[mirror_ubuntu-artful-kernel.git] / fs / ncpfs / sock.c
CommitLineData
1da177e4
LT
1/*
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
b41f8b84 11#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
1da177e4
LT
12
13#include <linux/time.h>
14#include <linux/errno.h>
15#include <linux/socket.h>
16#include <linux/fcntl.h>
17#include <linux/stat.h>
c5f93cf1 18#include <linux/string.h>
7c0f6ba6 19#include <linux/uaccess.h>
1da177e4
LT
20#include <linux/in.h>
21#include <linux/net.h>
22#include <linux/mm.h>
23#include <linux/netdevice.h>
24#include <linux/signal.h>
5a0e3ad6 25#include <linux/slab.h>
1da177e4
LT
26#include <net/scm.h>
27#include <net/sock.h>
28#include <linux/ipx.h>
29#include <linux/poll.h>
30#include <linux/file.h>
31
32c419d9 32#include "ncp_fs.h"
1da177e4
LT
33
34#include "ncpsign_kernel.h"
35
36static int _recv(struct socket *sock, void *buf, int size, unsigned flags)
37{
38 struct msghdr msg = {NULL, };
39 struct kvec iov = {buf, size};
40 return kernel_recvmsg(sock, &msg, &iov, 1, size, flags);
41}
42
1da177e4
LT
43static int _send(struct socket *sock, const void *buff, int len)
44{
b8e2df1f
AV
45 struct msghdr msg = { .msg_flags = 0 };
46 struct kvec vec = {.iov_base = (void *)buff, .iov_len = len};
47 iov_iter_kvec(&msg.msg_iter, WRITE | ITER_KVEC, &vec, 1, len);
48 return sock_sendmsg(sock, &msg);
1da177e4
LT
49}
50
51struct ncp_request_reply {
52 struct list_head req;
53 wait_queue_head_t wq;
c5f93cf1
PO
54 atomic_t refs;
55 unsigned char* reply_buf;
1da177e4
LT
56 size_t datalen;
57 int result;
c5f93cf1 58 enum { RQ_DONE, RQ_INPROGRESS, RQ_QUEUED, RQ_IDLE, RQ_ABANDONED } status;
2cebcc78 59 struct iov_iter from;
1da177e4
LT
60 struct kvec tx_iov[3];
61 u_int16_t tx_type;
62 u_int32_t sign[6];
63};
64
c5f93cf1
PO
65static inline struct ncp_request_reply* ncp_alloc_req(void)
66{
67 struct ncp_request_reply *req;
68
69 req = kmalloc(sizeof(struct ncp_request_reply), GFP_KERNEL);
70 if (!req)
71 return NULL;
72
73 init_waitqueue_head(&req->wq);
74 atomic_set(&req->refs, (1));
75 req->status = RQ_IDLE;
76
77 return req;
78}
79
80static void ncp_req_get(struct ncp_request_reply *req)
81{
82 atomic_inc(&req->refs);
83}
84
85static void ncp_req_put(struct ncp_request_reply *req)
86{
87 if (atomic_dec_and_test(&req->refs))
88 kfree(req);
89}
90
676d2369 91void ncp_tcp_data_ready(struct sock *sk)
1da177e4
LT
92{
93 struct ncp_server *server = sk->sk_user_data;
94
676d2369 95 server->data_ready(sk);
1da177e4
LT
96 schedule_work(&server->rcv.tq);
97}
98
99void ncp_tcp_error_report(struct sock *sk)
100{
101 struct ncp_server *server = sk->sk_user_data;
102
103 server->error_report(sk);
104 schedule_work(&server->rcv.tq);
105}
106
107void ncp_tcp_write_space(struct sock *sk)
108{
109 struct ncp_server *server = sk->sk_user_data;
110
111 /* We do not need any locking: we first set tx.creq, and then we do sendmsg,
112 not vice versa... */
113 server->write_space(sk);
114 if (server->tx.creq)
115 schedule_work(&server->tx.tq);
116}
117
118void ncpdgram_timeout_call(unsigned long v)
119{
120 struct ncp_server *server = (void*)v;
121
122 schedule_work(&server->timeout_tq);
123}
124
c5f93cf1 125static inline void ncp_finish_request(struct ncp_server *server, struct ncp_request_reply *req, int result)
1da177e4
LT
126{
127 req->result = result;
c5f93cf1
PO
128 if (req->status != RQ_ABANDONED)
129 memcpy(req->reply_buf, server->rxbuf, req->datalen);
1da177e4
LT
130 req->status = RQ_DONE;
131 wake_up_all(&req->wq);
c5f93cf1 132 ncp_req_put(req);
1da177e4
LT
133}
134
c5f93cf1 135static void __abort_ncp_connection(struct ncp_server *server)
1da177e4
LT
136{
137 struct ncp_request_reply *req;
138
139 ncp_invalidate_conn(server);
140 del_timer(&server->timeout_tm);
141 while (!list_empty(&server->tx.requests)) {
142 req = list_entry(server->tx.requests.next, struct ncp_request_reply, req);
143
144 list_del_init(&req->req);
c5f93cf1 145 ncp_finish_request(server, req, -EIO);
1da177e4
LT
146 }
147 req = server->rcv.creq;
148 if (req) {
149 server->rcv.creq = NULL;
c5f93cf1 150 ncp_finish_request(server, req, -EIO);
1da177e4
LT
151 server->rcv.ptr = NULL;
152 server->rcv.state = 0;
153 }
154 req = server->tx.creq;
155 if (req) {
156 server->tx.creq = NULL;
c5f93cf1 157 ncp_finish_request(server, req, -EIO);
1da177e4
LT
158 }
159}
160
161static inline int get_conn_number(struct ncp_reply_header *rp)
162{
163 return rp->conn_low | (rp->conn_high << 8);
164}
165
166static inline void __ncp_abort_request(struct ncp_server *server, struct ncp_request_reply *req, int err)
167{
168 /* If req is done, we got signal, but we also received answer... */
169 switch (req->status) {
170 case RQ_IDLE:
171 case RQ_DONE:
172 break;
173 case RQ_QUEUED:
174 list_del_init(&req->req);
c5f93cf1 175 ncp_finish_request(server, req, err);
1da177e4
LT
176 break;
177 case RQ_INPROGRESS:
c5f93cf1
PO
178 req->status = RQ_ABANDONED;
179 break;
180 case RQ_ABANDONED:
1da177e4
LT
181 break;
182 }
183}
184
185static inline void ncp_abort_request(struct ncp_server *server, struct ncp_request_reply *req, int err)
186{
8e3f9045 187 mutex_lock(&server->rcv.creq_mutex);
1da177e4 188 __ncp_abort_request(server, req, err);
8e3f9045 189 mutex_unlock(&server->rcv.creq_mutex);
1da177e4
LT
190}
191
192static inline void __ncptcp_abort(struct ncp_server *server)
193{
c5f93cf1 194 __abort_ncp_connection(server);
1da177e4
LT
195}
196
197static int ncpdgram_send(struct socket *sock, struct ncp_request_reply *req)
198{
2cebcc78
AV
199 struct msghdr msg = { .msg_iter = req->from, .msg_flags = MSG_DONTWAIT };
200 return sock_sendmsg(sock, &msg);
1da177e4
LT
201}
202
203static void __ncptcp_try_send(struct ncp_server *server)
204{
205 struct ncp_request_reply *rq;
2cebcc78 206 struct msghdr msg = { .msg_flags = MSG_NOSIGNAL | MSG_DONTWAIT };
1da177e4
LT
207 int result;
208
209 rq = server->tx.creq;
210 if (!rq)
211 return;
212
2cebcc78
AV
213 msg.msg_iter = rq->from;
214 result = sock_sendmsg(server->ncp_sock, &msg);
1da177e4
LT
215
216 if (result == -EAGAIN)
217 return;
218
219 if (result < 0) {
b41f8b84 220 pr_err("tcp: Send failed: %d\n", result);
1da177e4
LT
221 __ncp_abort_request(server, rq, result);
222 return;
223 }
2cebcc78 224 if (!msg_data_left(&msg)) {
1da177e4
LT
225 server->rcv.creq = rq;
226 server->tx.creq = NULL;
227 return;
228 }
2cebcc78 229 rq->from = msg.msg_iter;
1da177e4
LT
230}
231
232static inline void ncp_init_header(struct ncp_server *server, struct ncp_request_reply *req, struct ncp_request_header *h)
233{
234 req->status = RQ_INPROGRESS;
235 h->conn_low = server->connection;
236 h->conn_high = server->connection >> 8;
237 h->sequence = ++server->sequence;
238}
239
240static void ncpdgram_start_request(struct ncp_server *server, struct ncp_request_reply *req)
241{
2cebcc78
AV
242 size_t signlen, len = req->tx_iov[1].iov_len;
243 struct ncp_request_header *h = req->tx_iov[1].iov_base;
1da177e4 244
1da177e4 245 ncp_init_header(server, req, h);
2cebcc78
AV
246 signlen = sign_packet(server,
247 req->tx_iov[1].iov_base + sizeof(struct ncp_request_header) - 1,
248 len - sizeof(struct ncp_request_header) + 1,
249 cpu_to_le32(len), req->sign);
1da177e4 250 if (signlen) {
2cebcc78
AV
251 /* NCP over UDP appends signature */
252 req->tx_iov[2].iov_base = req->sign;
253 req->tx_iov[2].iov_len = signlen;
1da177e4 254 }
2cebcc78
AV
255 iov_iter_kvec(&req->from, WRITE | ITER_KVEC,
256 req->tx_iov + 1, signlen ? 2 : 1, len + signlen);
1da177e4
LT
257 server->rcv.creq = req;
258 server->timeout_last = server->m.time_out;
259 server->timeout_retries = server->m.retry_count;
260 ncpdgram_send(server->ncp_sock, req);
261 mod_timer(&server->timeout_tm, jiffies + server->m.time_out);
262}
263
264#define NCP_TCP_XMIT_MAGIC (0x446D6454)
265#define NCP_TCP_XMIT_VERSION (1)
266#define NCP_TCP_RCVD_MAGIC (0x744E6350)
267
268static void ncptcp_start_request(struct ncp_server *server, struct ncp_request_reply *req)
269{
2cebcc78
AV
270 size_t signlen, len = req->tx_iov[1].iov_len;
271 struct ncp_request_header *h = req->tx_iov[1].iov_base;
1da177e4 272
1da177e4
LT
273 ncp_init_header(server, req, h);
274 signlen = sign_packet(server, req->tx_iov[1].iov_base + sizeof(struct ncp_request_header) - 1,
2cebcc78
AV
275 len - sizeof(struct ncp_request_header) + 1,
276 cpu_to_be32(len + 24), req->sign + 4) + 16;
1da177e4
LT
277
278 req->sign[0] = htonl(NCP_TCP_XMIT_MAGIC);
2cebcc78 279 req->sign[1] = htonl(len + signlen);
1da177e4
LT
280 req->sign[2] = htonl(NCP_TCP_XMIT_VERSION);
281 req->sign[3] = htonl(req->datalen + 8);
2cebcc78 282 /* NCP over TCP prepends signature */
1da177e4
LT
283 req->tx_iov[0].iov_base = req->sign;
284 req->tx_iov[0].iov_len = signlen;
2cebcc78
AV
285 iov_iter_kvec(&req->from, WRITE | ITER_KVEC,
286 req->tx_iov, 2, len + signlen);
1da177e4
LT
287
288 server->tx.creq = req;
289 __ncptcp_try_send(server);
290}
291
292static inline void __ncp_start_request(struct ncp_server *server, struct ncp_request_reply *req)
293{
c5f93cf1
PO
294 /* we copy the data so that we do not depend on the caller
295 staying alive */
296 memcpy(server->txbuf, req->tx_iov[1].iov_base, req->tx_iov[1].iov_len);
297 req->tx_iov[1].iov_base = server->txbuf;
298
1da177e4
LT
299 if (server->ncp_sock->type == SOCK_STREAM)
300 ncptcp_start_request(server, req);
301 else
302 ncpdgram_start_request(server, req);
303}
304
305static int ncp_add_request(struct ncp_server *server, struct ncp_request_reply *req)
306{
8e3f9045 307 mutex_lock(&server->rcv.creq_mutex);
1da177e4 308 if (!ncp_conn_valid(server)) {
8e3f9045 309 mutex_unlock(&server->rcv.creq_mutex);
b41f8b84 310 pr_err("tcp: Server died\n");
1da177e4
LT
311 return -EIO;
312 }
c5f93cf1 313 ncp_req_get(req);
1da177e4
LT
314 if (server->tx.creq || server->rcv.creq) {
315 req->status = RQ_QUEUED;
316 list_add_tail(&req->req, &server->tx.requests);
8e3f9045 317 mutex_unlock(&server->rcv.creq_mutex);
1da177e4
LT
318 return 0;
319 }
320 __ncp_start_request(server, req);
8e3f9045 321 mutex_unlock(&server->rcv.creq_mutex);
1da177e4
LT
322 return 0;
323}
324
325static void __ncp_next_request(struct ncp_server *server)
326{
327 struct ncp_request_reply *req;
328
329 server->rcv.creq = NULL;
330 if (list_empty(&server->tx.requests)) {
331 return;
332 }
333 req = list_entry(server->tx.requests.next, struct ncp_request_reply, req);
334 list_del_init(&req->req);
335 __ncp_start_request(server, req);
336}
337
338static void info_server(struct ncp_server *server, unsigned int id, const void * data, size_t len)
339{
340 if (server->info_sock) {
b8e2df1f
AV
341 struct msghdr msg = { .msg_flags = MSG_NOSIGNAL };
342 __be32 hdr[2] = {cpu_to_be32(len + 8), cpu_to_be32(id)};
343 struct kvec iov[2] = {
344 {.iov_base = hdr, .iov_len = 8},
345 {.iov_base = (void *)data, .iov_len = len},
346 };
347
348 iov_iter_kvec(&msg.msg_iter, ITER_KVEC | WRITE,
349 iov, 2, len + 8);
1da177e4 350
b8e2df1f 351 sock_sendmsg(server->info_sock, &msg);
1da177e4
LT
352 }
353}
354
c4028958 355void ncpdgram_rcv_proc(struct work_struct *work)
1da177e4 356{
c4028958
DH
357 struct ncp_server *server =
358 container_of(work, struct ncp_server, rcv.tq);
1da177e4
LT
359 struct socket* sock;
360
361 sock = server->ncp_sock;
362
363 while (1) {
364 struct ncp_reply_header reply;
365 int result;
366
367 result = _recv(sock, &reply, sizeof(reply), MSG_PEEK | MSG_DONTWAIT);
368 if (result < 0) {
369 break;
370 }
371 if (result >= sizeof(reply)) {
372 struct ncp_request_reply *req;
373
374 if (reply.type == NCP_WATCHDOG) {
375 unsigned char buf[10];
376
377 if (server->connection != get_conn_number(&reply)) {
378 goto drop;
379 }
380 result = _recv(sock, buf, sizeof(buf), MSG_DONTWAIT);
381 if (result < 0) {
d3b73ca1 382 ncp_dbg(1, "recv failed with %d\n", result);
1da177e4
LT
383 continue;
384 }
385 if (result < 10) {
d3b73ca1 386 ncp_dbg(1, "too short (%u) watchdog packet\n", result);
1da177e4
LT
387 continue;
388 }
389 if (buf[9] != '?') {
d3b73ca1 390 ncp_dbg(1, "bad signature (%02X) in watchdog packet\n", buf[9]);
1da177e4
LT
391 continue;
392 }
393 buf[9] = 'Y';
394 _send(sock, buf, sizeof(buf));
395 continue;
396 }
397 if (reply.type != NCP_POSITIVE_ACK && reply.type != NCP_REPLY) {
398 result = _recv(sock, server->unexpected_packet.data, sizeof(server->unexpected_packet.data), MSG_DONTWAIT);
399 if (result < 0) {
400 continue;
401 }
402 info_server(server, 0, server->unexpected_packet.data, result);
403 continue;
404 }
8e3f9045 405 mutex_lock(&server->rcv.creq_mutex);
1da177e4
LT
406 req = server->rcv.creq;
407 if (req && (req->tx_type == NCP_ALLOC_SLOT_REQUEST || (server->sequence == reply.sequence &&
408 server->connection == get_conn_number(&reply)))) {
409 if (reply.type == NCP_POSITIVE_ACK) {
410 server->timeout_retries = server->m.retry_count;
411 server->timeout_last = NCP_MAX_RPC_TIMEOUT;
412 mod_timer(&server->timeout_tm, jiffies + NCP_MAX_RPC_TIMEOUT);
413 } else if (reply.type == NCP_REPLY) {
c5f93cf1 414 result = _recv(sock, server->rxbuf, req->datalen, MSG_DONTWAIT);
1da177e4
LT
415#ifdef CONFIG_NCPFS_PACKET_SIGNING
416 if (result >= 0 && server->sign_active && req->tx_type != NCP_DEALLOC_SLOT_REQUEST) {
417 if (result < 8 + 8) {
418 result = -EIO;
419 } else {
420 unsigned int hdrl;
421
422 result -= 8;
423 hdrl = sock->sk->sk_family == AF_INET ? 8 : 6;
c5f93cf1 424 if (sign_verify_reply(server, server->rxbuf + hdrl, result - hdrl, cpu_to_le32(result), server->rxbuf + result)) {
b41f8b84 425 pr_info("Signature violation\n");
1da177e4
LT
426 result = -EIO;
427 }
428 }
429 }
430#endif
431 del_timer(&server->timeout_tm);
432 server->rcv.creq = NULL;
c5f93cf1 433 ncp_finish_request(server, req, result);
1da177e4 434 __ncp_next_request(server);
8e3f9045 435 mutex_unlock(&server->rcv.creq_mutex);
1da177e4
LT
436 continue;
437 }
438 }
8e3f9045 439 mutex_unlock(&server->rcv.creq_mutex);
1da177e4
LT
440 }
441drop:;
442 _recv(sock, &reply, sizeof(reply), MSG_DONTWAIT);
443 }
444}
445
446static void __ncpdgram_timeout_proc(struct ncp_server *server)
447{
448 /* If timer is pending, we are processing another request... */
449 if (!timer_pending(&server->timeout_tm)) {
450 struct ncp_request_reply* req;
451
452 req = server->rcv.creq;
453 if (req) {
454 int timeout;
455
456 if (server->m.flags & NCP_MOUNT_SOFT) {
457 if (server->timeout_retries-- == 0) {
458 __ncp_abort_request(server, req, -ETIMEDOUT);
459 return;
460 }
461 }
462 /* Ignore errors */
463 ncpdgram_send(server->ncp_sock, req);
464 timeout = server->timeout_last << 1;
465 if (timeout > NCP_MAX_RPC_TIMEOUT) {
466 timeout = NCP_MAX_RPC_TIMEOUT;
467 }
468 server->timeout_last = timeout;
469 mod_timer(&server->timeout_tm, jiffies + timeout);
470 }
471 }
472}
473
c4028958 474void ncpdgram_timeout_proc(struct work_struct *work)
1da177e4 475{
c4028958
DH
476 struct ncp_server *server =
477 container_of(work, struct ncp_server, timeout_tq);
8e3f9045 478 mutex_lock(&server->rcv.creq_mutex);
1da177e4 479 __ncpdgram_timeout_proc(server);
8e3f9045 480 mutex_unlock(&server->rcv.creq_mutex);
1da177e4
LT
481}
482
1da177e4
LT
483static int do_tcp_rcv(struct ncp_server *server, void *buffer, size_t len)
484{
485 int result;
486
487 if (buffer) {
488 result = _recv(server->ncp_sock, buffer, len, MSG_DONTWAIT);
489 } else {
490 static unsigned char dummy[1024];
491
492 if (len > sizeof(dummy)) {
493 len = sizeof(dummy);
494 }
495 result = _recv(server->ncp_sock, dummy, len, MSG_DONTWAIT);
496 }
497 if (result < 0) {
498 return result;
499 }
500 if (result > len) {
b41f8b84 501 pr_err("tcp: bug in recvmsg (%u > %Zu)\n", result, len);
1da177e4
LT
502 return -EIO;
503 }
504 return result;
505}
506
507static int __ncptcp_rcv_proc(struct ncp_server *server)
508{
509 /* We have to check the result, so store the complete header */
510 while (1) {
511 int result;
512 struct ncp_request_reply *req;
513 int datalen;
514 int type;
515
516 while (server->rcv.len) {
517 result = do_tcp_rcv(server, server->rcv.ptr, server->rcv.len);
518 if (result == -EAGAIN) {
519 return 0;
520 }
521 if (result <= 0) {
522 req = server->rcv.creq;
523 if (req) {
524 __ncp_abort_request(server, req, -EIO);
525 } else {
526 __ncptcp_abort(server);
527 }
528 if (result < 0) {
b41f8b84 529 pr_err("tcp: error in recvmsg: %d\n", result);
1da177e4 530 } else {
d3b73ca1 531 ncp_dbg(1, "tcp: EOF\n");
1da177e4
LT
532 }
533 return -EIO;
534 }
535 if (server->rcv.ptr) {
536 server->rcv.ptr += result;
537 }
538 server->rcv.len -= result;
539 }
540 switch (server->rcv.state) {
541 case 0:
542 if (server->rcv.buf.magic != htonl(NCP_TCP_RCVD_MAGIC)) {
b41f8b84 543 pr_err("tcp: Unexpected reply type %08X\n", ntohl(server->rcv.buf.magic));
1da177e4
LT
544 __ncptcp_abort(server);
545 return -EIO;
546 }
547 datalen = ntohl(server->rcv.buf.len) & 0x0FFFFFFF;
548 if (datalen < 10) {
b41f8b84 549 pr_err("tcp: Unexpected reply len %d\n", datalen);
1da177e4
LT
550 __ncptcp_abort(server);
551 return -EIO;
552 }
553#ifdef CONFIG_NCPFS_PACKET_SIGNING
554 if (server->sign_active) {
555 if (datalen < 18) {
b41f8b84 556 pr_err("tcp: Unexpected reply len %d\n", datalen);
1da177e4
LT
557 __ncptcp_abort(server);
558 return -EIO;
559 }
560 server->rcv.buf.len = datalen - 8;
561 server->rcv.ptr = (unsigned char*)&server->rcv.buf.p1;
562 server->rcv.len = 8;
563 server->rcv.state = 4;
564 break;
565 }
566#endif
567 type = ntohs(server->rcv.buf.type);
568#ifdef CONFIG_NCPFS_PACKET_SIGNING
569cont:;
570#endif
571 if (type != NCP_REPLY) {
572 if (datalen - 8 <= sizeof(server->unexpected_packet.data)) {
573 *(__u16*)(server->unexpected_packet.data) = htons(type);
574 server->unexpected_packet.len = datalen - 8;
575
576 server->rcv.state = 5;
577 server->rcv.ptr = server->unexpected_packet.data + 2;
578 server->rcv.len = datalen - 10;
579 break;
580 }
d3b73ca1 581 ncp_dbg(1, "tcp: Unexpected NCP type %02X\n", type);
1da177e4
LT
582skipdata2:;
583 server->rcv.state = 2;
584skipdata:;
585 server->rcv.ptr = NULL;
586 server->rcv.len = datalen - 10;
587 break;
588 }
589 req = server->rcv.creq;
590 if (!req) {
d3b73ca1 591 ncp_dbg(1, "Reply without appropriate request\n");
1da177e4
LT
592 goto skipdata2;
593 }
594 if (datalen > req->datalen + 8) {
b41f8b84 595 pr_err("tcp: Unexpected reply len %d (expected at most %Zd)\n", datalen, req->datalen + 8);
1da177e4
LT
596 server->rcv.state = 3;
597 goto skipdata;
598 }
599 req->datalen = datalen - 8;
c5f93cf1
PO
600 ((struct ncp_reply_header*)server->rxbuf)->type = NCP_REPLY;
601 server->rcv.ptr = server->rxbuf + 2;
1da177e4
LT
602 server->rcv.len = datalen - 10;
603 server->rcv.state = 1;
604 break;
605#ifdef CONFIG_NCPFS_PACKET_SIGNING
606 case 4:
607 datalen = server->rcv.buf.len;
608 type = ntohs(server->rcv.buf.type2);
609 goto cont;
610#endif
611 case 1:
612 req = server->rcv.creq;
613 if (req->tx_type != NCP_ALLOC_SLOT_REQUEST) {
c5f93cf1 614 if (((struct ncp_reply_header*)server->rxbuf)->sequence != server->sequence) {
b41f8b84 615 pr_err("tcp: Bad sequence number\n");
1da177e4
LT
616 __ncp_abort_request(server, req, -EIO);
617 return -EIO;
618 }
c5f93cf1 619 if ((((struct ncp_reply_header*)server->rxbuf)->conn_low | (((struct ncp_reply_header*)server->rxbuf)->conn_high << 8)) != server->connection) {
b41f8b84 620 pr_err("tcp: Connection number mismatch\n");
1da177e4
LT
621 __ncp_abort_request(server, req, -EIO);
622 return -EIO;
623 }
624 }
625#ifdef CONFIG_NCPFS_PACKET_SIGNING
626 if (server->sign_active && req->tx_type != NCP_DEALLOC_SLOT_REQUEST) {
c5f93cf1 627 if (sign_verify_reply(server, server->rxbuf + 6, req->datalen - 6, cpu_to_be32(req->datalen + 16), &server->rcv.buf.type)) {
b41f8b84 628 pr_err("tcp: Signature violation\n");
1da177e4
LT
629 __ncp_abort_request(server, req, -EIO);
630 return -EIO;
631 }
632 }
633#endif
c5f93cf1 634 ncp_finish_request(server, req, req->datalen);
1da177e4
LT
635 nextreq:;
636 __ncp_next_request(server);
637 case 2:
638 next:;
639 server->rcv.ptr = (unsigned char*)&server->rcv.buf;
640 server->rcv.len = 10;
641 server->rcv.state = 0;
642 break;
643 case 3:
c5f93cf1 644 ncp_finish_request(server, server->rcv.creq, -EIO);
1da177e4
LT
645 goto nextreq;
646 case 5:
647 info_server(server, 0, server->unexpected_packet.data, server->unexpected_packet.len);
648 goto next;
649 }
650 }
651}
652
c4028958 653void ncp_tcp_rcv_proc(struct work_struct *work)
1da177e4 654{
c4028958
DH
655 struct ncp_server *server =
656 container_of(work, struct ncp_server, rcv.tq);
1da177e4 657
8e3f9045 658 mutex_lock(&server->rcv.creq_mutex);
1da177e4 659 __ncptcp_rcv_proc(server);
8e3f9045 660 mutex_unlock(&server->rcv.creq_mutex);
1da177e4
LT
661}
662
c4028958 663void ncp_tcp_tx_proc(struct work_struct *work)
1da177e4 664{
c4028958
DH
665 struct ncp_server *server =
666 container_of(work, struct ncp_server, tx.tq);
1da177e4 667
8e3f9045 668 mutex_lock(&server->rcv.creq_mutex);
1da177e4 669 __ncptcp_try_send(server);
8e3f9045 670 mutex_unlock(&server->rcv.creq_mutex);
1da177e4
LT
671}
672
673static int do_ncp_rpc_call(struct ncp_server *server, int size,
c5f93cf1 674 unsigned char* reply_buf, int max_reply_size)
1da177e4
LT
675{
676 int result;
c5f93cf1
PO
677 struct ncp_request_reply *req;
678
679 req = ncp_alloc_req();
680 if (!req)
681 return -ENOMEM;
682
683 req->reply_buf = reply_buf;
684 req->datalen = max_reply_size;
685 req->tx_iov[1].iov_base = server->packet;
686 req->tx_iov[1].iov_len = size;
c5f93cf1
PO
687 req->tx_type = *(u_int16_t*)server->packet;
688
689 result = ncp_add_request(server, req);
690 if (result < 0)
691 goto out;
692
693 if (wait_event_interruptible(req->wq, req->status == RQ_DONE)) {
694 ncp_abort_request(server, req, -EINTR);
695 result = -EINTR;
696 goto out;
1da177e4 697 }
c5f93cf1
PO
698
699 result = req->result;
700
701out:
702 ncp_req_put(req);
703
704 return result;
1da177e4
LT
705}
706
707/*
708 * We need the server to be locked here, so check!
709 */
710
711static int ncp_do_request(struct ncp_server *server, int size,
712 void* reply, int max_reply_size)
713{
714 int result;
715
716 if (server->lock == 0) {
b41f8b84 717 pr_err("Server not locked!\n");
1da177e4
LT
718 return -EIO;
719 }
720 if (!ncp_conn_valid(server)) {
1da177e4
LT
721 return -EIO;
722 }
723 {
724 sigset_t old_set;
725 unsigned long mask, flags;
726
727 spin_lock_irqsave(&current->sighand->siglock, flags);
728 old_set = current->blocked;
729 if (current->flags & PF_EXITING)
730 mask = 0;
731 else
732 mask = sigmask(SIGKILL);
733 if (server->m.flags & NCP_MOUNT_INTR) {
734 /* FIXME: This doesn't seem right at all. So, like,
735 we can't handle SIGINT and get whatever to stop?
736 What if we've blocked it ourselves? What about
737 alarms? Why, in fact, are we mucking with the
738 sigmask at all? -- r~ */
739 if (current->sighand->action[SIGINT - 1].sa.sa_handler == SIG_DFL)
740 mask |= sigmask(SIGINT);
741 if (current->sighand->action[SIGQUIT - 1].sa.sa_handler == SIG_DFL)
742 mask |= sigmask(SIGQUIT);
743 }
744 siginitsetinv(&current->blocked, mask);
745 recalc_sigpending();
746 spin_unlock_irqrestore(&current->sighand->siglock, flags);
747
748 result = do_ncp_rpc_call(server, size, reply, max_reply_size);
749
750 spin_lock_irqsave(&current->sighand->siglock, flags);
751 current->blocked = old_set;
752 recalc_sigpending();
753 spin_unlock_irqrestore(&current->sighand->siglock, flags);
754 }
755
d3b73ca1 756 ncp_dbg(2, "do_ncp_rpc_call returned %d\n", result);
1da177e4 757
1da177e4
LT
758 return result;
759}
760
761/* ncp_do_request assures that at least a complete reply header is
762 * received. It assumes that server->current_size contains the ncp
763 * request size
764 */
765int ncp_request2(struct ncp_server *server, int function,
766 void* rpl, int size)
767{
768 struct ncp_request_header *h;
769 struct ncp_reply_header* reply = rpl;
770 int result;
771
772 h = (struct ncp_request_header *) (server->packet);
773 if (server->has_subfunction != 0) {
774 *(__u16 *) & (h->data[0]) = htons(server->current_size - sizeof(*h) - 2);
775 }
776 h->type = NCP_REQUEST;
777 /*
778 * The server shouldn't know or care what task is making a
779 * request, so we always use the same task number.
780 */
781 h->task = 2; /* (current->pid) & 0xff; */
782 h->function = function;
783
784 result = ncp_do_request(server, server->current_size, reply, size);
785 if (result < 0) {
d3b73ca1 786 ncp_dbg(1, "ncp_request_error: %d\n", result);
1da177e4
LT
787 goto out;
788 }
789 server->completion = reply->completion_code;
790 server->conn_status = reply->connection_state;
791 server->reply_size = result;
792 server->ncp_reply_size = result - sizeof(struct ncp_reply_header);
793
794 result = reply->completion_code;
795
796 if (result != 0)
e45ca8ba 797 ncp_vdbg("completion code=%x\n", result);
1da177e4
LT
798out:
799 return result;
800}
801
802int ncp_connect(struct ncp_server *server)
803{
804 struct ncp_request_header *h;
805 int result;
806
807 server->connection = 0xFFFF;
808 server->sequence = 255;
809
810 h = (struct ncp_request_header *) (server->packet);
811 h->type = NCP_ALLOC_SLOT_REQUEST;
812 h->task = 2; /* see above */
813 h->function = 0;
814
815 result = ncp_do_request(server, sizeof(*h), server->packet, server->packet_size);
816 if (result < 0)
817 goto out;
818 server->connection = h->conn_low + (h->conn_high * 256);
819 result = 0;
820out:
821 return result;
822}
823
824int ncp_disconnect(struct ncp_server *server)
825{
826 struct ncp_request_header *h;
827
828 h = (struct ncp_request_header *) (server->packet);
829 h->type = NCP_DEALLOC_SLOT_REQUEST;
830 h->task = 2; /* see above */
831 h->function = 0;
832
833 return ncp_do_request(server, sizeof(*h), server->packet, server->packet_size);
834}
835
836void ncp_lock_server(struct ncp_server *server)
837{
8e3f9045 838 mutex_lock(&server->mutex);
1da177e4 839 if (server->lock)
b41f8b84 840 pr_warn("%s: was locked!\n", __func__);
1da177e4
LT
841 server->lock = 1;
842}
843
844void ncp_unlock_server(struct ncp_server *server)
845{
846 if (!server->lock) {
b41f8b84 847 pr_warn("%s: was not locked!\n", __func__);
1da177e4
LT
848 return;
849 }
850 server->lock = 0;
8e3f9045 851 mutex_unlock(&server->mutex);
1da177e4 852}