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 long long netlink_lseek(struct file * file, long long offset, int origin)
130{
131 return -ESPIPE;
132}
133
134static int netlink_open(struct inode * inode, struct file * file)
135{
136 unsigned int minor = MINOR(inode->i_rdev);
137
138 if(minor>=MAX_LINKS)
139 return -ENODEV;
140 if(active_map&(1<<minor))
141 {
142 if (file->f_mode & FMODE_READ)
143 {
144 if (open_map&(1<<minor))
145 return -EBUSY;
146 open_map|=(1<<minor);
147 }
148 MOD_INC_USE_COUNT;
149 return 0;
150 }
151 return -EUNATCH;
152}
153
154static int netlink_release(struct inode * inode, struct file * file)
155{
156 unsigned int minor = MINOR(inode->i_rdev);
157 if (file->f_mode & FMODE_READ)
158 open_map&=~(1<<minor);
159 MOD_DEC_USE_COUNT;
160 return 0;
161}
162
163
164static int netlink_ioctl(struct inode *inode, struct file *file,
165 unsigned int cmd, unsigned long arg)
166{
167 unsigned int minor = MINOR(inode->i_rdev);
168 int retval = 0;
169
170 if (minor >= MAX_LINKS)
171 return -ENODEV;
172 switch ( cmd ) {
173 default:
174 retval = -EINVAL;
175 }
176 return retval;
177}
178
179
180static struct file_operations netlink_fops = {
181 netlink_lseek,
182 netlink_read,
183 netlink_write,
184 NULL,
185 netlink_poll,
186 netlink_ioctl,
187 NULL,
188 netlink_open,
189 netlink_release
190};
191
192
193
194
195
196
197
198int netlink_attach(int unit, int (*function)(int minor, struct sk_buff *skb))
199{
200 if(unit>=MAX_LINKS)
201 return -ENODEV;
202 if(active_map&(1<<unit))
203 return -EBUSY;
204 active_map|=(1<<unit);
205 netlink_handler[unit]=function;
206 return 0;
207}
208
209void netlink_detach(int unit)
210{
211 active_map&=~(1<<unit);
212 netlink_handler[unit]=netlink_err;
213}
214
215int netlink_post(int unit, struct sk_buff *skb)
216{
217 unsigned long flags;
218 int ret=-EUNATCH;
219 if(open_map&(1<<unit))
220 {
221 save_flags(flags);
222 cli();
223 if(rdq_size[unit]+skb->len>MAX_QBYTES)
224 ret=-EAGAIN;
225 else
226 {
227 skb_queue_tail(&skb_queue_rd[unit], skb);
228 rdq_size[unit]+=skb->len;
229 ret=0;
230 wake_up_interruptible(&read_space_wait[unit]);
231 }
232 restore_flags(flags);
233 }
234 return ret;
235}
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
292void nlmsg_flush(struct nlmsg_ctl *ctl)
293{
294 if (ctl->nlmsg_skb == NULL)
295 return;
296
297 if (netlink_post(ctl->nlmsg_unit, ctl->nlmsg_skb) == 0)
298 {
299 ctl->nlmsg_skb = NULL;
300 return;
301 }
302
303 ctl->nlmsg_timer.expires = jiffies + NLMSG_RECOVERY_TIMEO;
304 ctl->nlmsg_timer.data = (unsigned long)ctl;
305 ctl->nlmsg_timer.function = (void (*)(unsigned long))nlmsg_flush;
306 add_timer(&ctl->nlmsg_timer);
307 return;
308}
309
310
311
312
313
314
315
316
317
318
319void* nlmsg_send(struct nlmsg_ctl *ctl, unsigned long type, int len,
320 unsigned long seq, unsigned long pid)
321{
322 struct nlmsghdr *nlh;
323 struct sk_buff *skb;
324 int rlen;
325
326 static __inline__ void nlmsg_lost(struct nlmsg_ctl *ctl,
327 unsigned long seq)
328 {
329 if (!ctl->nlmsg_overrun)
330 {
331 ctl->nlmsg_overrun_start = seq;
332 ctl->nlmsg_overrun_end = seq;
333 ctl->nlmsg_overrun = 1;
334 return;
335 }
336 if (!ctl->nlmsg_overrun_start)
337 ctl->nlmsg_overrun_start = seq;
338 if (seq)
339 ctl->nlmsg_overrun_end = seq;
340 }
341
342 if (!(open_map&(1<<ctl->nlmsg_unit)))
343 {
344 nlmsg_lost(ctl, seq);
345 return NULL;
346 }
347
348 rlen = NLMSG_ALIGN(len + sizeof(struct nlmsghdr));
349
350 if (rlen > ctl->nlmsg_maxsize)
351 {
352 printk(KERN_ERR "nlmsg_send: too big message\n");
353 return NULL;
354 }
355
356 if ((skb=ctl->nlmsg_skb) == NULL || skb_tailroom(skb) < rlen)
357 {
358 if (skb)
359 {
360 ctl->nlmsg_force++;
361 nlmsg_flush(ctl);
362 ctl->nlmsg_force--;
363 }
364
365 if (ctl->nlmsg_skb ||
366 (skb=alloc_skb(ctl->nlmsg_maxsize, GFP_ATOMIC)) == NULL)
367 {
368 printk (KERN_WARNING "nlmsg at unit %d overrunned\n", ctl->nlmsg_unit);
369 nlmsg_lost(ctl, seq);
370 return NULL;
371 }
372
373 ctl->nlmsg_skb = skb;
374
375 if (ctl->nlmsg_overrun)
376 {
377 int *seqp;
378 nlh = (struct nlmsghdr*)skb_put(skb, sizeof(struct nlmsghdr) + 2*sizeof(unsigned long));
379 nlh->nlmsg_type = NLMSG_OVERRUN;
380 nlh->nlmsg_len = sizeof(struct nlmsghdr) + 2*sizeof(unsigned long);
381 nlh->nlmsg_seq = 0;
382 nlh->nlmsg_pid = 0;
383 seqp = (int*)nlh->nlmsg_data;
384 seqp[0] = ctl->nlmsg_overrun_start;
385 seqp[1] = ctl->nlmsg_overrun_end;
386 ctl->nlmsg_overrun = 0;
387 }
388 if (ctl->nlmsg_timer.function)
389 {
390 del_timer(&ctl->nlmsg_timer);
391 ctl->nlmsg_timer.function = NULL;
392 }
393 if (ctl->nlmsg_delay)
394 {
395 ctl->nlmsg_timer.expires = jiffies + ctl->nlmsg_delay;
396 ctl->nlmsg_timer.function = (void (*)(unsigned long))nlmsg_flush;
397 ctl->nlmsg_timer.data = (unsigned long)ctl;
398 add_timer(&ctl->nlmsg_timer);
399 }
400 }
401
402 nlh = (struct nlmsghdr*)skb_put(skb, rlen);
403 nlh->nlmsg_type = type;
404 nlh->nlmsg_len = sizeof(struct nlmsghdr) + len;
405 nlh->nlmsg_seq = seq;
406 nlh->nlmsg_pid = pid;
407 return nlh->nlmsg_data;
408}
409
410
411
412
413
414
415
416
417void nlmsg_transmit(struct nlmsg_ctl *ctl)
418{
419 start_bh_atomic();
420
421 if (!ctl->nlmsg_delay)
422 {
423 if (ctl->nlmsg_timer.function)
424 {
425 del_timer(&ctl->nlmsg_timer);
426 ctl->nlmsg_timer.function = NULL;
427 }
428 ctl->nlmsg_force++;
429 nlmsg_flush(ctl);
430 ctl->nlmsg_force--;
431 end_bh_atomic();
432 return;
433 }
434 if (!ctl->nlmsg_timer.function)
435 {
436 ctl->nlmsg_timer.expires = jiffies + ctl->nlmsg_delay;
437 ctl->nlmsg_timer.function = (void (*)(unsigned long))nlmsg_flush;
438 ctl->nlmsg_timer.data = (unsigned long)ctl;
439 add_timer(&ctl->nlmsg_timer);
440 }
441
442 end_bh_atomic();
443}
444
445
446__initfunc(int init_netlink(void))
447{
448 int ct;
449
450 if(register_chrdev(NETLINK_MAJOR,"netlink", &netlink_fops)) {
451 printk(KERN_ERR "netlink: unable to get major %d\n", NETLINK_MAJOR);
452 return -EIO;
453 }
454 for(ct=0;ct<MAX_LINKS;ct++)
455 {
456 skb_queue_head_init(&skb_queue_rd[ct]);
457 netlink_handler[ct]=netlink_err;
458 }
459 return 0;
460}
461
462#ifdef MODULE
463
464int init_module(void)
465{
466 printk(KERN_INFO "Network Kernel/User communications module 0.05\n");
467 return init_netlink();
468}
469
470void cleanup_module(void)
471{
472 unregister_chrdev(NET_MAJOR,"netlink");
473}
474
475#endif
476