Linux-2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
This commit is contained in:
959
arch/sparc64/solaris/timod.c
Normal file
959
arch/sparc64/solaris/timod.c
Normal file
@@ -0,0 +1,959 @@
|
||||
/* $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, int 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__,__FUNCTION__,(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;
|
||||
|
||||
SOLD("wakeing socket");
|
||||
sock = SOCKET_I(current->files->fd[fd]->f_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;
|
||||
|
||||
SOLD("queuing primsg");
|
||||
sock = (struct sol_socket_struct *)current->files->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;
|
||||
|
||||
SOLD("queuing primsg at end");
|
||||
sock = (struct sol_socket_struct *)current->files->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 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);
|
||||
filp = current->files->fd[fd];
|
||||
ino = filp->f_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 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));
|
||||
filp = current->files->fd[fd];
|
||||
ino = filp->f_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;
|
||||
|
||||
SOLD("entry");
|
||||
lock_kernel();
|
||||
if(fd >= NR_OPEN) goto out;
|
||||
|
||||
filp = current->files->fd[fd];
|
||||
if(!filp) goto out;
|
||||
|
||||
ino = filp->f_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;
|
||||
|
||||
SOLD("entry");
|
||||
lock_kernel();
|
||||
if(fd >= NR_OPEN) goto out;
|
||||
|
||||
filp = current->files->fd[fd];
|
||||
if(!filp) goto out;
|
||||
|
||||
ino = filp->f_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;
|
||||
}
|
Reference in New Issue
Block a user