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