1/* $Id: socksys.c,v 1.1.1.1 2007/08/03 18:52:19 Exp $
2 * socksys.c: /dev/inet/ stuff for Solaris emulation.
3 *
4 * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
5 * Copyright (C) 1997, 1998 Patrik Rak (prak3264@ss1000.ms.mff.cuni.cz)
6 * Copyright (C) 1995, 1996 Mike Jagdis (jaggy@purplet.demon.co.uk)
7 */
8
9/*
10 *  Dave, _please_ give me specifications on this fscking mess so that I
11 * could at least get it into the state when it wouldn't screw the rest of
12 * the kernel over.  socksys.c and timod.c _stink_ and we are not talking
13 * H2S here, it's isopropilmercaptan in concentrations way over LD50. -- AV
14 */
15
16#include <linux/types.h>
17#include <linux/kernel.h>
18#include <linux/sched.h>
19#include <linux/smp.h>
20#include <linux/ioctl.h>
21#include <linux/fs.h>
22#include <linux/file.h>
23#include <linux/init.h>
24#include <linux/poll.h>
25#include <linux/slab.h>
26#include <linux/syscalls.h>
27#include <linux/in.h>
28
29#include <net/sock.h>
30
31#include <asm/uaccess.h>
32#include <asm/termios.h>
33
34#include "conv.h"
35#include "socksys.h"
36
37static int af_inet_protocols[] = {
38IPPROTO_ICMP, IPPROTO_ICMP, IPPROTO_IGMP, IPPROTO_IPIP, IPPROTO_TCP,
39IPPROTO_EGP, IPPROTO_PUP, IPPROTO_UDP, IPPROTO_IDP, IPPROTO_RAW,
400, 0, 0, 0, 0, 0,
41};
42
43#ifndef DEBUG_SOLARIS_KMALLOC
44
45#define mykmalloc kmalloc
46#define mykfree kfree
47
48#else
49
50extern void * mykmalloc(size_t s, gfp_t gfp);
51extern void mykfree(void *);
52
53#endif
54
55static unsigned int (*sock_poll)(struct file *, poll_table *);
56
57static struct file_operations socksys_file_ops = {
58	/* Currently empty */
59};
60
61static int socksys_open(struct inode * inode, struct file * filp)
62{
63	int family, type, protocol, fd;
64	struct dentry *dentry;
65	int (*sys_socket)(int,int,int) =
66		(int (*)(int,int,int))SUNOS(97);
67        struct sol_socket_struct * sock;
68
69	family = ((iminor(inode) >> 4) & 0xf);
70	switch (family) {
71	case AF_UNIX:
72		type = SOCK_STREAM;
73		protocol = 0;
74		break;
75	case AF_INET:
76		protocol = af_inet_protocols[iminor(inode) & 0xf];
77		switch (protocol) {
78		case IPPROTO_TCP: type = SOCK_STREAM; break;
79		case IPPROTO_UDP: type = SOCK_DGRAM; break;
80		default: type = SOCK_RAW; break;
81		}
82		break;
83	default:
84		type = SOCK_RAW;
85		protocol = 0;
86		break;
87	}
88
89	fd = sys_socket(family, type, protocol);
90	if (fd < 0)
91		return fd;
92	/*
93	 * N.B. The following operations are not legal!
94	 *
95	 * No shit.  WTF is it supposed to do, anyway?
96	 *
97	 * Try instead:
98	 * d_delete(filp->f_path.dentry), then d_instantiate with sock inode
99	 */
100	dentry = filp->f_path.dentry;
101	filp->f_path.dentry = dget(fcheck(fd)->f_path.dentry);
102	filp->f_path.dentry->d_inode->i_rdev = inode->i_rdev;
103	filp->f_path.dentry->d_inode->i_flock = inode->i_flock;
104	SOCKET_I(filp->f_path.dentry->d_inode)->file = filp;
105	filp->f_op = &socksys_file_ops;
106        sock = (struct sol_socket_struct*)
107        	mykmalloc(sizeof(struct sol_socket_struct), GFP_KERNEL);
108        if (!sock) return -ENOMEM;
109	SOLDD(("sock=%016lx(%016lx)\n", sock, filp));
110        sock->magic = SOLARIS_SOCKET_MAGIC;
111        sock->modcount = 0;
112        sock->state = TS_UNBND;
113        sock->offset = 0;
114        sock->pfirst = sock->plast = NULL;
115        filp->private_data = sock;
116	SOLDD(("filp->private_data %016lx\n", filp->private_data));
117
118	sys_close(fd);
119	dput(dentry);
120	return 0;
121}
122
123static int socksys_release(struct inode * inode, struct file * filp)
124{
125        struct sol_socket_struct * sock;
126        struct T_primsg *it;
127
128	sock = (struct sol_socket_struct *)filp->private_data;
129	SOLDD(("sock release %016lx(%016lx)\n", sock, filp));
130	it = sock->pfirst;
131	while (it) {
132		struct T_primsg *next = it->next;
133
134		SOLDD(("socksys_release %016lx->%016lx\n", it, next));
135		mykfree((char*)it);
136		it = next;
137	}
138	filp->private_data = NULL;
139	SOLDD(("socksys_release %016lx\n", sock));
140	mykfree((char*)sock);
141	return 0;
142}
143
144static unsigned int socksys_poll(struct file * filp, poll_table * wait)
145{
146	struct inode *ino;
147	unsigned int mask = 0;
148
149	ino=filp->f_path.dentry->d_inode;
150	if (ino && S_ISSOCK(ino->i_mode)) {
151		struct sol_socket_struct *sock;
152		sock = (struct sol_socket_struct*)filp->private_data;
153		if (sock && sock->pfirst) {
154			mask |= POLLIN | POLLRDNORM;
155			if (sock->pfirst->pri == MSG_HIPRI)
156				mask |= POLLPRI;
157		}
158	}
159	if (sock_poll)
160		mask |= (*sock_poll)(filp, wait);
161	return mask;
162}
163
164static const struct file_operations socksys_fops = {
165	.open =		socksys_open,
166	.release =	socksys_release,
167};
168
169int __init init_socksys(void)
170{
171	int ret;
172	struct file * file;
173	int (*sys_socket)(int,int,int) =
174		(int (*)(int,int,int))SUNOS(97);
175	int (*sys_close)(unsigned int) =
176		(int (*)(unsigned int))SYS(close);
177
178	ret = register_chrdev (30, "socksys", &socksys_fops);
179	if (ret < 0) {
180		printk ("Couldn't register socksys character device\n");
181		return ret;
182	}
183	ret = sys_socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
184	if (ret < 0) {
185		printk ("Couldn't create socket\n");
186		return ret;
187	}
188
189	file = fcheck(ret);
190	/* N.B. Is this valid? Suppose the f_ops are in a module ... */
191	socksys_file_ops = *file->f_op;
192	sys_close(ret);
193	sock_poll = socksys_file_ops.poll;
194	socksys_file_ops.poll = socksys_poll;
195	socksys_file_ops.release = socksys_release;
196	return 0;
197}
198
199void __exit cleanup_socksys(void)
200{
201	if (unregister_chrdev(30, "socksys"))
202		printk ("Couldn't unregister socksys character device\n");
203}
204