1/* $Id: timod.c,v 1.1.1.1 2007/08/03 18:52:19 Exp $
2 * timod.c: timod emulation.
3 *
4 * Copyright (C) 1998 Patrik Rak (prak3264@ss1000.ms.mff.cuni.cz)
5 *
6 * Streams & timod emulation based on code
7 * Copyright (C) 1995, 1996 Mike Jagdis (jaggy@purplet.demon.co.uk)
8 *
9 */
10
11#include <linux/types.h>
12#include <linux/kernel.h>
13#include <linux/sched.h>
14#include <linux/smp.h>
15#include <linux/smp_lock.h>
16#include <linux/ioctl.h>
17#include <linux/fs.h>
18#include <linux/file.h>
19#include <linux/netdevice.h>
20#include <linux/poll.h>
21
22#include <net/sock.h>
23
24#include <asm/uaccess.h>
25#include <asm/termios.h>
26
27#include "conv.h"
28#include "socksys.h"
29
30asmlinkage int solaris_ioctl(unsigned int fd, unsigned int cmd, u32 arg);
31
32static DEFINE_SPINLOCK(timod_pagelock);
33static char * page = NULL ;
34
35#ifndef DEBUG_SOLARIS_KMALLOC
36
37#define mykmalloc kmalloc
38#define mykfree kfree
39
40#else
41
42void * mykmalloc(size_t s, gfp_t gfp)
43{
44	static char * page;
45	static size_t free;
46	void * r;
47	s = ((s + 63) & ~63);
48	if( s > PAGE_SIZE ) {
49		SOLD("too big size, calling real kmalloc");
50		return kmalloc(s, gfp);
51	}
52	if( s > free ) {
53		/* we are wasting memory, but we don't care */
54		page = (char *)__get_free_page(gfp);
55		free = PAGE_SIZE;
56	}
57	r = page;
58	page += s;
59	free -= s;
60	return r;
61}
62
63void mykfree(void *p)
64{
65}
66
67#endif
68
69#ifndef DEBUG_SOLARIS
70
71#define BUF_SIZE	PAGE_SIZE
72#define PUT_MAGIC(a,m)
73#define SCHECK_MAGIC(a,m)
74#define BUF_OFFSET	0
75#define MKCTL_TRAILER	0
76
77#else
78
79#define BUF_SIZE	(PAGE_SIZE-2*sizeof(u64))
80#define BUFPAGE_MAGIC	0xBADC0DEDDEADBABEL
81#define MKCTL_MAGIC	0xDEADBABEBADC0DEDL
82#define PUT_MAGIC(a,m)	do{(*(u64*)(a))=(m);}while(0)
83#define SCHECK_MAGIC(a,m)	do{if((*(u64*)(a))!=(m))printk("%s,%u,%s(): magic %08x at %p corrupted!\n",\
84				__FILE__,__LINE__,__FUNCTION__,(m),(a));}while(0)
85#define BUF_OFFSET	sizeof(u64)
86#define MKCTL_TRAILER	sizeof(u64)
87
88#endif
89
90static char *getpage( void )
91{
92	char *r;
93	SOLD("getting page");
94	spin_lock(&timod_pagelock);
95	if (page) {
96		r = page;
97		page = NULL;
98		spin_unlock(&timod_pagelock);
99		SOLD("got cached");
100		return r + BUF_OFFSET;
101	}
102	spin_unlock(&timod_pagelock);
103	SOLD("getting new");
104	r = (char *)__get_free_page(GFP_KERNEL);
105	PUT_MAGIC(r,BUFPAGE_MAGIC);
106	PUT_MAGIC(r+PAGE_SIZE-sizeof(u64),BUFPAGE_MAGIC);
107	return r + BUF_OFFSET;
108}
109
110static void putpage(char *p)
111{
112	SOLD("putting page");
113	p = p - BUF_OFFSET;
114	SCHECK_MAGIC(p,BUFPAGE_MAGIC);
115	SCHECK_MAGIC(p+PAGE_SIZE-sizeof(u64),BUFPAGE_MAGIC);
116	spin_lock(&timod_pagelock);
117	if (page) {
118		spin_unlock(&timod_pagelock);
119		free_page((unsigned long)p);
120		SOLD("freed it");
121	} else {
122		page = p;
123		spin_unlock(&timod_pagelock);
124		SOLD("cached it");
125	}
126}
127
128static struct T_primsg *timod_mkctl(int size)
129{
130	struct T_primsg *it;
131
132	SOLD("creating primsg");
133	it = (struct T_primsg *)mykmalloc(size+sizeof(*it)-sizeof(s32)+2*MKCTL_TRAILER, GFP_KERNEL);
134	if (it) {
135		SOLD("got it");
136		it->pri = MSG_HIPRI;
137		it->length = size;
138		PUT_MAGIC((char*)((u64)(((char *)&it->type)+size+7)&~7),MKCTL_MAGIC);
139	}
140	return it;
141}
142
143static void timod_wake_socket(unsigned int fd)
144{
145	struct socket *sock;
146	struct fdtable *fdt;
147
148	SOLD("wakeing socket");
149	fdt = files_fdtable(current->files);
150	sock = SOCKET_I(fdt->fd[fd]->f_path.dentry->d_inode);
151	wake_up_interruptible(&sock->wait);
152	read_lock(&sock->sk->sk_callback_lock);
153	if (sock->fasync_list && !test_bit(SOCK_ASYNC_WAITDATA, &sock->flags))
154		__kill_fasync(sock->fasync_list, SIGIO, POLL_IN);
155	read_unlock(&sock->sk->sk_callback_lock);
156	SOLD("done");
157}
158
159static void timod_queue(unsigned int fd, struct T_primsg *it)
160{
161	struct sol_socket_struct *sock;
162	struct fdtable *fdt;
163
164	SOLD("queuing primsg");
165	fdt = files_fdtable(current->files);
166	sock = (struct sol_socket_struct *)fdt->fd[fd]->private_data;
167	it->next = sock->pfirst;
168	sock->pfirst = it;
169	if (!sock->plast)
170		sock->plast = it;
171	timod_wake_socket(fd);
172	SOLD("done");
173}
174
175static void timod_queue_end(unsigned int fd, struct T_primsg *it)
176{
177	struct sol_socket_struct *sock;
178	struct fdtable *fdt;
179
180	SOLD("queuing primsg at end");
181	fdt = files_fdtable(current->files);
182	sock = (struct sol_socket_struct *)fdt->fd[fd]->private_data;
183	it->next = NULL;
184	if (sock->plast)
185		sock->plast->next = it;
186	else
187		sock->pfirst = it;
188	sock->plast = it;
189	SOLD("done");
190}
191
192static void timod_error(unsigned int fd, int prim, int terr, int uerr)
193{
194	struct T_primsg *it;
195
196	SOLD("making error");
197	it = timod_mkctl(sizeof(struct T_error_ack));
198	if (it) {
199		struct T_error_ack *err = (struct T_error_ack *)&it->type;
200
201		SOLD("got it");
202		err->PRIM_type = T_ERROR_ACK;
203		err->ERROR_prim = prim;
204		err->TLI_error = terr;
205		err->UNIX_error = uerr;
206		timod_queue(fd, it);
207	}
208	SOLD("done");
209}
210
211static void timod_ok(unsigned int fd, int prim)
212{
213	struct T_primsg *it;
214	struct T_ok_ack *ok;
215
216	SOLD("creating ok ack");
217	it = timod_mkctl(sizeof(*ok));
218	if (it) {
219		SOLD("got it");
220		ok = (struct T_ok_ack *)&it->type;
221		ok->PRIM_type = T_OK_ACK;
222		ok->CORRECT_prim = prim;
223		timod_queue(fd, it);
224	}
225	SOLD("done");
226}
227
228static int timod_optmgmt(unsigned int fd, int flag, char __user *opt_buf, int opt_len, int do_ret)
229{
230	int error, failed;
231	int ret_space, ret_len;
232	long args[5];
233	char *ret_pos,*ret_buf;
234	int (*sys_socketcall)(int, unsigned long *) =
235		(int (*)(int, unsigned long *))SYS(socketcall);
236	mm_segment_t old_fs = get_fs();
237
238	SOLD("entry");
239	SOLDD(("fd %u flg %u buf %p len %u doret %u",fd,flag,opt_buf,opt_len,do_ret));
240	if (!do_ret && (!opt_buf || opt_len <= 0))
241		return 0;
242	SOLD("getting page");
243	ret_pos = ret_buf = getpage();
244	ret_space = BUF_SIZE;
245	ret_len = 0;
246
247	error = failed = 0;
248	SOLD("looping");
249	while(opt_len >= sizeof(struct opthdr)) {
250		struct opthdr *opt;
251		int orig_opt_len;
252		SOLD("loop start");
253		opt = (struct opthdr *)ret_pos;
254		if (ret_space < sizeof(struct opthdr)) {
255			failed = TSYSERR;
256			break;
257		}
258		SOLD("getting opthdr");
259		if (copy_from_user(opt, opt_buf, sizeof(struct opthdr)) ||
260			opt->len > opt_len) {
261			failed = TBADOPT;
262			break;
263		}
264		SOLD("got opthdr");
265		if (flag == T_NEGOTIATE) {
266			char *buf;
267
268			SOLD("handling T_NEGOTIATE");
269			buf = ret_pos + sizeof(struct opthdr);
270			if (ret_space < opt->len + sizeof(struct opthdr) ||
271				copy_from_user(buf, opt_buf+sizeof(struct opthdr), opt->len)) {
272				failed = TSYSERR;
273				break;
274			}
275			SOLD("got optdata");
276			args[0] = fd;
277			args[1] = opt->level;
278			args[2] = opt->name;
279			args[3] = (long)buf;
280			args[4] = opt->len;
281			SOLD("calling SETSOCKOPT");
282			set_fs(KERNEL_DS);
283			error = sys_socketcall(SYS_SETSOCKOPT, args);
284			set_fs(old_fs);
285			if (error) {
286				failed = TBADOPT;
287				break;
288			}
289			SOLD("SETSOCKOPT ok");
290		}
291		orig_opt_len = opt->len;
292		opt->len = ret_space - sizeof(struct opthdr);
293		if (opt->len < 0) {
294			failed = TSYSERR;
295			break;
296		}
297		args[0] = fd;
298		args[1] = opt->level;
299		args[2] = opt->name;
300		args[3] = (long)(ret_pos+sizeof(struct opthdr));
301		args[4] = (long)&opt->len;
302		SOLD("calling GETSOCKOPT");
303		set_fs(KERNEL_DS);
304		error = sys_socketcall(SYS_GETSOCKOPT, args);
305		set_fs(old_fs);
306		if (error) {
307			failed = TBADOPT;
308			break;
309		}
310		SOLD("GETSOCKOPT ok");
311		ret_space -= sizeof(struct opthdr) + opt->len;
312		ret_len += sizeof(struct opthdr) + opt->len;
313		ret_pos += sizeof(struct opthdr) + opt->len;
314		opt_len -= sizeof(struct opthdr) + orig_opt_len;
315		opt_buf += sizeof(struct opthdr) + orig_opt_len;
316		SOLD("loop end");
317	}
318	SOLD("loop done");
319	if (do_ret) {
320		SOLD("generating ret msg");
321		if (failed)
322			timod_error(fd, T_OPTMGMT_REQ, failed, -error);
323		else {
324			struct T_primsg *it;
325			it = timod_mkctl(sizeof(struct T_optmgmt_ack) + ret_len);
326			if (it) {
327				struct T_optmgmt_ack *ack =
328					(struct T_optmgmt_ack *)&it->type;
329				SOLD("got primsg");
330				ack->PRIM_type = T_OPTMGMT_ACK;
331				ack->OPT_length = ret_len;
332				ack->OPT_offset = sizeof(struct T_optmgmt_ack);
333				ack->MGMT_flags = (failed ? T_FAILURE : flag);
334				memcpy(((char*)ack)+sizeof(struct T_optmgmt_ack),
335					ret_buf, ret_len);
336				timod_queue(fd, it);
337			}
338		}
339	}
340	SOLDD(("put_page %p\n", ret_buf));
341	putpage(ret_buf);
342	SOLD("done");
343	return 0;
344}
345
346int timod_putmsg(unsigned int fd, char __user *ctl_buf, int ctl_len,
347			char __user *data_buf, int data_len, int flags)
348{
349	int ret, error, terror;
350	char *buf;
351	struct file *filp;
352	struct inode *ino;
353	struct fdtable *fdt;
354	struct sol_socket_struct *sock;
355	mm_segment_t old_fs = get_fs();
356	long args[6];
357	int (*sys_socketcall)(int, unsigned long __user *) =
358		(int (*)(int, unsigned long __user *))SYS(socketcall);
359	int (*sys_sendto)(int, void __user *, size_t, unsigned, struct sockaddr __user *, int) =
360		(int (*)(int, void __user *, size_t, unsigned, struct sockaddr __user *, int))SYS(sendto);
361
362	fdt = files_fdtable(current->files);
363	filp = fdt->fd[fd];
364	ino = filp->f_path.dentry->d_inode;
365	sock = (struct sol_socket_struct *)filp->private_data;
366	SOLD("entry");
367	if (get_user(ret, (int __user *)A(ctl_buf)))
368		return -EFAULT;
369	switch (ret) {
370	case T_BIND_REQ:
371	{
372		struct T_bind_req req;
373
374		SOLDD(("bind %016lx(%016lx)\n", sock, filp));
375		SOLD("T_BIND_REQ");
376		if (sock->state != TS_UNBND) {
377			timod_error(fd, T_BIND_REQ, TOUTSTATE, 0);
378			return 0;
379		}
380		SOLD("state ok");
381		if (copy_from_user(&req, ctl_buf, sizeof(req))) {
382			timod_error(fd, T_BIND_REQ, TSYSERR, EFAULT);
383			return 0;
384		}
385		SOLD("got ctl req");
386		if (req.ADDR_offset && req.ADDR_length) {
387			if (req.ADDR_length > BUF_SIZE) {
388				timod_error(fd, T_BIND_REQ, TSYSERR, EFAULT);
389				return 0;
390			}
391			SOLD("req size ok");
392			buf = getpage();
393			if (copy_from_user(buf, ctl_buf + req.ADDR_offset, req.ADDR_length)) {
394				timod_error(fd, T_BIND_REQ, TSYSERR, EFAULT);
395				putpage(buf);
396				return 0;
397			}
398			SOLD("got ctl data");
399			args[0] = fd;
400			args[1] = (long)buf;
401			args[2] = req.ADDR_length;
402			SOLD("calling BIND");
403			set_fs(KERNEL_DS);
404			error = sys_socketcall(SYS_BIND, args);
405			set_fs(old_fs);
406			putpage(buf);
407			SOLD("BIND returned");
408		} else
409			error = 0;
410		if (!error) {
411			struct T_primsg *it;
412			if (req.CONIND_number) {
413	  			args[0] = fd;
414  				args[1] = req.CONIND_number;
415  				SOLD("calling LISTEN");
416  				set_fs(KERNEL_DS);
417	  			error = sys_socketcall(SYS_LISTEN, args);
418  				set_fs(old_fs);
419  				SOLD("LISTEN done");
420  			}
421			it = timod_mkctl(sizeof(struct T_bind_ack)+sizeof(struct sockaddr));
422			if (it) {
423				struct T_bind_ack *ack;
424
425				ack = (struct T_bind_ack *)&it->type;
426				ack->PRIM_type = T_BIND_ACK;
427				ack->ADDR_offset = sizeof(*ack);
428				ack->ADDR_length = sizeof(struct sockaddr);
429				ack->CONIND_number = req.CONIND_number;
430				args[0] = fd;
431				args[1] = (long)(ack+sizeof(*ack));
432				args[2] = (long)&ack->ADDR_length;
433				set_fs(KERNEL_DS);
434				sys_socketcall(SYS_GETSOCKNAME,args);
435				set_fs(old_fs);
436				sock->state = TS_IDLE;
437				timod_ok(fd, T_BIND_REQ);
438				timod_queue_end(fd, it);
439				SOLD("BIND done");
440				return 0;
441			}
442		}
443		SOLD("some error");
444		switch (error) {
445			case -EINVAL:
446				terror = TOUTSTATE;
447				error = 0;
448				break;
449			case -EACCES:
450				terror = TACCES;
451				error = 0;
452				break;
453			case -EADDRNOTAVAIL:
454			case -EADDRINUSE:
455				terror = TNOADDR;
456				error = 0;
457				break;
458			default:
459				terror = TSYSERR;
460				break;
461		}
462		timod_error(fd, T_BIND_REQ, terror, -error);
463		SOLD("BIND done");
464		return 0;
465	}
466	case T_CONN_REQ:
467	{
468		struct T_conn_req req;
469		unsigned short oldflags;
470		struct T_primsg *it;
471		SOLD("T_CONN_REQ");
472		if (sock->state != TS_UNBND && sock->state != TS_IDLE) {
473			timod_error(fd, T_CONN_REQ, TOUTSTATE, 0);
474			return 0;
475		}
476		SOLD("state ok");
477		if (copy_from_user(&req, ctl_buf, sizeof(req))) {
478			timod_error(fd, T_CONN_REQ, TSYSERR, EFAULT);
479			return 0;
480		}
481		SOLD("got ctl req");
482		if (ctl_len > BUF_SIZE) {
483			timod_error(fd, T_CONN_REQ, TSYSERR, EFAULT);
484			return 0;
485		}
486		SOLD("req size ok");
487		buf = getpage();
488		if (copy_from_user(buf, ctl_buf, ctl_len)) {
489			timod_error(fd, T_CONN_REQ, TSYSERR, EFAULT);
490			putpage(buf);
491			return 0;
492		}
493#ifdef DEBUG_SOLARIS
494		{
495			char * ptr = buf;
496			int len = ctl_len;
497			printk("returned data (%d bytes): ",len);
498			while( len-- ) {
499				if (!(len & 7))
500					printk(" ");
501				printk("%02x",(unsigned char)*ptr++);
502			}
503			printk("\n");
504		}
505#endif
506		SOLD("got ctl data");
507		args[0] = fd;
508		args[1] = (long)buf+req.DEST_offset;
509		args[2] = req.DEST_length;
510		oldflags = filp->f_flags;
511		filp->f_flags &= ~O_NONBLOCK;
512		SOLD("calling CONNECT");
513		set_fs(KERNEL_DS);
514		error = sys_socketcall(SYS_CONNECT, args);
515		set_fs(old_fs);
516		filp->f_flags = oldflags;
517		SOLD("CONNECT done");
518		if (!error) {
519			struct T_conn_con *con;
520			SOLD("no error");
521			it = timod_mkctl(ctl_len);
522			if (!it) {
523				putpage(buf);
524				return -ENOMEM;
525			}
526			con = (struct T_conn_con *)&it->type;
527#ifdef DEBUG_SOLARIS
528			{
529				char * ptr = buf;
530				int len = ctl_len;
531				printk("returned data (%d bytes): ",len);
532				while( len-- ) {
533					if (!(len & 7))
534						printk(" ");
535					printk("%02x",(unsigned char)*ptr++);
536				}
537				printk("\n");
538			}
539#endif
540			memcpy(con, buf, ctl_len);
541			SOLD("copied ctl_buf");
542			con->PRIM_type = T_CONN_CON;
543			sock->state = TS_DATA_XFER;
544		} else {
545			struct T_discon_ind *dis;
546			SOLD("some error");
547			it = timod_mkctl(sizeof(*dis));
548			if (!it) {
549				putpage(buf);
550				return -ENOMEM;
551			}
552			SOLD("got primsg");
553			dis = (struct T_discon_ind *)&it->type;
554			dis->PRIM_type = T_DISCON_IND;
555			dis->DISCON_reason = -error;
556			dis->SEQ_number = 0;
557		}
558		putpage(buf);
559		timod_ok(fd, T_CONN_REQ);
560		it->pri = 0;
561		timod_queue_end(fd, it);
562		SOLD("CONNECT done");
563		return 0;
564	}
565	case T_OPTMGMT_REQ:
566	{
567		struct T_optmgmt_req req;
568		SOLD("OPTMGMT_REQ");
569		if (copy_from_user(&req, ctl_buf, sizeof(req)))
570			return -EFAULT;
571		SOLD("got req");
572		return timod_optmgmt(fd, req.MGMT_flags,
573				req.OPT_offset > 0 ? ctl_buf + req.OPT_offset : NULL,
574				req.OPT_length, 1);
575	}
576	case T_UNITDATA_REQ:
577	{
578		struct T_unitdata_req req;
579
580		int err;
581		SOLD("T_UNITDATA_REQ");
582		if (sock->state != TS_IDLE && sock->state != TS_DATA_XFER) {
583			timod_error(fd, T_CONN_REQ, TOUTSTATE, 0);
584			return 0;
585		}
586		SOLD("state ok");
587		if (copy_from_user(&req, ctl_buf, sizeof(req))) {
588			timod_error(fd, T_CONN_REQ, TSYSERR, EFAULT);
589			return 0;
590		}
591		SOLD("got ctl req");
592#ifdef DEBUG_SOLARIS
593		{
594			char * ptr = ctl_buf+req.DEST_offset;
595			int len = req.DEST_length;
596			printk("socket address (%d bytes): ",len);
597			while( len-- ) {
598				char c;
599				if (get_user(c,ptr))
600					printk("??");
601				else
602					printk("%02x",(unsigned char)c);
603				ptr++;
604			}
605			printk("\n");
606		}
607#endif
608		err = sys_sendto(fd, data_buf, data_len, 0, req.DEST_length > 0 ? (struct sockaddr __user *)(ctl_buf+req.DEST_offset) : NULL, req.DEST_length);
609		if (err == data_len)
610			return 0;
611		if(err >= 0) {
612			printk("timod: sendto failed to send all the data\n");
613			return 0;
614		}
615		timod_error(fd, T_CONN_REQ, TSYSERR, -err);
616		return 0;
617	}
618	default:
619		printk(KERN_INFO "timod_putmsg: unsupported command %u.\n", ret);
620		break;
621	}
622	return -EINVAL;
623}
624
625int timod_getmsg(unsigned int fd, char __user *ctl_buf, int ctl_maxlen, s32 __user *ctl_len,
626			char __user *data_buf, int data_maxlen, s32 __user *data_len, int *flags_p)
627{
628	int error;
629	int oldflags;
630	struct file *filp;
631	struct inode *ino;
632	struct fdtable *fdt;
633	struct sol_socket_struct *sock;
634	struct T_unitdata_ind udi;
635	mm_segment_t old_fs = get_fs();
636	long args[6];
637	char __user *tmpbuf;
638	int tmplen;
639	int (*sys_socketcall)(int, unsigned long __user *) =
640		(int (*)(int, unsigned long __user *))SYS(socketcall);
641	int (*sys_recvfrom)(int, void __user *, size_t, unsigned, struct sockaddr __user *, int __user *);
642
643	SOLD("entry");
644	SOLDD(("%u %p %d %p %p %d %p %d\n", fd, ctl_buf, ctl_maxlen, ctl_len, data_buf, data_maxlen, data_len, *flags_p));
645	fdt = files_fdtable(current->files);
646	filp = fdt->fd[fd];
647	ino = filp->f_path.dentry->d_inode;
648	sock = (struct sol_socket_struct *)filp->private_data;
649	SOLDD(("%p %p\n", sock->pfirst, sock->pfirst ? sock->pfirst->next : NULL));
650	if ( ctl_maxlen > 0 && !sock->pfirst && SOCKET_I(ino)->type == SOCK_STREAM
651		&& sock->state == TS_IDLE) {
652		SOLD("calling LISTEN");
653		args[0] = fd;
654		args[1] = -1;
655		set_fs(KERNEL_DS);
656		sys_socketcall(SYS_LISTEN, args);
657		set_fs(old_fs);
658		SOLD("LISTEN done");
659	}
660	if (!(filp->f_flags & O_NONBLOCK)) {
661		struct poll_wqueues wait_table;
662		poll_table *wait;
663
664		poll_initwait(&wait_table);
665		wait = &wait_table.pt;
666		for(;;) {
667			SOLD("loop");
668			set_current_state(TASK_INTERRUPTIBLE);
669			/* ! ( l<0 || ( l>=0 && ( ! pfirst || (flags == HIPRI && pri != HIPRI) ) ) ) */
670			/* ( ! l<0 && ! ( l>=0 && ( ! pfirst || (flags == HIPRI && pri != HIPRI) ) ) ) */
671			/* ( l>=0 && ( ! l>=0 || ! ( ! pfirst || (flags == HIPRI && pri != HIPRI) ) ) ) */
672			/* ( l>=0 && ( l<0 || ( pfirst && ! (flags == HIPRI && pri != HIPRI) ) ) ) */
673			/* ( l>=0 && ( l<0 || ( pfirst && (flags != HIPRI || pri == HIPRI) ) ) ) */
674			/* ( l>=0 && ( pfirst && (flags != HIPRI || pri == HIPRI) ) ) */
675			if (ctl_maxlen >= 0 && sock->pfirst && (*flags_p != MSG_HIPRI || sock->pfirst->pri == MSG_HIPRI))
676				break;
677			SOLD("cond 1 passed");
678			if (
679			#if 1
680				*flags_p != MSG_HIPRI &&
681			#endif
682				((filp->f_op->poll(filp, wait) & POLLIN) ||
683				(filp->f_op->poll(filp, NULL) & POLLIN) ||
684				signal_pending(current))
685			) {
686				break;
687			}
688			if( *flags_p == MSG_HIPRI ) {
689				SOLD("avoiding lockup");
690				break ;
691			}
692			if(wait_table.error) {
693				SOLD("wait-table error");
694				poll_freewait(&wait_table);
695				return wait_table.error;
696			}
697			SOLD("scheduling");
698			schedule();
699		}
700		SOLD("loop done");
701		current->state = TASK_RUNNING;
702		poll_freewait(&wait_table);
703		if (signal_pending(current)) {
704			SOLD("signal pending");
705			return -EINTR;
706		}
707	}
708	if (ctl_maxlen >= 0 && sock->pfirst) {
709		struct T_primsg *it = sock->pfirst;
710		int l = min_t(int, ctl_maxlen, it->length);
711		SCHECK_MAGIC((char*)((u64)(((char *)&it->type)+sock->offset+it->length+7)&~7),MKCTL_MAGIC);
712		SOLD("purting ctl data");
713		if(copy_to_user(ctl_buf,
714			(char*)&it->type + sock->offset, l))
715			return -EFAULT;
716		SOLD("pur it");
717		if(put_user(l, ctl_len))
718			return -EFAULT;
719		SOLD("set ctl_len");
720		*flags_p = it->pri;
721		it->length -= l;
722		if (it->length) {
723			SOLD("more ctl");
724			sock->offset += l;
725			return MORECTL;
726		} else {
727			SOLD("removing message");
728			sock->pfirst = it->next;
729			if (!sock->pfirst)
730				sock->plast = NULL;
731			SOLDD(("getmsg kfree %016lx->%016lx\n", it, sock->pfirst));
732			mykfree(it);
733			sock->offset = 0;
734			SOLD("ctl done");
735			return 0;
736		}
737	}
738	*flags_p = 0;
739	if (ctl_maxlen >= 0) {
740		SOLD("ACCEPT perhaps?");
741		if (SOCKET_I(ino)->type == SOCK_STREAM && sock->state == TS_IDLE) {
742			struct T_conn_ind ind;
743			char *buf = getpage();
744			int len = BUF_SIZE;
745
746			SOLD("trying ACCEPT");
747			if (put_user(ctl_maxlen - sizeof(ind), ctl_len))
748				return -EFAULT;
749			args[0] = fd;
750			args[1] = (long)buf;
751			args[2] = (long)&len;
752			oldflags = filp->f_flags;
753			filp->f_flags |= O_NONBLOCK;
754			SOLD("calling ACCEPT");
755			set_fs(KERNEL_DS);
756			error = sys_socketcall(SYS_ACCEPT, args);
757			set_fs(old_fs);
758			filp->f_flags = oldflags;
759			if (error < 0) {
760				SOLD("some error");
761				putpage(buf);
762				return error;
763			}
764			if (error) {
765				SOLD("connect");
766				putpage(buf);
767				if (sizeof(ind) > ctl_maxlen) {
768					SOLD("generating CONN_IND");
769					ind.PRIM_type = T_CONN_IND;
770					ind.SRC_length = len;
771					ind.SRC_offset = sizeof(ind);
772					ind.OPT_length = ind.OPT_offset = 0;
773					ind.SEQ_number = error;
774					if(copy_to_user(ctl_buf, &ind, sizeof(ind))||
775					   put_user(sizeof(ind)+ind.SRC_length,ctl_len))
776						return -EFAULT;
777					SOLD("CONN_IND created");
778				}
779				if (data_maxlen >= 0)
780					put_user(0, data_len);
781				SOLD("CONN_IND done");
782				return 0;
783			}
784			if (len>ctl_maxlen) {
785				SOLD("data don't fit");
786				putpage(buf);
787				return -EFAULT;
788			}
789			if(copy_to_user(ctl_buf,buf,len) || put_user(len,ctl_len)){
790				SOLD("can't copy data");
791				putpage(buf);
792				return -EFAULT;
793			}
794			SOLD("ACCEPT done");
795			putpage(buf);
796		}
797	}
798	SOLD("checking data req");
799	if (data_maxlen <= 0) {
800		if (data_maxlen == 0)
801			put_user(0, data_len);
802		if (ctl_maxlen >= 0)
803			put_user(0, ctl_len);
804		return -EAGAIN;
805	}
806	SOLD("wants data");
807	if (ctl_maxlen > sizeof(udi) && sock->state == TS_IDLE) {
808		SOLD("udi fits");
809		tmpbuf = ctl_buf + sizeof(udi);
810		tmplen = ctl_maxlen - sizeof(udi);
811	} else {
812		SOLD("udi does not fit");
813		tmpbuf = NULL;
814		tmplen = 0;
815	}
816	if (put_user(tmplen, ctl_len))
817		return -EFAULT;
818	SOLD("set ctl_len");
819	oldflags = filp->f_flags;
820	filp->f_flags |= O_NONBLOCK;
821	SOLD("calling recvfrom");
822	sys_recvfrom = (int (*)(int, void __user *, size_t, unsigned, struct sockaddr __user *, int __user *))SYS(recvfrom);
823	error = sys_recvfrom(fd, data_buf, data_maxlen, 0, (struct sockaddr __user *)tmpbuf, ctl_len);
824	filp->f_flags = oldflags;
825	if (error < 0)
826		return error;
827	SOLD("error >= 0" ) ;
828	if (error && ctl_maxlen > sizeof(udi) && sock->state == TS_IDLE) {
829		SOLD("generating udi");
830		udi.PRIM_type = T_UNITDATA_IND;
831		if (get_user(udi.SRC_length, ctl_len))
832			return -EFAULT;
833		udi.SRC_offset = sizeof(udi);
834		udi.OPT_length = udi.OPT_offset = 0;
835		if (copy_to_user(ctl_buf, &udi, sizeof(udi)) ||
836		    put_user(sizeof(udi)+udi.SRC_length, ctl_len))
837			return -EFAULT;
838		SOLD("udi done");
839	} else {
840		if (put_user(0, ctl_len))
841			return -EFAULT;
842	}
843	put_user(error, data_len);
844	SOLD("done");
845	return 0;
846}
847
848asmlinkage int solaris_getmsg(unsigned int fd, u32 arg1, u32 arg2, u32 arg3)
849{
850	struct file *filp;
851	struct inode *ino;
852	struct strbuf __user *ctlptr;
853	struct strbuf __user *datptr;
854	struct strbuf ctl, dat;
855	int __user *flgptr;
856	int flags;
857	int error = -EBADF;
858	struct fdtable *fdt;
859
860	SOLD("entry");
861	lock_kernel();
862	if(fd >= NR_OPEN) goto out;
863
864	fdt = files_fdtable(current->files);
865	filp = fdt->fd[fd];
866	if(!filp) goto out;
867
868	ino = filp->f_path.dentry->d_inode;
869	if (!ino || !S_ISSOCK(ino->i_mode))
870		goto out;
871
872	ctlptr = (struct strbuf __user *)A(arg1);
873	datptr = (struct strbuf __user *)A(arg2);
874	flgptr = (int __user *)A(arg3);
875
876	error = -EFAULT;
877
878	if (ctlptr) {
879		if (copy_from_user(&ctl,ctlptr,sizeof(struct strbuf)) ||
880		    put_user(-1,&ctlptr->len))
881			goto out;
882	} else
883		ctl.maxlen = -1;
884
885	if (datptr) {
886		if (copy_from_user(&dat,datptr,sizeof(struct strbuf)) ||
887		    put_user(-1,&datptr->len))
888			goto out;
889	} else
890		dat.maxlen = -1;
891
892	if (get_user(flags,flgptr))
893		goto out;
894
895	switch (flags) {
896	case 0:
897	case MSG_HIPRI:
898	case MSG_ANY:
899	case MSG_BAND:
900		break;
901	default:
902		error = -EINVAL;
903		goto out;
904	}
905
906	error = timod_getmsg(fd,A(ctl.buf),ctl.maxlen,&ctlptr->len,
907				A(dat.buf),dat.maxlen,&datptr->len,&flags);
908
909	if (!error && put_user(flags,flgptr))
910		error = -EFAULT;
911out:
912	unlock_kernel();
913	SOLD("done");
914	return error;
915}
916
917asmlinkage int solaris_putmsg(unsigned int fd, u32 arg1, u32 arg2, u32 arg3)
918{
919	struct file *filp;
920	struct inode *ino;
921	struct strbuf __user *ctlptr;
922	struct strbuf __user *datptr;
923	struct strbuf ctl, dat;
924	int flags = (int) arg3;
925	int error = -EBADF;
926	struct fdtable *fdt;
927
928	SOLD("entry");
929	lock_kernel();
930	if(fd >= NR_OPEN) goto out;
931
932	fdt = files_fdtable(current->files);
933	filp = fdt->fd[fd];
934	if(!filp) goto out;
935
936	ino = filp->f_path.dentry->d_inode;
937	if (!ino) goto out;
938
939	if (!S_ISSOCK(ino->i_mode) &&
940		(imajor(ino) != 30 || iminor(ino) != 1))
941		goto out;
942
943	ctlptr = A(arg1);
944	datptr = A(arg2);
945
946	error = -EFAULT;
947
948	if (ctlptr) {
949		if (copy_from_user(&ctl,ctlptr,sizeof(ctl)))
950			goto out;
951		if (ctl.len < 0 && flags) {
952			error = -EINVAL;
953			goto out;
954		}
955	} else {
956		ctl.len = 0;
957		ctl.buf = 0;
958	}
959
960	if (datptr) {
961		if (copy_from_user(&dat,datptr,sizeof(dat)))
962			goto out;
963	} else {
964		dat.len = 0;
965		dat.buf = 0;
966	}
967
968	error = timod_putmsg(fd,A(ctl.buf),ctl.len,
969				A(dat.buf),dat.len,flags);
970out:
971	unlock_kernel();
972	SOLD("done");
973	return error;
974}
975