Main Page | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

timod.c

Go to the documentation of this file.
00001 /* $Id: timod.c,v 1.1 1998/03/26 08:46:18 jj Exp $
00002  * timod.c: timod emulation.
00003  *
00004  * Copyright (C) 1998 Patrik Rak (prak3264@ss1000.ms.mff.cuni.cz)
00005  *
00006  * Streams & timod emulation based on code
00007  * Copyright (C) 1995, 1996 Mike Jagdis (jaggy@purplet.demon.co.uk)
00008  *
00009  */
00010  
00011 #include <linux/types.h>
00012 #include <linux/kernel.h>
00013 #include <linux/sched.h>
00014 #include <linux/smp.h>
00015 #include <linux/smp_lock.h>
00016 #include <linux/ioctl.h>
00017 #include <linux/fs.h>
00018 #include <linux/netdevice.h>
00019 #include <linux/poll.h>
00020 
00021 #include <asm/uaccess.h>
00022 #include <asm/termios.h>
00023 
00024 #include "conv.h"
00025 #include "socksys.h"
00026 
00027 extern char *getname32(u32 filename);
00028 #define putname32 putname
00029 
00030 extern asmlinkage int sys_ioctl(unsigned int fd, unsigned int cmd, 
00031         unsigned long arg);
00032 extern asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd,
00033         u32 arg);
00034 asmlinkage int solaris_ioctl(unsigned int fd, unsigned int cmd, u32 arg);
00035 
00036 #ifdef __SMP__
00037 spinlock_t timod_pagelock = SPIN_LOCK_UNLOCKED;
00038 #endif
00039 static char * page = NULL ;
00040 
00041 #ifndef DEBUG_SOLARIS_KMALLOC
00042 
00043 #define mykmalloc kmalloc
00044 #define mykfree kfree
00045 
00046 #else
00047 
00048 void * mykmalloc(size_t s, int gfp)
00049 {
00050         static char * page;
00051         static size_t free = 0;
00052         void * r;
00053         s = ((s + 63) & ~63);
00054         if( s > PAGE_SIZE ) {
00055                 SOLD("too big size, calling real kmalloc");
00056                 return kmalloc(s, gfp);
00057         }
00058         if( s > free ) {
00059                 /* we are wasting memory, but we don't care */
00060                 page = (char *)__get_free_page(gfp);
00061                 free = PAGE_SIZE;
00062         }
00063         r = page;
00064         page += s;
00065         free -= s;
00066         return r;
00067 }
00068 
00069 void mykfree(void *p)
00070 {
00071 }
00072 
00073 #endif
00074 
00075 #ifndef DEBUG_SOLARIS
00076 
00077 #define BUF_SIZE        PAGE_SIZE
00078 #define PUT_MAGIC(a,m)
00079 #define CHECK_MAGIC(a,m)
00080 #define BUF_OFFSET      0
00081 #define MKCTL_TRAILER   0
00082 
00083 #else
00084 
00085 #define BUF_SIZE        (PAGE_SIZE-2*sizeof(u64))
00086 #define BUFPAGE_MAGIC   0xBADC0DEDDEADBABEL
00087 #define MKCTL_MAGIC     0xDEADBABEBADC0DEDL
00088 #define PUT_MAGIC(a,m)  do{(*(u64*)(a))=(m);}while(0)
00089 #define CHECK_MAGIC(a,m)        do{if((*(u64*)(a))!=(m))printk("%s,%u,%s(): magic %08x at %p corrupted!\n",\
00090                                 __FILE__,__LINE__,__FUNCTION__,(m),(a));}while(0)
00091 #define BUF_OFFSET      sizeof(u64)
00092 #define MKCTL_TRAILER   sizeof(u64)
00093 
00094 #endif
00095 
00096 static char *getpage( void )
00097 {
00098         char *r;
00099         SOLD("getting page");
00100         spin_lock(&timod_pagelock);
00101         if (page) {
00102                 r = page;
00103                 page = NULL;
00104                 spin_unlock(&timod_pagelock);
00105                 SOLD("got cached");
00106                 return r + BUF_OFFSET;
00107         }
00108         spin_unlock(&timod_pagelock);
00109         SOLD("getting new");
00110         r = (char *)__get_free_page(GFP_KERNEL);
00111         PUT_MAGIC(r,BUFPAGE_MAGIC);
00112         PUT_MAGIC(r+PAGE_SIZE-sizeof(u64),BUFPAGE_MAGIC);
00113         return r + BUF_OFFSET;
00114 }
00115 
00116 static void putpage(char *p)
00117 {
00118         SOLD("putting page");
00119         p = p - BUF_OFFSET;
00120         CHECK_MAGIC(p,BUFPAGE_MAGIC);
00121         CHECK_MAGIC(p+PAGE_SIZE-sizeof(u64),BUFPAGE_MAGIC);
00122         spin_lock(&timod_pagelock);
00123         if (page) {
00124                 spin_unlock(&timod_pagelock);
00125                 free_page((unsigned long)p);
00126                 SOLD("freed it");
00127         } else {
00128                 page = p;
00129                 spin_unlock(&timod_pagelock);
00130                 SOLD("cached it");
00131         }
00132 }
00133 
00134 static struct T_primsg *timod_mkctl(int size)
00135 {
00136         struct T_primsg *it;
00137 
00138         SOLD("creating primsg");
00139         it = (struct T_primsg *)mykmalloc(size+sizeof(*it)-sizeof(s32)+2*MKCTL_TRAILER, GFP_KERNEL);
00140         if (it) {
00141                 SOLD("got it");
00142                 it->pri = MSG_HIPRI;
00143                 it->length = size;
00144                 PUT_MAGIC((char*)((u64)(((char *)&it->type)+size+7)&~7),MKCTL_MAGIC);
00145         }
00146         return it;
00147 }
00148 
00149 static void timod_wake_socket(unsigned int fd)
00150 {
00151         struct socket *sock;
00152 
00153         SOLD("wakeing socket");
00154         sock = &current->files->fd[fd]->f_dentry->d_inode->u.socket_i;
00155         wake_up_interruptible(&sock->wait);
00156         if (sock->fasync_list && !(sock->flags & SO_WAITDATA))
00157                 kill_fasync(sock->fasync_list, SIGIO);
00158         SOLD("done");
00159 }
00160 
00161 static void timod_queue(unsigned int fd, struct T_primsg *it)
00162 {
00163         struct sol_socket_struct *sock;
00164 
00165         SOLD("queuing primsg");
00166         sock = (struct sol_socket_struct *)current->files->fd[fd]->private_data;
00167         it->next = sock->pfirst;
00168         sock->pfirst = it;
00169         if (!sock->plast)
00170                 sock->plast = it;
00171         timod_wake_socket(fd);
00172         SOLD("done");
00173 }
00174 
00175 static void timod_queue_end(unsigned int fd, struct T_primsg *it)
00176 {
00177         struct sol_socket_struct *sock;
00178 
00179         SOLD("queuing primsg at end");
00180         sock = (struct sol_socket_struct *)current->files->fd[fd]->private_data;
00181         it->next = NULL;
00182         if (sock->plast)
00183                 sock->plast->next = it;
00184         else
00185                 sock->pfirst = it;
00186         sock->plast = it;
00187         SOLD("done");
00188 }
00189 
00190 static void timod_error(unsigned int fd, int prim, int terr, int uerr)
00191 {
00192         struct T_primsg *it;
00193         
00194         SOLD("making error");
00195         it = timod_mkctl(sizeof(struct T_error_ack));
00196         if (it) {
00197                 struct T_error_ack *err = (struct T_error_ack *)&it->type;
00198                 
00199                 SOLD("got it");
00200                 err->PRIM_type = T_ERROR_ACK;
00201                 err->ERROR_prim = prim;
00202                 err->TLI_error = terr;
00203                 err->UNIX_error = uerr; /* FIXME: convert this */
00204                 timod_queue(fd, it);
00205         }
00206         SOLD("done");
00207 }
00208 
00209 static void timod_ok(unsigned int fd, int prim)
00210 {
00211         struct T_primsg *it;
00212         struct T_ok_ack *ok;
00213         
00214         SOLD("creating ok ack");
00215         it = timod_mkctl(sizeof(*ok));
00216         if (it) {
00217                 SOLD("got it");
00218                 ok = (struct T_ok_ack *)&it->type;
00219                 ok->PRIM_type = T_OK_ACK;
00220                 ok->CORRECT_prim = prim;
00221                 timod_queue(fd, it);
00222         }
00223         SOLD("done");
00224 }
00225 
00226 static int timod_optmgmt(unsigned int fd, int flag, char *opt_buf, int opt_len, int do_ret)
00227 {
00228         int error, failed;
00229         int ret_space, ret_len;
00230         long args[5];
00231         char *ret_pos,*ret_buf;
00232         int (*sys_socketcall)(int, unsigned long *) =
00233                 (int (*)(int, unsigned long *))SYS(socketcall);
00234         mm_segment_t old_fs = get_fs();
00235 
00236         SOLD("entry");
00237         SOLDD(("fd %u flg %u buf %p len %u doret %u",fd,flag,opt_buf,opt_len,do_ret));
00238         if (!do_ret && (!opt_buf || opt_len <= 0))
00239                 return 0;
00240         SOLD("getting page");
00241         ret_pos = ret_buf = getpage();
00242         ret_space = BUF_SIZE;
00243         ret_len = 0;
00244         
00245         error = failed = 0;
00246         SOLD("looping");
00247         while(opt_len >= sizeof(struct opthdr)) {
00248                 struct opthdr *opt;
00249                 int orig_opt_len; 
00250                 SOLD("loop start");
00251                 opt = (struct opthdr *)ret_pos; 
00252                 if (ret_space < sizeof(struct opthdr)) {
00253                         failed = TSYSERR;
00254                         break;
00255                 }
00256                 SOLD("getting opthdr");
00257                 if (copy_from_user(opt, opt_buf, sizeof(struct opthdr)) ||
00258                         opt->len > opt_len) {
00259                         failed = TBADOPT;
00260                         break;
00261                 }
00262                 SOLD("got opthdr");
00263                 if (flag == T_NEGOTIATE) {
00264                         char *buf;
00265                         
00266                         SOLD("handling T_NEGOTIATE");
00267                         buf = ret_pos + sizeof(struct opthdr);
00268                         if (ret_space < opt->len + sizeof(struct opthdr) ||
00269                                 copy_from_user(buf, opt_buf+sizeof(struct opthdr), opt->len)) {
00270                                 failed = TSYSERR;
00271                                 break;
00272                         }
00273                         SOLD("got optdata");
00274                         args[0] = fd;
00275                         args[1] = opt->level;
00276                         args[2] = opt->name;
00277                         args[3] = (long)buf;
00278                         args[4] = opt->len;
00279                         SOLD("calling SETSOCKOPT");
00280                         set_fs(KERNEL_DS);
00281                         error = sys_socketcall(SYS_SETSOCKOPT, args);
00282                         set_fs(old_fs);
00283                         if (error) {
00284                                 failed = TBADOPT;
00285                                 break;
00286                         }
00287                         SOLD("SETSOCKOPT ok");
00288                 }
00289                 orig_opt_len = opt->len;
00290                 opt->len = ret_space - sizeof(struct opthdr);
00291                 if (opt->len < 0) {
00292                         failed = TSYSERR;
00293                         break;
00294                 }
00295                 args[0] = fd;
00296                 args[1] = opt->level;
00297                 args[2] = opt->name;
00298                 args[3] = (long)(ret_pos+sizeof(struct opthdr));
00299                 args[4] = (long)&opt->len;
00300                 SOLD("calling GETSOCKOPT");
00301                 set_fs(KERNEL_DS);
00302                 error = sys_socketcall(SYS_GETSOCKOPT, args);
00303                 set_fs(old_fs);;
00304                 if (error) {
00305                         failed = TBADOPT;
00306                         break;
00307                 }
00308                 SOLD("GETSOCKOPT ok");
00309                 ret_space -= sizeof(struct opthdr) + opt->len;
00310                 ret_len += sizeof(struct opthdr) + opt->len;
00311                 ret_pos += sizeof(struct opthdr) + opt->len;
00312                 opt_len -= sizeof(struct opthdr) + orig_opt_len;
00313                 opt_buf += sizeof(struct opthdr) + orig_opt_len;
00314                 SOLD("loop end");
00315         }
00316         SOLD("loop done");
00317         if (do_ret) {
00318                 SOLD("generating ret msg");
00319                 if (failed)
00320                         timod_error(fd, T_OPTMGMT_REQ, failed, -error);
00321                 else {
00322                         struct T_primsg *it;
00323                         it = timod_mkctl(sizeof(struct T_optmgmt_ack) + ret_len);
00324                         if (it) {
00325                                 struct T_optmgmt_ack *ack =
00326                                         (struct T_optmgmt_ack *)&it->type;
00327                                 SOLD("got primsg");
00328                                 ack->PRIM_type = T_OPTMGMT_ACK;
00329                                 ack->OPT_length = ret_len;
00330                                 ack->OPT_offset = sizeof(struct T_optmgmt_ack);
00331                                 ack->MGMT_flags = (failed ? T_FAILURE : flag);
00332                                 memcpy(((char*)ack)+sizeof(struct T_optmgmt_ack),
00333                                         ret_buf, ret_len);
00334                                 timod_queue(fd, it);
00335                         }
00336                 }
00337         }
00338         SOLDD(("put_page %p\n", ret_buf));
00339         putpage(ret_buf);
00340         SOLD("done");   
00341         return 0;
00342 }
00343 
00344 int timod_putmsg(unsigned int fd, char *ctl_buf, int ctl_len,
00345                         char *data_buf, int data_len, int flags)
00346 {
00347         int ret, error, terror;
00348         char *buf;
00349         struct file *filp;
00350         struct inode *ino;
00351         struct sol_socket_struct *sock;
00352         mm_segment_t old_fs = get_fs();
00353         long args[6];
00354         int (*sys_socketcall)(int, unsigned long *) =
00355                 (int (*)(int, unsigned long *))SYS(socketcall);
00356         int (*sys_sendto)(int, void *, size_t, unsigned, struct sockaddr *, int) =
00357                 (int (*)(int, void *, size_t, unsigned, struct sockaddr *, int))SYS(sendto);
00358         filp = current->files->fd[fd];
00359         ino = filp->f_dentry->d_inode;
00360         sock = (struct sol_socket_struct *)filp->private_data;
00361         SOLD("entry");
00362         if (get_user(ret, (int *)A(ctl_buf)))
00363                 return -EFAULT;
00364         switch (ret) {
00365         case T_BIND_REQ:
00366         {
00367                 struct T_bind_req req;
00368                 
00369                 SOLDD(("bind %016lx(%016lx)\n", sock, filp));
00370                 SOLD("T_BIND_REQ");
00371                 if (sock->state != TS_UNBND) {
00372                         timod_error(fd, T_BIND_REQ, TOUTSTATE, 0);
00373                         return 0;
00374                 }
00375                 SOLD("state ok");
00376                 if (copy_from_user(&req, ctl_buf, sizeof(req))) {
00377                         timod_error(fd, T_BIND_REQ, TSYSERR, EFAULT);
00378                         return 0;
00379                 }
00380                 SOLD("got ctl req");
00381                 if (req.ADDR_offset && req.ADDR_length) {
00382                         if (req.ADDR_length > BUF_SIZE) {
00383                                 timod_error(fd, T_BIND_REQ, TSYSERR, EFAULT);
00384                                 return 0;
00385                         }
00386                         SOLD("req size ok");
00387                         buf = getpage();
00388                         if (copy_from_user(buf, ctl_buf + req.ADDR_offset, req.ADDR_length)) {
00389                                 timod_error(fd, T_BIND_REQ, TSYSERR, EFAULT);
00390                                 putpage(buf);
00391                                 return 0;
00392                         }
00393                         SOLD("got ctl data");
00394                         args[0] = fd;
00395                         args[1] = (long)buf;
00396                         args[2] = req.ADDR_length;
00397                         SOLD("calling BIND");
00398                         set_fs(KERNEL_DS);
00399                         error = sys_socketcall(SYS_BIND, args);
00400                         set_fs(old_fs);
00401                         putpage(buf);
00402                         SOLD("BIND returned");
00403                 } else 
00404                         error = 0;
00405                 if (!error) {
00406                         struct T_primsg *it;
00407                         if (req.CONIND_number) {
00408                                 args[0] = fd;
00409                                 args[1] = req.CONIND_number;
00410                                 SOLD("calling LISTEN");
00411                                 set_fs(KERNEL_DS);
00412                                 error = sys_socketcall(SYS_LISTEN, args);
00413                                 set_fs(old_fs);
00414                                 SOLD("LISTEN done");
00415                         }
00416                         it = timod_mkctl(sizeof(struct T_bind_ack)+sizeof(struct sockaddr));
00417                         if (it) {
00418                                 struct T_bind_ack *ack;
00419 
00420                                 ack = (struct T_bind_ack *)&it->type;
00421                                 ack->PRIM_type = T_BIND_ACK;
00422                                 ack->ADDR_offset = sizeof(*ack);
00423                                 ack->ADDR_length = sizeof(struct sockaddr);
00424                                 ack->CONIND_number = req.CONIND_number;
00425                                 args[0] = fd;
00426                                 args[1] = (long)(ack+sizeof(*ack));
00427                                 args[2] = (long)&ack->ADDR_length;
00428                                 set_fs(KERNEL_DS);
00429                                 sys_socketcall(SYS_GETSOCKNAME,args);
00430                                 set_fs(old_fs);
00431                                 sock->state = TS_IDLE;
00432                                 timod_ok(fd, T_BIND_REQ);
00433                                 timod_queue_end(fd, it);
00434                                 SOLD("BIND done");
00435                                 return 0;
00436                         }
00437                 }
00438                 SOLD("some error");
00439                 switch (error) {
00440                         case -EINVAL:
00441                                 terror = TOUTSTATE;
00442                                 error = 0;
00443                                 break;
00444                         case -EACCES:
00445                                 terror = TACCES;
00446                                 error = 0;
00447                                 break;
00448                         case -EADDRNOTAVAIL:
00449                         case -EADDRINUSE:
00450                                 terror = TNOADDR;
00451                                 error = 0;
00452                                 break;
00453                         default:
00454                                 terror = TSYSERR;
00455                                 break;
00456                 }
00457                 timod_error(fd, T_BIND_REQ, terror, -error);
00458                 SOLD("BIND done");
00459                 return 0;
00460         }
00461         case T_CONN_REQ:
00462         {
00463                 struct T_conn_req req;
00464                 unsigned short oldflags;
00465                 struct T_primsg *it;
00466                 SOLD("T_CONN_REQ");
00467                 if (sock->state != TS_UNBND && sock->state != TS_IDLE) {
00468                         timod_error(fd, T_CONN_REQ, TOUTSTATE, 0);
00469                         return 0;
00470                 }
00471                 SOLD("state ok");
00472                 if (copy_from_user(&req, ctl_buf, sizeof(req))) {
00473                         timod_error(fd, T_CONN_REQ, TSYSERR, EFAULT);
00474                         return 0;
00475                 }
00476                 SOLD("got ctl req");
00477                 if (ctl_len > BUF_SIZE) {
00478                         timod_error(fd, T_CONN_REQ, TSYSERR, EFAULT);
00479                         return 0;
00480                 }
00481                 SOLD("req size ok");
00482                 buf = getpage();
00483                 if (copy_from_user(buf, ctl_buf, ctl_len)) {
00484                         timod_error(fd, T_CONN_REQ, TSYSERR, EFAULT);
00485                         putpage(buf);
00486                         return 0;
00487                 }
00488 #ifdef DEBUG_SOLARIS            
00489                 {
00490                         char * ptr = buf;
00491                         int len = ctl_len;
00492                         printk("returned data (%d bytes): ",len);
00493                         while( len-- ) {
00494                                 if (!(len & 7))
00495                                         printk(" ");
00496                                 printk("%02x",(unsigned char)*ptr++);
00497                         }
00498                         printk("\n");
00499                 }
00500 #endif
00501                 SOLD("got ctl data");
00502                 args[0] = fd;
00503                 args[1] = (long)buf+req.DEST_offset;
00504                 args[2] = req.DEST_length;
00505                 oldflags = filp->f_flags;
00506                 filp->f_flags &= ~O_NONBLOCK;
00507                 SOLD("calling CONNECT");
00508                 set_fs(KERNEL_DS);
00509                 error = sys_socketcall(SYS_CONNECT, args);
00510                 set_fs(old_fs);
00511                 filp->f_flags = oldflags;
00512                 SOLD("CONNECT done");
00513                 if (!error) {
00514                         struct T_conn_con *con;
00515                         SOLD("no error");
00516                         it = timod_mkctl(ctl_len);
00517                         if (!it) {
00518                                 putpage(buf);
00519                                 return -ENOMEM;
00520                         }
00521                         con = (struct T_conn_con *)&it->type;
00522 #ifdef DEBUG_SOLARIS                    
00523                         {
00524                                 char * ptr = buf;
00525                                 int len = ctl_len;
00526                                 printk("returned data (%d bytes): ",len);
00527                                 while( len-- ) {
00528                                         if (!(len & 7))
00529                                                 printk(" ");
00530                                         printk("%02x",(unsigned char)*ptr++);
00531                                 }
00532                                 printk("\n");
00533                         }
00534 #endif
00535                         memcpy(con, buf, ctl_len);
00536                         SOLD("copied ctl_buf");
00537                         con->PRIM_type = T_CONN_CON;
00538                         sock->state = TS_DATA_XFER;
00539                 } else {
00540                         struct T_discon_ind *dis;
00541                         SOLD("some error");
00542                         it = timod_mkctl(sizeof(*dis));
00543                         if (!it) {
00544                                 putpage(buf);
00545                                 return -ENOMEM;
00546                         }
00547                         SOLD("got primsg");
00548                         dis = (struct T_discon_ind *)&it->type;
00549                         dis->PRIM_type = T_DISCON_IND;
00550                         dis->DISCON_reason = -error;    /* FIXME: convert this as in iABI_errors() */
00551                         dis->SEQ_number = 0;
00552                 }
00553                 putpage(buf);
00554                 timod_ok(fd, T_CONN_REQ);
00555                 it->pri = 0;
00556                 timod_queue_end(fd, it);
00557                 SOLD("CONNECT done");
00558                 return 0;
00559         }
00560         case T_OPTMGMT_REQ:
00561         {
00562                 struct T_optmgmt_req req;
00563                 SOLD("OPTMGMT_REQ");
00564                 if (copy_from_user(&req, ctl_buf, sizeof(req)))
00565                         return -EFAULT;
00566                 SOLD("got req");
00567                 return timod_optmgmt(fd, req.MGMT_flags,
00568                                 req.OPT_offset > 0 ? ctl_buf + req.OPT_offset : NULL,
00569                                 req.OPT_length, 1);
00570         }
00571         case T_UNITDATA_REQ:
00572         {
00573                 struct T_unitdata_req req;
00574                 
00575                 int err;
00576                 SOLD("T_UNITDATA_REQ");
00577                 if (sock->state != TS_IDLE && sock->state != TS_DATA_XFER) {
00578                         timod_error(fd, T_CONN_REQ, TOUTSTATE, 0);
00579                         return 0;
00580                 }
00581                 SOLD("state ok");
00582                 if (copy_from_user(&req, ctl_buf, sizeof(req))) {
00583                         timod_error(fd, T_CONN_REQ, TSYSERR, EFAULT);
00584                         return 0;
00585                 }
00586                 SOLD("got ctl req");
00587 #ifdef DEBUG_SOLARIS            
00588                 {
00589                         char * ptr = ctl_buf+req.DEST_offset;
00590                         int len = req.DEST_length;
00591                         printk("socket address (%d bytes): ",len);
00592                         while( len-- ) {
00593                                 char c;
00594                                 if (get_user(c,ptr))
00595                                         printk("??");
00596                                 else
00597                                         printk("%02x",(unsigned char)c);
00598                                 ptr++;
00599                         }
00600                         printk("\n");
00601                 }
00602 #endif          
00603                 err = sys_sendto(fd, data_buf, data_len, 0, req.DEST_length > 0 ? (struct sockaddr*)(ctl_buf+req.DEST_offset) : NULL, req.DEST_length);
00604                 if (err == data_len)
00605                         return 0;
00606                 if(err >= 0) {
00607                         printk("timod: sendto failed to send all the data\n");
00608                         return 0;
00609                 }
00610                 timod_error(fd, T_CONN_REQ, TSYSERR, -err);
00611                 return 0;
00612         }
00613         default:
00614                 printk("timod_putmsg: unsuported command %u.\n", ret);
00615                 break;
00616         }
00617         return -EINVAL;
00618 }
00619 
00620 /* copied directly from fs/select.c */
00621 
00622 static void free_wait(poll_table * p)
00623 {
00624         struct poll_table_entry * entry = p->entry + p->nr;
00625 
00626         SOLD("entry");
00627         while (p->nr > 0) {
00628                 p->nr--;
00629                 entry--;
00630                 remove_wait_queue(entry->wait_address,&entry->wait);
00631         }
00632         SOLD("done");
00633 }
00634 
00635 
00636 int timod_getmsg(unsigned int fd, char *ctl_buf, int ctl_maxlen, s32 *ctl_len,
00637                         char *data_buf, int data_maxlen, s32 *data_len, int *flags_p)
00638 {
00639         int error;
00640         int oldflags;
00641         struct file *filp;
00642         struct inode *ino;
00643         struct sol_socket_struct *sock;
00644         struct T_unitdata_ind udi;
00645         mm_segment_t old_fs = get_fs();
00646         long args[6];
00647         char *tmpbuf;
00648         int tmplen;
00649         int (*sys_socketcall)(int, unsigned long *) =
00650                 (int (*)(int, unsigned long *))SYS(socketcall);
00651         int (*sys_recvfrom)(int, void *, size_t, unsigned, struct sockaddr *, int *);
00652         
00653         SOLD("entry");
00654         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));
00655         filp = current->files->fd[fd];
00656         ino = filp->f_dentry->d_inode;
00657         sock = (struct sol_socket_struct *)filp->private_data;
00658         SOLDD(("%p %p\n", sock->pfirst, sock->pfirst ? sock->pfirst->next : NULL));
00659         if ( ctl_maxlen > 0 && !sock->pfirst && ino->u.socket_i.type == SOCK_STREAM
00660                 && sock->state == TS_IDLE) {
00661                 SOLD("calling LISTEN");
00662                 args[0] = fd;
00663                 args[1] = -1;
00664                 set_fs(KERNEL_DS);
00665                 sys_socketcall(SYS_LISTEN, args);
00666                 set_fs(old_fs);
00667                 SOLD("LISTEN done");
00668         }
00669         if (!(filp->f_flags & O_NONBLOCK)) {
00670                 poll_table wait_table, *wait;
00671                 struct poll_table_entry *entry;
00672                 SOLD("getting poll_table");
00673                 entry = (struct poll_table_entry *)__get_free_page(GFP_KERNEL);
00674                 if (!entry)
00675                         return -ENOMEM;
00676                 SOLD("got one");
00677                 wait_table.nr = 0;
00678                 wait_table.entry = entry;
00679                 wait = &wait_table;
00680                 for(;;) {
00681                         SOLD("loop");
00682                         current->state = TASK_INTERRUPTIBLE;
00683                         /* ! ( l<0 || ( l>=0 && ( ! pfirst || (flags == HIPRI && pri != HIPRI) ) ) ) */ 
00684                         /* ( ! l<0 && ! ( l>=0 && ( ! pfirst || (flags == HIPRI && pri != HIPRI) ) ) ) */ 
00685                         /* ( l>=0 && ( ! l>=0 || ! ( ! pfirst || (flags == HIPRI && pri != HIPRI) ) ) ) */ 
00686                         /* ( l>=0 && ( l<0 || ( pfirst && ! (flags == HIPRI && pri != HIPRI) ) ) ) */ 
00687                         /* ( l>=0 && ( l<0 || ( pfirst && (flags != HIPRI || pri == HIPRI) ) ) ) */ 
00688                         /* ( l>=0 && ( pfirst && (flags != HIPRI || pri == HIPRI) ) ) */ 
00689                         if (ctl_maxlen >= 0 && sock->pfirst && (*flags_p != MSG_HIPRI || sock->pfirst->pri == MSG_HIPRI))
00690                                 break;
00691                         SOLD("cond 1 passed");
00692                         if (
00693                         #if 1
00694                                 *flags_p != MSG_HIPRI &&
00695                         #endif
00696                                 ((filp->f_op->poll(filp, wait) & POLLIN) ||
00697                                 (filp->f_op->poll(filp, NULL) & POLLIN) ||
00698                                 signal_pending(current))
00699                         ) {
00700                                 break;
00701                         }
00702                         if( *flags_p == MSG_HIPRI ) {
00703                                 SOLD("avoiding lockup");
00704                                 break ;
00705                         }
00706                         SOLD("scheduling");
00707                         schedule();
00708                 }
00709                 SOLD("loop done");
00710                 current->state = TASK_RUNNING;
00711                 free_wait(&wait_table);
00712                 free_page((unsigned long)entry);
00713                 if (signal_pending(current)) {
00714                         SOLD("signal pending");
00715                         return -EINTR;
00716                 }
00717         }
00718         if (ctl_maxlen >= 0 && sock->pfirst) {
00719                 struct T_primsg *it = sock->pfirst;
00720 #ifndef min
00721 #define min(a,b) ((a)<(b)?(a):(b))
00722 #endif
00723                 int l = min(ctl_maxlen, it->length);
00724                 CHECK_MAGIC((char*)((u64)(((char *)&it->type)+sock->offset+it->length+7)&~7),MKCTL_MAGIC);
00725                 SOLD("purting ctl data");
00726                 if(copy_to_user(ctl_buf,
00727                         (char*)&it->type + sock->offset, l))
00728                         return -EFAULT;
00729                 SOLD("pur it");
00730                 if(put_user(l, ctl_len))
00731                         return -EFAULT;
00732                 SOLD("set ctl_len");
00733                 *flags_p = it->pri;
00734                 it->length -= l;
00735                 if (it->length) {
00736                         SOLD("more ctl");
00737                         sock->offset += l;
00738                         return MORECTL;
00739                 } else {
00740                         SOLD("removing message");
00741                         sock->pfirst = it->next;
00742                         if (!sock->pfirst)
00743                                 sock->plast = NULL;
00744                         SOLDD(("getmsg kfree %016lx->%016lx\n", it, sock->pfirst));
00745                         mykfree(it);
00746                         sock->offset = 0;
00747                         SOLD("ctl done");
00748                         return 0;
00749                 }
00750         }
00751         *flags_p = 0;
00752         if (ctl_maxlen >= 0) {
00753                 SOLD("ACCEPT perhaps?");
00754                 if (ino->u.socket_i.type == SOCK_STREAM && sock->state == TS_IDLE) {
00755                         struct T_conn_ind ind;
00756                         char *buf = getpage();
00757                         int len = BUF_SIZE;
00758 
00759                         SOLD("trying ACCEPT");
00760                         if (put_user(ctl_maxlen - sizeof(ind), ctl_len))
00761                                 return -EFAULT;
00762                         args[0] = fd;
00763                         args[1] = (long)buf;
00764                         args[2] = (long)&len;
00765                         oldflags = filp->f_flags;
00766                         filp->f_flags |= O_NONBLOCK;
00767                         SOLD("calling ACCEPT");
00768                         set_fs(KERNEL_DS);
00769                         error = sys_socketcall(SYS_ACCEPT, args);
00770                         set_fs(old_fs);
00771                         filp->f_flags = oldflags;
00772                         if (error < 0) {
00773                                 SOLD("some error");
00774                                 putpage(buf);
00775                                 return error;
00776                         }
00777                         if (error) {
00778                                 SOLD("connect");
00779                                 putpage(buf);
00780                                 if (sizeof(ind) > ctl_maxlen) {
00781                                         SOLD("generating CONN_IND");
00782                                         ind.PRIM_type = T_CONN_IND;
00783                                         ind.SRC_length = len;
00784                                         ind.SRC_offset = sizeof(ind);
00785                                         ind.OPT_length = ind.OPT_offset = 0;
00786                                         ind.SEQ_number = error;
00787                                         if(copy_to_user(ctl_buf, &ind, sizeof(ind))||
00788                                            put_user(sizeof(ind)+ind.SRC_length,ctl_len))
00789                                                 return -EFAULT;
00790                                         SOLD("CONN_IND created");
00791                                 }
00792                                 if (data_maxlen >= 0)
00793                                         put_user(0, data_len);
00794                                 SOLD("CONN_IND done");
00795                                 return 0;
00796                         }
00797                         if (len>ctl_maxlen) {
00798                                 SOLD("data don't fit");
00799                                 putpage(buf);
00800                                 return -EFAULT;         /* XXX - is this ok ? */
00801                         }
00802                         if(copy_to_user(ctl_buf,buf,len) || put_user(len,ctl_len)){
00803                                 SOLD("can't copy data");
00804                                 putpage(buf);
00805                                 return -EFAULT;
00806                         }
00807                         SOLD("ACCEPT done");
00808                         putpage(buf);
00809                 }
00810         }
00811         SOLD("checking data req");
00812         if (data_maxlen <= 0) {
00813                 if (data_maxlen == 0)
00814                         put_user(0, data_len);
00815                 if (ctl_maxlen >= 0)
00816                         put_user(0, ctl_len);
00817                 return -EAGAIN;
00818         }
00819         SOLD("wants data");
00820         if (ctl_maxlen > sizeof(udi) && sock->state == TS_IDLE) {
00821                 SOLD("udi fits");
00822                 tmpbuf = ctl_buf + sizeof(udi);
00823                 tmplen = ctl_maxlen - sizeof(udi);
00824         } else {
00825                 SOLD("udi does not fit");
00826                 tmpbuf = NULL;
00827                 tmplen = 0;
00828         }
00829         if (put_user(tmplen, ctl_len))
00830                 return -EFAULT;
00831         SOLD("set ctl_len");
00832         oldflags = filp->f_flags;
00833         filp->f_flags |= O_NONBLOCK;
00834         SOLD("calling recvfrom");
00835         sys_recvfrom = (int (*)(int, void *, size_t, unsigned, struct sockaddr *, int *))SYS(recvfrom);
00836         error = sys_recvfrom(fd, data_buf, min(0,data_maxlen), 0, (struct sockaddr*)tmpbuf, ctl_len);
00837         filp->f_flags = oldflags;
00838         if (error < 0)
00839                 return error;
00840         SOLD("error >= 0" ) ;
00841         if (error && ctl_maxlen > sizeof(udi) && sock->state == TS_IDLE) {
00842                 SOLD("generating udi");
00843                 udi.PRIM_type = T_UNITDATA_IND;
00844                 get_user(udi.SRC_length, ctl_len);
00845                 udi.SRC_offset = sizeof(udi);
00846                 udi.OPT_length = udi.OPT_offset = 0;
00847                 copy_to_user(ctl_buf, &udi, sizeof(udi));
00848                 put_user(sizeof(udi)+udi.SRC_length, ctl_len);
00849                 SOLD("udi done");
00850         } else
00851                 put_user(0, ctl_len);
00852         put_user(error, data_len);
00853         SOLD("done");
00854         return 0;
00855 }
00856 
00857 asmlinkage int solaris_getmsg(unsigned int fd, u32 arg1, u32 arg2, u32 arg3)
00858 {
00859         struct file *filp;
00860         struct inode *ino;
00861         struct strbuf *ctlptr, *datptr;
00862         struct strbuf ctl, dat;
00863         int *flgptr;
00864         int flags;
00865         int error = -EBADF;
00866 
00867         SOLD("entry");
00868         lock_kernel();
00869         if(fd >= NR_OPEN) goto out;
00870 
00871         filp = current->files->fd[fd];
00872         if(!filp) goto out;
00873 
00874         ino = filp->f_dentry->d_inode;
00875         if (!ino) goto out;
00876 
00877         if (!ino->i_sock)
00878                 goto out;
00879 
00880         ctlptr = (struct strbuf *)A(arg1);
00881         datptr = (struct strbuf *)A(arg2);
00882         flgptr = (int *)A(arg3);
00883 
00884         error = -EFAULT;
00885 
00886         if (ctlptr) {
00887                 if (copy_from_user(&ctl,ctlptr,sizeof(struct strbuf)) || 
00888                     put_user(-1,&ctlptr->len))
00889                         goto out;
00890         } else
00891                 ctl.maxlen = -1;
00892 
00893         if (datptr) {
00894                 if (copy_from_user(&dat,datptr,sizeof(struct strbuf)) || 
00895                     put_user(-1,&datptr->len))
00896                         goto out;
00897         } else
00898                 dat.maxlen = -1;
00899 
00900         if (get_user(flags,flgptr))
00901                 goto out;
00902 
00903         switch (flags) {
00904         case 0:
00905         case MSG_HIPRI:
00906         case MSG_ANY:
00907         case MSG_BAND:
00908                 break;
00909         default:
00910                 error = -EINVAL;
00911                 goto out;
00912         }
00913 
00914         error = timod_getmsg(fd,(char*)A(ctl.buf),ctl.maxlen,&ctlptr->len,
00915                                 (char*)A(dat.buf),dat.maxlen,&datptr->len,&flags);
00916 
00917         if (!error && put_user(flags,flgptr))
00918                 error = -EFAULT;
00919 out:
00920         unlock_kernel();
00921         SOLD("done");
00922         return error;
00923 }
00924 
00925 asmlinkage int solaris_putmsg(unsigned int fd, u32 arg1, u32 arg2, u32 arg3)
00926 {
00927         struct file *filp;
00928         struct inode *ino;
00929         struct strbuf *ctlptr, *datptr;
00930         struct strbuf ctl, dat;
00931         int flags = (int) arg3;
00932         int error = -EBADF;
00933 
00934         SOLD("entry");
00935         lock_kernel();
00936         if(fd >= NR_OPEN) goto out;
00937 
00938         filp = current->files->fd[fd];
00939         if(!filp) goto out;
00940 
00941         ino = filp->f_dentry->d_inode;
00942         if (!ino) goto out;
00943 
00944         if (!ino->i_sock &&
00945                 (MAJOR(ino->i_rdev) != 30 || MINOR(ino->i_rdev) != 1))
00946                 goto out;
00947 
00948         ctlptr = (struct strbuf *)A(arg1);
00949         datptr = (struct strbuf *)A(arg2);
00950 
00951         error = -EFAULT;
00952 
00953         if (ctlptr) {
00954                 if (copy_from_user(&ctl,ctlptr,sizeof(ctl)))
00955                         goto out;
00956                 if (ctl.len < 0 && flags) {
00957                         error = -EINVAL;
00958                         goto out;
00959                 }
00960         } else {
00961                 ctl.len = 0;
00962                 ctl.buf = 0;
00963         }
00964 
00965         if (datptr) {
00966                 if (copy_from_user(&dat,datptr,sizeof(dat)))
00967                         goto out;
00968         } else {
00969                 dat.len = 0;
00970                 dat.buf = 0;
00971         }
00972 
00973         error = timod_putmsg(fd,(char*)A(ctl.buf),ctl.len,
00974                                 (char*)A(dat.buf),dat.len,flags);
00975 out:
00976         unlock_kernel();
00977         SOLD("done");
00978         return error;
00979 }