Committer: Michael Beasley <mike@snafu.setup>
[mikesnafu-overlay.git] / arch / sparc64 / solaris / timod.c
blob15234fcd191a209041a6dd6712cdfae9c7fd3000
1 /* $Id: timod.c,v 1.19 2002/02/08 03:57:14 davem Exp $
2 * timod.c: timod emulation.
4 * Copyright (C) 1998 Patrik Rak (prak3264@ss1000.ms.mff.cuni.cz)
6 * Streams & timod emulation based on code
7 * Copyright (C) 1995, 1996 Mike Jagdis (jaggy@purplet.demon.co.uk)
9 */
11 #include <linux/types.h>
12 #include <linux/kernel.h>
13 #include <linux/sched.h>
14 #include <linux/smp.h>
15 #include <linux/smp_lock.h>
16 #include <linux/ioctl.h>
17 #include <linux/fs.h>
18 #include <linux/file.h>
19 #include <linux/netdevice.h>
20 #include <linux/poll.h>
22 #include <net/sock.h>
24 #include <asm/uaccess.h>
25 #include <asm/termios.h>
27 #include "conv.h"
28 #include "socksys.h"
30 asmlinkage int solaris_ioctl(unsigned int fd, unsigned int cmd, u32 arg);
32 static DEFINE_SPINLOCK(timod_pagelock);
33 static char * page = NULL ;
35 #ifndef DEBUG_SOLARIS_KMALLOC
37 #define mykmalloc kmalloc
38 #define mykfree kfree
40 #else
42 void * mykmalloc(size_t s, gfp_t gfp)
44 static char * page;
45 static size_t free;
46 void * r;
47 s = ((s + 63) & ~63);
48 if( s > PAGE_SIZE ) {
49 SOLD("too big size, calling real kmalloc");
50 return kmalloc(s, gfp);
52 if( s > free ) {
53 /* we are wasting memory, but we don't care */
54 page = (char *)__get_free_page(gfp);
55 free = PAGE_SIZE;
57 r = page;
58 page += s;
59 free -= s;
60 return r;
63 void mykfree(void *p)
67 #endif
69 #ifndef DEBUG_SOLARIS
71 #define BUF_SIZE PAGE_SIZE
72 #define PUT_MAGIC(a,m)
73 #define SCHECK_MAGIC(a,m)
74 #define BUF_OFFSET 0
75 #define MKCTL_TRAILER 0
77 #else
79 #define BUF_SIZE (PAGE_SIZE-2*sizeof(u64))
80 #define BUFPAGE_MAGIC 0xBADC0DEDDEADBABEL
81 #define MKCTL_MAGIC 0xDEADBABEBADC0DEDL
82 #define PUT_MAGIC(a,m) do{(*(u64*)(a))=(m);}while(0)
83 #define SCHECK_MAGIC(a,m) do{if((*(u64*)(a))!=(m))printk("%s,%u,%s(): magic %08x at %p corrupted!\n",\
84 __FILE__,__LINE__,__func__,(m),(a));}while(0)
85 #define BUF_OFFSET sizeof(u64)
86 #define MKCTL_TRAILER sizeof(u64)
88 #endif
90 static char *getpage( void )
92 char *r;
93 SOLD("getting page");
94 spin_lock(&timod_pagelock);
95 if (page) {
96 r = page;
97 page = NULL;
98 spin_unlock(&timod_pagelock);
99 SOLD("got cached");
100 return r + BUF_OFFSET;
102 spin_unlock(&timod_pagelock);
103 SOLD("getting new");
104 r = (char *)__get_free_page(GFP_KERNEL);
105 PUT_MAGIC(r,BUFPAGE_MAGIC);
106 PUT_MAGIC(r+PAGE_SIZE-sizeof(u64),BUFPAGE_MAGIC);
107 return r + BUF_OFFSET;
110 static void putpage(char *p)
112 SOLD("putting page");
113 p = p - BUF_OFFSET;
114 SCHECK_MAGIC(p,BUFPAGE_MAGIC);
115 SCHECK_MAGIC(p+PAGE_SIZE-sizeof(u64),BUFPAGE_MAGIC);
116 spin_lock(&timod_pagelock);
117 if (page) {
118 spin_unlock(&timod_pagelock);
119 free_page((unsigned long)p);
120 SOLD("freed it");
121 } else {
122 page = p;
123 spin_unlock(&timod_pagelock);
124 SOLD("cached it");
128 static struct T_primsg *timod_mkctl(int size)
130 struct T_primsg *it;
132 SOLD("creating primsg");
133 it = (struct T_primsg *)mykmalloc(size+sizeof(*it)-sizeof(s32)+2*MKCTL_TRAILER, GFP_KERNEL);
134 if (it) {
135 SOLD("got it");
136 it->pri = MSG_HIPRI;
137 it->length = size;
138 PUT_MAGIC((char*)((u64)(((char *)&it->type)+size+7)&~7),MKCTL_MAGIC);
140 return it;
143 static void timod_wake_socket(unsigned int fd)
145 struct socket *sock;
146 struct fdtable *fdt;
148 SOLD("wakeing socket");
149 fdt = files_fdtable(current->files);
150 sock = SOCKET_I(fdt->fd[fd]->f_path.dentry->d_inode);
151 wake_up_interruptible(&sock->wait);
152 read_lock(&sock->sk->sk_callback_lock);
153 if (sock->fasync_list && !test_bit(SOCK_ASYNC_WAITDATA, &sock->flags))
154 __kill_fasync(sock->fasync_list, SIGIO, POLL_IN);
155 read_unlock(&sock->sk->sk_callback_lock);
156 SOLD("done");
159 static void timod_queue(unsigned int fd, struct T_primsg *it)
161 struct sol_socket_struct *sock;
162 struct fdtable *fdt;
164 SOLD("queuing primsg");
165 fdt = files_fdtable(current->files);
166 sock = (struct sol_socket_struct *)fdt->fd[fd]->private_data;
167 it->next = sock->pfirst;
168 sock->pfirst = it;
169 if (!sock->plast)
170 sock->plast = it;
171 timod_wake_socket(fd);
172 SOLD("done");
175 static void timod_queue_end(unsigned int fd, struct T_primsg *it)
177 struct sol_socket_struct *sock;
178 struct fdtable *fdt;
180 SOLD("queuing primsg at end");
181 fdt = files_fdtable(current->files);
182 sock = (struct sol_socket_struct *)fdt->fd[fd]->private_data;
183 it->next = NULL;
184 if (sock->plast)
185 sock->plast->next = it;
186 else
187 sock->pfirst = it;
188 sock->plast = it;
189 SOLD("done");
192 static void timod_error(unsigned int fd, int prim, int terr, int uerr)
194 struct T_primsg *it;
196 SOLD("making error");
197 it = timod_mkctl(sizeof(struct T_error_ack));
198 if (it) {
199 struct T_error_ack *err = (struct T_error_ack *)&it->type;
201 SOLD("got it");
202 err->PRIM_type = T_ERROR_ACK;
203 err->ERROR_prim = prim;
204 err->TLI_error = terr;
205 err->UNIX_error = uerr; /* FIXME: convert this */
206 timod_queue(fd, it);
208 SOLD("done");
211 static void timod_ok(unsigned int fd, int prim)
213 struct T_primsg *it;
214 struct T_ok_ack *ok;
216 SOLD("creating ok ack");
217 it = timod_mkctl(sizeof(*ok));
218 if (it) {
219 SOLD("got it");
220 ok = (struct T_ok_ack *)&it->type;
221 ok->PRIM_type = T_OK_ACK;
222 ok->CORRECT_prim = prim;
223 timod_queue(fd, it);
225 SOLD("done");
228 static int timod_optmgmt(unsigned int fd, int flag, char __user *opt_buf, int opt_len, int do_ret)
230 int error, failed;
231 int ret_space, ret_len;
232 long args[5];
233 char *ret_pos,*ret_buf;
234 int (*sys_socketcall)(int, unsigned long *) =
235 (int (*)(int, unsigned long *))SYS(socketcall);
236 mm_segment_t old_fs = get_fs();
238 SOLD("entry");
239 SOLDD(("fd %u flg %u buf %p len %u doret %u",fd,flag,opt_buf,opt_len,do_ret));
240 if (!do_ret && (!opt_buf || opt_len <= 0))
241 return 0;
242 SOLD("getting page");
243 ret_pos = ret_buf = getpage();
244 ret_space = BUF_SIZE;
245 ret_len = 0;
247 error = failed = 0;
248 SOLD("looping");
249 while(opt_len >= sizeof(struct opthdr)) {
250 struct opthdr *opt;
251 int orig_opt_len;
252 SOLD("loop start");
253 opt = (struct opthdr *)ret_pos;
254 if (ret_space < sizeof(struct opthdr)) {
255 failed = TSYSERR;
256 break;
258 SOLD("getting opthdr");
259 if (copy_from_user(opt, opt_buf, sizeof(struct opthdr)) ||
260 opt->len > opt_len) {
261 failed = TBADOPT;
262 break;
264 SOLD("got opthdr");
265 if (flag == T_NEGOTIATE) {
266 char *buf;
268 SOLD("handling T_NEGOTIATE");
269 buf = ret_pos + sizeof(struct opthdr);
270 if (ret_space < opt->len + sizeof(struct opthdr) ||
271 copy_from_user(buf, opt_buf+sizeof(struct opthdr), opt->len)) {
272 failed = TSYSERR;
273 break;
275 SOLD("got optdata");
276 args[0] = fd;
277 args[1] = opt->level;
278 args[2] = opt->name;
279 args[3] = (long)buf;
280 args[4] = opt->len;
281 SOLD("calling SETSOCKOPT");
282 set_fs(KERNEL_DS);
283 error = sys_socketcall(SYS_SETSOCKOPT, args);
284 set_fs(old_fs);
285 if (error) {
286 failed = TBADOPT;
287 break;
289 SOLD("SETSOCKOPT ok");
291 orig_opt_len = opt->len;
292 opt->len = ret_space - sizeof(struct opthdr);
293 if (opt->len < 0) {
294 failed = TSYSERR;
295 break;
297 args[0] = fd;
298 args[1] = opt->level;
299 args[2] = opt->name;
300 args[3] = (long)(ret_pos+sizeof(struct opthdr));
301 args[4] = (long)&opt->len;
302 SOLD("calling GETSOCKOPT");
303 set_fs(KERNEL_DS);
304 error = sys_socketcall(SYS_GETSOCKOPT, args);
305 set_fs(old_fs);
306 if (error) {
307 failed = TBADOPT;
308 break;
310 SOLD("GETSOCKOPT ok");
311 ret_space -= sizeof(struct opthdr) + opt->len;
312 ret_len += sizeof(struct opthdr) + opt->len;
313 ret_pos += sizeof(struct opthdr) + opt->len;
314 opt_len -= sizeof(struct opthdr) + orig_opt_len;
315 opt_buf += sizeof(struct opthdr) + orig_opt_len;
316 SOLD("loop end");
318 SOLD("loop done");
319 if (do_ret) {
320 SOLD("generating ret msg");
321 if (failed)
322 timod_error(fd, T_OPTMGMT_REQ, failed, -error);
323 else {
324 struct T_primsg *it;
325 it = timod_mkctl(sizeof(struct T_optmgmt_ack) + ret_len);
326 if (it) {
327 struct T_optmgmt_ack *ack =
328 (struct T_optmgmt_ack *)&it->type;
329 SOLD("got primsg");
330 ack->PRIM_type = T_OPTMGMT_ACK;
331 ack->OPT_length = ret_len;
332 ack->OPT_offset = sizeof(struct T_optmgmt_ack);
333 ack->MGMT_flags = (failed ? T_FAILURE : flag);
334 memcpy(((char*)ack)+sizeof(struct T_optmgmt_ack),
335 ret_buf, ret_len);
336 timod_queue(fd, it);
340 SOLDD(("put_page %p\n", ret_buf));
341 putpage(ret_buf);
342 SOLD("done");
343 return 0;
346 int timod_putmsg(unsigned int fd, char __user *ctl_buf, int ctl_len,
347 char __user *data_buf, int data_len, int flags)
349 int ret, error, terror;
350 char *buf;
351 struct file *filp;
352 struct inode *ino;
353 struct fdtable *fdt;
354 struct sol_socket_struct *sock;
355 mm_segment_t old_fs = get_fs();
356 long args[6];
357 int (*sys_socketcall)(int, unsigned long __user *) =
358 (int (*)(int, unsigned long __user *))SYS(socketcall);
359 int (*sys_sendto)(int, void __user *, size_t, unsigned, struct sockaddr __user *, int) =
360 (int (*)(int, void __user *, size_t, unsigned, struct sockaddr __user *, int))SYS(sendto);
362 fdt = files_fdtable(current->files);
363 filp = fdt->fd[fd];
364 ino = filp->f_path.dentry->d_inode;
365 sock = (struct sol_socket_struct *)filp->private_data;
366 SOLD("entry");
367 if (get_user(ret, (int __user *)A(ctl_buf)))
368 return -EFAULT;
369 switch (ret) {
370 case T_BIND_REQ:
372 struct T_bind_req req;
374 SOLDD(("bind %016lx(%016lx)\n", sock, filp));
375 SOLD("T_BIND_REQ");
376 if (sock->state != TS_UNBND) {
377 timod_error(fd, T_BIND_REQ, TOUTSTATE, 0);
378 return 0;
380 SOLD("state ok");
381 if (copy_from_user(&req, ctl_buf, sizeof(req))) {
382 timod_error(fd, T_BIND_REQ, TSYSERR, EFAULT);
383 return 0;
385 SOLD("got ctl req");
386 if (req.ADDR_offset && req.ADDR_length) {
387 if (req.ADDR_length > BUF_SIZE) {
388 timod_error(fd, T_BIND_REQ, TSYSERR, EFAULT);
389 return 0;
391 SOLD("req size ok");
392 buf = getpage();
393 if (copy_from_user(buf, ctl_buf + req.ADDR_offset, req.ADDR_length)) {
394 timod_error(fd, T_BIND_REQ, TSYSERR, EFAULT);
395 putpage(buf);
396 return 0;
398 SOLD("got ctl data");
399 args[0] = fd;
400 args[1] = (long)buf;
401 args[2] = req.ADDR_length;
402 SOLD("calling BIND");
403 set_fs(KERNEL_DS);
404 error = sys_socketcall(SYS_BIND, args);
405 set_fs(old_fs);
406 putpage(buf);
407 SOLD("BIND returned");
408 } else
409 error = 0;
410 if (!error) {
411 struct T_primsg *it;
412 if (req.CONIND_number) {
413 args[0] = fd;
414 args[1] = req.CONIND_number;
415 SOLD("calling LISTEN");
416 set_fs(KERNEL_DS);
417 error = sys_socketcall(SYS_LISTEN, args);
418 set_fs(old_fs);
419 SOLD("LISTEN done");
421 it = timod_mkctl(sizeof(struct T_bind_ack)+sizeof(struct sockaddr));
422 if (it) {
423 struct T_bind_ack *ack;
425 ack = (struct T_bind_ack *)&it->type;
426 ack->PRIM_type = T_BIND_ACK;
427 ack->ADDR_offset = sizeof(*ack);
428 ack->ADDR_length = sizeof(struct sockaddr);
429 ack->CONIND_number = req.CONIND_number;
430 args[0] = fd;
431 args[1] = (long)(ack+sizeof(*ack));
432 args[2] = (long)&ack->ADDR_length;
433 set_fs(KERNEL_DS);
434 sys_socketcall(SYS_GETSOCKNAME,args);
435 set_fs(old_fs);
436 sock->state = TS_IDLE;
437 timod_ok(fd, T_BIND_REQ);
438 timod_queue_end(fd, it);
439 SOLD("BIND done");
440 return 0;
443 SOLD("some error");
444 switch (error) {
445 case -EINVAL:
446 terror = TOUTSTATE;
447 error = 0;
448 break;
449 case -EACCES:
450 terror = TACCES;
451 error = 0;
452 break;
453 case -EADDRNOTAVAIL:
454 case -EADDRINUSE:
455 terror = TNOADDR;
456 error = 0;
457 break;
458 default:
459 terror = TSYSERR;
460 break;
462 timod_error(fd, T_BIND_REQ, terror, -error);
463 SOLD("BIND done");
464 return 0;
466 case T_CONN_REQ:
468 struct T_conn_req req;
469 unsigned short oldflags;
470 struct T_primsg *it;
471 SOLD("T_CONN_REQ");
472 if (sock->state != TS_UNBND && sock->state != TS_IDLE) {
473 timod_error(fd, T_CONN_REQ, TOUTSTATE, 0);
474 return 0;
476 SOLD("state ok");
477 if (copy_from_user(&req, ctl_buf, sizeof(req))) {
478 timod_error(fd, T_CONN_REQ, TSYSERR, EFAULT);
479 return 0;
481 SOLD("got ctl req");
482 if (ctl_len > BUF_SIZE) {
483 timod_error(fd, T_CONN_REQ, TSYSERR, EFAULT);
484 return 0;
486 SOLD("req size ok");
487 buf = getpage();
488 if (copy_from_user(buf, ctl_buf, ctl_len)) {
489 timod_error(fd, T_CONN_REQ, TSYSERR, EFAULT);
490 putpage(buf);
491 return 0;
493 #ifdef DEBUG_SOLARIS
495 char * ptr = buf;
496 int len = ctl_len;
497 printk("returned data (%d bytes): ",len);
498 while( len-- ) {
499 if (!(len & 7))
500 printk(" ");
501 printk("%02x",(unsigned char)*ptr++);
503 printk("\n");
505 #endif
506 SOLD("got ctl data");
507 args[0] = fd;
508 args[1] = (long)buf+req.DEST_offset;
509 args[2] = req.DEST_length;
510 oldflags = filp->f_flags;
511 filp->f_flags &= ~O_NONBLOCK;
512 SOLD("calling CONNECT");
513 set_fs(KERNEL_DS);
514 error = sys_socketcall(SYS_CONNECT, args);
515 set_fs(old_fs);
516 filp->f_flags = oldflags;
517 SOLD("CONNECT done");
518 if (!error) {
519 struct T_conn_con *con;
520 SOLD("no error");
521 it = timod_mkctl(ctl_len);
522 if (!it) {
523 putpage(buf);
524 return -ENOMEM;
526 con = (struct T_conn_con *)&it->type;
527 #ifdef DEBUG_SOLARIS
529 char * ptr = buf;
530 int len = ctl_len;
531 printk("returned data (%d bytes): ",len);
532 while( len-- ) {
533 if (!(len & 7))
534 printk(" ");
535 printk("%02x",(unsigned char)*ptr++);
537 printk("\n");
539 #endif
540 memcpy(con, buf, ctl_len);
541 SOLD("copied ctl_buf");
542 con->PRIM_type = T_CONN_CON;
543 sock->state = TS_DATA_XFER;
544 } else {
545 struct T_discon_ind *dis;
546 SOLD("some error");
547 it = timod_mkctl(sizeof(*dis));
548 if (!it) {
549 putpage(buf);
550 return -ENOMEM;
552 SOLD("got primsg");
553 dis = (struct T_discon_ind *)&it->type;
554 dis->PRIM_type = T_DISCON_IND;
555 dis->DISCON_reason = -error; /* FIXME: convert this as in iABI_errors() */
556 dis->SEQ_number = 0;
558 putpage(buf);
559 timod_ok(fd, T_CONN_REQ);
560 it->pri = 0;
561 timod_queue_end(fd, it);
562 SOLD("CONNECT done");
563 return 0;
565 case T_OPTMGMT_REQ:
567 struct T_optmgmt_req req;
568 SOLD("OPTMGMT_REQ");
569 if (copy_from_user(&req, ctl_buf, sizeof(req)))
570 return -EFAULT;
571 SOLD("got req");
572 return timod_optmgmt(fd, req.MGMT_flags,
573 req.OPT_offset > 0 ? ctl_buf + req.OPT_offset : NULL,
574 req.OPT_length, 1);
576 case T_UNITDATA_REQ:
578 struct T_unitdata_req req;
580 int err;
581 SOLD("T_UNITDATA_REQ");
582 if (sock->state != TS_IDLE && sock->state != TS_DATA_XFER) {
583 timod_error(fd, T_CONN_REQ, TOUTSTATE, 0);
584 return 0;
586 SOLD("state ok");
587 if (copy_from_user(&req, ctl_buf, sizeof(req))) {
588 timod_error(fd, T_CONN_REQ, TSYSERR, EFAULT);
589 return 0;
591 SOLD("got ctl req");
592 #ifdef DEBUG_SOLARIS
594 char * ptr = ctl_buf+req.DEST_offset;
595 int len = req.DEST_length;
596 printk("socket address (%d bytes): ",len);
597 while( len-- ) {
598 char c;
599 if (get_user(c,ptr))
600 printk("??");
601 else
602 printk("%02x",(unsigned char)c);
603 ptr++;
605 printk("\n");
607 #endif
608 err = sys_sendto(fd, data_buf, data_len, 0, req.DEST_length > 0 ? (struct sockaddr __user *)(ctl_buf+req.DEST_offset) : NULL, req.DEST_length);
609 if (err == data_len)
610 return 0;
611 if(err >= 0) {
612 printk("timod: sendto failed to send all the data\n");
613 return 0;
615 timod_error(fd, T_CONN_REQ, TSYSERR, -err);
616 return 0;
618 default:
619 printk(KERN_INFO "timod_putmsg: unsupported command %u.\n", ret);
620 break;
622 return -EINVAL;
625 int timod_getmsg(unsigned int fd, char __user *ctl_buf, int ctl_maxlen, s32 __user *ctl_len,
626 char __user *data_buf, int data_maxlen, s32 __user *data_len, int *flags_p)
628 int error;
629 int oldflags;
630 struct file *filp;
631 struct inode *ino;
632 struct fdtable *fdt;
633 struct sol_socket_struct *sock;
634 struct T_unitdata_ind udi;
635 mm_segment_t old_fs = get_fs();
636 long args[6];
637 char __user *tmpbuf;
638 int tmplen;
639 int (*sys_socketcall)(int, unsigned long __user *) =
640 (int (*)(int, unsigned long __user *))SYS(socketcall);
641 int (*sys_recvfrom)(int, void __user *, size_t, unsigned, struct sockaddr __user *, int __user *);
643 SOLD("entry");
644 SOLDD(("%u %p %d %p %p %d %p %d\n", fd, ctl_buf, ctl_maxlen, ctl_len, data_buf, data_maxlen, data_len, *flags_p));
645 fdt = files_fdtable(current->files);
646 filp = fdt->fd[fd];
647 ino = filp->f_path.dentry->d_inode;
648 sock = (struct sol_socket_struct *)filp->private_data;
649 SOLDD(("%p %p\n", sock->pfirst, sock->pfirst ? sock->pfirst->next : NULL));
650 if ( ctl_maxlen > 0 && !sock->pfirst && SOCKET_I(ino)->type == SOCK_STREAM
651 && sock->state == TS_IDLE) {
652 SOLD("calling LISTEN");
653 args[0] = fd;
654 args[1] = -1;
655 set_fs(KERNEL_DS);
656 sys_socketcall(SYS_LISTEN, args);
657 set_fs(old_fs);
658 SOLD("LISTEN done");
660 if (!(filp->f_flags & O_NONBLOCK)) {
661 struct poll_wqueues wait_table;
662 poll_table *wait;
664 poll_initwait(&wait_table);
665 wait = &wait_table.pt;
666 for(;;) {
667 SOLD("loop");
668 set_current_state(TASK_INTERRUPTIBLE);
669 /* ! ( l<0 || ( l>=0 && ( ! pfirst || (flags == HIPRI && pri != HIPRI) ) ) ) */
670 /* ( ! l<0 && ! ( l>=0 && ( ! pfirst || (flags == HIPRI && pri != HIPRI) ) ) ) */
671 /* ( l>=0 && ( ! l>=0 || ! ( ! pfirst || (flags == HIPRI && pri != HIPRI) ) ) ) */
672 /* ( l>=0 && ( l<0 || ( pfirst && ! (flags == HIPRI && pri != HIPRI) ) ) ) */
673 /* ( l>=0 && ( l<0 || ( pfirst && (flags != HIPRI || pri == HIPRI) ) ) ) */
674 /* ( l>=0 && ( pfirst && (flags != HIPRI || pri == HIPRI) ) ) */
675 if (ctl_maxlen >= 0 && sock->pfirst && (*flags_p != MSG_HIPRI || sock->pfirst->pri == MSG_HIPRI))
676 break;
677 SOLD("cond 1 passed");
678 if (
679 #if 1
680 *flags_p != MSG_HIPRI &&
681 #endif
682 ((filp->f_op->poll(filp, wait) & POLLIN) ||
683 (filp->f_op->poll(filp, NULL) & POLLIN) ||
684 signal_pending(current))
686 break;
688 if( *flags_p == MSG_HIPRI ) {
689 SOLD("avoiding lockup");
690 break ;
692 if(wait_table.error) {
693 SOLD("wait-table error");
694 poll_freewait(&wait_table);
695 return wait_table.error;
697 SOLD("scheduling");
698 schedule();
700 SOLD("loop done");
701 current->state = TASK_RUNNING;
702 poll_freewait(&wait_table);
703 if (signal_pending(current)) {
704 SOLD("signal pending");
705 return -EINTR;
708 if (ctl_maxlen >= 0 && sock->pfirst) {
709 struct T_primsg *it = sock->pfirst;
710 int l = min_t(int, ctl_maxlen, it->length);
711 SCHECK_MAGIC((char*)((u64)(((char *)&it->type)+sock->offset+it->length+7)&~7),MKCTL_MAGIC);
712 SOLD("purting ctl data");
713 if(copy_to_user(ctl_buf,
714 (char*)&it->type + sock->offset, l))
715 return -EFAULT;
716 SOLD("pur it");
717 if(put_user(l, ctl_len))
718 return -EFAULT;
719 SOLD("set ctl_len");
720 *flags_p = it->pri;
721 it->length -= l;
722 if (it->length) {
723 SOLD("more ctl");
724 sock->offset += l;
725 return MORECTL;
726 } else {
727 SOLD("removing message");
728 sock->pfirst = it->next;
729 if (!sock->pfirst)
730 sock->plast = NULL;
731 SOLDD(("getmsg kfree %016lx->%016lx\n", it, sock->pfirst));
732 mykfree(it);
733 sock->offset = 0;
734 SOLD("ctl done");
735 return 0;
738 *flags_p = 0;
739 if (ctl_maxlen >= 0) {
740 SOLD("ACCEPT perhaps?");
741 if (SOCKET_I(ino)->type == SOCK_STREAM && sock->state == TS_IDLE) {
742 struct T_conn_ind ind;
743 char *buf = getpage();
744 int len = BUF_SIZE;
746 SOLD("trying ACCEPT");
747 if (put_user(ctl_maxlen - sizeof(ind), ctl_len))
748 return -EFAULT;
749 args[0] = fd;
750 args[1] = (long)buf;
751 args[2] = (long)&len;
752 oldflags = filp->f_flags;
753 filp->f_flags |= O_NONBLOCK;
754 SOLD("calling ACCEPT");
755 set_fs(KERNEL_DS);
756 error = sys_socketcall(SYS_ACCEPT, args);
757 set_fs(old_fs);
758 filp->f_flags = oldflags;
759 if (error < 0) {
760 SOLD("some error");
761 putpage(buf);
762 return error;
764 if (error) {
765 SOLD("connect");
766 putpage(buf);
767 if (sizeof(ind) > ctl_maxlen) {
768 SOLD("generating CONN_IND");
769 ind.PRIM_type = T_CONN_IND;
770 ind.SRC_length = len;
771 ind.SRC_offset = sizeof(ind);
772 ind.OPT_length = ind.OPT_offset = 0;
773 ind.SEQ_number = error;
774 if(copy_to_user(ctl_buf, &ind, sizeof(ind))||
775 put_user(sizeof(ind)+ind.SRC_length,ctl_len))
776 return -EFAULT;
777 SOLD("CONN_IND created");
779 if (data_maxlen >= 0)
780 put_user(0, data_len);
781 SOLD("CONN_IND done");
782 return 0;
784 if (len>ctl_maxlen) {
785 SOLD("data don't fit");
786 putpage(buf);
787 return -EFAULT; /* XXX - is this ok ? */
789 if(copy_to_user(ctl_buf,buf,len) || put_user(len,ctl_len)){
790 SOLD("can't copy data");
791 putpage(buf);
792 return -EFAULT;
794 SOLD("ACCEPT done");
795 putpage(buf);
798 SOLD("checking data req");
799 if (data_maxlen <= 0) {
800 if (data_maxlen == 0)
801 put_user(0, data_len);
802 if (ctl_maxlen >= 0)
803 put_user(0, ctl_len);
804 return -EAGAIN;
806 SOLD("wants data");
807 if (ctl_maxlen > sizeof(udi) && sock->state == TS_IDLE) {
808 SOLD("udi fits");
809 tmpbuf = ctl_buf + sizeof(udi);
810 tmplen = ctl_maxlen - sizeof(udi);
811 } else {
812 SOLD("udi does not fit");
813 tmpbuf = NULL;
814 tmplen = 0;
816 if (put_user(tmplen, ctl_len))
817 return -EFAULT;
818 SOLD("set ctl_len");
819 oldflags = filp->f_flags;
820 filp->f_flags |= O_NONBLOCK;
821 SOLD("calling recvfrom");
822 sys_recvfrom = (int (*)(int, void __user *, size_t, unsigned, struct sockaddr __user *, int __user *))SYS(recvfrom);
823 error = sys_recvfrom(fd, data_buf, data_maxlen, 0, (struct sockaddr __user *)tmpbuf, ctl_len);
824 filp->f_flags = oldflags;
825 if (error < 0)
826 return error;
827 SOLD("error >= 0" ) ;
828 if (error && ctl_maxlen > sizeof(udi) && sock->state == TS_IDLE) {
829 SOLD("generating udi");
830 udi.PRIM_type = T_UNITDATA_IND;
831 if (get_user(udi.SRC_length, ctl_len))
832 return -EFAULT;
833 udi.SRC_offset = sizeof(udi);
834 udi.OPT_length = udi.OPT_offset = 0;
835 if (copy_to_user(ctl_buf, &udi, sizeof(udi)) ||
836 put_user(sizeof(udi)+udi.SRC_length, ctl_len))
837 return -EFAULT;
838 SOLD("udi done");
839 } else {
840 if (put_user(0, ctl_len))
841 return -EFAULT;
843 put_user(error, data_len);
844 SOLD("done");
845 return 0;
848 asmlinkage int solaris_getmsg(unsigned int fd, u32 arg1, u32 arg2, u32 arg3)
850 struct file *filp;
851 struct inode *ino;
852 struct strbuf __user *ctlptr;
853 struct strbuf __user *datptr;
854 struct strbuf ctl, dat;
855 int __user *flgptr;
856 int flags;
857 int error = -EBADF;
858 struct fdtable *fdt;
860 SOLD("entry");
861 lock_kernel();
862 if (fd >= sysctl_nr_open)
863 goto out;
865 fdt = files_fdtable(current->files);
866 filp = fdt->fd[fd];
867 if(!filp) goto out;
869 ino = filp->f_path.dentry->d_inode;
870 if (!ino || !S_ISSOCK(ino->i_mode))
871 goto out;
873 ctlptr = (struct strbuf __user *)A(arg1);
874 datptr = (struct strbuf __user *)A(arg2);
875 flgptr = (int __user *)A(arg3);
877 error = -EFAULT;
879 if (ctlptr) {
880 if (copy_from_user(&ctl,ctlptr,sizeof(struct strbuf)) ||
881 put_user(-1,&ctlptr->len))
882 goto out;
883 } else
884 ctl.maxlen = -1;
886 if (datptr) {
887 if (copy_from_user(&dat,datptr,sizeof(struct strbuf)) ||
888 put_user(-1,&datptr->len))
889 goto out;
890 } else
891 dat.maxlen = -1;
893 if (get_user(flags,flgptr))
894 goto out;
896 switch (flags) {
897 case 0:
898 case MSG_HIPRI:
899 case MSG_ANY:
900 case MSG_BAND:
901 break;
902 default:
903 error = -EINVAL;
904 goto out;
907 error = timod_getmsg(fd,A(ctl.buf),ctl.maxlen,&ctlptr->len,
908 A(dat.buf),dat.maxlen,&datptr->len,&flags);
910 if (!error && put_user(flags,flgptr))
911 error = -EFAULT;
912 out:
913 unlock_kernel();
914 SOLD("done");
915 return error;
918 asmlinkage int solaris_putmsg(unsigned int fd, u32 arg1, u32 arg2, u32 arg3)
920 struct file *filp;
921 struct inode *ino;
922 struct strbuf __user *ctlptr;
923 struct strbuf __user *datptr;
924 struct strbuf ctl, dat;
925 int flags = (int) arg3;
926 int error = -EBADF;
927 struct fdtable *fdt;
929 SOLD("entry");
930 lock_kernel();
931 if (fd >= sysctl_nr_open)
932 goto out;
934 fdt = files_fdtable(current->files);
935 filp = fdt->fd[fd];
936 if(!filp) goto out;
938 ino = filp->f_path.dentry->d_inode;
939 if (!ino) goto out;
941 if (!S_ISSOCK(ino->i_mode) &&
942 (imajor(ino) != 30 || iminor(ino) != 1))
943 goto out;
945 ctlptr = A(arg1);
946 datptr = A(arg2);
948 error = -EFAULT;
950 if (ctlptr) {
951 if (copy_from_user(&ctl,ctlptr,sizeof(ctl)))
952 goto out;
953 if (ctl.len < 0 && flags) {
954 error = -EINVAL;
955 goto out;
957 } else {
958 ctl.len = 0;
959 ctl.buf = 0;
962 if (datptr) {
963 if (copy_from_user(&dat,datptr,sizeof(dat)))
964 goto out;
965 } else {
966 dat.len = 0;
967 dat.buf = 0;
970 error = timod_putmsg(fd,A(ctl.buf),ctl.len,
971 A(dat.buf),dat.len,flags);
972 out:
973 unlock_kernel();
974 SOLD("done");
975 return error;