2 * NETLINK An implementation of a loadable kernel mode driver providing
3 * multiple kernel/user space bidirectional communications links.
5 * Author: Alan Cox <alan@redhat.com>
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version
10 * 2 of the License, or (at your option) any later version.
12 * Now netlink devices are emulated on the top of netlink sockets
13 * by compatibility reasons. Remove this file after a period. --ANK
17 #include <linux/module.h>
19 #include <linux/errno.h>
20 #include <linux/kernel.h>
21 #include <linux/major.h>
22 #include <linux/sched.h>
23 #include <linux/slab.h>
24 #include <linux/skbuff.h>
25 #include <linux/netlink.h>
26 #include <linux/poll.h>
27 #include <linux/init.h>
28 #include <linux/devfs_fs_kernel.h>
29 #include <linux/smp_lock.h>
31 #include <asm/bitops.h>
32 #include <asm/system.h>
33 #include <asm/uaccess.h>
36 static struct socket
*netlink_user
[MAX_LINKS
];
42 static unsigned int netlink_poll(struct file
*file
, poll_table
* wait
)
44 struct socket
*sock
= netlink_user
[minor(file
->f_dentry
->d_inode
->i_rdev
)];
46 if (sock
->ops
->poll
==NULL
)
48 return sock
->ops
->poll(file
, sock
, wait
);
52 * Write a message to the kernel side of a communication link
55 static ssize_t
netlink_write(struct file
* file
, const char * buf
,
56 size_t count
, loff_t
*pos
)
58 struct inode
*inode
= file
->f_dentry
->d_inode
;
59 struct socket
*sock
= netlink_user
[minor(inode
->i_rdev
)];
63 iov
.iov_base
= (void*)buf
;
72 return sock_sendmsg(sock
, &msg
, count
);
76 * Read a message from the kernel side of the communication link
79 static ssize_t
netlink_read(struct file
* file
, char * buf
,
80 size_t count
, loff_t
*pos
)
82 struct inode
*inode
= file
->f_dentry
->d_inode
;
83 struct socket
*sock
= netlink_user
[minor(inode
->i_rdev
)];
95 if (file
->f_flags
&O_NONBLOCK
)
96 msg
.msg_flags
=MSG_DONTWAIT
;
98 return sock_recvmsg(sock
, &msg
, count
, msg
.msg_flags
);
101 static int netlink_open(struct inode
* inode
, struct file
* file
)
103 unsigned int minor
= minor(inode
->i_rdev
);
105 struct sockaddr_nl nladdr
;
108 if (minor
>=MAX_LINKS
)
110 if (test_and_set_bit(minor
, &open_map
))
113 err
= sock_create(PF_NETLINK
, SOCK_RAW
, minor
, &sock
);
117 memset(&nladdr
, 0, sizeof(nladdr
));
118 nladdr
.nl_family
= AF_NETLINK
;
119 nladdr
.nl_groups
= ~0;
120 if ((err
= sock
->ops
->bind(sock
, (struct sockaddr
*)&nladdr
, sizeof(nladdr
))) < 0) {
125 netlink_user
[minor
] = sock
;
129 clear_bit(minor
, &open_map
);
133 static int netlink_release(struct inode
* inode
, struct file
* file
)
135 unsigned int minor
= minor(inode
->i_rdev
);
138 sock
= netlink_user
[minor
];
139 netlink_user
[minor
] = NULL
;
140 clear_bit(minor
, &open_map
);
146 static int netlink_ioctl(struct inode
*inode
, struct file
*file
,
147 unsigned int cmd
, unsigned long arg
)
149 unsigned int minor
= minor(inode
->i_rdev
);
152 if (minor
>= MAX_LINKS
)
162 static struct file_operations netlink_fops
= {
163 .owner
= THIS_MODULE
,
165 .read
= netlink_read
,
166 .write
= netlink_write
,
167 .poll
= netlink_poll
,
168 .ioctl
= netlink_ioctl
,
169 .open
= netlink_open
,
170 .release
= netlink_release
,
179 .minor
= NETLINK_ROUTE
,
183 .minor
= NETLINK_SKIP
,
187 .minor
= NETLINK_USERSOCK
,
191 .minor
= NETLINK_FIREWALL
,
195 .minor
= NETLINK_TCPDIAG
,
199 .minor
= NETLINK_NFLOG
,
203 .minor
= NETLINK_XFRM
,
207 .minor
= NETLINK_ARPD
,
211 .minor
= NETLINK_ROUTE6
,
215 .minor
= NETLINK_IP6_FW
,
219 .minor
= NETLINK_DNRTMSG
,
223 static int __init
init_netlink(void)
227 if (register_chrdev(NETLINK_MAJOR
,"netlink", &netlink_fops
)) {
228 printk(KERN_ERR
"netlink: unable to get major %d\n", NETLINK_MAJOR
);
232 devfs_mk_dir("netlink");
234 /* Someone tell me the official names for the uppercase ones */
235 for (i
= 0; i
< ARRAY_SIZE(entries
); i
++) {
236 devfs_mk_cdev(MKDEV(NETLINK_MAJOR
, entries
[i
].minor
),
237 S_IFCHR
|S_IRUSR
|S_IWUSR
, "netlink/%s", entries
[i
].name
);
240 for (i
= 0; i
< 16; i
++) {
241 devfs_mk_cdev(MKDEV(NETLINK_MAJOR
, i
+ 16),
242 S_IFCHR
|S_IRUSR
|S_IWUSR
, "netlink/tap%d", i
);
248 static void __exit
cleanup_netlink(void)
252 for (i
= 0; i
< ARRAY_SIZE(entries
); i
++)
253 devfs_remove("netlink/%s", entries
[i
].name
);
254 for (i
= 0; i
< 16; i
++)
255 devfs_remove("netlink/tap%d", i
);
256 devfs_remove("netlink");
257 unregister_chrdev(NETLINK_MAJOR
, "netlink");
260 MODULE_LICENSE("GPL");
261 module_init(init_netlink
);
262 module_exit(cleanup_netlink
);