1 /* $Id: socksys.c,v 1.18 2001/02/13 01:16:44 davem 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 #include <linux/types.h>
10 #include <linux/kernel.h>
11 #include <linux/sched.h>
12 #include <linux/smp.h>
13 #include <linux/smp_lock.h>
14 #include <linux/ioctl.h>
15 #include <linux/fs.h>
16 #include <linux/file.h>
17 #include <linux/init.h>
18 #include <linux/poll.h>
19 #include <linux/slab.h>
20 #include <linux/in.h>
21 #include <linux/devfs_fs_kernel.h>
22 
23 #include <asm/uaccess.h>
24 #include <asm/termios.h>
25 
26 #include "conv.h"
27 #include "socksys.h"
28 
29 extern asmlinkage int sys_ioctl(unsigned int fd, unsigned int cmd,
30 	unsigned long arg);
31 
32 static int af_inet_protocols[] = {
33 IPPROTO_ICMP, IPPROTO_ICMP, IPPROTO_IGMP, IPPROTO_IPIP, IPPROTO_TCP,
34 IPPROTO_EGP, IPPROTO_PUP, IPPROTO_UDP, IPPROTO_IDP, IPPROTO_RAW,
35 0, 0, 0, 0, 0, 0,
36 };
37 
38 #ifndef DEBUG_SOLARIS_KMALLOC
39 
40 #define mykmalloc kmalloc
41 #define mykfree kfree
42 
43 #else
44 
45 extern void * mykmalloc(size_t s, int gfp);
46 extern void mykfree(void *);
47 
48 #endif
49 
50 static unsigned int (*sock_poll)(struct file *, poll_table *);
51 
52 static struct file_operations socksys_file_ops = {
53 	/* Currently empty */
54 };
55 
socksys_open(struct inode * inode,struct file * filp)56 static int socksys_open(struct inode * inode, struct file * filp)
57 {
58 	int family, type, protocol, fd;
59 	struct dentry *dentry;
60 	int (*sys_socket)(int,int,int) =
61 		(int (*)(int,int,int))SUNOS(97);
62         struct sol_socket_struct * sock;
63 
64 	family = ((MINOR(inode->i_rdev) >> 4) & 0xf);
65 	switch (family) {
66 	case AF_UNIX:
67 		type = SOCK_STREAM;
68 		protocol = 0;
69 		break;
70 	case AF_INET:
71 		protocol = af_inet_protocols[MINOR(inode->i_rdev) & 0xf];
72 		switch (protocol) {
73 		case IPPROTO_TCP: type = SOCK_STREAM; break;
74 		case IPPROTO_UDP: type = SOCK_DGRAM; break;
75 		default: type = SOCK_RAW; break;
76 		}
77 		break;
78 	default:
79 		type = SOCK_RAW;
80 		protocol = 0;
81 		break;
82 	}
83 
84 	fd = sys_socket(family, type, protocol);
85 	if (fd < 0)
86 		return fd;
87 	/*
88 	 * N.B. The following operations are not legal!
89 	 * Try instead:
90 	 * d_delete(filp->f_dentry), then d_instantiate with sock inode
91 	 */
92 	dentry = filp->f_dentry;
93 	filp->f_dentry = dget(fcheck(fd)->f_dentry);
94 	filp->f_dentry->d_inode->i_rdev = inode->i_rdev;
95 	filp->f_dentry->d_inode->i_flock = inode->i_flock;
96 	filp->f_dentry->d_inode->u.socket_i.file = filp;
97 	filp->f_op = &socksys_file_ops;
98         sock = (struct sol_socket_struct*)
99         	mykmalloc(sizeof(struct sol_socket_struct), GFP_KERNEL);
100         if (!sock) return -ENOMEM;
101 	SOLDD(("sock=%016lx(%016lx)\n", sock, filp));
102         sock->magic = SOLARIS_SOCKET_MAGIC;
103         sock->modcount = 0;
104         sock->state = TS_UNBND;
105         sock->offset = 0;
106         sock->pfirst = sock->plast = NULL;
107         filp->private_data = sock;
108 	SOLDD(("filp->private_data %016lx\n", filp->private_data));
109 
110 	sys_close(fd);
111 	dput(dentry);
112 	return 0;
113 }
114 
socksys_release(struct inode * inode,struct file * filp)115 static int socksys_release(struct inode * inode, struct file * filp)
116 {
117         struct sol_socket_struct * sock;
118         struct T_primsg *it;
119 
120 	/* XXX: check this */
121 	lock_kernel();
122 	sock = (struct sol_socket_struct *)filp->private_data;
123 	SOLDD(("sock release %016lx(%016lx)\n", sock, filp));
124 	it = sock->pfirst;
125 	while (it) {
126 		struct T_primsg *next = it->next;
127 
128 		SOLDD(("socksys_release %016lx->%016lx\n", it, next));
129 		mykfree((char*)it);
130 		it = next;
131 	}
132 	filp->private_data = NULL;
133 	SOLDD(("socksys_release %016lx\n", sock));
134 	mykfree((char*)sock);
135 	unlock_kernel();
136 	return 0;
137 }
138 
socksys_poll(struct file * filp,poll_table * wait)139 static unsigned int socksys_poll(struct file * filp, poll_table * wait)
140 {
141 	struct inode *ino;
142 	unsigned int mask = 0;
143 
144 	ino=filp->f_dentry->d_inode;
145 	if (ino && ino->i_sock) {
146 		struct sol_socket_struct *sock;
147 		sock = (struct sol_socket_struct*)filp->private_data;
148 		if (sock && sock->pfirst) {
149 			mask |= POLLIN | POLLRDNORM;
150 			if (sock->pfirst->pri == MSG_HIPRI)
151 				mask |= POLLPRI;
152 		}
153 	}
154 	if (sock_poll)
155 		mask |= (*sock_poll)(filp, wait);
156 	return mask;
157 }
158 
159 static struct file_operations socksys_fops = {
160 	open:		socksys_open,
161 	release:	socksys_release,
162 };
163 
164 static devfs_handle_t devfs_handle;
165 
166 int __init
init_socksys(void)167 init_socksys(void)
168 {
169 	int ret;
170 	struct file * file;
171 	int (*sys_socket)(int,int,int) =
172 		(int (*)(int,int,int))SUNOS(97);
173 	int (*sys_close)(unsigned int) =
174 		(int (*)(unsigned int))SYS(close);
175 
176 	ret = devfs_register_chrdev (30, "socksys", &socksys_fops);
177 	if (ret < 0) {
178 		printk ("Couldn't register socksys character device\n");
179 		return ret;
180 	}
181 	ret = sys_socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
182 	if (ret < 0) {
183 		printk ("Couldn't create socket\n");
184 		return ret;
185 	}
186 	devfs_handle = devfs_register (NULL, "socksys", DEVFS_FL_DEFAULT,
187 				       30, 0,
188 				       S_IFCHR | S_IRUSR | S_IWUSR,
189 				       &socksys_fops, NULL);
190 	file = fcheck(ret);
191 	/* N.B. Is this valid? Suppose the f_ops are in a module ... */
192 	socksys_file_ops = *file->f_op;
193 	sys_close(ret);
194 	sock_poll = socksys_file_ops.poll;
195 	socksys_file_ops.poll = socksys_poll;
196 	socksys_file_ops.release = socksys_release;
197 	return 0;
198 }
199 
200 void
cleanup_socksys(void)201 cleanup_socksys(void)
202 {
203 	if (devfs_unregister_chrdev(30, "socksys"))
204 		printk ("Couldn't unregister socksys character device\n");
205 	devfs_unregister (devfs_handle);
206 }
207