[SPARC64]: Implement atomic backoff.
[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, gfp_t 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         struct fdtable *fdt;
147
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");
157 }
158
159 static void timod_queue(unsigned int fd, struct T_primsg *it)
160 {
161         struct sol_socket_struct *sock;
162         struct fdtable *fdt;
163
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");
173 }
174
175 static void timod_queue_end(unsigned int fd, struct T_primsg *it)
176 {
177         struct sol_socket_struct *sock;
178         struct fdtable *fdt;
179
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");
190 }
191
192 static void timod_error(unsigned int fd, int prim, int terr, int uerr)
193 {
194         struct T_primsg *it;
195         
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;
200                 
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);
207         }
208         SOLD("done");
209 }
210
211 static void timod_ok(unsigned int fd, int prim)
212 {
213         struct T_primsg *it;
214         struct T_ok_ack *ok;
215         
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);
224         }
225         SOLD("done");
226 }
227
228 static int timod_optmgmt(unsigned int fd, int flag, char __user *opt_buf, int opt_len, int do_ret)
229 {
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();
237
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;
246         
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;
257                 }
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;
263                 }
264                 SOLD("got opthdr");
265                 if (flag == T_NEGOTIATE) {
266                         char *buf;
267                         
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;
274                         }
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;
288                         }
289                         SOLD("SETSOCKOPT ok");
290                 }
291                 orig_opt_len = opt->len;
292                 opt->len = ret_space - sizeof(struct opthdr);
293                 if (opt->len < 0) {
294                         failed = TSYSERR;
295                         break;
296                 }
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;
309                 }
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");
317         }
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);
337                         }
338                 }
339         }
340         SOLDD(("put_page %p\n", ret_buf));
341         putpage(ret_buf);
342         SOLD("done");   
343         return 0;
344 }
345
346 int timod_putmsg(unsigned int fd, char __user *ctl_buf, int ctl_len,
347                         char __user *data_buf, int data_len, int flags)
348 {
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);
361
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:
371         {
372                 struct T_bind_req req;
373                 
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;
379                 }
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;
384                 }
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;
390                         }
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;
397                         }
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");
420                         }
421                         it = timod_mkctl(sizeof(struct T_bind_ack)+sizeof(struct sockaddr));
422                         if (it) {
423                                 struct T_bind_ack *ack;
424
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;
441                         }
442                 }
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;
461                 }
462                 timod_error(fd, T_BIND_REQ, terror, -error);
463                 SOLD("BIND done");
464                 return 0;
465         }
466         case T_CONN_REQ:
467         {
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;
475                 }
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;
480                 }
481                 SOLD("got ctl req");
482                 if (ctl_len > BUF_SIZE) {
483                         timod_error(fd, T_CONN_REQ, TSYSERR, EFAULT);
484                         return 0;
485                 }
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;
492                 }
493 #ifdef DEBUG_SOLARIS            
494                 {
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++);
502                         }
503                         printk("\n");
504                 }
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;
525                         }
526                         con = (struct T_conn_con *)&it->type;
527 #ifdef DEBUG_SOLARIS                    
528                         {
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++);
536                                 }
537                                 printk("\n");
538                         }
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;
551                         }
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;
557                 }
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;
564         }
565         case T_OPTMGMT_REQ:
566         {
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);
575         }
576         case T_UNITDATA_REQ:
577         {
578                 struct T_unitdata_req req;
579                 
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;
585                 }
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;
590                 }
591                 SOLD("got ctl req");
592 #ifdef DEBUG_SOLARIS            
593                 {
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++;
604                         }
605                         printk("\n");
606                 }
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;
614                 }
615                 timod_error(fd, T_CONN_REQ, TSYSERR, -err);
616                 return 0;
617         }
618         default:
619                 printk(KERN_INFO "timod_putmsg: unsupported command %u.\n", ret);
620                 break;
621         }
622         return -EINVAL;
623 }
624
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)
627 {
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 *);
642         
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");
659         }
660         if (!(filp->f_flags & O_NONBLOCK)) {
661                 struct poll_wqueues wait_table;
662                 poll_table *wait;
663
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))
685                         ) {
686                                 break;
687                         }
688                         if( *flags_p == MSG_HIPRI ) {
689                                 SOLD("avoiding lockup");
690                                 break ;
691                         }
692                         if(wait_table.error) {
693                                 SOLD("wait-table error");
694                                 poll_freewait(&wait_table);
695                                 return wait_table.error;
696                         }
697                         SOLD("scheduling");
698                         schedule();
699                 }
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;
706                 }
707         }
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;
736                 }
737         }
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;
745
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;
763                         }
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");
778                                 }
779                                 if (data_maxlen >= 0)
780                                         put_user(0, data_len);
781                                 SOLD("CONN_IND done");
782                                 return 0;
783                         }
784                         if (len>ctl_maxlen) {
785                                 SOLD("data don't fit");
786                                 putpage(buf);
787                                 return -EFAULT;         /* XXX - is this ok ? */
788                         }
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;
793                         }
794                         SOLD("ACCEPT done");
795                         putpage(buf);
796                 }
797         }
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;
805         }
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;
815         }
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;
842         }
843         put_user(error, data_len);
844         SOLD("done");
845         return 0;
846 }
847
848 asmlinkage int solaris_getmsg(unsigned int fd, u32 arg1, u32 arg2, u32 arg3)
849 {
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;
859
860         SOLD("entry");
861         lock_kernel();
862         if(fd >= NR_OPEN) goto out;
863
864         fdt = files_fdtable(current->files);
865         filp = fdt->fd[fd];
866         if(!filp) goto out;
867
868         ino = filp->f_path.dentry->d_inode;
869         if (!ino || !S_ISSOCK(ino->i_mode))
870                 goto out;
871
872         ctlptr = (struct strbuf __user *)A(arg1);
873         datptr = (struct strbuf __user *)A(arg2);
874         flgptr = (int __user *)A(arg3);
875
876         error = -EFAULT;
877
878         if (ctlptr) {
879                 if (copy_from_user(&ctl,ctlptr,sizeof(struct strbuf)) || 
880                     put_user(-1,&ctlptr->len))
881                         goto out;
882         } else
883                 ctl.maxlen = -1;
884
885         if (datptr) {
886                 if (copy_from_user(&dat,datptr,sizeof(struct strbuf)) || 
887                     put_user(-1,&datptr->len))
888                         goto out;
889         } else
890                 dat.maxlen = -1;
891
892         if (get_user(flags,flgptr))
893                 goto out;
894
895         switch (flags) {
896         case 0:
897         case MSG_HIPRI:
898         case MSG_ANY:
899         case MSG_BAND:
900                 break;
901         default:
902                 error = -EINVAL;
903                 goto out;
904         }
905
906         error = timod_getmsg(fd,A(ctl.buf),ctl.maxlen,&ctlptr->len,
907                                 A(dat.buf),dat.maxlen,&datptr->len,&flags);
908
909         if (!error && put_user(flags,flgptr))
910                 error = -EFAULT;
911 out:
912         unlock_kernel();
913         SOLD("done");
914         return error;
915 }
916
917 asmlinkage int solaris_putmsg(unsigned int fd, u32 arg1, u32 arg2, u32 arg3)
918 {
919         struct file *filp;
920         struct inode *ino;
921         struct strbuf __user *ctlptr;
922         struct strbuf __user *datptr;
923         struct strbuf ctl, dat;
924         int flags = (int) arg3;
925         int error = -EBADF;
926         struct fdtable *fdt;
927
928         SOLD("entry");
929         lock_kernel();
930         if(fd >= NR_OPEN) goto out;
931
932         fdt = files_fdtable(current->files);
933         filp = fdt->fd[fd];
934         if(!filp) goto out;
935
936         ino = filp->f_path.dentry->d_inode;
937         if (!ino) goto out;
938
939         if (!S_ISSOCK(ino->i_mode) &&
940                 (imajor(ino) != 30 || iminor(ino) != 1))
941                 goto out;
942
943         ctlptr = A(arg1);
944         datptr = A(arg2);
945
946         error = -EFAULT;
947
948         if (ctlptr) {
949                 if (copy_from_user(&ctl,ctlptr,sizeof(ctl)))
950                         goto out;
951                 if (ctl.len < 0 && flags) {
952                         error = -EINVAL;
953                         goto out;
954                 }
955         } else {
956                 ctl.len = 0;
957                 ctl.buf = 0;
958         }
959
960         if (datptr) {
961                 if (copy_from_user(&dat,datptr,sizeof(dat)))
962                         goto out;
963         } else {
964                 dat.len = 0;
965                 dat.buf = 0;
966         }
967
968         error = timod_putmsg(fd,A(ctl.buf),ctl.len,
969                                 A(dat.buf),dat.len,flags);
970 out:
971         unlock_kernel();
972         SOLD("done");
973         return error;
974 }