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