1
2
3
4
5
6
7
8
9
10
11
12
13
14#include <linux/module.h>
15
16#include <linux/errno.h>
17#include <linux/kernel.h>
18#include <linux/major.h>
19#include <linux/sched.h>
20#include <linux/malloc.h>
21#include <linux/ioport.h>
22#include <linux/fcntl.h>
23#include <linux/delay.h>
24#include <linux/interrupt.h>
25#include <linux/skbuff.h>
26#include <linux/init.h>
27
28#include <net/netlink.h>
29
30#include <asm/poll.h>
31#include <asm/io.h>
32#include <asm/uaccess.h>
33#include <asm/system.h>
34
35static int (*netlink_handler[MAX_LINKS])(int minor, struct sk_buff *skb);
36static struct sk_buff_head skb_queue_rd[MAX_LINKS];
37static int rdq_size[MAX_LINKS];
38static struct wait_queue *read_space_wait[MAX_LINKS];
39
40static unsigned long active_map = 0;
41static unsigned long open_map = 0;
42
43
44
45
46
47
48
49
50
51static int netlink_err(int minor, struct sk_buff *skb)
52{
53 kfree_skb(skb, FREE_READ);
54 return -EUNATCH;
55}
56
57
58
59
60
61
62int netlink_donothing(int minor, struct sk_buff *skb)
63{
64 kfree_skb(skb, FREE_READ);
65 return -EINVAL;
66}
67
68static unsigned int netlink_poll(struct file *file, poll_table * wait)
69{
70 unsigned int mask;
71 unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
72
73 poll_wait(&read_space_wait[minor], wait);
74 mask = POLLOUT | POLLWRNORM;
75 if (skb_peek(&skb_queue_rd[minor]))
76 mask |= POLLIN | POLLRDNORM;
77 return mask;
78}
79
80
81
82
83
84static long netlink_write(struct inode * inode, struct file * file,
85 const char * buf, unsigned long count)
86{
87 int err;
88 unsigned int minor = MINOR(inode->i_rdev);
89 struct sk_buff *skb;
90 skb=alloc_skb(count, GFP_KERNEL);
91 err = copy_from_user(skb_put(skb,count),buf, count);
92 return err ? -EFAULT : (netlink_handler[minor])(minor,skb);
93}
94
95
96
97
98
99static long netlink_read(struct inode * inode, struct file * file, char * buf,
100 unsigned long count)
101{
102 int err;
103 unsigned int minor = MINOR(inode->i_rdev);
104 struct sk_buff *skb;
105 cli();
106 while((skb=skb_dequeue(&skb_queue_rd[minor]))==NULL)
107 {
108 if(file->f_flags&O_NONBLOCK)
109 {
110 sti();
111 return -EAGAIN;
112 }
113 interruptible_sleep_on(&read_space_wait[minor]);
114 if(current->signal & ~current->blocked)
115 {
116 sti();
117 return -ERESTARTSYS;
118 }
119 }
120 rdq_size[minor]-=skb->len;
121 sti();
122 if(skb->len<count)
123 count=skb->len;
124 err = copy_to_user(buf,skb->data,count);
125 kfree_skb(skb, FREE_READ);
126 return err ? -EFAULT : count;
127}
128
129static loff_t netlink_lseek(struct inode * inode, struct file * file,
130 loff_t offset, int origin)
131{
132 return -ESPIPE;
133}
134
135static int netlink_open(struct inode * inode, struct file * file)
136{
137 unsigned int minor = MINOR(inode->i_rdev);
138
139 if(minor>=MAX_LINKS)
140 return -ENODEV;
141 if(active_map&(1<<minor))
142 {
143 if (file->f_mode & FMODE_READ)
144 {
145 if (open_map&(1<<minor))
146 return -EBUSY;
147 open_map|=(1<<minor);
148 }
149 MOD_INC_USE_COUNT;
150 return 0;
151 }
152 return -EUNATCH;
153}
154
155static int netlink_release(struct inode * inode, struct file * file)
156{
157 unsigned int minor = MINOR(inode->i_rdev);
158 if (file->f_mode & FMODE_READ)
159 open_map&=~(1<<minor);
160 MOD_DEC_USE_COUNT;
161 return 0;
162}
163
164
165static int netlink_ioctl(struct inode *inode, struct file *file,
166 unsigned int cmd, unsigned long arg)
167{
168 unsigned int minor = MINOR(inode->i_rdev);
169 int retval = 0;
170
171 if (minor >= MAX_LINKS)
172 return -ENODEV;
173 switch ( cmd ) {
174 default:
175 retval = -EINVAL;
176 }
177 return retval;
178}
179
180
181static struct file_operations netlink_fops = {
182 netlink_lseek,
183 netlink_read,
184 netlink_write,
185 NULL,
186 netlink_poll,
187 netlink_ioctl,
188 NULL,
189 netlink_open,
190 netlink_release
191};
192
193
194
195
196
197
198
199int netlink_attach(int unit, int (*function)(int minor, struct sk_buff *skb))
200{
201 if(unit>=MAX_LINKS)
202 return -ENODEV;
203 if(active_map&(1<<unit))
204 return -EBUSY;
205 active_map|=(1<<unit);
206 netlink_handler[unit]=function;
207 return 0;
208}
209
210void netlink_detach(int unit)
211{
212 active_map&=~(1<<unit);
213 netlink_handler[unit]=netlink_err;
214}
215
216int netlink_post(int unit, struct sk_buff *skb)
217{
218 unsigned long flags;
219 int ret=-EUNATCH;
220 if(open_map&(1<<unit))
221 {
222 save_flags(flags);
223 cli();
224 if(rdq_size[unit]+skb->len>MAX_QBYTES)
225 ret=-EAGAIN;
226 else
227 {
228 skb_queue_tail(&skb_queue_rd[unit], skb);
229 rdq_size[unit]+=skb->len;
230 ret=0;
231 wake_up_interruptible(&read_space_wait[unit]);
232 }
233 restore_flags(flags);
234 }
235 return ret;
236}
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293void nlmsg_flush(struct nlmsg_ctl *ctl)
294{
295 if (ctl->nlmsg_skb == NULL)
296 return;
297
298 if (netlink_post(ctl->nlmsg_unit, ctl->nlmsg_skb) == 0)
299 {
300 ctl->nlmsg_skb = NULL;
301 return;
302 }
303
304 ctl->nlmsg_timer.expires = jiffies + NLMSG_RECOVERY_TIMEO;
305 ctl->nlmsg_timer.data = (unsigned long)ctl;
306 ctl->nlmsg_timer.function = (void (*)(unsigned long))nlmsg_flush;
307 add_timer(&ctl->nlmsg_timer);
308 return;
309}
310
311
312
313
314
315
316
317
318
319
320void* nlmsg_send(struct nlmsg_ctl *ctl, unsigned long type, int len,
321 unsigned long seq, unsigned long pid)
322{
323 struct nlmsghdr *nlh;
324 struct sk_buff *skb;
325 int rlen;
326
327 static __inline__ void nlmsg_lost(struct nlmsg_ctl *ctl,
328 unsigned long seq)
329 {
330 if (!ctl->nlmsg_overrun)
331 {
332 ctl->nlmsg_overrun_start = seq;
333 ctl->nlmsg_overrun_end = seq;
334 ctl->nlmsg_overrun = 1;
335 return;
336 }
337 if (!ctl->nlmsg_overrun_start)
338 ctl->nlmsg_overrun_start = seq;
339 if (seq)
340 ctl->nlmsg_overrun_end = seq;
341 }
342
343 if (!(open_map&(1<<ctl->nlmsg_unit)))
344 {
345 nlmsg_lost(ctl, seq);
346 return NULL;
347 }
348
349 rlen = NLMSG_ALIGN(len + sizeof(struct nlmsghdr));
350
351 if (rlen > ctl->nlmsg_maxsize)
352 {
353 printk(KERN_ERR "nlmsg_send: too big message\n");
354 return NULL;
355 }
356
357 if ((skb=ctl->nlmsg_skb) == NULL || skb_tailroom(skb) < rlen)
358 {
359 if (skb)
360 {
361 ctl->nlmsg_force++;
362 nlmsg_flush(ctl);
363 ctl->nlmsg_force--;
364 }
365
366 if (ctl->nlmsg_skb ||
367 (skb=alloc_skb(ctl->nlmsg_maxsize, GFP_ATOMIC)) == NULL)
368 {
369 printk (KERN_WARNING "nlmsg at unit %d overrunned\n", ctl->nlmsg_unit);
370 nlmsg_lost(ctl, seq);
371 return NULL;
372 }
373
374 ctl->nlmsg_skb = skb;
375
376 if (ctl->nlmsg_overrun)
377 {
378 int *seqp;
379 nlh = (struct nlmsghdr*)skb_put(skb, sizeof(struct nlmsghdr) + 2*sizeof(unsigned long));
380 nlh->nlmsg_type = NLMSG_OVERRUN;
381 nlh->nlmsg_len = sizeof(struct nlmsghdr) + 2*sizeof(unsigned long);
382 nlh->nlmsg_seq = 0;
383 nlh->nlmsg_pid = 0;
384 seqp = (int*)nlh->nlmsg_data;
385 seqp[0] = ctl->nlmsg_overrun_start;
386 seqp[1] = ctl->nlmsg_overrun_end;
387 ctl->nlmsg_overrun = 0;
388 }
389 if (ctl->nlmsg_timer.function)
390 {
391 del_timer(&ctl->nlmsg_timer);
392 ctl->nlmsg_timer.function = NULL;
393 }
394 if (ctl->nlmsg_delay)
395 {
396 ctl->nlmsg_timer.expires = jiffies + ctl->nlmsg_delay;
397 ctl->nlmsg_timer.function = (void (*)(unsigned long))nlmsg_flush;
398 ctl->nlmsg_timer.data = (unsigned long)ctl;
399 add_timer(&ctl->nlmsg_timer);
400 }
401 }
402
403 nlh = (struct nlmsghdr*)skb_put(skb, rlen);
404 nlh->nlmsg_type = type;
405 nlh->nlmsg_len = sizeof(struct nlmsghdr) + len;
406 nlh->nlmsg_seq = seq;
407 nlh->nlmsg_pid = pid;
408 return nlh->nlmsg_data;
409}
410
411
412
413
414
415
416
417
418void nlmsg_transmit(struct nlmsg_ctl *ctl)
419{
420 start_bh_atomic();
421
422 if (!ctl->nlmsg_delay)
423 {
424 if (ctl->nlmsg_timer.function)
425 {
426 del_timer(&ctl->nlmsg_timer);
427 ctl->nlmsg_timer.function = NULL;
428 }
429 ctl->nlmsg_force++;
430 nlmsg_flush(ctl);
431 ctl->nlmsg_force--;
432 end_bh_atomic();
433 return;
434 }
435 if (!ctl->nlmsg_timer.function)
436 {
437 ctl->nlmsg_timer.expires = jiffies + ctl->nlmsg_delay;
438 ctl->nlmsg_timer.function = (void (*)(unsigned long))nlmsg_flush;
439 ctl->nlmsg_timer.data = (unsigned long)ctl;
440 add_timer(&ctl->nlmsg_timer);
441 }
442
443 end_bh_atomic();
444}
445
446
447__initfunc(int init_netlink(void))
448{
449 int ct;
450
451 if(register_chrdev(NETLINK_MAJOR,"netlink", &netlink_fops)) {
452 printk(KERN_ERR "netlink: unable to get major %d\n", NETLINK_MAJOR);
453 return -EIO;
454 }
455 for(ct=0;ct<MAX_LINKS;ct++)
456 {
457 skb_queue_head_init(&skb_queue_rd[ct]);
458 netlink_handler[ct]=netlink_err;
459 }
460 return 0;
461}
462
463#ifdef MODULE
464
465int init_module(void)
466{
467 printk(KERN_INFO "Network Kernel/User communications module 0.05\n");
468 return init_netlink();
469}
470
471void cleanup_module(void)
472{
473 unregister_chrdev(NET_MAJOR,"netlink");
474}
475
476#endif
477