diff options
Diffstat (limited to 'arch/sparc64/solaris/timod.c')
-rw-r--r-- | arch/sparc64/solaris/timod.c | 976 |
1 files changed, 0 insertions, 976 deletions
diff --git a/arch/sparc64/solaris/timod.c b/arch/sparc64/solaris/timod.c deleted file mode 100644 index 15234fcd191a..000000000000 --- a/arch/sparc64/solaris/timod.c +++ /dev/null @@ -1,976 +0,0 @@ -/* $Id: timod.c,v 1.19 2002/02/08 03:57:14 davem Exp $ - * timod.c: timod emulation. - * - * Copyright (C) 1998 Patrik Rak (prak3264@ss1000.ms.mff.cuni.cz) - * - * Streams & timod emulation based on code - * Copyright (C) 1995, 1996 Mike Jagdis (jaggy@purplet.demon.co.uk) - * - */ - -#include <linux/types.h> -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/smp.h> -#include <linux/smp_lock.h> -#include <linux/ioctl.h> -#include <linux/fs.h> -#include <linux/file.h> -#include <linux/netdevice.h> -#include <linux/poll.h> - -#include <net/sock.h> - -#include <asm/uaccess.h> -#include <asm/termios.h> - -#include "conv.h" -#include "socksys.h" - -asmlinkage int solaris_ioctl(unsigned int fd, unsigned int cmd, u32 arg); - -static DEFINE_SPINLOCK(timod_pagelock); -static char * page = NULL ; - -#ifndef DEBUG_SOLARIS_KMALLOC - -#define mykmalloc kmalloc -#define mykfree kfree - -#else - -void * mykmalloc(size_t s, gfp_t gfp) -{ - static char * page; - static size_t free; - void * r; - s = ((s + 63) & ~63); - if( s > PAGE_SIZE ) { - SOLD("too big size, calling real kmalloc"); - return kmalloc(s, gfp); - } - if( s > free ) { - /* we are wasting memory, but we don't care */ - page = (char *)__get_free_page(gfp); - free = PAGE_SIZE; - } - r = page; - page += s; - free -= s; - return r; -} - -void mykfree(void *p) -{ -} - -#endif - -#ifndef DEBUG_SOLARIS - -#define BUF_SIZE PAGE_SIZE -#define PUT_MAGIC(a,m) -#define SCHECK_MAGIC(a,m) -#define BUF_OFFSET 0 -#define MKCTL_TRAILER 0 - -#else - -#define BUF_SIZE (PAGE_SIZE-2*sizeof(u64)) -#define BUFPAGE_MAGIC 0xBADC0DEDDEADBABEL -#define MKCTL_MAGIC 0xDEADBABEBADC0DEDL -#define PUT_MAGIC(a,m) do{(*(u64*)(a))=(m);}while(0) -#define SCHECK_MAGIC(a,m) do{if((*(u64*)(a))!=(m))printk("%s,%u,%s(): magic %08x at %p corrupted!\n",\ - __FILE__,__LINE__,__func__,(m),(a));}while(0) -#define BUF_OFFSET sizeof(u64) -#define MKCTL_TRAILER sizeof(u64) - -#endif - -static char *getpage( void ) -{ - char *r; - SOLD("getting page"); - spin_lock(&timod_pagelock); - if (page) { - r = page; - page = NULL; - spin_unlock(&timod_pagelock); - SOLD("got cached"); - return r + BUF_OFFSET; - } - spin_unlock(&timod_pagelock); - SOLD("getting new"); - r = (char *)__get_free_page(GFP_KERNEL); - PUT_MAGIC(r,BUFPAGE_MAGIC); - PUT_MAGIC(r+PAGE_SIZE-sizeof(u64),BUFPAGE_MAGIC); - return r + BUF_OFFSET; -} - -static void putpage(char *p) -{ - SOLD("putting page"); - p = p - BUF_OFFSET; - SCHECK_MAGIC(p,BUFPAGE_MAGIC); - SCHECK_MAGIC(p+PAGE_SIZE-sizeof(u64),BUFPAGE_MAGIC); - spin_lock(&timod_pagelock); - if (page) { - spin_unlock(&timod_pagelock); - free_page((unsigned long)p); - SOLD("freed it"); - } else { - page = p; - spin_unlock(&timod_pagelock); - SOLD("cached it"); - } -} - -static struct T_primsg *timod_mkctl(int size) -{ - struct T_primsg *it; - - SOLD("creating primsg"); - it = (struct T_primsg *)mykmalloc(size+sizeof(*it)-sizeof(s32)+2*MKCTL_TRAILER, GFP_KERNEL); - if (it) { - SOLD("got it"); - it->pri = MSG_HIPRI; - it->length = size; - PUT_MAGIC((char*)((u64)(((char *)&it->type)+size+7)&~7),MKCTL_MAGIC); - } - return it; -} - -static void timod_wake_socket(unsigned int fd) -{ - struct socket *sock; - struct fdtable *fdt; - - SOLD("wakeing socket"); - fdt = files_fdtable(current->files); - sock = SOCKET_I(fdt->fd[fd]->f_path.dentry->d_inode); - wake_up_interruptible(&sock->wait); - read_lock(&sock->sk->sk_callback_lock); - if (sock->fasync_list && !test_bit(SOCK_ASYNC_WAITDATA, &sock->flags)) - __kill_fasync(sock->fasync_list, SIGIO, POLL_IN); - read_unlock(&sock->sk->sk_callback_lock); - SOLD("done"); -} - -static void timod_queue(unsigned int fd, struct T_primsg *it) -{ - struct sol_socket_struct *sock; - struct fdtable *fdt; - - SOLD("queuing primsg"); - fdt = files_fdtable(current->files); - sock = (struct sol_socket_struct *)fdt->fd[fd]->private_data; - it->next = sock->pfirst; - sock->pfirst = it; - if (!sock->plast) - sock->plast = it; - timod_wake_socket(fd); - SOLD("done"); -} - -static void timod_queue_end(unsigned int fd, struct T_primsg *it) -{ - struct sol_socket_struct *sock; - struct fdtable *fdt; - - SOLD("queuing primsg at end"); - fdt = files_fdtable(current->files); - sock = (struct sol_socket_struct *)fdt->fd[fd]->private_data; - it->next = NULL; - if (sock->plast) - sock->plast->next = it; - else - sock->pfirst = it; - sock->plast = it; - SOLD("done"); -} - -static void timod_error(unsigned int fd, int prim, int terr, int uerr) -{ - struct T_primsg *it; - - SOLD("making error"); - it = timod_mkctl(sizeof(struct T_error_ack)); - if (it) { - struct T_error_ack *err = (struct T_error_ack *)&it->type; - - SOLD("got it"); - err->PRIM_type = T_ERROR_ACK; - err->ERROR_prim = prim; - err->TLI_error = terr; - err->UNIX_error = uerr; /* FIXME: convert this */ - timod_queue(fd, it); - } - SOLD("done"); -} - -static void timod_ok(unsigned int fd, int prim) -{ - struct T_primsg *it; - struct T_ok_ack *ok; - - SOLD("creating ok ack"); - it = timod_mkctl(sizeof(*ok)); - if (it) { - SOLD("got it"); - ok = (struct T_ok_ack *)&it->type; - ok->PRIM_type = T_OK_ACK; - ok->CORRECT_prim = prim; - timod_queue(fd, it); - } - SOLD("done"); -} - -static int timod_optmgmt(unsigned int fd, int flag, char __user *opt_buf, int opt_len, int do_ret) -{ - int error, failed; - int ret_space, ret_len; - long args[5]; - char *ret_pos,*ret_buf; - int (*sys_socketcall)(int, unsigned long *) = - (int (*)(int, unsigned long *))SYS(socketcall); - mm_segment_t old_fs = get_fs(); - - SOLD("entry"); - SOLDD(("fd %u flg %u buf %p len %u doret %u",fd,flag,opt_buf,opt_len,do_ret)); - if (!do_ret && (!opt_buf || opt_len <= 0)) - return 0; - SOLD("getting page"); - ret_pos = ret_buf = getpage(); - ret_space = BUF_SIZE; - ret_len = 0; - - error = failed = 0; - SOLD("looping"); - while(opt_len >= sizeof(struct opthdr)) { - struct opthdr *opt; - int orig_opt_len; - SOLD("loop start"); - opt = (struct opthdr *)ret_pos; - if (ret_space < sizeof(struct opthdr)) { - failed = TSYSERR; - break; - } - SOLD("getting opthdr"); - if (copy_from_user(opt, opt_buf, sizeof(struct opthdr)) || - opt->len > opt_len) { - failed = TBADOPT; - break; - } - SOLD("got opthdr"); - if (flag == T_NEGOTIATE) { - char *buf; - - SOLD("handling T_NEGOTIATE"); - buf = ret_pos + sizeof(struct opthdr); - if (ret_space < opt->len + sizeof(struct opthdr) || - copy_from_user(buf, opt_buf+sizeof(struct opthdr), opt->len)) { - failed = TSYSERR; - break; - } - SOLD("got optdata"); - args[0] = fd; - args[1] = opt->level; - args[2] = opt->name; - args[3] = (long)buf; - args[4] = opt->len; - SOLD("calling SETSOCKOPT"); - set_fs(KERNEL_DS); - error = sys_socketcall(SYS_SETSOCKOPT, args); - set_fs(old_fs); - if (error) { - failed = TBADOPT; - break; - } - SOLD("SETSOCKOPT ok"); - } - orig_opt_len = opt->len; - opt->len = ret_space - sizeof(struct opthdr); - if (opt->len < 0) { - failed = TSYSERR; - break; - } - args[0] = fd; - args[1] = opt->level; - args[2] = opt->name; - args[3] = (long)(ret_pos+sizeof(struct opthdr)); - args[4] = (long)&opt->len; - SOLD("calling GETSOCKOPT"); - set_fs(KERNEL_DS); - error = sys_socketcall(SYS_GETSOCKOPT, args); - set_fs(old_fs); - if (error) { - failed = TBADOPT; - break; - } - SOLD("GETSOCKOPT ok"); - ret_space -= sizeof(struct opthdr) + opt->len; - ret_len += sizeof(struct opthdr) + opt->len; - ret_pos += sizeof(struct opthdr) + opt->len; - opt_len -= sizeof(struct opthdr) + orig_opt_len; - opt_buf += sizeof(struct opthdr) + orig_opt_len; - SOLD("loop end"); - } - SOLD("loop done"); - if (do_ret) { - SOLD("generating ret msg"); - if (failed) - timod_error(fd, T_OPTMGMT_REQ, failed, -error); - else { - struct T_primsg *it; - it = timod_mkctl(sizeof(struct T_optmgmt_ack) + ret_len); - if (it) { - struct T_optmgmt_ack *ack = - (struct T_optmgmt_ack *)&it->type; - SOLD("got primsg"); - ack->PRIM_type = T_OPTMGMT_ACK; - ack->OPT_length = ret_len; - ack->OPT_offset = sizeof(struct T_optmgmt_ack); - ack->MGMT_flags = (failed ? T_FAILURE : flag); - memcpy(((char*)ack)+sizeof(struct T_optmgmt_ack), - ret_buf, ret_len); - timod_queue(fd, it); - } - } - } - SOLDD(("put_page %p\n", ret_buf)); - putpage(ret_buf); - SOLD("done"); - return 0; -} - -int timod_putmsg(unsigned int fd, char __user *ctl_buf, int ctl_len, - char __user *data_buf, int data_len, int flags) -{ - int ret, error, terror; - char *buf; - struct file *filp; - struct inode *ino; - struct fdtable *fdt; - struct sol_socket_struct *sock; - mm_segment_t old_fs = get_fs(); - long args[6]; - int (*sys_socketcall)(int, unsigned long __user *) = - (int (*)(int, unsigned long __user *))SYS(socketcall); - int (*sys_sendto)(int, void __user *, size_t, unsigned, struct sockaddr __user *, int) = - (int (*)(int, void __user *, size_t, unsigned, struct sockaddr __user *, int))SYS(sendto); - - fdt = files_fdtable(current->files); - filp = fdt->fd[fd]; - ino = filp->f_path.dentry->d_inode; - sock = (struct sol_socket_struct *)filp->private_data; - SOLD("entry"); - if (get_user(ret, (int __user *)A(ctl_buf))) - return -EFAULT; - switch (ret) { - case T_BIND_REQ: - { - struct T_bind_req req; - - SOLDD(("bind %016lx(%016lx)\n", sock, filp)); - SOLD("T_BIND_REQ"); - if (sock->state != TS_UNBND) { - timod_error(fd, T_BIND_REQ, TOUTSTATE, 0); - return 0; - } - SOLD("state ok"); - if (copy_from_user(&req, ctl_buf, sizeof(req))) { - timod_error(fd, T_BIND_REQ, TSYSERR, EFAULT); - return 0; - } - SOLD("got ctl req"); - if (req.ADDR_offset && req.ADDR_length) { - if (req.ADDR_length > BUF_SIZE) { - timod_error(fd, T_BIND_REQ, TSYSERR, EFAULT); - return 0; - } - SOLD("req size ok"); - buf = getpage(); - if (copy_from_user(buf, ctl_buf + req.ADDR_offset, req.ADDR_length)) { - timod_error(fd, T_BIND_REQ, TSYSERR, EFAULT); - putpage(buf); - return 0; - } - SOLD("got ctl data"); - args[0] = fd; - args[1] = (long)buf; - args[2] = req.ADDR_length; - SOLD("calling BIND"); - set_fs(KERNEL_DS); - error = sys_socketcall(SYS_BIND, args); - set_fs(old_fs); - putpage(buf); - SOLD("BIND returned"); - } else - error = 0; - if (!error) { - struct T_primsg *it; - if (req.CONIND_number) { - args[0] = fd; - args[1] = req.CONIND_number; - SOLD("calling LISTEN"); - set_fs(KERNEL_DS); - error = sys_socketcall(SYS_LISTEN, args); - set_fs(old_fs); - SOLD("LISTEN done"); - } - it = timod_mkctl(sizeof(struct T_bind_ack)+sizeof(struct sockaddr)); - if (it) { - struct T_bind_ack *ack; - - ack = (struct T_bind_ack *)&it->type; - ack->PRIM_type = T_BIND_ACK; - ack->ADDR_offset = sizeof(*ack); - ack->ADDR_length = sizeof(struct sockaddr); - ack->CONIND_number = req.CONIND_number; - args[0] = fd; - args[1] = (long)(ack+sizeof(*ack)); - args[2] = (long)&ack->ADDR_length; - set_fs(KERNEL_DS); - sys_socketcall(SYS_GETSOCKNAME,args); - set_fs(old_fs); - sock->state = TS_IDLE; - timod_ok(fd, T_BIND_REQ); - timod_queue_end(fd, it); - SOLD("BIND done"); - return 0; - } - } - SOLD("some error"); - switch (error) { - case -EINVAL: - terror = TOUTSTATE; - error = 0; - break; - case -EACCES: - terror = TACCES; - error = 0; - break; - case -EADDRNOTAVAIL: - case -EADDRINUSE: - terror = TNOADDR; - error = 0; - break; - default: - terror = TSYSERR; - break; - } - timod_error(fd, T_BIND_REQ, terror, -error); - SOLD("BIND done"); - return 0; - } - case T_CONN_REQ: - { - struct T_conn_req req; - unsigned short oldflags; - struct T_primsg *it; - SOLD("T_CONN_REQ"); - if (sock->state != TS_UNBND && sock->state != TS_IDLE) { - timod_error(fd, T_CONN_REQ, TOUTSTATE, 0); - return 0; - } - SOLD("state ok"); - if (copy_from_user(&req, ctl_buf, sizeof(req))) { - timod_error(fd, T_CONN_REQ, TSYSERR, EFAULT); - return 0; - } - SOLD("got ctl req"); - if (ctl_len > BUF_SIZE) { - timod_error(fd, T_CONN_REQ, TSYSERR, EFAULT); - return 0; - } - SOLD("req size ok"); - buf = getpage(); - if (copy_from_user(buf, ctl_buf, ctl_len)) { - timod_error(fd, T_CONN_REQ, TSYSERR, EFAULT); - putpage(buf); - return 0; - } -#ifdef DEBUG_SOLARIS - { - char * ptr = buf; - int len = ctl_len; - printk("returned data (%d bytes): ",len); - while( len-- ) { - if (!(len & 7)) - printk(" "); - printk("%02x",(unsigned char)*ptr++); - } - printk("\n"); - } -#endif - SOLD("got ctl data"); - args[0] = fd; - args[1] = (long)buf+req.DEST_offset; - args[2] = req.DEST_length; - oldflags = filp->f_flags; - filp->f_flags &= ~O_NONBLOCK; - SOLD("calling CONNECT"); - set_fs(KERNEL_DS); - error = sys_socketcall(SYS_CONNECT, args); - set_fs(old_fs); - filp->f_flags = oldflags; - SOLD("CONNECT done"); - if (!error) { - struct T_conn_con *con; - SOLD("no error"); - it = timod_mkctl(ctl_len); - if (!it) { - putpage(buf); - return -ENOMEM; - } - con = (struct T_conn_con *)&it->type; -#ifdef DEBUG_SOLARIS - { - char * ptr = buf; - int len = ctl_len; - printk("returned data (%d bytes): ",len); - while( len-- ) { - if (!(len & 7)) - printk(" "); - printk("%02x",(unsigned char)*ptr++); - } - printk("\n"); - } -#endif - memcpy(con, buf, ctl_len); - SOLD("copied ctl_buf"); - con->PRIM_type = T_CONN_CON; - sock->state = TS_DATA_XFER; - } else { - struct T_discon_ind *dis; - SOLD("some error"); - it = timod_mkctl(sizeof(*dis)); - if (!it) { - putpage(buf); - return -ENOMEM; - } - SOLD("got primsg"); - dis = (struct T_discon_ind *)&it->type; - dis->PRIM_type = T_DISCON_IND; - dis->DISCON_reason = -error; /* FIXME: convert this as in iABI_errors() */ - dis->SEQ_number = 0; - } - putpage(buf); - timod_ok(fd, T_CONN_REQ); - it->pri = 0; - timod_queue_end(fd, it); - SOLD("CONNECT done"); - return 0; - } - case T_OPTMGMT_REQ: - { - struct T_optmgmt_req req; - SOLD("OPTMGMT_REQ"); - if (copy_from_user(&req, ctl_buf, sizeof(req))) - return -EFAULT; - SOLD("got req"); - return timod_optmgmt(fd, req.MGMT_flags, - req.OPT_offset > 0 ? ctl_buf + req.OPT_offset : NULL, - req.OPT_length, 1); - } - case T_UNITDATA_REQ: - { - struct T_unitdata_req req; - - int err; - SOLD("T_UNITDATA_REQ"); - if (sock->state != TS_IDLE && sock->state != TS_DATA_XFER) { - timod_error(fd, T_CONN_REQ, TOUTSTATE, 0); - return 0; - } - SOLD("state ok"); - if (copy_from_user(&req, ctl_buf, sizeof(req))) { - timod_error(fd, T_CONN_REQ, TSYSERR, EFAULT); - return 0; - } - SOLD("got ctl req"); -#ifdef DEBUG_SOLARIS - { - char * ptr = ctl_buf+req.DEST_offset; - int len = req.DEST_length; - printk("socket address (%d bytes): ",len); - while( len-- ) { - char c; - if (get_user(c,ptr)) - printk("??"); - else - printk("%02x",(unsigned char)c); - ptr++; - } - printk("\n"); - } -#endif - 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); - if (err == data_len) - return 0; - if(err >= 0) { - printk("timod: sendto failed to send all the data\n"); - return 0; - } - timod_error(fd, T_CONN_REQ, TSYSERR, -err); - return 0; - } - default: - printk(KERN_INFO "timod_putmsg: unsupported command %u.\n", ret); - break; - } - return -EINVAL; -} - -int timod_getmsg(unsigned int fd, char __user *ctl_buf, int ctl_maxlen, s32 __user *ctl_len, - char __user *data_buf, int data_maxlen, s32 __user *data_len, int *flags_p) -{ - int error; - int oldflags; - struct file *filp; - struct inode *ino; - struct fdtable *fdt; - struct sol_socket_struct *sock; - struct T_unitdata_ind udi; - mm_segment_t old_fs = get_fs(); - long args[6]; - char __user *tmpbuf; - int tmplen; - int (*sys_socketcall)(int, unsigned long __user *) = - (int (*)(int, unsigned long __user *))SYS(socketcall); - int (*sys_recvfrom)(int, void __user *, size_t, unsigned, struct sockaddr __user *, int __user *); - - SOLD("entry"); - 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)); - fdt = files_fdtable(current->files); - filp = fdt->fd[fd]; - ino = filp->f_path.dentry->d_inode; - sock = (struct sol_socket_struct *)filp->private_data; - SOLDD(("%p %p\n", sock->pfirst, sock->pfirst ? sock->pfirst->next : NULL)); - if ( ctl_maxlen > 0 && !sock->pfirst && SOCKET_I(ino)->type == SOCK_STREAM - && sock->state == TS_IDLE) { - SOLD("calling LISTEN"); - args[0] = fd; - args[1] = -1; - set_fs(KERNEL_DS); - sys_socketcall(SYS_LISTEN, args); - set_fs(old_fs); - SOLD("LISTEN done"); - } - if (!(filp->f_flags & O_NONBLOCK)) { - struct poll_wqueues wait_table; - poll_table *wait; - - poll_initwait(&wait_table); - wait = &wait_table.pt; - for(;;) { - SOLD("loop"); - set_current_state(TASK_INTERRUPTIBLE); - /* ! ( l<0 || ( l>=0 && ( ! pfirst || (flags == HIPRI && pri != HIPRI) ) ) ) */ - /* ( ! l<0 && ! ( l>=0 && ( ! pfirst || (flags == HIPRI && pri != HIPRI) ) ) ) */ - /* ( l>=0 && ( ! l>=0 || ! ( ! pfirst || (flags == HIPRI && pri != HIPRI) ) ) ) */ - /* ( l>=0 && ( l<0 || ( pfirst && ! (flags == HIPRI && pri != HIPRI) ) ) ) */ - /* ( l>=0 && ( l<0 || ( pfirst && (flags != HIPRI || pri == HIPRI) ) ) ) */ - /* ( l>=0 && ( pfirst && (flags != HIPRI || pri == HIPRI) ) ) */ - if (ctl_maxlen >= 0 && sock->pfirst && (*flags_p != MSG_HIPRI || sock->pfirst->pri == MSG_HIPRI)) - break; - SOLD("cond 1 passed"); - if ( - #if 1 - *flags_p != MSG_HIPRI && - #endif - ((filp->f_op->poll(filp, wait) & POLLIN) || - (filp->f_op->poll(filp, NULL) & POLLIN) || - signal_pending(current)) - ) { - break; - } - if( *flags_p == MSG_HIPRI ) { - SOLD("avoiding lockup"); - break ; - } - if(wait_table.error) { - SOLD("wait-table error"); - poll_freewait(&wait_table); - return wait_table.error; - } - SOLD("scheduling"); - schedule(); - } - SOLD("loop done"); - current->state = TASK_RUNNING; - poll_freewait(&wait_table); - if (signal_pending(current)) { - SOLD("signal pending"); - return -EINTR; - } - } - if (ctl_maxlen >= 0 && sock->pfirst) { - struct T_primsg *it = sock->pfirst; - int l = min_t(int, ctl_maxlen, it->length); - SCHECK_MAGIC((char*)((u64)(((char *)&it->type)+sock->offset+it->length+7)&~7),MKCTL_MAGIC); - SOLD("purting ctl data"); - if(copy_to_user(ctl_buf, - (char*)&it->type + sock->offset, l)) - return -EFAULT; - SOLD("pur it"); - if(put_user(l, ctl_len)) - return -EFAULT; - SOLD("set ctl_len"); - *flags_p = it->pri; - it->length -= l; - if (it->length) { - SOLD("more ctl"); - sock->offset += l; - return MORECTL; - } else { - SOLD("removing message"); - sock->pfirst = it->next; - if (!sock->pfirst) - sock->plast = NULL; - SOLDD(("getmsg kfree %016lx->%016lx\n", it, sock->pfirst)); - mykfree(it); - sock->offset = 0; - SOLD("ctl done"); - return 0; - } - } - *flags_p = 0; - if (ctl_maxlen >= 0) { - SOLD("ACCEPT perhaps?"); - if (SOCKET_I(ino)->type == SOCK_STREAM && sock->state == TS_IDLE) { - struct T_conn_ind ind; - char *buf = getpage(); - int len = BUF_SIZE; - - SOLD("trying ACCEPT"); - if (put_user(ctl_maxlen - sizeof(ind), ctl_len)) - return -EFAULT; - args[0] = fd; - args[1] = (long)buf; - args[2] = (long)&len; - oldflags = filp->f_flags; - filp->f_flags |= O_NONBLOCK; - SOLD("calling ACCEPT"); - set_fs(KERNEL_DS); - error = sys_socketcall(SYS_ACCEPT, args); - set_fs(old_fs); - filp->f_flags = oldflags; - if (error < 0) { - SOLD("some error"); - putpage(buf); - return error; - } - if (error) { - SOLD("connect"); - putpage(buf); - if (sizeof(ind) > ctl_maxlen) { - SOLD("generating CONN_IND"); - ind.PRIM_type = T_CONN_IND; - ind.SRC_length = len; - ind.SRC_offset = sizeof(ind); - ind.OPT_length = ind.OPT_offset = 0; - ind.SEQ_number = error; - if(copy_to_user(ctl_buf, &ind, sizeof(ind))|| - put_user(sizeof(ind)+ind.SRC_length,ctl_len)) - return -EFAULT; - SOLD("CONN_IND created"); - } - if (data_maxlen >= 0) - put_user(0, data_len); - SOLD("CONN_IND done"); - return 0; - } - if (len>ctl_maxlen) { - SOLD("data don't fit"); - putpage(buf); - return -EFAULT; /* XXX - is this ok ? */ - } - if(copy_to_user(ctl_buf,buf,len) || put_user(len,ctl_len)){ - SOLD("can't copy data"); - putpage(buf); - return -EFAULT; - } - SOLD("ACCEPT done"); - putpage(buf); - } - } - SOLD("checking data req"); - if (data_maxlen <= 0) { - if (data_maxlen == 0) - put_user(0, data_len); - if (ctl_maxlen >= 0) - put_user(0, ctl_len); - return -EAGAIN; - } - SOLD("wants data"); - if (ctl_maxlen > sizeof(udi) && sock->state == TS_IDLE) { - SOLD("udi fits"); - tmpbuf = ctl_buf + sizeof(udi); - tmplen = ctl_maxlen - sizeof(udi); - } else { - SOLD("udi does not fit"); - tmpbuf = NULL; - tmplen = 0; - } - if (put_user(tmplen, ctl_len)) - return -EFAULT; - SOLD("set ctl_len"); - oldflags = filp->f_flags; - filp->f_flags |= O_NONBLOCK; - SOLD("calling recvfrom"); - sys_recvfrom = (int (*)(int, void __user *, size_t, unsigned, struct sockaddr __user *, int __user *))SYS(recvfrom); - error = sys_recvfrom(fd, data_buf, data_maxlen, 0, (struct sockaddr __user *)tmpbuf, ctl_len); - filp->f_flags = oldflags; - if (error < 0) - return error; - SOLD("error >= 0" ) ; - if (error && ctl_maxlen > sizeof(udi) && sock->state == TS_IDLE) { - SOLD("generating udi"); - udi.PRIM_type = T_UNITDATA_IND; - if (get_user(udi.SRC_length, ctl_len)) - return -EFAULT; - udi.SRC_offset = sizeof(udi); - udi.OPT_length = udi.OPT_offset = 0; - if (copy_to_user(ctl_buf, &udi, sizeof(udi)) || - put_user(sizeof(udi)+udi.SRC_length, ctl_len)) - return -EFAULT; - SOLD("udi done"); - } else { - if (put_user(0, ctl_len)) - return -EFAULT; - } - put_user(error, data_len); - SOLD("done"); - return 0; -} - -asmlinkage int solaris_getmsg(unsigned int fd, u32 arg1, u32 arg2, u32 arg3) -{ - struct file *filp; - struct inode *ino; - struct strbuf __user *ctlptr; - struct strbuf __user *datptr; - struct strbuf ctl, dat; - int __user *flgptr; - int flags; - int error = -EBADF; - struct fdtable *fdt; - - SOLD("entry"); - lock_kernel(); - if (fd >= sysctl_nr_open) - goto out; - - fdt = files_fdtable(current->files); - filp = fdt->fd[fd]; - if(!filp) goto out; - - ino = filp->f_path.dentry->d_inode; - if (!ino || !S_ISSOCK(ino->i_mode)) - goto out; - - ctlptr = (struct strbuf __user *)A(arg1); - datptr = (struct strbuf __user *)A(arg2); - flgptr = (int __user *)A(arg3); - - error = -EFAULT; - - if (ctlptr) { - if (copy_from_user(&ctl,ctlptr,sizeof(struct strbuf)) || - put_user(-1,&ctlptr->len)) - goto out; - } else - ctl.maxlen = -1; - - if (datptr) { - if (copy_from_user(&dat,datptr,sizeof(struct strbuf)) || - put_user(-1,&datptr->len)) - goto out; - } else - dat.maxlen = -1; - - if (get_user(flags,flgptr)) - goto out; - - switch (flags) { - case 0: - case MSG_HIPRI: - case MSG_ANY: - case MSG_BAND: - break; - default: - error = -EINVAL; - goto out; - } - - error = timod_getmsg(fd,A(ctl.buf),ctl.maxlen,&ctlptr->len, - A(dat.buf),dat.maxlen,&datptr->len,&flags); - - if (!error && put_user(flags,flgptr)) - error = -EFAULT; -out: - unlock_kernel(); - SOLD("done"); - return error; -} - -asmlinkage int solaris_putmsg(unsigned int fd, u32 arg1, u32 arg2, u32 arg3) -{ - struct file *filp; - struct inode *ino; - struct strbuf __user *ctlptr; - struct strbuf __user *datptr; - struct strbuf ctl, dat; - int flags = (int) arg3; - int error = -EBADF; - struct fdtable *fdt; - - SOLD("entry"); - lock_kernel(); - if (fd >= sysctl_nr_open) - goto out; - - fdt = files_fdtable(current->files); - filp = fdt->fd[fd]; - if(!filp) goto out; - - ino = filp->f_path.dentry->d_inode; - if (!ino) goto out; - - if (!S_ISSOCK(ino->i_mode) && - (imajor(ino) != 30 || iminor(ino) != 1)) - goto out; - - ctlptr = A(arg1); - datptr = A(arg2); - - error = -EFAULT; - - if (ctlptr) { - if (copy_from_user(&ctl,ctlptr,sizeof(ctl))) - goto out; - if (ctl.len < 0 && flags) { - error = -EINVAL; - goto out; - } - } else { - ctl.len = 0; - ctl.buf = 0; - } - - if (datptr) { - if (copy_from_user(&dat,datptr,sizeof(dat))) - goto out; - } else { - dat.len = 0; - dat.buf = 0; - } - - error = timod_putmsg(fd,A(ctl.buf),ctl.len, - A(dat.buf),dat.len,flags); -out: - unlock_kernel(); - SOLD("done"); - return error; -} |