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