Ok. I didn't make 2.4.0 in 2000. Tough. I tried, but we had some
[davej-history.git] / arch / sparc64 / solaris / timod.c
blob3ef9c943b5d2258d7aefb95437c02816356fcccf
1 /* $Id: timod.c,v 1.10 2000/07/28 12:15:02 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/file.h>
19 #include <linux/netdevice.h>
20 #include <linux/poll.h>
22 #include <net/sock.h>
24 #include <asm/uaccess.h>
25 #include <asm/termios.h>
27 #include "conv.h"
28 #include "socksys.h"
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 read_lock(&sock->sk->callback_lock);
155 if (sock->fasync_list && !test_bit(SOCK_ASYNC_WAITDATA, &sock->flags))
156 __kill_fasync(sock->fasync_list, SIGIO, POLL_IN);
157 read_unlock(&sock->sk->callback_lock);
158 SOLD("done");
161 static void timod_queue(unsigned int fd, struct T_primsg *it)
163 struct sol_socket_struct *sock;
165 SOLD("queuing primsg");
166 sock = (struct sol_socket_struct *)current->files->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");
175 static void timod_queue_end(unsigned int fd, struct T_primsg *it)
177 struct sol_socket_struct *sock;
179 SOLD("queuing primsg at end");
180 sock = (struct sol_socket_struct *)current->files->fd[fd]->private_data;
181 it->next = NULL;
182 if (sock->plast)
183 sock->plast->next = it;
184 else
185 sock->pfirst = it;
186 sock->plast = it;
187 SOLD("done");
190 static void timod_error(unsigned int fd, int prim, int terr, int uerr)
192 struct T_primsg *it;
194 SOLD("making error");
195 it = timod_mkctl(sizeof(struct T_error_ack));
196 if (it) {
197 struct T_error_ack *err = (struct T_error_ack *)&it->type;
199 SOLD("got it");
200 err->PRIM_type = T_ERROR_ACK;
201 err->ERROR_prim = prim;
202 err->TLI_error = terr;
203 err->UNIX_error = uerr; /* FIXME: convert this */
204 timod_queue(fd, it);
206 SOLD("done");
209 static void timod_ok(unsigned int fd, int prim)
211 struct T_primsg *it;
212 struct T_ok_ack *ok;
214 SOLD("creating ok ack");
215 it = timod_mkctl(sizeof(*ok));
216 if (it) {
217 SOLD("got it");
218 ok = (struct T_ok_ack *)&it->type;
219 ok->PRIM_type = T_OK_ACK;
220 ok->CORRECT_prim = prim;
221 timod_queue(fd, it);
223 SOLD("done");
226 static int timod_optmgmt(unsigned int fd, int flag, char *opt_buf, int opt_len, int do_ret)
228 int error, failed;
229 int ret_space, ret_len;
230 long args[5];
231 char *ret_pos,*ret_buf;
232 int (*sys_socketcall)(int, unsigned long *) =
233 (int (*)(int, unsigned long *))SYS(socketcall);
234 mm_segment_t old_fs = get_fs();
236 SOLD("entry");
237 SOLDD(("fd %u flg %u buf %p len %u doret %u",fd,flag,opt_buf,opt_len,do_ret));
238 if (!do_ret && (!opt_buf || opt_len <= 0))
239 return 0;
240 SOLD("getting page");
241 ret_pos = ret_buf = getpage();
242 ret_space = BUF_SIZE;
243 ret_len = 0;
245 error = failed = 0;
246 SOLD("looping");
247 while(opt_len >= sizeof(struct opthdr)) {
248 struct opthdr *opt;
249 int orig_opt_len;
250 SOLD("loop start");
251 opt = (struct opthdr *)ret_pos;
252 if (ret_space < sizeof(struct opthdr)) {
253 failed = TSYSERR;
254 break;
256 SOLD("getting opthdr");
257 if (copy_from_user(opt, opt_buf, sizeof(struct opthdr)) ||
258 opt->len > opt_len) {
259 failed = TBADOPT;
260 break;
262 SOLD("got opthdr");
263 if (flag == T_NEGOTIATE) {
264 char *buf;
266 SOLD("handling T_NEGOTIATE");
267 buf = ret_pos + sizeof(struct opthdr);
268 if (ret_space < opt->len + sizeof(struct opthdr) ||
269 copy_from_user(buf, opt_buf+sizeof(struct opthdr), opt->len)) {
270 failed = TSYSERR;
271 break;
273 SOLD("got optdata");
274 args[0] = fd;
275 args[1] = opt->level;
276 args[2] = opt->name;
277 args[3] = (long)buf;
278 args[4] = opt->len;
279 SOLD("calling SETSOCKOPT");
280 set_fs(KERNEL_DS);
281 error = sys_socketcall(SYS_SETSOCKOPT, args);
282 set_fs(old_fs);
283 if (error) {
284 failed = TBADOPT;
285 break;
287 SOLD("SETSOCKOPT ok");
289 orig_opt_len = opt->len;
290 opt->len = ret_space - sizeof(struct opthdr);
291 if (opt->len < 0) {
292 failed = TSYSERR;
293 break;
295 args[0] = fd;
296 args[1] = opt->level;
297 args[2] = opt->name;
298 args[3] = (long)(ret_pos+sizeof(struct opthdr));
299 args[4] = (long)&opt->len;
300 SOLD("calling GETSOCKOPT");
301 set_fs(KERNEL_DS);
302 error = sys_socketcall(SYS_GETSOCKOPT, args);
303 set_fs(old_fs);;
304 if (error) {
305 failed = TBADOPT;
306 break;
308 SOLD("GETSOCKOPT ok");
309 ret_space -= sizeof(struct opthdr) + opt->len;
310 ret_len += sizeof(struct opthdr) + opt->len;
311 ret_pos += sizeof(struct opthdr) + opt->len;
312 opt_len -= sizeof(struct opthdr) + orig_opt_len;
313 opt_buf += sizeof(struct opthdr) + orig_opt_len;
314 SOLD("loop end");
316 SOLD("loop done");
317 if (do_ret) {
318 SOLD("generating ret msg");
319 if (failed)
320 timod_error(fd, T_OPTMGMT_REQ, failed, -error);
321 else {
322 struct T_primsg *it;
323 it = timod_mkctl(sizeof(struct T_optmgmt_ack) + ret_len);
324 if (it) {
325 struct T_optmgmt_ack *ack =
326 (struct T_optmgmt_ack *)&it->type;
327 SOLD("got primsg");
328 ack->PRIM_type = T_OPTMGMT_ACK;
329 ack->OPT_length = ret_len;
330 ack->OPT_offset = sizeof(struct T_optmgmt_ack);
331 ack->MGMT_flags = (failed ? T_FAILURE : flag);
332 memcpy(((char*)ack)+sizeof(struct T_optmgmt_ack),
333 ret_buf, ret_len);
334 timod_queue(fd, it);
338 SOLDD(("put_page %p\n", ret_buf));
339 putpage(ret_buf);
340 SOLD("done");
341 return 0;
344 int timod_putmsg(unsigned int fd, char *ctl_buf, int ctl_len,
345 char *data_buf, int data_len, int flags)
347 int ret, error, terror;
348 char *buf;
349 struct file *filp;
350 struct inode *ino;
351 struct sol_socket_struct *sock;
352 mm_segment_t old_fs = get_fs();
353 long args[6];
354 int (*sys_socketcall)(int, unsigned long *) =
355 (int (*)(int, unsigned long *))SYS(socketcall);
356 int (*sys_sendto)(int, void *, size_t, unsigned, struct sockaddr *, int) =
357 (int (*)(int, void *, size_t, unsigned, struct sockaddr *, int))SYS(sendto);
358 filp = current->files->fd[fd];
359 ino = filp->f_dentry->d_inode;
360 sock = (struct sol_socket_struct *)filp->private_data;
361 SOLD("entry");
362 if (get_user(ret, (int *)A(ctl_buf)))
363 return -EFAULT;
364 switch (ret) {
365 case T_BIND_REQ:
367 struct T_bind_req req;
369 SOLDD(("bind %016lx(%016lx)\n", sock, filp));
370 SOLD("T_BIND_REQ");
371 if (sock->state != TS_UNBND) {
372 timod_error(fd, T_BIND_REQ, TOUTSTATE, 0);
373 return 0;
375 SOLD("state ok");
376 if (copy_from_user(&req, ctl_buf, sizeof(req))) {
377 timod_error(fd, T_BIND_REQ, TSYSERR, EFAULT);
378 return 0;
380 SOLD("got ctl req");
381 if (req.ADDR_offset && req.ADDR_length) {
382 if (req.ADDR_length > BUF_SIZE) {
383 timod_error(fd, T_BIND_REQ, TSYSERR, EFAULT);
384 return 0;
386 SOLD("req size ok");
387 buf = getpage();
388 if (copy_from_user(buf, ctl_buf + req.ADDR_offset, req.ADDR_length)) {
389 timod_error(fd, T_BIND_REQ, TSYSERR, EFAULT);
390 putpage(buf);
391 return 0;
393 SOLD("got ctl data");
394 args[0] = fd;
395 args[1] = (long)buf;
396 args[2] = req.ADDR_length;
397 SOLD("calling BIND");
398 set_fs(KERNEL_DS);
399 error = sys_socketcall(SYS_BIND, args);
400 set_fs(old_fs);
401 putpage(buf);
402 SOLD("BIND returned");
403 } else
404 error = 0;
405 if (!error) {
406 struct T_primsg *it;
407 if (req.CONIND_number) {
408 args[0] = fd;
409 args[1] = req.CONIND_number;
410 SOLD("calling LISTEN");
411 set_fs(KERNEL_DS);
412 error = sys_socketcall(SYS_LISTEN, args);
413 set_fs(old_fs);
414 SOLD("LISTEN done");
416 it = timod_mkctl(sizeof(struct T_bind_ack)+sizeof(struct sockaddr));
417 if (it) {
418 struct T_bind_ack *ack;
420 ack = (struct T_bind_ack *)&it->type;
421 ack->PRIM_type = T_BIND_ACK;
422 ack->ADDR_offset = sizeof(*ack);
423 ack->ADDR_length = sizeof(struct sockaddr);
424 ack->CONIND_number = req.CONIND_number;
425 args[0] = fd;
426 args[1] = (long)(ack+sizeof(*ack));
427 args[2] = (long)&ack->ADDR_length;
428 set_fs(KERNEL_DS);
429 sys_socketcall(SYS_GETSOCKNAME,args);
430 set_fs(old_fs);
431 sock->state = TS_IDLE;
432 timod_ok(fd, T_BIND_REQ);
433 timod_queue_end(fd, it);
434 SOLD("BIND done");
435 return 0;
438 SOLD("some error");
439 switch (error) {
440 case -EINVAL:
441 terror = TOUTSTATE;
442 error = 0;
443 break;
444 case -EACCES:
445 terror = TACCES;
446 error = 0;
447 break;
448 case -EADDRNOTAVAIL:
449 case -EADDRINUSE:
450 terror = TNOADDR;
451 error = 0;
452 break;
453 default:
454 terror = TSYSERR;
455 break;
457 timod_error(fd, T_BIND_REQ, terror, -error);
458 SOLD("BIND done");
459 return 0;
461 case T_CONN_REQ:
463 struct T_conn_req req;
464 unsigned short oldflags;
465 struct T_primsg *it;
466 SOLD("T_CONN_REQ");
467 if (sock->state != TS_UNBND && sock->state != TS_IDLE) {
468 timod_error(fd, T_CONN_REQ, TOUTSTATE, 0);
469 return 0;
471 SOLD("state ok");
472 if (copy_from_user(&req, ctl_buf, sizeof(req))) {
473 timod_error(fd, T_CONN_REQ, TSYSERR, EFAULT);
474 return 0;
476 SOLD("got ctl req");
477 if (ctl_len > BUF_SIZE) {
478 timod_error(fd, T_CONN_REQ, TSYSERR, EFAULT);
479 return 0;
481 SOLD("req size ok");
482 buf = getpage();
483 if (copy_from_user(buf, ctl_buf, ctl_len)) {
484 timod_error(fd, T_CONN_REQ, TSYSERR, EFAULT);
485 putpage(buf);
486 return 0;
488 #ifdef DEBUG_SOLARIS
490 char * ptr = buf;
491 int len = ctl_len;
492 printk("returned data (%d bytes): ",len);
493 while( len-- ) {
494 if (!(len & 7))
495 printk(" ");
496 printk("%02x",(unsigned char)*ptr++);
498 printk("\n");
500 #endif
501 SOLD("got ctl data");
502 args[0] = fd;
503 args[1] = (long)buf+req.DEST_offset;
504 args[2] = req.DEST_length;
505 oldflags = filp->f_flags;
506 filp->f_flags &= ~O_NONBLOCK;
507 SOLD("calling CONNECT");
508 set_fs(KERNEL_DS);
509 error = sys_socketcall(SYS_CONNECT, args);
510 set_fs(old_fs);
511 filp->f_flags = oldflags;
512 SOLD("CONNECT done");
513 if (!error) {
514 struct T_conn_con *con;
515 SOLD("no error");
516 it = timod_mkctl(ctl_len);
517 if (!it) {
518 putpage(buf);
519 return -ENOMEM;
521 con = (struct T_conn_con *)&it->type;
522 #ifdef DEBUG_SOLARIS
524 char * ptr = buf;
525 int len = ctl_len;
526 printk("returned data (%d bytes): ",len);
527 while( len-- ) {
528 if (!(len & 7))
529 printk(" ");
530 printk("%02x",(unsigned char)*ptr++);
532 printk("\n");
534 #endif
535 memcpy(con, buf, ctl_len);
536 SOLD("copied ctl_buf");
537 con->PRIM_type = T_CONN_CON;
538 sock->state = TS_DATA_XFER;
539 } else {
540 struct T_discon_ind *dis;
541 SOLD("some error");
542 it = timod_mkctl(sizeof(*dis));
543 if (!it) {
544 putpage(buf);
545 return -ENOMEM;
547 SOLD("got primsg");
548 dis = (struct T_discon_ind *)&it->type;
549 dis->PRIM_type = T_DISCON_IND;
550 dis->DISCON_reason = -error; /* FIXME: convert this as in iABI_errors() */
551 dis->SEQ_number = 0;
553 putpage(buf);
554 timod_ok(fd, T_CONN_REQ);
555 it->pri = 0;
556 timod_queue_end(fd, it);
557 SOLD("CONNECT done");
558 return 0;
560 case T_OPTMGMT_REQ:
562 struct T_optmgmt_req req;
563 SOLD("OPTMGMT_REQ");
564 if (copy_from_user(&req, ctl_buf, sizeof(req)))
565 return -EFAULT;
566 SOLD("got req");
567 return timod_optmgmt(fd, req.MGMT_flags,
568 req.OPT_offset > 0 ? ctl_buf + req.OPT_offset : NULL,
569 req.OPT_length, 1);
571 case T_UNITDATA_REQ:
573 struct T_unitdata_req req;
575 int err;
576 SOLD("T_UNITDATA_REQ");
577 if (sock->state != TS_IDLE && sock->state != TS_DATA_XFER) {
578 timod_error(fd, T_CONN_REQ, TOUTSTATE, 0);
579 return 0;
581 SOLD("state ok");
582 if (copy_from_user(&req, ctl_buf, sizeof(req))) {
583 timod_error(fd, T_CONN_REQ, TSYSERR, EFAULT);
584 return 0;
586 SOLD("got ctl req");
587 #ifdef DEBUG_SOLARIS
589 char * ptr = ctl_buf+req.DEST_offset;
590 int len = req.DEST_length;
591 printk("socket address (%d bytes): ",len);
592 while( len-- ) {
593 char c;
594 if (get_user(c,ptr))
595 printk("??");
596 else
597 printk("%02x",(unsigned char)c);
598 ptr++;
600 printk("\n");
602 #endif
603 err = sys_sendto(fd, data_buf, data_len, 0, req.DEST_length > 0 ? (struct sockaddr*)(ctl_buf+req.DEST_offset) : NULL, req.DEST_length);
604 if (err == data_len)
605 return 0;
606 if(err >= 0) {
607 printk("timod: sendto failed to send all the data\n");
608 return 0;
610 timod_error(fd, T_CONN_REQ, TSYSERR, -err);
611 return 0;
613 default:
614 printk("timod_putmsg: unsuported command %u.\n", ret);
615 break;
617 return -EINVAL;
620 int timod_getmsg(unsigned int fd, char *ctl_buf, int ctl_maxlen, s32 *ctl_len,
621 char *data_buf, int data_maxlen, s32 *data_len, int *flags_p)
623 int error;
624 int oldflags;
625 struct file *filp;
626 struct inode *ino;
627 struct sol_socket_struct *sock;
628 struct T_unitdata_ind udi;
629 mm_segment_t old_fs = get_fs();
630 long args[6];
631 char *tmpbuf;
632 int tmplen;
633 int (*sys_socketcall)(int, unsigned long *) =
634 (int (*)(int, unsigned long *))SYS(socketcall);
635 int (*sys_recvfrom)(int, void *, size_t, unsigned, struct sockaddr *, int *);
637 SOLD("entry");
638 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));
639 filp = current->files->fd[fd];
640 ino = filp->f_dentry->d_inode;
641 sock = (struct sol_socket_struct *)filp->private_data;
642 SOLDD(("%p %p\n", sock->pfirst, sock->pfirst ? sock->pfirst->next : NULL));
643 if ( ctl_maxlen > 0 && !sock->pfirst && ino->u.socket_i.type == SOCK_STREAM
644 && sock->state == TS_IDLE) {
645 SOLD("calling LISTEN");
646 args[0] = fd;
647 args[1] = -1;
648 set_fs(KERNEL_DS);
649 sys_socketcall(SYS_LISTEN, args);
650 set_fs(old_fs);
651 SOLD("LISTEN done");
653 if (!(filp->f_flags & O_NONBLOCK)) {
654 poll_table wait_table, *wait;
656 poll_initwait(&wait_table);
657 wait = &wait_table;
658 for(;;) {
659 SOLD("loop");
660 set_current_state(TASK_INTERRUPTIBLE);
661 /* ! ( l<0 || ( l>=0 && ( ! pfirst || (flags == HIPRI && pri != HIPRI) ) ) ) */
662 /* ( ! l<0 && ! ( l>=0 && ( ! pfirst || (flags == HIPRI && pri != HIPRI) ) ) ) */
663 /* ( l>=0 && ( ! l>=0 || ! ( ! pfirst || (flags == HIPRI && pri != HIPRI) ) ) ) */
664 /* ( l>=0 && ( l<0 || ( pfirst && ! (flags == HIPRI && pri != HIPRI) ) ) ) */
665 /* ( l>=0 && ( l<0 || ( pfirst && (flags != HIPRI || pri == HIPRI) ) ) ) */
666 /* ( l>=0 && ( pfirst && (flags != HIPRI || pri == HIPRI) ) ) */
667 if (ctl_maxlen >= 0 && sock->pfirst && (*flags_p != MSG_HIPRI || sock->pfirst->pri == MSG_HIPRI))
668 break;
669 SOLD("cond 1 passed");
670 if (
671 #if 1
672 *flags_p != MSG_HIPRI &&
673 #endif
674 ((filp->f_op->poll(filp, wait) & POLLIN) ||
675 (filp->f_op->poll(filp, NULL) & POLLIN) ||
676 signal_pending(current))
678 break;
680 if( *flags_p == MSG_HIPRI ) {
681 SOLD("avoiding lockup");
682 break ;
684 if(wait_table.error) {
685 SOLD("wait-table error");
686 poll_freewait(&wait_table);
687 return wait_table.error;
689 SOLD("scheduling");
690 schedule();
692 SOLD("loop done");
693 current->state = TASK_RUNNING;
694 poll_freewait(&wait_table);
695 if (signal_pending(current)) {
696 SOLD("signal pending");
697 return -EINTR;
700 if (ctl_maxlen >= 0 && sock->pfirst) {
701 struct T_primsg *it = sock->pfirst;
702 #ifndef min
703 #define min(a,b) ((a)<(b)?(a):(b))
704 #endif
705 int l = min(ctl_maxlen, it->length);
706 SCHECK_MAGIC((char*)((u64)(((char *)&it->type)+sock->offset+it->length+7)&~7),MKCTL_MAGIC);
707 SOLD("purting ctl data");
708 if(copy_to_user(ctl_buf,
709 (char*)&it->type + sock->offset, l))
710 return -EFAULT;
711 SOLD("pur it");
712 if(put_user(l, ctl_len))
713 return -EFAULT;
714 SOLD("set ctl_len");
715 *flags_p = it->pri;
716 it->length -= l;
717 if (it->length) {
718 SOLD("more ctl");
719 sock->offset += l;
720 return MORECTL;
721 } else {
722 SOLD("removing message");
723 sock->pfirst = it->next;
724 if (!sock->pfirst)
725 sock->plast = NULL;
726 SOLDD(("getmsg kfree %016lx->%016lx\n", it, sock->pfirst));
727 mykfree(it);
728 sock->offset = 0;
729 SOLD("ctl done");
730 return 0;
733 *flags_p = 0;
734 if (ctl_maxlen >= 0) {
735 SOLD("ACCEPT perhaps?");
736 if (ino->u.socket_i.type == SOCK_STREAM && sock->state == TS_IDLE) {
737 struct T_conn_ind ind;
738 char *buf = getpage();
739 int len = BUF_SIZE;
741 SOLD("trying ACCEPT");
742 if (put_user(ctl_maxlen - sizeof(ind), ctl_len))
743 return -EFAULT;
744 args[0] = fd;
745 args[1] = (long)buf;
746 args[2] = (long)&len;
747 oldflags = filp->f_flags;
748 filp->f_flags |= O_NONBLOCK;
749 SOLD("calling ACCEPT");
750 set_fs(KERNEL_DS);
751 error = sys_socketcall(SYS_ACCEPT, args);
752 set_fs(old_fs);
753 filp->f_flags = oldflags;
754 if (error < 0) {
755 SOLD("some error");
756 putpage(buf);
757 return error;
759 if (error) {
760 SOLD("connect");
761 putpage(buf);
762 if (sizeof(ind) > ctl_maxlen) {
763 SOLD("generating CONN_IND");
764 ind.PRIM_type = T_CONN_IND;
765 ind.SRC_length = len;
766 ind.SRC_offset = sizeof(ind);
767 ind.OPT_length = ind.OPT_offset = 0;
768 ind.SEQ_number = error;
769 if(copy_to_user(ctl_buf, &ind, sizeof(ind))||
770 put_user(sizeof(ind)+ind.SRC_length,ctl_len))
771 return -EFAULT;
772 SOLD("CONN_IND created");
774 if (data_maxlen >= 0)
775 put_user(0, data_len);
776 SOLD("CONN_IND done");
777 return 0;
779 if (len>ctl_maxlen) {
780 SOLD("data don't fit");
781 putpage(buf);
782 return -EFAULT; /* XXX - is this ok ? */
784 if(copy_to_user(ctl_buf,buf,len) || put_user(len,ctl_len)){
785 SOLD("can't copy data");
786 putpage(buf);
787 return -EFAULT;
789 SOLD("ACCEPT done");
790 putpage(buf);
793 SOLD("checking data req");
794 if (data_maxlen <= 0) {
795 if (data_maxlen == 0)
796 put_user(0, data_len);
797 if (ctl_maxlen >= 0)
798 put_user(0, ctl_len);
799 return -EAGAIN;
801 SOLD("wants data");
802 if (ctl_maxlen > sizeof(udi) && sock->state == TS_IDLE) {
803 SOLD("udi fits");
804 tmpbuf = ctl_buf + sizeof(udi);
805 tmplen = ctl_maxlen - sizeof(udi);
806 } else {
807 SOLD("udi does not fit");
808 tmpbuf = NULL;
809 tmplen = 0;
811 if (put_user(tmplen, ctl_len))
812 return -EFAULT;
813 SOLD("set ctl_len");
814 oldflags = filp->f_flags;
815 filp->f_flags |= O_NONBLOCK;
816 SOLD("calling recvfrom");
817 sys_recvfrom = (int (*)(int, void *, size_t, unsigned, struct sockaddr *, int *))SYS(recvfrom);
818 error = sys_recvfrom(fd, data_buf, min(0,data_maxlen), 0, (struct sockaddr*)tmpbuf, ctl_len);
819 filp->f_flags = oldflags;
820 if (error < 0)
821 return error;
822 SOLD("error >= 0" ) ;
823 if (error && ctl_maxlen > sizeof(udi) && sock->state == TS_IDLE) {
824 SOLD("generating udi");
825 udi.PRIM_type = T_UNITDATA_IND;
826 get_user(udi.SRC_length, ctl_len);
827 udi.SRC_offset = sizeof(udi);
828 udi.OPT_length = udi.OPT_offset = 0;
829 copy_to_user(ctl_buf, &udi, sizeof(udi));
830 put_user(sizeof(udi)+udi.SRC_length, ctl_len);
831 SOLD("udi done");
832 } else
833 put_user(0, ctl_len);
834 put_user(error, data_len);
835 SOLD("done");
836 return 0;
839 asmlinkage int solaris_getmsg(unsigned int fd, u32 arg1, u32 arg2, u32 arg3)
841 struct file *filp;
842 struct inode *ino;
843 struct strbuf *ctlptr, *datptr;
844 struct strbuf ctl, dat;
845 int *flgptr;
846 int flags;
847 int error = -EBADF;
849 SOLD("entry");
850 lock_kernel();
851 if(fd >= NR_OPEN) goto out;
853 filp = current->files->fd[fd];
854 if(!filp) goto out;
856 ino = filp->f_dentry->d_inode;
857 if (!ino) goto out;
859 if (!ino->i_sock)
860 goto out;
862 ctlptr = (struct strbuf *)A(arg1);
863 datptr = (struct strbuf *)A(arg2);
864 flgptr = (int *)A(arg3);
866 error = -EFAULT;
868 if (ctlptr) {
869 if (copy_from_user(&ctl,ctlptr,sizeof(struct strbuf)) ||
870 put_user(-1,&ctlptr->len))
871 goto out;
872 } else
873 ctl.maxlen = -1;
875 if (datptr) {
876 if (copy_from_user(&dat,datptr,sizeof(struct strbuf)) ||
877 put_user(-1,&datptr->len))
878 goto out;
879 } else
880 dat.maxlen = -1;
882 if (get_user(flags,flgptr))
883 goto out;
885 switch (flags) {
886 case 0:
887 case MSG_HIPRI:
888 case MSG_ANY:
889 case MSG_BAND:
890 break;
891 default:
892 error = -EINVAL;
893 goto out;
896 error = timod_getmsg(fd,(char*)A(ctl.buf),ctl.maxlen,&ctlptr->len,
897 (char*)A(dat.buf),dat.maxlen,&datptr->len,&flags);
899 if (!error && put_user(flags,flgptr))
900 error = -EFAULT;
901 out:
902 unlock_kernel();
903 SOLD("done");
904 return error;
907 asmlinkage int solaris_putmsg(unsigned int fd, u32 arg1, u32 arg2, u32 arg3)
909 struct file *filp;
910 struct inode *ino;
911 struct strbuf *ctlptr, *datptr;
912 struct strbuf ctl, dat;
913 int flags = (int) arg3;
914 int error = -EBADF;
916 SOLD("entry");
917 lock_kernel();
918 if(fd >= NR_OPEN) goto out;
920 filp = current->files->fd[fd];
921 if(!filp) goto out;
923 ino = filp->f_dentry->d_inode;
924 if (!ino) goto out;
926 if (!ino->i_sock &&
927 (MAJOR(ino->i_rdev) != 30 || MINOR(ino->i_rdev) != 1))
928 goto out;
930 ctlptr = (struct strbuf *)A(arg1);
931 datptr = (struct strbuf *)A(arg2);
933 error = -EFAULT;
935 if (ctlptr) {
936 if (copy_from_user(&ctl,ctlptr,sizeof(ctl)))
937 goto out;
938 if (ctl.len < 0 && flags) {
939 error = -EINVAL;
940 goto out;
942 } else {
943 ctl.len = 0;
944 ctl.buf = 0;
947 if (datptr) {
948 if (copy_from_user(&dat,datptr,sizeof(dat)))
949 goto out;
950 } else {
951 dat.len = 0;
952 dat.buf = 0;
955 error = timod_putmsg(fd,(char*)A(ctl.buf),ctl.len,
956 (char*)A(dat.buf),dat.len,flags);
957 out:
958 unlock_kernel();
959 SOLD("done");
960 return error;