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