Linux-2.6.12-rc2
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / arch / sparc64 / solaris / timod.c
blob022c80f4339233add3d1c156028506b5aa53cdbc
1 /* $Id: timod.c,v 1.19 2002/02/08 03:57:14 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 asmlinkage int solaris_ioctl(unsigned int fd, unsigned int cmd, u32 arg);
32 static DEFINE_SPINLOCK(timod_pagelock);
33 static char * page = NULL ;
35 #ifndef DEBUG_SOLARIS_KMALLOC
37 #define mykmalloc kmalloc
38 #define mykfree kfree
40 #else
42 void * mykmalloc(size_t s, int gfp)
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);
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;
57 r = page;
58 page += s;
59 free -= s;
60 return r;
63 void mykfree(void *p)
67 #endif
69 #ifndef DEBUG_SOLARIS
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
77 #else
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)
88 #endif
90 static char *getpage( void )
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;
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;
110 static void putpage(char *p)
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");
128 static struct T_primsg *timod_mkctl(int size)
130 struct T_primsg *it;
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);
140 return it;
143 static void timod_wake_socket(unsigned int fd)
145 struct socket *sock;
147 SOLD("wakeing socket");
148 sock = SOCKET_I(current->files->fd[fd]->f_dentry->d_inode);
149 wake_up_interruptible(&sock->wait);
150 read_lock(&sock->sk->sk_callback_lock);
151 if (sock->fasync_list && !test_bit(SOCK_ASYNC_WAITDATA, &sock->flags))
152 __kill_fasync(sock->fasync_list, SIGIO, POLL_IN);
153 read_unlock(&sock->sk->sk_callback_lock);
154 SOLD("done");
157 static void timod_queue(unsigned int fd, struct T_primsg *it)
159 struct sol_socket_struct *sock;
161 SOLD("queuing primsg");
162 sock = (struct sol_socket_struct *)current->files->fd[fd]->private_data;
163 it->next = sock->pfirst;
164 sock->pfirst = it;
165 if (!sock->plast)
166 sock->plast = it;
167 timod_wake_socket(fd);
168 SOLD("done");
171 static void timod_queue_end(unsigned int fd, struct T_primsg *it)
173 struct sol_socket_struct *sock;
175 SOLD("queuing primsg at end");
176 sock = (struct sol_socket_struct *)current->files->fd[fd]->private_data;
177 it->next = NULL;
178 if (sock->plast)
179 sock->plast->next = it;
180 else
181 sock->pfirst = it;
182 sock->plast = it;
183 SOLD("done");
186 static void timod_error(unsigned int fd, int prim, int terr, int uerr)
188 struct T_primsg *it;
190 SOLD("making error");
191 it = timod_mkctl(sizeof(struct T_error_ack));
192 if (it) {
193 struct T_error_ack *err = (struct T_error_ack *)&it->type;
195 SOLD("got it");
196 err->PRIM_type = T_ERROR_ACK;
197 err->ERROR_prim = prim;
198 err->TLI_error = terr;
199 err->UNIX_error = uerr; /* FIXME: convert this */
200 timod_queue(fd, it);
202 SOLD("done");
205 static void timod_ok(unsigned int fd, int prim)
207 struct T_primsg *it;
208 struct T_ok_ack *ok;
210 SOLD("creating ok ack");
211 it = timod_mkctl(sizeof(*ok));
212 if (it) {
213 SOLD("got it");
214 ok = (struct T_ok_ack *)&it->type;
215 ok->PRIM_type = T_OK_ACK;
216 ok->CORRECT_prim = prim;
217 timod_queue(fd, it);
219 SOLD("done");
222 static int timod_optmgmt(unsigned int fd, int flag, char __user *opt_buf, int opt_len, int do_ret)
224 int error, failed;
225 int ret_space, ret_len;
226 long args[5];
227 char *ret_pos,*ret_buf;
228 int (*sys_socketcall)(int, unsigned long *) =
229 (int (*)(int, unsigned long *))SYS(socketcall);
230 mm_segment_t old_fs = get_fs();
232 SOLD("entry");
233 SOLDD(("fd %u flg %u buf %p len %u doret %u",fd,flag,opt_buf,opt_len,do_ret));
234 if (!do_ret && (!opt_buf || opt_len <= 0))
235 return 0;
236 SOLD("getting page");
237 ret_pos = ret_buf = getpage();
238 ret_space = BUF_SIZE;
239 ret_len = 0;
241 error = failed = 0;
242 SOLD("looping");
243 while(opt_len >= sizeof(struct opthdr)) {
244 struct opthdr *opt;
245 int orig_opt_len;
246 SOLD("loop start");
247 opt = (struct opthdr *)ret_pos;
248 if (ret_space < sizeof(struct opthdr)) {
249 failed = TSYSERR;
250 break;
252 SOLD("getting opthdr");
253 if (copy_from_user(opt, opt_buf, sizeof(struct opthdr)) ||
254 opt->len > opt_len) {
255 failed = TBADOPT;
256 break;
258 SOLD("got opthdr");
259 if (flag == T_NEGOTIATE) {
260 char *buf;
262 SOLD("handling T_NEGOTIATE");
263 buf = ret_pos + sizeof(struct opthdr);
264 if (ret_space < opt->len + sizeof(struct opthdr) ||
265 copy_from_user(buf, opt_buf+sizeof(struct opthdr), opt->len)) {
266 failed = TSYSERR;
267 break;
269 SOLD("got optdata");
270 args[0] = fd;
271 args[1] = opt->level;
272 args[2] = opt->name;
273 args[3] = (long)buf;
274 args[4] = opt->len;
275 SOLD("calling SETSOCKOPT");
276 set_fs(KERNEL_DS);
277 error = sys_socketcall(SYS_SETSOCKOPT, args);
278 set_fs(old_fs);
279 if (error) {
280 failed = TBADOPT;
281 break;
283 SOLD("SETSOCKOPT ok");
285 orig_opt_len = opt->len;
286 opt->len = ret_space - sizeof(struct opthdr);
287 if (opt->len < 0) {
288 failed = TSYSERR;
289 break;
291 args[0] = fd;
292 args[1] = opt->level;
293 args[2] = opt->name;
294 args[3] = (long)(ret_pos+sizeof(struct opthdr));
295 args[4] = (long)&opt->len;
296 SOLD("calling GETSOCKOPT");
297 set_fs(KERNEL_DS);
298 error = sys_socketcall(SYS_GETSOCKOPT, args);
299 set_fs(old_fs);
300 if (error) {
301 failed = TBADOPT;
302 break;
304 SOLD("GETSOCKOPT ok");
305 ret_space -= sizeof(struct opthdr) + opt->len;
306 ret_len += sizeof(struct opthdr) + opt->len;
307 ret_pos += sizeof(struct opthdr) + opt->len;
308 opt_len -= sizeof(struct opthdr) + orig_opt_len;
309 opt_buf += sizeof(struct opthdr) + orig_opt_len;
310 SOLD("loop end");
312 SOLD("loop done");
313 if (do_ret) {
314 SOLD("generating ret msg");
315 if (failed)
316 timod_error(fd, T_OPTMGMT_REQ, failed, -error);
317 else {
318 struct T_primsg *it;
319 it = timod_mkctl(sizeof(struct T_optmgmt_ack) + ret_len);
320 if (it) {
321 struct T_optmgmt_ack *ack =
322 (struct T_optmgmt_ack *)&it->type;
323 SOLD("got primsg");
324 ack->PRIM_type = T_OPTMGMT_ACK;
325 ack->OPT_length = ret_len;
326 ack->OPT_offset = sizeof(struct T_optmgmt_ack);
327 ack->MGMT_flags = (failed ? T_FAILURE : flag);
328 memcpy(((char*)ack)+sizeof(struct T_optmgmt_ack),
329 ret_buf, ret_len);
330 timod_queue(fd, it);
334 SOLDD(("put_page %p\n", ret_buf));
335 putpage(ret_buf);
336 SOLD("done");
337 return 0;
340 int timod_putmsg(unsigned int fd, char __user *ctl_buf, int ctl_len,
341 char __user *data_buf, int data_len, int flags)
343 int ret, error, terror;
344 char *buf;
345 struct file *filp;
346 struct inode *ino;
347 struct sol_socket_struct *sock;
348 mm_segment_t old_fs = get_fs();
349 long args[6];
350 int (*sys_socketcall)(int, unsigned long __user *) =
351 (int (*)(int, unsigned long __user *))SYS(socketcall);
352 int (*sys_sendto)(int, void __user *, size_t, unsigned, struct sockaddr __user *, int) =
353 (int (*)(int, void __user *, size_t, unsigned, struct sockaddr __user *, int))SYS(sendto);
354 filp = current->files->fd[fd];
355 ino = filp->f_dentry->d_inode;
356 sock = (struct sol_socket_struct *)filp->private_data;
357 SOLD("entry");
358 if (get_user(ret, (int __user *)A(ctl_buf)))
359 return -EFAULT;
360 switch (ret) {
361 case T_BIND_REQ:
363 struct T_bind_req req;
365 SOLDD(("bind %016lx(%016lx)\n", sock, filp));
366 SOLD("T_BIND_REQ");
367 if (sock->state != TS_UNBND) {
368 timod_error(fd, T_BIND_REQ, TOUTSTATE, 0);
369 return 0;
371 SOLD("state ok");
372 if (copy_from_user(&req, ctl_buf, sizeof(req))) {
373 timod_error(fd, T_BIND_REQ, TSYSERR, EFAULT);
374 return 0;
376 SOLD("got ctl req");
377 if (req.ADDR_offset && req.ADDR_length) {
378 if (req.ADDR_length > BUF_SIZE) {
379 timod_error(fd, T_BIND_REQ, TSYSERR, EFAULT);
380 return 0;
382 SOLD("req size ok");
383 buf = getpage();
384 if (copy_from_user(buf, ctl_buf + req.ADDR_offset, req.ADDR_length)) {
385 timod_error(fd, T_BIND_REQ, TSYSERR, EFAULT);
386 putpage(buf);
387 return 0;
389 SOLD("got ctl data");
390 args[0] = fd;
391 args[1] = (long)buf;
392 args[2] = req.ADDR_length;
393 SOLD("calling BIND");
394 set_fs(KERNEL_DS);
395 error = sys_socketcall(SYS_BIND, args);
396 set_fs(old_fs);
397 putpage(buf);
398 SOLD("BIND returned");
399 } else
400 error = 0;
401 if (!error) {
402 struct T_primsg *it;
403 if (req.CONIND_number) {
404 args[0] = fd;
405 args[1] = req.CONIND_number;
406 SOLD("calling LISTEN");
407 set_fs(KERNEL_DS);
408 error = sys_socketcall(SYS_LISTEN, args);
409 set_fs(old_fs);
410 SOLD("LISTEN done");
412 it = timod_mkctl(sizeof(struct T_bind_ack)+sizeof(struct sockaddr));
413 if (it) {
414 struct T_bind_ack *ack;
416 ack = (struct T_bind_ack *)&it->type;
417 ack->PRIM_type = T_BIND_ACK;
418 ack->ADDR_offset = sizeof(*ack);
419 ack->ADDR_length = sizeof(struct sockaddr);
420 ack->CONIND_number = req.CONIND_number;
421 args[0] = fd;
422 args[1] = (long)(ack+sizeof(*ack));
423 args[2] = (long)&ack->ADDR_length;
424 set_fs(KERNEL_DS);
425 sys_socketcall(SYS_GETSOCKNAME,args);
426 set_fs(old_fs);
427 sock->state = TS_IDLE;
428 timod_ok(fd, T_BIND_REQ);
429 timod_queue_end(fd, it);
430 SOLD("BIND done");
431 return 0;
434 SOLD("some error");
435 switch (error) {
436 case -EINVAL:
437 terror = TOUTSTATE;
438 error = 0;
439 break;
440 case -EACCES:
441 terror = TACCES;
442 error = 0;
443 break;
444 case -EADDRNOTAVAIL:
445 case -EADDRINUSE:
446 terror = TNOADDR;
447 error = 0;
448 break;
449 default:
450 terror = TSYSERR;
451 break;
453 timod_error(fd, T_BIND_REQ, terror, -error);
454 SOLD("BIND done");
455 return 0;
457 case T_CONN_REQ:
459 struct T_conn_req req;
460 unsigned short oldflags;
461 struct T_primsg *it;
462 SOLD("T_CONN_REQ");
463 if (sock->state != TS_UNBND && sock->state != TS_IDLE) {
464 timod_error(fd, T_CONN_REQ, TOUTSTATE, 0);
465 return 0;
467 SOLD("state ok");
468 if (copy_from_user(&req, ctl_buf, sizeof(req))) {
469 timod_error(fd, T_CONN_REQ, TSYSERR, EFAULT);
470 return 0;
472 SOLD("got ctl req");
473 if (ctl_len > BUF_SIZE) {
474 timod_error(fd, T_CONN_REQ, TSYSERR, EFAULT);
475 return 0;
477 SOLD("req size ok");
478 buf = getpage();
479 if (copy_from_user(buf, ctl_buf, ctl_len)) {
480 timod_error(fd, T_CONN_REQ, TSYSERR, EFAULT);
481 putpage(buf);
482 return 0;
484 #ifdef DEBUG_SOLARIS
486 char * ptr = buf;
487 int len = ctl_len;
488 printk("returned data (%d bytes): ",len);
489 while( len-- ) {
490 if (!(len & 7))
491 printk(" ");
492 printk("%02x",(unsigned char)*ptr++);
494 printk("\n");
496 #endif
497 SOLD("got ctl data");
498 args[0] = fd;
499 args[1] = (long)buf+req.DEST_offset;
500 args[2] = req.DEST_length;
501 oldflags = filp->f_flags;
502 filp->f_flags &= ~O_NONBLOCK;
503 SOLD("calling CONNECT");
504 set_fs(KERNEL_DS);
505 error = sys_socketcall(SYS_CONNECT, args);
506 set_fs(old_fs);
507 filp->f_flags = oldflags;
508 SOLD("CONNECT done");
509 if (!error) {
510 struct T_conn_con *con;
511 SOLD("no error");
512 it = timod_mkctl(ctl_len);
513 if (!it) {
514 putpage(buf);
515 return -ENOMEM;
517 con = (struct T_conn_con *)&it->type;
518 #ifdef DEBUG_SOLARIS
520 char * ptr = buf;
521 int len = ctl_len;
522 printk("returned data (%d bytes): ",len);
523 while( len-- ) {
524 if (!(len & 7))
525 printk(" ");
526 printk("%02x",(unsigned char)*ptr++);
528 printk("\n");
530 #endif
531 memcpy(con, buf, ctl_len);
532 SOLD("copied ctl_buf");
533 con->PRIM_type = T_CONN_CON;
534 sock->state = TS_DATA_XFER;
535 } else {
536 struct T_discon_ind *dis;
537 SOLD("some error");
538 it = timod_mkctl(sizeof(*dis));
539 if (!it) {
540 putpage(buf);
541 return -ENOMEM;
543 SOLD("got primsg");
544 dis = (struct T_discon_ind *)&it->type;
545 dis->PRIM_type = T_DISCON_IND;
546 dis->DISCON_reason = -error; /* FIXME: convert this as in iABI_errors() */
547 dis->SEQ_number = 0;
549 putpage(buf);
550 timod_ok(fd, T_CONN_REQ);
551 it->pri = 0;
552 timod_queue_end(fd, it);
553 SOLD("CONNECT done");
554 return 0;
556 case T_OPTMGMT_REQ:
558 struct T_optmgmt_req req;
559 SOLD("OPTMGMT_REQ");
560 if (copy_from_user(&req, ctl_buf, sizeof(req)))
561 return -EFAULT;
562 SOLD("got req");
563 return timod_optmgmt(fd, req.MGMT_flags,
564 req.OPT_offset > 0 ? ctl_buf + req.OPT_offset : NULL,
565 req.OPT_length, 1);
567 case T_UNITDATA_REQ:
569 struct T_unitdata_req req;
571 int err;
572 SOLD("T_UNITDATA_REQ");
573 if (sock->state != TS_IDLE && sock->state != TS_DATA_XFER) {
574 timod_error(fd, T_CONN_REQ, TOUTSTATE, 0);
575 return 0;
577 SOLD("state ok");
578 if (copy_from_user(&req, ctl_buf, sizeof(req))) {
579 timod_error(fd, T_CONN_REQ, TSYSERR, EFAULT);
580 return 0;
582 SOLD("got ctl req");
583 #ifdef DEBUG_SOLARIS
585 char * ptr = ctl_buf+req.DEST_offset;
586 int len = req.DEST_length;
587 printk("socket address (%d bytes): ",len);
588 while( len-- ) {
589 char c;
590 if (get_user(c,ptr))
591 printk("??");
592 else
593 printk("%02x",(unsigned char)c);
594 ptr++;
596 printk("\n");
598 #endif
599 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);
600 if (err == data_len)
601 return 0;
602 if(err >= 0) {
603 printk("timod: sendto failed to send all the data\n");
604 return 0;
606 timod_error(fd, T_CONN_REQ, TSYSERR, -err);
607 return 0;
609 default:
610 printk(KERN_INFO "timod_putmsg: unsupported command %u.\n", ret);
611 break;
613 return -EINVAL;
616 int timod_getmsg(unsigned int fd, char __user *ctl_buf, int ctl_maxlen, s32 __user *ctl_len,
617 char __user *data_buf, int data_maxlen, s32 __user *data_len, int *flags_p)
619 int error;
620 int oldflags;
621 struct file *filp;
622 struct inode *ino;
623 struct sol_socket_struct *sock;
624 struct T_unitdata_ind udi;
625 mm_segment_t old_fs = get_fs();
626 long args[6];
627 char __user *tmpbuf;
628 int tmplen;
629 int (*sys_socketcall)(int, unsigned long __user *) =
630 (int (*)(int, unsigned long __user *))SYS(socketcall);
631 int (*sys_recvfrom)(int, void __user *, size_t, unsigned, struct sockaddr __user *, int __user *);
633 SOLD("entry");
634 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));
635 filp = current->files->fd[fd];
636 ino = filp->f_dentry->d_inode;
637 sock = (struct sol_socket_struct *)filp->private_data;
638 SOLDD(("%p %p\n", sock->pfirst, sock->pfirst ? sock->pfirst->next : NULL));
639 if ( ctl_maxlen > 0 && !sock->pfirst && SOCKET_I(ino)->type == SOCK_STREAM
640 && sock->state == TS_IDLE) {
641 SOLD("calling LISTEN");
642 args[0] = fd;
643 args[1] = -1;
644 set_fs(KERNEL_DS);
645 sys_socketcall(SYS_LISTEN, args);
646 set_fs(old_fs);
647 SOLD("LISTEN done");
649 if (!(filp->f_flags & O_NONBLOCK)) {
650 struct poll_wqueues wait_table;
651 poll_table *wait;
653 poll_initwait(&wait_table);
654 wait = &wait_table.pt;
655 for(;;) {
656 SOLD("loop");
657 set_current_state(TASK_INTERRUPTIBLE);
658 /* ! ( l<0 || ( l>=0 && ( ! pfirst || (flags == HIPRI && pri != HIPRI) ) ) ) */
659 /* ( ! l<0 && ! ( l>=0 && ( ! pfirst || (flags == HIPRI && pri != HIPRI) ) ) ) */
660 /* ( l>=0 && ( ! l>=0 || ! ( ! pfirst || (flags == HIPRI && pri != HIPRI) ) ) ) */
661 /* ( l>=0 && ( l<0 || ( pfirst && ! (flags == HIPRI && pri != HIPRI) ) ) ) */
662 /* ( l>=0 && ( l<0 || ( pfirst && (flags != HIPRI || pri == HIPRI) ) ) ) */
663 /* ( l>=0 && ( pfirst && (flags != HIPRI || pri == HIPRI) ) ) */
664 if (ctl_maxlen >= 0 && sock->pfirst && (*flags_p != MSG_HIPRI || sock->pfirst->pri == MSG_HIPRI))
665 break;
666 SOLD("cond 1 passed");
667 if (
668 #if 1
669 *flags_p != MSG_HIPRI &&
670 #endif
671 ((filp->f_op->poll(filp, wait) & POLLIN) ||
672 (filp->f_op->poll(filp, NULL) & POLLIN) ||
673 signal_pending(current))
675 break;
677 if( *flags_p == MSG_HIPRI ) {
678 SOLD("avoiding lockup");
679 break ;
681 if(wait_table.error) {
682 SOLD("wait-table error");
683 poll_freewait(&wait_table);
684 return wait_table.error;
686 SOLD("scheduling");
687 schedule();
689 SOLD("loop done");
690 current->state = TASK_RUNNING;
691 poll_freewait(&wait_table);
692 if (signal_pending(current)) {
693 SOLD("signal pending");
694 return -EINTR;
697 if (ctl_maxlen >= 0 && sock->pfirst) {
698 struct T_primsg *it = sock->pfirst;
699 int l = min_t(int, ctl_maxlen, it->length);
700 SCHECK_MAGIC((char*)((u64)(((char *)&it->type)+sock->offset+it->length+7)&~7),MKCTL_MAGIC);
701 SOLD("purting ctl data");
702 if(copy_to_user(ctl_buf,
703 (char*)&it->type + sock->offset, l))
704 return -EFAULT;
705 SOLD("pur it");
706 if(put_user(l, ctl_len))
707 return -EFAULT;
708 SOLD("set ctl_len");
709 *flags_p = it->pri;
710 it->length -= l;
711 if (it->length) {
712 SOLD("more ctl");
713 sock->offset += l;
714 return MORECTL;
715 } else {
716 SOLD("removing message");
717 sock->pfirst = it->next;
718 if (!sock->pfirst)
719 sock->plast = NULL;
720 SOLDD(("getmsg kfree %016lx->%016lx\n", it, sock->pfirst));
721 mykfree(it);
722 sock->offset = 0;
723 SOLD("ctl done");
724 return 0;
727 *flags_p = 0;
728 if (ctl_maxlen >= 0) {
729 SOLD("ACCEPT perhaps?");
730 if (SOCKET_I(ino)->type == SOCK_STREAM && sock->state == TS_IDLE) {
731 struct T_conn_ind ind;
732 char *buf = getpage();
733 int len = BUF_SIZE;
735 SOLD("trying ACCEPT");
736 if (put_user(ctl_maxlen - sizeof(ind), ctl_len))
737 return -EFAULT;
738 args[0] = fd;
739 args[1] = (long)buf;
740 args[2] = (long)&len;
741 oldflags = filp->f_flags;
742 filp->f_flags |= O_NONBLOCK;
743 SOLD("calling ACCEPT");
744 set_fs(KERNEL_DS);
745 error = sys_socketcall(SYS_ACCEPT, args);
746 set_fs(old_fs);
747 filp->f_flags = oldflags;
748 if (error < 0) {
749 SOLD("some error");
750 putpage(buf);
751 return error;
753 if (error) {
754 SOLD("connect");
755 putpage(buf);
756 if (sizeof(ind) > ctl_maxlen) {
757 SOLD("generating CONN_IND");
758 ind.PRIM_type = T_CONN_IND;
759 ind.SRC_length = len;
760 ind.SRC_offset = sizeof(ind);
761 ind.OPT_length = ind.OPT_offset = 0;
762 ind.SEQ_number = error;
763 if(copy_to_user(ctl_buf, &ind, sizeof(ind))||
764 put_user(sizeof(ind)+ind.SRC_length,ctl_len))
765 return -EFAULT;
766 SOLD("CONN_IND created");
768 if (data_maxlen >= 0)
769 put_user(0, data_len);
770 SOLD("CONN_IND done");
771 return 0;
773 if (len>ctl_maxlen) {
774 SOLD("data don't fit");
775 putpage(buf);
776 return -EFAULT; /* XXX - is this ok ? */
778 if(copy_to_user(ctl_buf,buf,len) || put_user(len,ctl_len)){
779 SOLD("can't copy data");
780 putpage(buf);
781 return -EFAULT;
783 SOLD("ACCEPT done");
784 putpage(buf);
787 SOLD("checking data req");
788 if (data_maxlen <= 0) {
789 if (data_maxlen == 0)
790 put_user(0, data_len);
791 if (ctl_maxlen >= 0)
792 put_user(0, ctl_len);
793 return -EAGAIN;
795 SOLD("wants data");
796 if (ctl_maxlen > sizeof(udi) && sock->state == TS_IDLE) {
797 SOLD("udi fits");
798 tmpbuf = ctl_buf + sizeof(udi);
799 tmplen = ctl_maxlen - sizeof(udi);
800 } else {
801 SOLD("udi does not fit");
802 tmpbuf = NULL;
803 tmplen = 0;
805 if (put_user(tmplen, ctl_len))
806 return -EFAULT;
807 SOLD("set ctl_len");
808 oldflags = filp->f_flags;
809 filp->f_flags |= O_NONBLOCK;
810 SOLD("calling recvfrom");
811 sys_recvfrom = (int (*)(int, void __user *, size_t, unsigned, struct sockaddr __user *, int __user *))SYS(recvfrom);
812 error = sys_recvfrom(fd, data_buf, data_maxlen, 0, (struct sockaddr __user *)tmpbuf, ctl_len);
813 filp->f_flags = oldflags;
814 if (error < 0)
815 return error;
816 SOLD("error >= 0" ) ;
817 if (error && ctl_maxlen > sizeof(udi) && sock->state == TS_IDLE) {
818 SOLD("generating udi");
819 udi.PRIM_type = T_UNITDATA_IND;
820 if (get_user(udi.SRC_length, ctl_len))
821 return -EFAULT;
822 udi.SRC_offset = sizeof(udi);
823 udi.OPT_length = udi.OPT_offset = 0;
824 if (copy_to_user(ctl_buf, &udi, sizeof(udi)) ||
825 put_user(sizeof(udi)+udi.SRC_length, ctl_len))
826 return -EFAULT;
827 SOLD("udi done");
828 } else {
829 if (put_user(0, ctl_len))
830 return -EFAULT;
832 put_user(error, data_len);
833 SOLD("done");
834 return 0;
837 asmlinkage int solaris_getmsg(unsigned int fd, u32 arg1, u32 arg2, u32 arg3)
839 struct file *filp;
840 struct inode *ino;
841 struct strbuf __user *ctlptr;
842 struct strbuf __user *datptr;
843 struct strbuf ctl, dat;
844 int __user *flgptr;
845 int flags;
846 int error = -EBADF;
848 SOLD("entry");
849 lock_kernel();
850 if(fd >= NR_OPEN) goto out;
852 filp = current->files->fd[fd];
853 if(!filp) goto out;
855 ino = filp->f_dentry->d_inode;
856 if (!ino || !S_ISSOCK(ino->i_mode))
857 goto out;
859 ctlptr = (struct strbuf __user *)A(arg1);
860 datptr = (struct strbuf __user *)A(arg2);
861 flgptr = (int __user *)A(arg3);
863 error = -EFAULT;
865 if (ctlptr) {
866 if (copy_from_user(&ctl,ctlptr,sizeof(struct strbuf)) ||
867 put_user(-1,&ctlptr->len))
868 goto out;
869 } else
870 ctl.maxlen = -1;
872 if (datptr) {
873 if (copy_from_user(&dat,datptr,sizeof(struct strbuf)) ||
874 put_user(-1,&datptr->len))
875 goto out;
876 } else
877 dat.maxlen = -1;
879 if (get_user(flags,flgptr))
880 goto out;
882 switch (flags) {
883 case 0:
884 case MSG_HIPRI:
885 case MSG_ANY:
886 case MSG_BAND:
887 break;
888 default:
889 error = -EINVAL;
890 goto out;
893 error = timod_getmsg(fd,A(ctl.buf),ctl.maxlen,&ctlptr->len,
894 A(dat.buf),dat.maxlen,&datptr->len,&flags);
896 if (!error && put_user(flags,flgptr))
897 error = -EFAULT;
898 out:
899 unlock_kernel();
900 SOLD("done");
901 return error;
904 asmlinkage int solaris_putmsg(unsigned int fd, u32 arg1, u32 arg2, u32 arg3)
906 struct file *filp;
907 struct inode *ino;
908 struct strbuf __user *ctlptr;
909 struct strbuf __user *datptr;
910 struct strbuf ctl, dat;
911 int flags = (int) arg3;
912 int error = -EBADF;
914 SOLD("entry");
915 lock_kernel();
916 if(fd >= NR_OPEN) goto out;
918 filp = current->files->fd[fd];
919 if(!filp) goto out;
921 ino = filp->f_dentry->d_inode;
922 if (!ino) goto out;
924 if (!S_ISSOCK(ino->i_mode) &&
925 (imajor(ino) != 30 || iminor(ino) != 1))
926 goto out;
928 ctlptr = A(arg1);
929 datptr = A(arg2);
931 error = -EFAULT;
933 if (ctlptr) {
934 if (copy_from_user(&ctl,ctlptr,sizeof(ctl)))
935 goto out;
936 if (ctl.len < 0 && flags) {
937 error = -EINVAL;
938 goto out;
940 } else {
941 ctl.len = 0;
942 ctl.buf = 0;
945 if (datptr) {
946 if (copy_from_user(&dat,datptr,sizeof(dat)))
947 goto out;
948 } else {
949 dat.len = 0;
950 dat.buf = 0;
953 error = timod_putmsg(fd,A(ctl.buf),ctl.len,
954 A(dat.buf),dat.len,flags);
955 out:
956 unlock_kernel();
957 SOLD("done");
958 return error;