Пример #1
0
static void
timod_ok(int fd, int prim)
{
	struct file		*fp;
	struct T_primsg		*it;
	struct T_ok_ack 	*ok;

#if defined(CONFIG_ABI_TRACE)
	abi_trace(ABI_TRACE_STREAMS, "TI: %u ok ack prim=%d\n", fd, prim);
#endif

	fp = fcheck(fd);
	it = timod_mkctl(sizeof(struct T_ok_ack));
	if (!it)
		return;

	ok = (struct T_ok_ack *)&it->type;
	ok->PRIM_type = T_OK_ACK;
	ok->CORRECT_prim = prim;

	it->pri = MSG_HIPRI;
	it->length = sizeof(struct T_ok_ack);
	it->next = Priv(fp)->pfirst;

	Priv(fp)->pfirst = it;
	if (!Priv(fp)->plast)
		Priv(fp)->plast = it;
	timod_socket_wakeup(fp);
}
Пример #2
0
static void
timod_error(int fd, int prim, int terr, int uerr)
{
	struct file		*fp;
	struct T_primsg		*it;
	struct T_error_ack	*err;

#if defined(CONFIG_ABI_TRACE)
	abi_trace(ABI_TRACE_STREAMS, "TI: %u error prim=%d, TLI=%d, UNIX=%d\n",
			fd, prim, terr, uerr);
#endif

	fp = fcheck(fd);
	it = timod_mkctl(sizeof(struct T_error_ack));
	if (!it)
		return;

	err = (struct T_error_ack *)&it->type;
	err->PRIM_type = T_ERROR_ACK;
	err->ERROR_prim = prim;
	err->TLI_error = terr;
	err->UNIX_error = iABI_errors(uerr);

	it->pri = MSG_HIPRI;
	it->length = sizeof(struct T_error_ack);
	it->next = Priv(fp)->pfirst;

	Priv(fp)->pfirst = it;
	if (!Priv(fp)->plast)
		Priv(fp)->plast = it;
	timod_socket_wakeup(fp);
}
Пример #3
0
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");
}
Пример #4
0
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");
}
Пример #5
0
int timod_putmsg(unsigned int fd, char *ctl_buf, int ctl_len,
			char *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 *) =
		(int (*)(int, unsigned long *))SYS(socketcall);
	int (*sys_sendto)(int, void *, size_t, unsigned, struct sockaddr *, int) =
		(int (*)(int, void *, size_t, unsigned, struct sockaddr *, 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 *)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*)(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;
}
Пример #6
0
static int timod_optmgmt(unsigned int fd, int flag, char *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;
}