linux-old/net/ipv4/ip_masq_mfw.c
<<
>>
Prefs
   1/*
   2 *              IP_MASQ_MARKFW masquerading module
   3 *
   4 *      Does (reverse-masq) forwarding based on skb->fwmark value
   5 *
   6 *      $Id: ip_masq_mfw.c,v 1.3 1999/01/26 05:33:47 davem Exp $
   7 *
   8 * Author:      Juan Jose Ciarlante   <jjciarla@raiz.uncu.edu.ar>
   9 *                based on Steven Clarke's portfw
  10 *
  11 * Fixes:       
  12 *      JuanJo Ciarlante:       added u-space sched support
  13 *      JuanJo Ciarlante:       if rport==0, use packet dest port *grin*
  14 *      JuanJo Ciarlante:       fixed tcp syn&&!ack creation
  15 *
  16 *
  17 */
  18#include <linux/config.h>
  19#include <linux/module.h>
  20#include <linux/types.h>
  21#include <linux/kernel.h>
  22#include <linux/errno.h>
  23#include <linux/list.h>
  24#include <net/ip.h>
  25#include <linux/ip_fw.h>
  26#include <linux/ip_masq.h>
  27#include <net/ip_masq.h>
  28#include <net/ip_masq_mod.h>
  29#include <linux/proc_fs.h>
  30#include <linux/init.h>
  31#include <asm/softirq.h>
  32#include <asm/spinlock.h>
  33#include <asm/atomic.h>
  34
  35static struct ip_masq_mod *mmod_self = NULL;
  36#ifdef CONFIG_IP_MASQ_DEBUG
  37static int debug=0;
  38MODULE_PARM(debug, "i");
  39#endif
  40
  41/*
  42 *  Lists structure:
  43 *      There is a "main" linked list with entries hashed
  44 *      by fwmark value (struct ip_masq_mfw, the "m-entries").
  45 *
  46 *      Each of this m-entry holds a double linked list
  47 *      of "forward-to" hosts (struct ip_masq_mfw_host, the "m.host"),
  48 *      the round-robin scheduling takes place by rotating m.host entries
  49 *      "inside" its m-entry.
  50 */
  51
  52/*
  53 *      Each forwarded host (addr:port) is stored here
  54 */
  55struct ip_masq_mfw_host {
  56        struct  list_head list;
  57        __u32   addr;
  58        __u16   port;
  59        __u16   pad0;
  60        __u32   fwmark;
  61        int     pref;
  62        atomic_t        pref_cnt;
  63};
  64
  65#define IP_MASQ_MFW_HSIZE       16
  66/*
  67 *      This entries are indexed by fwmark, 
  68 *      they hold a list of forwarded addr:port
  69 */     
  70
  71struct ip_masq_mfw {
  72        struct ip_masq_mfw *next;       /* linked list */
  73        __u32 fwmark;                   /* key: firewall mark */
  74        struct list_head hosts;         /* list of forward-to hosts */
  75        atomic_t nhosts;                /* number of "" */
  76#ifdef __SMP__
  77        rwlock_t lock;
  78#endif
  79};
  80
  81
  82static struct semaphore mfw_sema = MUTEX;
  83#ifdef __SMP__
  84static rwlock_t mfw_lock = RW_LOCK_UNLOCKED;
  85#endif
  86
  87static struct ip_masq_mfw *ip_masq_mfw_table[IP_MASQ_MFW_HSIZE];
  88
  89static __inline__ int mfw_hash_val(int fwmark)
  90{
  91        return fwmark & 0x0f;
  92}
  93
  94/*
  95 *      Get m-entry by "fwmark"
  96 *      Caller must lock tables.
  97 */
  98
  99static struct ip_masq_mfw *__mfw_get(int fwmark)
 100{
 101        struct ip_masq_mfw* mfw;
 102        int hash = mfw_hash_val(fwmark);
 103
 104        for (mfw=ip_masq_mfw_table[hash];mfw;mfw=mfw->next) {
 105                if (mfw->fwmark==fwmark) {
 106                        goto out;
 107                }
 108        }
 109out:
 110        return mfw;
 111}
 112
 113/*
 114 *      Links m-entry.
 115 *      Caller should have checked if already present for same fwmark
 116 *
 117 *      Caller must lock tables.
 118 */
 119static int __mfw_add(struct ip_masq_mfw *mfw)
 120{
 121        int fwmark = mfw->fwmark;
 122        int hash = mfw_hash_val(fwmark);
 123
 124        mfw->next = ip_masq_mfw_table[hash];
 125        ip_masq_mfw_table[hash] = mfw;
 126        ip_masq_mod_inc_nent(mmod_self);
 127
 128        return 0;
 129}
 130
 131/*
 132 *      Creates a m-entry (doesn't link it)
 133 */
 134
 135static struct ip_masq_mfw * mfw_new(int fwmark)
 136{
 137        struct ip_masq_mfw *mfw;
 138
 139        mfw = kmalloc(sizeof(*mfw), GFP_KERNEL);
 140        if (mfw == NULL) 
 141                goto out;
 142
 143        MOD_INC_USE_COUNT;
 144        memset(mfw, 0, sizeof(*mfw));
 145        mfw->fwmark = fwmark;
 146#ifdef __SMP__
 147        mfw->lock = (rwlock_t) RW_LOCK_UNLOCKED;
 148#endif
 149
 150        INIT_LIST_HEAD(&mfw->hosts);
 151out:
 152        return mfw;
 153}
 154
 155static void mfw_host_to_user(struct ip_masq_mfw_host *h, struct ip_mfw_user *mu)
 156{
 157        mu->raddr = h->addr;
 158        mu->rport = h->port;
 159        mu->fwmark = h->fwmark;
 160        mu->pref = h->pref;
 161}
 162
 163/*
 164 *      Creates a m.host (doesn't link it in a m-entry)
 165 */
 166static struct ip_masq_mfw_host * mfw_host_new(struct ip_mfw_user *mu)
 167{
 168        struct ip_masq_mfw_host * mfw_host;
 169        mfw_host = kmalloc(sizeof (*mfw_host), GFP_KERNEL);
 170        if (!mfw_host)
 171                return NULL;
 172
 173        MOD_INC_USE_COUNT;
 174        memset(mfw_host, 0, sizeof(*mfw_host));
 175        mfw_host->addr = mu->raddr;
 176        mfw_host->port = mu->rport;
 177        mfw_host->fwmark = mu->fwmark;
 178        mfw_host->pref = mu->pref;
 179        atomic_set(&mfw_host->pref_cnt, mu->pref);
 180
 181        return mfw_host;
 182}
 183
 184/*
 185 *      Create AND link m.host to m-entry.
 186 *      It locks m.lock.
 187 */
 188static int mfw_addhost(struct ip_masq_mfw *mfw, struct ip_mfw_user *mu, int attail)
 189{
 190        struct ip_masq_mfw_host *mfw_host;
 191
 192        mfw_host = mfw_host_new(mu);
 193        if (!mfw_host) 
 194                return -ENOMEM;
 195
 196        write_lock_bh(&mfw->lock);
 197        list_add(&mfw_host->list, attail? mfw->hosts.prev : &mfw->hosts);
 198        atomic_inc(&mfw->nhosts);
 199        write_unlock_bh(&mfw->lock);
 200
 201        return 0;
 202}
 203
 204/*
 205 *      Unlink AND destroy m.host(s) from m-entry.
 206 *      Wildcard (nul host or addr) ok.
 207 *      It uses m.lock.
 208 */
 209static int mfw_delhost(struct ip_masq_mfw *mfw, struct ip_mfw_user *mu)
 210{
 211
 212        struct list_head *l,*e;
 213        struct ip_masq_mfw_host *h;
 214        int n_del = 0;
 215        l = &mfw->hosts;
 216
 217        write_lock_bh(&mfw->lock);
 218        for (e=l->next; e!=l; e=e->next)
 219        {
 220                h = list_entry(e, struct ip_masq_mfw_host, list);
 221                if ((!mu->raddr || h->addr == mu->raddr) && 
 222                        (!mu->rport || h->port == mu->rport)) {
 223                        /* HIT */
 224                        atomic_dec(&mfw->nhosts);
 225                        list_del(&h->list);
 226                        kfree_s(h, sizeof(*h));
 227                        MOD_DEC_USE_COUNT;
 228                        n_del++;
 229                }
 230                                
 231        }
 232        write_unlock_bh(&mfw->lock);
 233        return n_del? 0 : -ESRCH;
 234}
 235
 236/*
 237 *      Changes m.host parameters
 238 *      Wildcards ok
 239 *
 240 *      Caller must lock tables.
 241 */
 242static int __mfw_edithost(struct ip_masq_mfw *mfw, struct ip_mfw_user *mu)
 243{
 244
 245        struct list_head *l,*e;
 246        struct ip_masq_mfw_host *h;
 247        int n_edit = 0;
 248        l = &mfw->hosts;
 249
 250        for (e=l->next; e!=l; e=e->next)
 251        {
 252                h = list_entry(e, struct ip_masq_mfw_host, list);
 253                if ((!mu->raddr || h->addr == mu->raddr) && 
 254                        (!mu->rport || h->port == mu->rport)) {
 255                        /* HIT */
 256                        h->pref = mu->pref;
 257                        atomic_set(&h->pref_cnt, mu->pref);
 258                        n_edit++;
 259                }
 260                                
 261        }
 262        return n_edit? 0 : -ESRCH;
 263}
 264
 265/*
 266 *      Destroys m-entry.
 267 *      Caller must have checked that it doesn't hold any m.host(s)
 268 */
 269static void mfw_destroy(struct ip_masq_mfw *mfw)
 270{
 271        kfree_s(mfw, sizeof(*mfw));
 272        MOD_DEC_USE_COUNT;
 273}
 274
 275/* 
 276 *      Unlink m-entry.
 277 *
 278 *      Caller must lock tables.
 279 */
 280static int __mfw_del(struct ip_masq_mfw *mfw)
 281{
 282        struct ip_masq_mfw **mfw_p;
 283        int ret = -EINVAL;
 284
 285
 286        for(mfw_p=&ip_masq_mfw_table[mfw_hash_val(mfw->fwmark)]; 
 287                        *mfw_p; 
 288                        mfw_p = &((*mfw_p)->next)) 
 289        {
 290                if (mfw==(*mfw_p)) {
 291                        *mfw_p = mfw->next;
 292                        ip_masq_mod_dec_nent(mmod_self);
 293                        ret = 0;
 294                        goto out;
 295                }
 296        }
 297out:
 298        return ret;
 299}
 300
 301/*
 302 *      Crude m.host scheduler
 303 *      This interface could be exported to allow playing with 
 304 *      other sched policies.
 305 *
 306 *      Caller must lock m-entry.
 307 */
 308static struct ip_masq_mfw_host * __mfw_sched(struct ip_masq_mfw *mfw, int force)
 309{
 310        struct ip_masq_mfw_host *h = NULL;
 311
 312        if (atomic_read(&mfw->nhosts) == 0)
 313                goto out;
 314
 315        /*
 316         *      Here resides actual sched policy: 
 317         *      When pref_cnt touches 0, entry gets shifted to tail and
 318         *      its pref_cnt reloaded from h->pref (actual value
 319         *      passed from u-space).
 320         *
 321         *      Exception is pref==0: avoid scheduling.
 322         */
 323
 324        h = list_entry(mfw->hosts.next, struct ip_masq_mfw_host, list);
 325
 326        if (atomic_read(&mfw->nhosts) <= 1)
 327                goto out;
 328
 329        if ((h->pref && atomic_dec_and_test(&h->pref_cnt)) || force) {
 330                atomic_set(&h->pref_cnt, h->pref);
 331                list_del(&h->list);
 332                list_add(&h->list, mfw->hosts.prev);
 333        }
 334out:
 335        return h;
 336}
 337
 338/*
 339 *      Main lookup routine.
 340 *      HITs fwmark and schedules m.host entries if required
 341 */
 342static struct ip_masq_mfw_host * mfw_lookup(int fwmark)
 343{
 344        struct ip_masq_mfw *mfw;
 345        struct ip_masq_mfw_host *h = NULL;
 346
 347        read_lock(&mfw_lock);
 348        mfw = __mfw_get(fwmark);
 349
 350        if (mfw) {
 351                write_lock(&mfw->lock);
 352                h = __mfw_sched(mfw, 0);
 353                write_unlock(&mfw->lock);
 354        }
 355
 356        read_unlock(&mfw_lock);
 357        return h;
 358}
 359
 360#ifdef CONFIG_PROC_FS
 361static int mfw_procinfo(char *buffer, char **start, off_t offset,
 362                              int length, int dummy)
 363{
 364        struct ip_masq_mfw *mfw;
 365        struct ip_masq_mfw_host *h;
 366        struct list_head *l,*e;
 367        off_t pos=0, begin;
 368        char temp[129];
 369        int idx = 0;
 370        int len=0;
 371
 372        MOD_INC_USE_COUNT;
 373
 374        IP_MASQ_DEBUG(1-debug, "Entered mfw_info\n");
 375
 376        if (offset < 64)
 377        {
 378                sprintf(temp, "FwMark > RAddr    RPort PrCnt  Pref");
 379                len = sprintf(buffer, "%-63s\n", temp);
 380        }
 381        pos = 64;
 382
 383        for(idx = 0; idx < IP_MASQ_MFW_HSIZE; idx++)
 384        {
 385                read_lock(&mfw_lock);
 386                for(mfw = ip_masq_mfw_table[idx]; mfw ; mfw = mfw->next)
 387                {
 388                        read_lock_bh(&mfw->lock);
 389                        l=&mfw->hosts;
 390
 391                        for(e=l->next;l!=e;e=e->next) {
 392                                h = list_entry(e, struct ip_masq_mfw_host, list);
 393                                pos += 64;
 394                                if (pos <= offset) {
 395                                        len = 0;
 396                                        continue;
 397                                }
 398
 399                                sprintf(temp,"0x%x > %08lX %5u %5d %5d",
 400                                                h->fwmark,
 401                                                ntohl(h->addr), ntohs(h->port),
 402                                                atomic_read(&h->pref_cnt), h->pref);
 403                                len += sprintf(buffer+len, "%-63s\n", temp);
 404
 405                                if(len >= length) {
 406                                        read_unlock_bh(&mfw->lock);
 407                                        read_unlock(&mfw_lock);
 408                                        goto done;
 409                                }
 410                        }
 411                        read_unlock_bh(&mfw->lock);
 412                }
 413                read_unlock(&mfw_lock);
 414        }
 415
 416done:
 417
 418        if (len) {
 419                begin = len - (pos - offset);
 420                *start = buffer + begin;
 421                len -= begin;
 422        }
 423        if(len>length)
 424                len = length;
 425        MOD_DEC_USE_COUNT;
 426        return len;
 427}
 428static struct proc_dir_entry mfw_proc_entry = {
 429/*              0, 0, NULL", */
 430                0, 3, "mfw",
 431                S_IFREG | S_IRUGO, 1, 0, 0,
 432                0, &proc_net_inode_operations,
 433                mfw_procinfo
 434};
 435
 436#define proc_ent &mfw_proc_entry
 437#else /* !CONFIG_PROC_FS */
 438
 439#define proc_ent NULL
 440#endif
 441
 442
 443static void mfw_flush(void)
 444{
 445        struct ip_masq_mfw *mfw, *local_table[IP_MASQ_MFW_HSIZE];
 446        struct ip_masq_mfw_host *h;
 447        struct ip_masq_mfw *mfw_next;
 448        int idx;
 449        struct list_head *l,*e;
 450
 451        write_lock_bh(&mfw_lock);
 452        memcpy(local_table, ip_masq_mfw_table, sizeof ip_masq_mfw_table);
 453        memset(ip_masq_mfw_table, 0, sizeof ip_masq_mfw_table);
 454        write_unlock_bh(&mfw_lock);
 455
 456        /*
 457         *      For every hash table row ...
 458         */
 459        for(idx=0;idx<IP_MASQ_MFW_HSIZE;idx++) {
 460
 461                /*
 462                 *      For every m-entry in row ...
 463                 */
 464                for(mfw=local_table[idx];mfw;mfw=mfw_next) {
 465                        /*
 466                         *      For every m.host in m-entry ...
 467                         */
 468                        l=&mfw->hosts;
 469                        while((e=l->next) != l) {
 470                                h = list_entry(e, struct ip_masq_mfw_host, list);
 471                                atomic_dec(&mfw->nhosts);
 472                                list_del(&h->list);
 473                                kfree_s(h, sizeof(*h));
 474                                MOD_DEC_USE_COUNT;
 475                        }
 476
 477                        if (atomic_read(&mfw->nhosts)) {
 478                                IP_MASQ_ERR("mfw_flush(): after flushing row nhosts=%d\n",
 479                                                atomic_read(&mfw->nhosts));
 480                        }
 481                        mfw_next = mfw->next;
 482                        kfree_s(mfw, sizeof(*mfw));     
 483                        MOD_DEC_USE_COUNT;
 484                        ip_masq_mod_dec_nent(mmod_self);
 485                }
 486        }
 487}
 488
 489/*
 490 *      User space control entry point
 491 */
 492static int mfw_ctl(int optname, struct ip_masq_ctl *mctl, int optlen)
 493{
 494        struct ip_mfw_user *mu =  &mctl->u.mfw_user;
 495        struct ip_masq_mfw *mfw;
 496        int ret = EINVAL;
 497        int arglen = optlen - IP_MASQ_CTL_BSIZE;
 498        int cmd;
 499
 500
 501        IP_MASQ_DEBUG(1-debug, "ip_masq_user_ctl(len=%d/%d|%d/%d)\n",
 502                arglen,
 503                sizeof (*mu),
 504                optlen,
 505                sizeof (*mctl));
 506
 507        /*
 508         *      checks ...
 509         */
 510        if (arglen != sizeof(*mu) && optlen != sizeof(*mctl)) 
 511                return -EINVAL;
 512 
 513        /* 
 514         *      Don't trust the lusers - plenty of error checking! 
 515         */
 516        cmd = mctl->m_cmd;
 517        IP_MASQ_DEBUG(1-debug, "ip_masq_mfw_ctl(cmd=%d, fwmark=%d)\n",
 518                        cmd, mu->fwmark);
 519
 520
 521        switch(cmd) {
 522                case IP_MASQ_CMD_NONE:
 523                        return 0;
 524                case IP_MASQ_CMD_FLUSH:
 525                        break;
 526                case IP_MASQ_CMD_ADD:
 527                case IP_MASQ_CMD_INSERT:
 528                case IP_MASQ_CMD_SET:
 529                        if (mu->fwmark == 0) {
 530                                IP_MASQ_DEBUG(1-debug, "invalid fwmark==0\n");
 531                                return -EINVAL;
 532                        }
 533                        if (mu->pref < 0) {
 534                                IP_MASQ_DEBUG(1-debug, "invalid pref==%d\n",
 535                                        mu->pref);
 536                                return -EINVAL;
 537                        }
 538                        break;
 539        }
 540
 541
 542        ret = -EINVAL;
 543
 544        switch(cmd) {
 545        case IP_MASQ_CMD_ADD:
 546        case IP_MASQ_CMD_INSERT:
 547                if (!mu->raddr) {
 548                        IP_MASQ_DEBUG(0-debug, "ip_masq_mfw_ctl(ADD): invalid redirect 0x%x:%d\n",
 549                                        mu->raddr, mu->rport);
 550                        goto out;
 551                }
 552
 553                /*
 554                 *      Cannot just use mfw_lock because below
 555                 *      are allocations that can sleep; so
 556                 *      to assure "new entry" atomic creation
 557                 *      I use a semaphore.
 558                 *
 559                 */
 560                down(&mfw_sema);
 561
 562                read_lock(&mfw_lock);
 563                mfw = __mfw_get(mu->fwmark);
 564                read_unlock(&mfw_lock);
 565                
 566                /*
 567                 *      If first host, create m-entry
 568                 */
 569                if (mfw == NULL) {
 570                        mfw = mfw_new(mu->fwmark);
 571                        if (mfw == NULL) 
 572                                ret = -ENOMEM;
 573                } 
 574
 575                if (mfw) {
 576                        /*
 577                         *      Put m.host in m-entry.
 578                         */
 579                        ret = mfw_addhost(mfw, mu, cmd == IP_MASQ_CMD_ADD);
 580
 581                        /*
 582                         *      If first host, link m-entry to hash table.
 583                         *      Already protected by global lock.
 584                         */
 585                        if (ret == 0 && atomic_read(&mfw->nhosts) == 1)  {
 586                                write_lock_bh(&mfw_lock);
 587                                __mfw_add(mfw);
 588                                write_unlock_bh(&mfw_lock);
 589                        } 
 590                        if (atomic_read(&mfw->nhosts) == 0) {
 591                                mfw_destroy(mfw);
 592                        }
 593                }
 594
 595                up(&mfw_sema);
 596
 597                break;
 598
 599        case IP_MASQ_CMD_DEL:
 600                down(&mfw_sema);
 601
 602                read_lock(&mfw_lock);
 603                mfw = __mfw_get(mu->fwmark);
 604                read_unlock(&mfw_lock);
 605
 606                if (mfw) {
 607                        ret = mfw_delhost(mfw, mu);
 608
 609                        /*
 610                         *      Last lease will free
 611                         *      XXX check logic XXX
 612                         */
 613                        if (atomic_read(&mfw->nhosts) == 0) {
 614                                write_lock_bh(&mfw_lock);
 615                                __mfw_del(mfw);
 616                                write_unlock_bh(&mfw_lock);
 617                                mfw_destroy(mfw);
 618                        }
 619                } else 
 620                        ret = -ESRCH;
 621
 622                up(&mfw_sema);
 623                break;
 624        case IP_MASQ_CMD_FLUSH:
 625
 626                down(&mfw_sema);
 627                mfw_flush();
 628                up(&mfw_sema);
 629                ret = 0;
 630                break;
 631        case IP_MASQ_CMD_SET:
 632                /*
 633                 *      No need to semaphorize here, main list is not 
 634                 *      modified.
 635                 */
 636                read_lock(&mfw_lock);
 637                
 638                mfw = __mfw_get(mu->fwmark);
 639                if (mfw) {
 640                        write_lock_bh(&mfw->lock);
 641                        
 642                        if (mu->flags & IP_MASQ_MFW_SCHED) {
 643                                struct ip_masq_mfw_host *h;
 644                                if ((h=__mfw_sched(mfw, 1))) {
 645                                        mfw_host_to_user(h, mu);
 646                                        ret = 0;
 647                                } 
 648                        } else {
 649                                ret = __mfw_edithost(mfw, mu);
 650                        }
 651                                
 652                        write_unlock_bh(&mfw->lock);
 653                }
 654
 655                read_unlock(&mfw_lock);
 656                break;
 657        }
 658out:
 659        
 660        return ret;
 661}
 662
 663/*
 664 *      Module stubs called from ip_masq core module
 665 */
 666 
 667/*
 668 *      Input rule stub, called very early for each incoming packet, 
 669 *      to see if this module has "interest" in packet.
 670 */
 671static int mfw_in_rule(const struct sk_buff *skb, const struct iphdr *iph)
 672{
 673        int val;
 674        read_lock(&mfw_lock);
 675        val = ( __mfw_get(skb->fwmark) != 0);
 676        read_unlock(&mfw_lock);
 677        return val;
 678}
 679
 680/*
 681 *      Input-create stub, called to allow "custom" masq creation
 682 */
 683static struct ip_masq * mfw_in_create(const struct sk_buff *skb, const struct iphdr *iph, __u32 maddr)
 684{
 685        union ip_masq_tphdr tph;
 686        struct ip_masq *ms = NULL;
 687        struct ip_masq_mfw_host *h = NULL;
 688
 689        tph.raw = (char*) iph + iph->ihl * 4;
 690
 691        switch (iph->protocol) {
 692                case IPPROTO_TCP:
 693                        /*      
 694                         *      Only open TCP tunnel if SYN+!ACK packet
 695                         */
 696                        if (!tph.th->syn && tph.th->ack)
 697                                return NULL;
 698                case IPPROTO_UDP:
 699                        break;
 700                default:
 701                        return NULL;
 702        }
 703
 704        /* 
 705         *      If no entry exists in the masquerading table
 706         *      and the port is involved
 707         *      in port forwarding, create a new masq entry 
 708         */
 709
 710        if ((h=mfw_lookup(skb->fwmark))) {
 711                ms = ip_masq_new(iph->protocol,
 712                                iph->daddr, tph.portp[1],       
 713                                /* if no redir-port, use packet dest port */
 714                                h->addr, h->port? h->port : tph.portp[1],
 715                                iph->saddr, tph.portp[0],
 716                                0);
 717
 718                if (ms != NULL)
 719                        ip_masq_listen(ms);
 720        }
 721        return ms;
 722}
 723
 724
 725#define mfw_in_update   NULL
 726#define mfw_out_rule    NULL
 727#define mfw_out_create  NULL
 728#define mfw_out_update  NULL
 729
 730static struct ip_masq_mod mfw_mod = {
 731        NULL,                   /* next */
 732        NULL,                   /* next_reg */
 733        "mfw",          /* name */
 734        ATOMIC_INIT(0),         /* nent */
 735        ATOMIC_INIT(0),         /* refcnt */
 736        proc_ent,
 737        mfw_ctl,
 738        NULL,                   /* masq_mod_init */
 739        NULL,                   /* masq_mod_done */
 740        mfw_in_rule,
 741        mfw_in_update,
 742        mfw_in_create,
 743        mfw_out_rule,
 744        mfw_out_update,
 745        mfw_out_create,
 746};
 747
 748
 749__initfunc(int ip_mfw_init(void))
 750{
 751        return register_ip_masq_mod ((mmod_self=&mfw_mod));
 752}
 753
 754int ip_mfw_done(void)
 755{
 756        return unregister_ip_masq_mod(&mfw_mod);
 757}
 758
 759#ifdef MODULE
 760EXPORT_NO_SYMBOLS;
 761
 762int init_module(void)
 763{
 764        if (ip_mfw_init() != 0)
 765                return -EIO;
 766        return 0;
 767}
 768
 769void cleanup_module(void)
 770{
 771        if (ip_mfw_done() != 0)
 772                printk(KERN_INFO "can't remove module");
 773}
 774
 775#endif /* MODULE */
 776
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.