/* $Id: socksys.c,v 1.21 2002/02/08 03:57:14 davem Exp $ * socksys.c: /dev/inet/ stuff for Solaris emulation. * * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) * Copyright (C) 1997, 1998 Patrik Rak (prak3264@ss1000.ms.mff.cuni.cz) * Copyright (C) 1995, 1996 Mike Jagdis (jaggy@purplet.demon.co.uk) */ /* * Dave, _please_ give me specifications on this fscking mess so that I * could at least get it into the state when it wouldn't screw the rest of * the kernel over. socksys.c and timod.c _stink_ and we are not talking * H2S here, it's isopropilmercaptan in concentrations way over LD50. -- AV */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "conv.h" #include "socksys.h" static int af_inet_protocols[] = { IPPROTO_ICMP, IPPROTO_ICMP, IPPROTO_IGMP, IPPROTO_IPIP, IPPROTO_TCP, IPPROTO_EGP, IPPROTO_PUP, IPPROTO_UDP, IPPROTO_IDP, IPPROTO_RAW, 0, 0, 0, 0, 0, 0, }; #ifndef DEBUG_SOLARIS_KMALLOC #define mykmalloc kmalloc #define mykfree kfree #else extern void * mykmalloc(size_t s, gfp_t gfp); extern void mykfree(void *); #endif static unsigned int (*sock_poll)(struct file *, poll_table *); static struct file_operations socksys_file_ops = { /* Currently empty */ }; static int socksys_open(struct inode * inode, struct file * filp) { int family, type, protocol, fd; struct dentry *dentry; int (*sys_socket)(int,int,int) = (int (*)(int,int,int))SUNOS(97); struct sol_socket_struct * sock; family = ((iminor(inode) >> 4) & 0xf); switch (family) { case AF_UNIX: type = SOCK_STREAM; protocol = 0; break; case AF_INET: protocol = af_inet_protocols[iminor(inode) & 0xf]; switch (protocol) { case IPPROTO_TCP: type = SOCK_STREAM; break; case IPPROTO_UDP: type = SOCK_DGRAM; break; default: type = SOCK_RAW; break; } break; default: type = SOCK_RAW; protocol = 0; break; } fd = sys_socket(family, type, protocol); if (fd < 0) return fd; /* * N.B. The following operations are not legal! * * No shit. WTF is it supposed to do, anyway? * * Try instead: * d_delete(filp->f_path.dentry), then d_instantiate with sock inode */ dentry = filp->f_path.dentry; filp->f_path.dentry = dget(fcheck(fd)->f_path.dentry); filp->f_path.dentry->d_inode->i_rdev = inode->i_rdev; filp->f_path.dentry->d_inode->i_flock = inode->i_flock; SOCKET_I(filp->f_path.dentry->d_inode)->file = filp; filp->f_op = &socksys_file_ops; sock = (struct sol_socket_struct*) mykmalloc(sizeof(struct sol_socket_struct), GFP_KERNEL); if (!sock) return -ENOMEM; SOLDD(("sock=%016lx(%016lx)\n", sock, filp)); sock->magic = SOLARIS_SOCKET_MAGIC; sock->modcount = 0; sock->state = TS_UNBND; sock->offset = 0; sock->pfirst = sock->plast = NULL; filp->private_data = sock; SOLDD(("filp->private_data %016lx\n", filp->private_data)); sys_close(fd); dput(dentry); return 0; } static int socksys_release(struct inode * inode, struct file * filp) { struct sol_socket_struct * sock; struct T_primsg *it; /* XXX: check this */ sock = (struct sol_socket_struct *)filp->private_data; SOLDD(("sock release %016lx(%016lx)\n", sock, filp)); it = sock->pfirst; while (it) { struct T_primsg *next = it->next; SOLDD(("socksys_release %016lx->%016lx\n", it, next)); mykfree((char*)it); it = next; } filp->private_data = NULL; SOLDD(("socksys_release %016lx\n", sock)); mykfree((char*)sock); return 0; } static unsigned int socksys_poll(struct file * filp, poll_table * wait) { struct inode *ino; unsigned int mask = 0; ino=filp->f_path.dentry->d_inode; if (ino && S_ISSOCK(ino->i_mode)) { struct sol_socket_struct *sock; sock = (struct sol_socket_struct*)filp->private_data; if (sock && sock->pfirst) { mask |= POLLIN | POLLRDNORM; if (sock->pfirst->pri == MSG_HIPRI) mask |= POLLPRI; } } if (sock_poll) mask |= (*sock_poll)(filp, wait); return mask; } static const struct file_operations socksys_fops = { .open = socksys_open, .release = socksys_release, }; int __init init_socksys(void) { int ret; struct file * file; int (*sys_socket)(int,int,int) = (int (*)(int,int,int))SUNOS(97); int (*sys_close)(unsigned int) = (int (*)(unsigned int))SYS(close); ret = register_chrdev (30, "socksys", &socksys_fops); if (ret < 0) { printk ("Couldn't register socksys character device\n"); return ret; } ret = sys_socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (ret < 0) { printk ("Couldn't create socket\n"); return ret; } file = fcheck(ret); /* N.B. Is this valid? Suppose the f_ops are in a module ... */ socksys_file_ops = *file->f_op; sys_close(ret); sock_poll = socksys_file_ops.poll; socksys_file_ops.poll = socksys_poll; socksys_file_ops.release = socksys_release; return 0; } void __exit cleanup_socksys(void) { unregister_chrdev(30, "socksys"); }