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 #include <linux/config.h>
12
13 #include <linux/sched.h>
14 #include <linux/errno.h>
15 #include <linux/socket.h>
16 #include <linux/fcntl.h>
17 #include <linux/stat.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 <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 #ifdef CONFIG_NCPFS_PACKET_SIGNING
33 #include "ncpsign_kernel.h"
34 #endif
35
36 static int _recv(struct socket *sock, unsigned char *ubuf, int size,
37 unsigned flags)
38 {
39 struct iovec iov;
40 struct msghdr msg;
41 struct scm_cookie scm;
42
43 memset(&scm, 0, sizeof(scm));
44
45 iov.iov_base = ubuf;
46 iov.iov_len = size;
47
48 msg.msg_name = NULL;
49 msg.msg_namelen = 0;
50 msg.msg_control = NULL;
51 msg.msg_iov = &iov;
52 msg.msg_iovlen = 1;
53 return sock->ops->recvmsg(sock, &msg, size, flags, &scm);
54 }
55
56 static int _send(struct socket *sock, const void *buff, int len)
57 {
58 struct iovec iov;
59 struct msghdr msg;
60 struct scm_cookie scm;
61 int err;
62
63 iov.iov_base = (void *) buff;
64 iov.iov_len = len;
65
66 msg.msg_name = NULL;
67 msg.msg_namelen = 0;
68 msg.msg_control = NULL;
69 msg.msg_iov = &iov;
70 msg.msg_iovlen = 1;
71 msg.msg_flags = 0;
72
73 err = scm_send(sock, &msg, &scm);
74 if (err < 0) {
75 return err;
76 }
77 err = sock->ops->sendmsg(sock, &msg, len, &scm);
78 scm_destroy(&scm);
79 return err;
80 }
81
82 static int do_ncp_rpc_call(struct ncp_server *server, int size,
83 struct ncp_reply_header* reply_buf, int max_reply_size)
84 {
85 struct file *file;
86 struct socket *sock;
87 int result;
88 char *start = server->packet;
89 poll_table wait_table;
90 int init_timeout, max_timeout;
91 int timeout;
92 int retrans;
93 int major_timeout_seen;
94 int acknowledge_seen;
95 int n;
96
97 /* We have to check the result, so store the complete header */
98 struct ncp_request_header request =
99 *((struct ncp_request_header *) (server->packet));
100
101 struct ncp_reply_header reply;
102
103 file = server->ncp_filp;
104 sock = &file->f_dentry->d_inode->u.socket_i;
105
106 init_timeout = server->m.time_out;
107 max_timeout = NCP_MAX_RPC_TIMEOUT;
108 retrans = server->m.retry_count;
109 major_timeout_seen = 0;
110 acknowledge_seen = 0;
111
112 for (n = 0, timeout = init_timeout;; n++, timeout <<= 1) {
113 /*
114 DDPRINTK("ncpfs: %08lX:%02X%02X%02X%02X%02X%02X:%04X\n",
115 htonl(server->m.serv_addr.sipx_network),
116 server->m.serv_addr.sipx_node[0],
117 server->m.serv_addr.sipx_node[1],
118 server->m.serv_addr.sipx_node[2],
119 server->m.serv_addr.sipx_node[3],
120 server->m.serv_addr.sipx_node[4],
121 server->m.serv_addr.sipx_node[5],
122 ntohs(server->m.serv_addr.sipx_port));
123 */
124 DDPRINTK("ncpfs: req.typ: %04X, con: %d, "
125 "seq: %d",
126 request.type,
127 (request.conn_high << 8) + request.conn_low,
128 request.sequence);
129 DDPRINTK(" func: %d\n",
130 request.function);
131
132 result = _send(sock, (void *) start, size);
133 if (result < 0) {
134 printk(KERN_ERR "ncp_rpc_call: send error = %d\n", result);
135 break;
136 }
137 re_select:
138 poll_initwait(&wait_table);
139 /* mb() is not necessary because ->poll() will serialize
140 instructions adding the wait_table waitqueues in the
141 waitqueue-head before going to calculate the mask-retval. */
142 __set_current_state(TASK_INTERRUPTIBLE);
143 if (!(sock->ops->poll(file, sock, &wait_table) & POLLIN)) {
144 int timed_out;
145 if (timeout > max_timeout) {
146 /* JEJB/JSP 2/7/94
147 * This is useful to see if the system is
148 * hanging */
149 if (acknowledge_seen == 0) {
150 printk(KERN_WARNING "NCP max timeout\n");
151 }
152 timeout = max_timeout;
153 }
154 timed_out = !schedule_timeout(timeout);
155 poll_freewait(&wait_table);
156 current->state = TASK_RUNNING;
157 if (signal_pending(current)) {
158 result = -ERESTARTSYS;
159 break;
160 }
161 if(wait_table.error) {
162 result = wait_table.error;
163 break;
164 }
165 if (timed_out) {
166 if (n < retrans)
167 continue;
168 if (server->m.flags & NCP_MOUNT_SOFT) {
169 printk(KERN_WARNING "NCP server not responding\n");
170 result = -EIO;
171 break;
172 }
173 n = 0;
174 timeout = init_timeout;
175 if (init_timeout < max_timeout)
176 init_timeout <<= 1;
177 if (!major_timeout_seen) {
178 printk(KERN_WARNING "NCP server not responding\n");
179 }
180 major_timeout_seen = 1;
181 continue;
182 }
183 } else {
184 poll_freewait(&wait_table);
185 }
186 current->state = TASK_RUNNING;
187
188 /* Get the header from the next packet using a peek, so keep it
189 * on the recv queue. If it is wrong, it will be some reply
190 * we don't now need, so discard it */
191 result = _recv(sock, (void *) &reply, sizeof(reply),
192 MSG_PEEK | MSG_DONTWAIT);
193 if (result < 0) {
194 if (result == -EAGAIN) {
195 DDPRINTK("ncp_rpc_call: bad select ready\n");
196 goto re_select;
197 }
198 if (result == -ECONNREFUSED) {
199 DPRINTK("ncp_rpc_call: server playing coy\n");
200 goto re_select;
201 }
202 if (result != -ERESTARTSYS) {
203 printk(KERN_ERR "ncp_rpc_call: recv error = %d\n",
204 -result);
205 }
206 break;
207 }
208 if ((result == sizeof(reply))
209 && (reply.type == NCP_POSITIVE_ACK)) {
210 /* Throw away the packet */
211 DPRINTK("ncp_rpc_call: got positive acknowledge\n");
212 _recv(sock, (void *) &reply, sizeof(reply),
213 MSG_DONTWAIT);
214 n = 0;
215 timeout = max_timeout;
216 acknowledge_seen = 1;
217 goto re_select;
218 }
219 DDPRINTK("ncpfs: rep.typ: %04X, con: %d, tsk: %d,"
220 "seq: %d\n",
221 reply.type,
222 (reply.conn_high << 8) + reply.conn_low,
223 reply.task,
224 reply.sequence);
225
226 if ((result >= sizeof(reply))
227 && (reply.type == NCP_REPLY)
228 && ((request.type == NCP_ALLOC_SLOT_REQUEST)
229 || ((reply.sequence == request.sequence)
230 && (reply.conn_low == request.conn_low)
231 /* seem to get wrong task from NW311 && (reply.task == request.task) */
232 && (reply.conn_high == request.conn_high)))) {
233 if (major_timeout_seen)
234 printk(KERN_NOTICE "NCP server OK\n");
235 break;
236 }
237 /* JEJB/JSP 2/7/94
238 * we have xid mismatch, so discard the packet and start
239 * again. What a hack! but I can't call recvfrom with
240 * a null buffer yet. */
241 _recv(sock, (void *) &reply, sizeof(reply), MSG_DONTWAIT);
242
243 DPRINTK("ncp_rpc_call: reply mismatch\n");
244 goto re_select;
245 }
246 /*
247 * we have the correct reply, so read into the correct place and
248 * return it
249 */
250 result = _recv(sock, (void *)reply_buf, max_reply_size, MSG_DONTWAIT);
251 if (result < 0) {
252 printk(KERN_WARNING "NCP: notice message: result=%d\n", result);
253 } else if (result < sizeof(struct ncp_reply_header)) {
254 printk(KERN_ERR "NCP: just caught a too small read memory size..., "
255 "email to NET channel\n");
256 printk(KERN_ERR "NCP: result=%d\n", result);
257 result = -EIO;
258 }
259
260 return result;
261 }
262
263 static int do_tcp_rcv(struct ncp_server *server, void *buffer, size_t len) {
264 poll_table wait_table;
265 struct file *file;
266 struct socket *sock;
267 int init_timeout;
268 size_t dataread;
269 int result = 0;
270
271 file = server->ncp_filp;
272 sock = &file->f_dentry->d_inode->u.socket_i;
273
274 dataread = 0;
275
276 init_timeout = server->m.time_out * 20;
277
278 /* hard-mounted volumes have no timeout, except connection close... */
279 if (!(server->m.flags & NCP_MOUNT_SOFT))
280 init_timeout = 0x7FFF0000;
281
282 while (len) {
283 poll_initwait(&wait_table);
284 /* mb() is not necessary because ->poll() will serialize
285 instructions adding the wait_table waitqueues in the
286 waitqueue-head before going to calculate the mask-retval. */
287 __set_current_state(TASK_INTERRUPTIBLE);
288 if (!(sock->ops->poll(file, sock, &wait_table) & POLLIN)) {
289 init_timeout = schedule_timeout(init_timeout);
290 poll_freewait(&wait_table);
291 current->state = TASK_RUNNING;
292 if (signal_pending(current)) {
293 return -ERESTARTSYS;
294 }
295 if (!init_timeout) {
296 return -EIO;
297 }
298 if(wait_table.error) {
299 return wait_table.error;
300 }
301 } else {
302 poll_freewait(&wait_table);
303 }
304 current->state = TASK_RUNNING;
305
306 result = _recv(sock, buffer, len, MSG_DONTWAIT);
307 if (result < 0) {
308 if (result == -EAGAIN) {
309 DDPRINTK("ncpfs: tcp: bad select ready\n");
310 continue;
311 }
312 return result;
313 }
314 if (result == 0) {
315 printk(KERN_ERR "ncpfs: tcp: EOF on socket\n");
316 return -EIO;
317 }
318 if (result > len) {
319 printk(KERN_ERR "ncpfs: tcp: bug in recvmsg\n");
320 return -EIO;
321 }
322 dataread += result;
323 buffer += result;
324 len -= result;
325 }
326 return 0;
327 }
328
329 #define NCP_TCP_XMIT_MAGIC (0x446D6454)
330 #define NCP_TCP_XMIT_VERSION (1)
331 #define NCP_TCP_RCVD_MAGIC (0x744E6350)
332
333 static int do_ncp_tcp_rpc_call(struct ncp_server *server, int size,
334 struct ncp_reply_header* reply_buf, int max_reply_size)
335 {
336 struct file *file;
337 struct socket *sock;
338 int result;
339 struct iovec iov[2];
340 struct msghdr msg;
341 struct scm_cookie scm;
342 __u32 ncptcp_rcvd_hdr[2];
343 __u32 ncptcp_xmit_hdr[4];
344 int datalen;
345
346 /* We have to check the result, so store the complete header */
347 struct ncp_request_header request =
348 *((struct ncp_request_header *) (server->packet));
349
350 file = server->ncp_filp;
351 sock = &file->f_dentry->d_inode->u.socket_i;
352
353 ncptcp_xmit_hdr[0] = htonl(NCP_TCP_XMIT_MAGIC);
354 ncptcp_xmit_hdr[1] = htonl(size + 16);
355 ncptcp_xmit_hdr[2] = htonl(NCP_TCP_XMIT_VERSION);
356 ncptcp_xmit_hdr[3] = htonl(max_reply_size + 8);
357
358 DDPRINTK("ncpfs: req.typ: %04X, con: %d, "
359 "seq: %d",
360 request.type,
361 (request.conn_high << 8) + request.conn_low,
362 request.sequence);
363 DDPRINTK(" func: %d\n",
364 request.function);
365
366 iov[1].iov_base = (void *) server->packet;
367 iov[1].iov_len = size;
368 iov[0].iov_base = ncptcp_xmit_hdr;
369 iov[0].iov_len = 16;
370 msg.msg_name = NULL;
371 msg.msg_namelen = 0;
372 msg.msg_control = NULL;
373 msg.msg_iov = iov;
374 msg.msg_iovlen = 2;
375 msg.msg_flags = MSG_NOSIGNAL;
376
377 result = scm_send(sock, &msg, &scm);
378 if (result < 0) {
379 return result;
380 }
381 result = sock->ops->sendmsg(sock, &msg, size + 16, &scm);
382 scm_destroy(&scm);
383 if (result < 0) {
384 printk(KERN_ERR "ncpfs: tcp: Send failed: %d\n", result);
385 return result;
386 }
387 rstrcv:
388 result = do_tcp_rcv(server, ncptcp_rcvd_hdr, 8);
389 if (result)
390 return result;
391 if (ncptcp_rcvd_hdr[0] != htonl(NCP_TCP_RCVD_MAGIC)) {
392 printk(KERN_ERR "ncpfs: tcp: Unexpected reply type %08X\n", ntohl(ncptcp_rcvd_hdr[0]));
393 return -EIO;
394 }
395 datalen = ntohl(ncptcp_rcvd_hdr[1]);
396 if (datalen < 8 + sizeof(*reply_buf) || datalen > max_reply_size + 8) {
397 printk(KERN_ERR "ncpfs: tcp: Unexpected reply len %d\n", datalen);
398 return -EIO;
399 }
400 datalen -= 8;
401 result = do_tcp_rcv(server, reply_buf, datalen);
402 if (result)
403 return result;
404 if (reply_buf->type != NCP_REPLY) {
405 DDPRINTK("ncpfs: tcp: Unexpected NCP type %02X\n", reply_buf->type);
406 goto rstrcv;
407 }
408 if (request.type == NCP_ALLOC_SLOT_REQUEST)
409 return datalen;
410 if (reply_buf->sequence != request.sequence) {
411 printk(KERN_ERR "ncpfs: tcp: Bad sequence number\n");
412 return -EIO;
413 }
414 if ((reply_buf->conn_low != request.conn_low) ||
415 (reply_buf->conn_high != request.conn_high)) {
416 printk(KERN_ERR "ncpfs: tcp: Connection number mismatch\n");
417 return -EIO;
418 }
419 return datalen;
420 }
421
422 /*
423 * We need the server to be locked here, so check!
424 */
425
426 static int ncp_do_request(struct ncp_server *server, int size,
427 void* reply, int max_reply_size)
428 {
429 struct file *file;
430 struct socket *sock;
431 int result;
432
433 if (server->lock == 0) {
434 printk(KERN_ERR "ncpfs: Server not locked!\n");
435 return -EIO;
436 }
437 if (!ncp_conn_valid(server)) {
438 return -EIO;
439 }
440 #ifdef CONFIG_NCPFS_PACKET_SIGNING
441 if (server->sign_active)
442 {
443 sign_packet(server, &size);
444 }
445 #endif /* CONFIG_NCPFS_PACKET_SIGNING */
446 file = server->ncp_filp;
447 sock = &file->f_dentry->d_inode->u.socket_i;
448 /* N.B. this isn't needed ... check socket type? */
449 if (!sock) {
450 printk(KERN_ERR "ncp_rpc_call: socki_lookup failed\n");
451 result = -EBADF;
452 } else {
453 mm_segment_t fs;
454 sigset_t old_set;
455 unsigned long mask, flags;
456
457 spin_lock_irqsave(¤t->sigmask_lock, flags);
458 old_set = current->blocked;
459 mask = sigmask(SIGKILL) | sigmask(SIGSTOP);
460 if (server->m.flags & NCP_MOUNT_INTR) {
461 /* FIXME: This doesn't seem right at all. So, like,
462 we can't handle SIGINT and get whatever to stop?
463 What if we've blocked it ourselves? What about
464 alarms? Why, in fact, are we mucking with the
465 sigmask at all? -- r~ */
466 if (current->sig->action[SIGINT - 1].sa.sa_handler == SIG_DFL)
467 mask |= sigmask(SIGINT);
468 if (current->sig->action[SIGQUIT - 1].sa.sa_handler == SIG_DFL)
469 mask |= sigmask(SIGQUIT);
470 }
471 siginitsetinv(¤t->blocked, mask);
472 recalc_sigpending(current);
473 spin_unlock_irqrestore(¤t->sigmask_lock, flags);
474
475 fs = get_fs();
476 set_fs(get_ds());
477
478 if (sock->type == SOCK_STREAM)
479 result = do_ncp_tcp_rpc_call(server, size, reply, max_reply_size);
480 else
481 result = do_ncp_rpc_call(server, size, reply, max_reply_size);
482
483 set_fs(fs);
484
485 spin_lock_irqsave(¤t->sigmask_lock, flags);
486 current->blocked = old_set;
487 recalc_sigpending(current);
488 spin_unlock_irqrestore(¤t->sigmask_lock, flags);
489 }
490
491 DDPRINTK("do_ncp_rpc_call returned %d\n", result);
492
493 if (result < 0) {
494 /* There was a problem with I/O, so the connections is
495 * no longer usable. */
496 ncp_invalidate_conn(server);
497 }
498 return result;
499 }
500
501 /* ncp_do_request assures that at least a complete reply header is
502 * received. It assumes that server->current_size contains the ncp
503 * request size
504 */
505 int ncp_request2(struct ncp_server *server, int function,
506 void* rpl, int size)
507 {
508 struct ncp_request_header *h;
509 struct ncp_reply_header* reply = rpl;
510 int request_size = server->current_size
511 - sizeof(struct ncp_request_header);
512 int result;
513
514 h = (struct ncp_request_header *) (server->packet);
515 if (server->has_subfunction != 0) {
516 *(__u16 *) & (h->data[0]) = htons(request_size - 2);
517 }
518 h->type = NCP_REQUEST;
519
520 server->sequence += 1;
521 h->sequence = server->sequence;
522 h->conn_low = (server->connection) & 0xff;
523 h->conn_high = ((server->connection) & 0xff00) >> 8;
524 /*
525 * The server shouldn't know or care what task is making a
526 * request, so we always use the same task number.
527 */
528 h->task = 2; /* (current->pid) & 0xff; */
529 h->function = function;
530
531 result = ncp_do_request(server, request_size + sizeof(*h), reply, size);
532 if (result < 0) {
533 DPRINTK("ncp_request_error: %d\n", result);
534 goto out;
535 }
536 server->completion = reply->completion_code;
537 server->conn_status = reply->connection_state;
538 server->reply_size = result;
539 server->ncp_reply_size = result - sizeof(struct ncp_reply_header);
540
541 result = reply->completion_code;
542
543 if (result != 0)
544 PPRINTK("ncp_request: completion code=%x\n", result);
545 out:
546 return result;
547 }
548
549 int ncp_connect(struct ncp_server *server)
550 {
551 struct ncp_request_header *h;
552 int result;
553
554 h = (struct ncp_request_header *) (server->packet);
555 h->type = NCP_ALLOC_SLOT_REQUEST;
556
557 server->sequence = 0;
558 h->sequence = server->sequence;
559 h->conn_low = 0xff;
560 h->conn_high = 0xff;
561 h->task = 2; /* see above */
562 h->function = 0;
563
564 result = ncp_do_request(server, sizeof(*h), server->packet, server->packet_size);
565 if (result < 0)
566 goto out;
567 server->sequence = 0;
568 server->connection = h->conn_low + (h->conn_high * 256);
569 result = 0;
570 out:
571 return result;
572 }
573
574 int ncp_disconnect(struct ncp_server *server)
575 {
576 struct ncp_request_header *h;
577
578 h = (struct ncp_request_header *) (server->packet);
579 h->type = NCP_DEALLOC_SLOT_REQUEST;
580
581 server->sequence += 1;
582 h->sequence = server->sequence;
583 h->conn_low = (server->connection) & 0xff;
584 h->conn_high = ((server->connection) & 0xff00) >> 8;
585 h->task = 2; /* see above */
586 h->function = 0;
587
588 return ncp_do_request(server, sizeof(*h), server->packet, server->packet_size);
589 }
590
591 void ncp_lock_server(struct ncp_server *server)
592 {
593 down(&server->sem);
594 if (server->lock)
595 printk(KERN_WARNING "ncp_lock_server: was locked!\n");
596 server->lock = 1;
597 }
598
599 void ncp_unlock_server(struct ncp_server *server)
600 {
601 if (!server->lock) {
602 printk(KERN_WARNING "ncp_unlock_server: was not locked!\n");
603 return;
604 }
605 server->lock = 0;
606 up(&server->sem);
607 }
608
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.