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