linux-old/net/netlink.c
<<
>>
Prefs
   1/*
   2 * NETLINK      An implementation of a loadable kernel mode driver providing
   3 *              multiple kernel/user space bidirectional communications links.
   4 *
   5 *              Author:         Alan Cox <alan@cymru.net>
   6 *
   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.
  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 *      Device operations
  45 */
  46 
  47/*
  48 *      Default write handler.
  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 *      Exported do nothing receiver for one way
  59 *      interfaces.
  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 *      Write a message to the kernel side of a communication link
  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 *      Read a message from the kernel side of the communication link
  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,           /* netlink_readdir */
 186        netlink_poll,
 187        netlink_ioctl,
 188        NULL,           /* netlink_mmap */
 189        netlink_open,
 190        netlink_release
 191};
 192
 193/*
 194 *      We export these functions to other modules. They provide a 
 195 *      complete set of kernel non-blocking support for message
 196 *      queueing.
 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 *      "High" level netlink interface. (ANK)
 241 *      
 242 *      Features:
 243 *              - standard message format.
 244 *              - pseudo-reliable delivery. Messages can be still lost, but
 245 *                user level will know that they were lost and can
 246 *                recover (f.e. gated could reread FIB and device list)
 247 *              - messages are batched.
 248 *              - if user is not attached, we do not make useless work.
 249 *
 250 *      Examples:
 251 *              - netlink_post equivalent (but with pseudo-reliable delivery)
 252 *                      ctl.nlmsg_delay = 0;
 253 *                      ctl.nlmsg_maxsize = <one message size>;
 254 *                      ....
 255 *                      msg = nlmsg_send(&ctl, ...);
 256 *                      if (msg) {
 257 *                              ... make it ...
 258 *                              nlmsg_transmit(&ctl);
 259 *                      }
 260 *
 261 *              - batched messages.
 262 *                      if nlmsg_delay==0, messages are delivered only
 263 *                      by nlmsg_transmit, or when batch is completed,
 264 *                      otherwise nlmsg_transmit is noop (only starts
 265 *                      timer)
 266 *
 267 *                      ctl.nlmsg_delay = ...;
 268 *                      ctl.nlmsg_maxsize = <one batch size>;
 269 *                      ....
 270 *                      msg = nlmsg_send(&ctl, ...);
 271 *                      if (msg)
 272 *                              ... make it ...
 273 *                      ....
 274 *                      msg = nlmsg_send(&ctl, ...);
 275 *                      if (msg)
 276 *                              ... make it ...
 277 *                      ....
 278 *                      if (ctl.nlmsg_skb)
 279 *                              nlmsg_transmit(&ctl);
 280 *
 281 */
 282
 283/*
 284 *      Try to deliver queued messages.
 285 *      If the delivery fails (netlink is not attached or congested),
 286 *      do not free skb to avoid useless new message creation.
 287 *
 288 *      Notes:
 289 *              - timer should be already stopped.
 290 *              - NET SPL.
 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 *      Allocate room for new message. If it is impossible,
 314 *      start "overrun" mode and return NULL.
 315 *
 316 *      Notes:
 317 *              - NET SPL.
 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 *      Kick message queue.
 413 *      Two modes:
 414 *              - synchronous (delay==0). Messages are delivered immediately.
 415 *              - delayed. Do not deliver, but start delivery timer.
 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
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.