linux/net/ipv4/netfilter/arp_tables.c
<<
>>
Prefs
   1/*
   2 * Packet matching code for ARP packets.
   3 *
   4 * Based heavily, if not almost entirely, upon ip_tables.c framework.
   5 *
   6 * Some ARP specific bits are:
   7 *
   8 * Copyright (C) 2002 David S. Miller (davem@redhat.com)
   9 *
  10 */
  11#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  12#include <linux/kernel.h>
  13#include <linux/skbuff.h>
  14#include <linux/netdevice.h>
  15#include <linux/capability.h>
  16#include <linux/if_arp.h>
  17#include <linux/kmod.h>
  18#include <linux/vmalloc.h>
  19#include <linux/proc_fs.h>
  20#include <linux/module.h>
  21#include <linux/init.h>
  22#include <linux/mutex.h>
  23#include <linux/err.h>
  24#include <net/compat.h>
  25#include <net/sock.h>
  26#include <asm/uaccess.h>
  27
  28#include <linux/netfilter/x_tables.h>
  29#include <linux/netfilter_arp/arp_tables.h>
  30
  31MODULE_LICENSE("GPL");
  32MODULE_AUTHOR("David S. Miller <davem@redhat.com>");
  33MODULE_DESCRIPTION("arptables core");
  34
  35/*#define DEBUG_ARP_TABLES*/
  36/*#define DEBUG_ARP_TABLES_USER*/
  37
  38#ifdef DEBUG_ARP_TABLES
  39#define dprintf(format, args...)  printk(format , ## args)
  40#else
  41#define dprintf(format, args...)
  42#endif
  43
  44#ifdef DEBUG_ARP_TABLES_USER
  45#define duprintf(format, args...) printk(format , ## args)
  46#else
  47#define duprintf(format, args...)
  48#endif
  49
  50#ifdef CONFIG_NETFILTER_DEBUG
  51#define ARP_NF_ASSERT(x)                                        \
  52do {                                                            \
  53        if (!(x))                                               \
  54                printk("ARP_NF_ASSERT: %s:%s:%u\n",             \
  55                       __func__, __FILE__, __LINE__);   \
  56} while(0)
  57#else
  58#define ARP_NF_ASSERT(x)
  59#endif
  60
  61static inline int arp_devaddr_compare(const struct arpt_devaddr_info *ap,
  62                                      const char *hdr_addr, int len)
  63{
  64        int i, ret;
  65
  66        if (len > ARPT_DEV_ADDR_LEN_MAX)
  67                len = ARPT_DEV_ADDR_LEN_MAX;
  68
  69        ret = 0;
  70        for (i = 0; i < len; i++)
  71                ret |= (hdr_addr[i] ^ ap->addr[i]) & ap->mask[i];
  72
  73        return (ret != 0);
  74}
  75
  76/*
  77 * Unfortunatly, _b and _mask are not aligned to an int (or long int)
  78 * Some arches dont care, unrolling the loop is a win on them.
  79 * For other arches, we only have a 16bit alignement.
  80 */
  81static unsigned long ifname_compare(const char *_a, const char *_b, const char *_mask)
  82{
  83#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
  84        unsigned long ret = ifname_compare_aligned(_a, _b, _mask);
  85#else
  86        unsigned long ret = 0;
  87        const u16 *a = (const u16 *)_a;
  88        const u16 *b = (const u16 *)_b;
  89        const u16 *mask = (const u16 *)_mask;
  90        int i;
  91
  92        for (i = 0; i < IFNAMSIZ/sizeof(u16); i++)
  93                ret |= (a[i] ^ b[i]) & mask[i];
  94#endif
  95        return ret;
  96}
  97
  98/* Returns whether packet matches rule or not. */
  99static inline int arp_packet_match(const struct arphdr *arphdr,
 100                                   struct net_device *dev,
 101                                   const char *indev,
 102                                   const char *outdev,
 103                                   const struct arpt_arp *arpinfo)
 104{
 105        const char *arpptr = (char *)(arphdr + 1);
 106        const char *src_devaddr, *tgt_devaddr;
 107        __be32 src_ipaddr, tgt_ipaddr;
 108        long ret;
 109
 110#define FWINV(bool, invflg) ((bool) ^ !!(arpinfo->invflags & (invflg)))
 111
 112        if (FWINV((arphdr->ar_op & arpinfo->arpop_mask) != arpinfo->arpop,
 113                  ARPT_INV_ARPOP)) {
 114                dprintf("ARP operation field mismatch.\n");
 115                dprintf("ar_op: %04x info->arpop: %04x info->arpop_mask: %04x\n",
 116                        arphdr->ar_op, arpinfo->arpop, arpinfo->arpop_mask);
 117                return 0;
 118        }
 119
 120        if (FWINV((arphdr->ar_hrd & arpinfo->arhrd_mask) != arpinfo->arhrd,
 121                  ARPT_INV_ARPHRD)) {
 122                dprintf("ARP hardware address format mismatch.\n");
 123                dprintf("ar_hrd: %04x info->arhrd: %04x info->arhrd_mask: %04x\n",
 124                        arphdr->ar_hrd, arpinfo->arhrd, arpinfo->arhrd_mask);
 125                return 0;
 126        }
 127
 128        if (FWINV((arphdr->ar_pro & arpinfo->arpro_mask) != arpinfo->arpro,
 129                  ARPT_INV_ARPPRO)) {
 130                dprintf("ARP protocol address format mismatch.\n");
 131                dprintf("ar_pro: %04x info->arpro: %04x info->arpro_mask: %04x\n",
 132                        arphdr->ar_pro, arpinfo->arpro, arpinfo->arpro_mask);
 133                return 0;
 134        }
 135
 136        if (FWINV((arphdr->ar_hln & arpinfo->arhln_mask) != arpinfo->arhln,
 137                  ARPT_INV_ARPHLN)) {
 138                dprintf("ARP hardware address length mismatch.\n");
 139                dprintf("ar_hln: %02x info->arhln: %02x info->arhln_mask: %02x\n",
 140                        arphdr->ar_hln, arpinfo->arhln, arpinfo->arhln_mask);
 141                return 0;
 142        }
 143
 144        src_devaddr = arpptr;
 145        arpptr += dev->addr_len;
 146        memcpy(&src_ipaddr, arpptr, sizeof(u32));
 147        arpptr += sizeof(u32);
 148        tgt_devaddr = arpptr;
 149        arpptr += dev->addr_len;
 150        memcpy(&tgt_ipaddr, arpptr, sizeof(u32));
 151
 152        if (FWINV(arp_devaddr_compare(&arpinfo->src_devaddr, src_devaddr, dev->addr_len),
 153                  ARPT_INV_SRCDEVADDR) ||
 154            FWINV(arp_devaddr_compare(&arpinfo->tgt_devaddr, tgt_devaddr, dev->addr_len),
 155                  ARPT_INV_TGTDEVADDR)) {
 156                dprintf("Source or target device address mismatch.\n");
 157
 158                return 0;
 159        }
 160
 161        if (FWINV((src_ipaddr & arpinfo->smsk.s_addr) != arpinfo->src.s_addr,
 162                  ARPT_INV_SRCIP) ||
 163            FWINV(((tgt_ipaddr & arpinfo->tmsk.s_addr) != arpinfo->tgt.s_addr),
 164                  ARPT_INV_TGTIP)) {
 165                dprintf("Source or target IP address mismatch.\n");
 166
 167                dprintf("SRC: %pI4. Mask: %pI4. Target: %pI4.%s\n",
 168                        &src_ipaddr,
 169                        &arpinfo->smsk.s_addr,
 170                        &arpinfo->src.s_addr,
 171                        arpinfo->invflags & ARPT_INV_SRCIP ? " (INV)" : "");
 172                dprintf("TGT: %pI4 Mask: %pI4 Target: %pI4.%s\n",
 173                        &tgt_ipaddr,
 174                        &arpinfo->tmsk.s_addr,
 175                        &arpinfo->tgt.s_addr,
 176                        arpinfo->invflags & ARPT_INV_TGTIP ? " (INV)" : "");
 177                return 0;
 178        }
 179
 180        /* Look for ifname matches.  */
 181        ret = ifname_compare(indev, arpinfo->iniface, arpinfo->iniface_mask);
 182
 183        if (FWINV(ret != 0, ARPT_INV_VIA_IN)) {
 184                dprintf("VIA in mismatch (%s vs %s).%s\n",
 185                        indev, arpinfo->iniface,
 186                        arpinfo->invflags&ARPT_INV_VIA_IN ?" (INV)":"");
 187                return 0;
 188        }
 189
 190        ret = ifname_compare(outdev, arpinfo->outiface, arpinfo->outiface_mask);
 191
 192        if (FWINV(ret != 0, ARPT_INV_VIA_OUT)) {
 193                dprintf("VIA out mismatch (%s vs %s).%s\n",
 194                        outdev, arpinfo->outiface,
 195                        arpinfo->invflags&ARPT_INV_VIA_OUT ?" (INV)":"");
 196                return 0;
 197        }
 198
 199        return 1;
 200#undef FWINV
 201}
 202
 203static inline int arp_checkentry(const struct arpt_arp *arp)
 204{
 205        if (arp->flags & ~ARPT_F_MASK) {
 206                duprintf("Unknown flag bits set: %08X\n",
 207                         arp->flags & ~ARPT_F_MASK);
 208                return 0;
 209        }
 210        if (arp->invflags & ~ARPT_INV_MASK) {
 211                duprintf("Unknown invflag bits set: %08X\n",
 212                         arp->invflags & ~ARPT_INV_MASK);
 213                return 0;
 214        }
 215
 216        return 1;
 217}
 218
 219static unsigned int
 220arpt_error(struct sk_buff *skb, const struct xt_target_param *par)
 221{
 222        if (net_ratelimit())
 223                printk("arp_tables: error: '%s'\n",
 224                       (const char *)par->targinfo);
 225
 226        return NF_DROP;
 227}
 228
 229static inline struct arpt_entry *get_entry(void *base, unsigned int offset)
 230{
 231        return (struct arpt_entry *)(base + offset);
 232}
 233
 234static inline __pure
 235struct arpt_entry *arpt_next_entry(const struct arpt_entry *entry)
 236{
 237        return (void *)entry + entry->next_offset;
 238}
 239
 240unsigned int arpt_do_table(struct sk_buff *skb,
 241                           unsigned int hook,
 242                           const struct net_device *in,
 243                           const struct net_device *out,
 244                           struct xt_table *table)
 245{
 246        static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long))));
 247        unsigned int verdict = NF_DROP;
 248        const struct arphdr *arp;
 249        bool hotdrop = false;
 250        struct arpt_entry *e, *back;
 251        const char *indev, *outdev;
 252        void *table_base;
 253        const struct xt_table_info *private;
 254        struct xt_target_param tgpar;
 255
 256        if (!pskb_may_pull(skb, arp_hdr_len(skb->dev)))
 257                return NF_DROP;
 258
 259        indev = in ? in->name : nulldevname;
 260        outdev = out ? out->name : nulldevname;
 261
 262        xt_info_rdlock_bh();
 263        private = table->private;
 264        table_base = private->entries[smp_processor_id()];
 265
 266        e = get_entry(table_base, private->hook_entry[hook]);
 267        back = get_entry(table_base, private->underflow[hook]);
 268
 269        tgpar.in      = in;
 270        tgpar.out     = out;
 271        tgpar.hooknum = hook;
 272        tgpar.family  = NFPROTO_ARP;
 273
 274        arp = arp_hdr(skb);
 275        do {
 276                struct arpt_entry_target *t;
 277                int hdr_len;
 278
 279                if (!arp_packet_match(arp, skb->dev, indev, outdev, &e->arp)) {
 280                        e = arpt_next_entry(e);
 281                        continue;
 282                }
 283
 284                hdr_len = sizeof(*arp) + (2 * sizeof(struct in_addr)) +
 285                        (2 * skb->dev->addr_len);
 286                ADD_COUNTER(e->counters, hdr_len, 1);
 287
 288                t = arpt_get_target(e);
 289
 290                /* Standard target? */
 291                if (!t->u.kernel.target->target) {
 292                        int v;
 293
 294                        v = ((struct arpt_standard_target *)t)->verdict;
 295                        if (v < 0) {
 296                                /* Pop from stack? */
 297                                if (v != ARPT_RETURN) {
 298                                        verdict = (unsigned)(-v) - 1;
 299                                        break;
 300                                }
 301                                e = back;
 302                                back = get_entry(table_base, back->comefrom);
 303                                continue;
 304                        }
 305                        if (table_base + v
 306                            != arpt_next_entry(e)) {
 307                                /* Save old back ptr in next entry */
 308                                struct arpt_entry *next = arpt_next_entry(e);
 309                                next->comefrom = (void *)back - table_base;
 310
 311                                /* set back pointer to next entry */
 312                                back = next;
 313                        }
 314
 315                        e = get_entry(table_base, v);
 316                        continue;
 317                }
 318
 319                /* Targets which reenter must return
 320                 * abs. verdicts
 321                 */
 322                tgpar.target   = t->u.kernel.target;
 323                tgpar.targinfo = t->data;
 324                verdict = t->u.kernel.target->target(skb, &tgpar);
 325
 326                /* Target might have changed stuff. */
 327                arp = arp_hdr(skb);
 328
 329                if (verdict == ARPT_CONTINUE)
 330                        e = arpt_next_entry(e);
 331                else
 332                        /* Verdict */
 333                        break;
 334        } while (!hotdrop);
 335        xt_info_rdunlock_bh();
 336
 337        if (hotdrop)
 338                return NF_DROP;
 339        else
 340                return verdict;
 341}
 342
 343/* All zeroes == unconditional rule. */
 344static inline bool unconditional(const struct arpt_arp *arp)
 345{
 346        static const struct arpt_arp uncond;
 347
 348        return memcmp(arp, &uncond, sizeof(uncond)) == 0;
 349}
 350
 351/* Figures out from what hook each rule can be called: returns 0 if
 352 * there are loops.  Puts hook bitmask in comefrom.
 353 */
 354static int mark_source_chains(struct xt_table_info *newinfo,
 355                              unsigned int valid_hooks, void *entry0)
 356{
 357        unsigned int hook;
 358
 359        /* No recursion; use packet counter to save back ptrs (reset
 360         * to 0 as we leave), and comefrom to save source hook bitmask.
 361         */
 362        for (hook = 0; hook < NF_ARP_NUMHOOKS; hook++) {
 363                unsigned int pos = newinfo->hook_entry[hook];
 364                struct arpt_entry *e
 365                        = (struct arpt_entry *)(entry0 + pos);
 366
 367                if (!(valid_hooks & (1 << hook)))
 368                        continue;
 369
 370                /* Set initial back pointer. */
 371                e->counters.pcnt = pos;
 372
 373                for (;;) {
 374                        const struct arpt_standard_target *t
 375                                = (void *)arpt_get_target(e);
 376                        int visited = e->comefrom & (1 << hook);
 377
 378                        if (e->comefrom & (1 << NF_ARP_NUMHOOKS)) {
 379                                printk("arptables: loop hook %u pos %u %08X.\n",
 380                                       hook, pos, e->comefrom);
 381                                return 0;
 382                        }
 383                        e->comefrom
 384                                |= ((1 << hook) | (1 << NF_ARP_NUMHOOKS));
 385
 386                        /* Unconditional return/END. */
 387                        if ((e->target_offset == sizeof(struct arpt_entry)
 388                            && (strcmp(t->target.u.user.name,
 389                                       ARPT_STANDARD_TARGET) == 0)
 390                            && t->verdict < 0
 391                            && unconditional(&e->arp)) || visited) {
 392                                unsigned int oldpos, size;
 393
 394                                if ((strcmp(t->target.u.user.name,
 395                                            ARPT_STANDARD_TARGET) == 0) &&
 396                                    t->verdict < -NF_MAX_VERDICT - 1) {
 397                                        duprintf("mark_source_chains: bad "
 398                                                "negative verdict (%i)\n",
 399                                                                t->verdict);
 400                                        return 0;
 401                                }
 402
 403                                /* Return: backtrack through the last
 404                                 * big jump.
 405                                 */
 406                                do {
 407                                        e->comefrom ^= (1<<NF_ARP_NUMHOOKS);
 408                                        oldpos = pos;
 409                                        pos = e->counters.pcnt;
 410                                        e->counters.pcnt = 0;
 411
 412                                        /* We're at the start. */
 413                                        if (pos == oldpos)
 414                                                goto next;
 415
 416                                        e = (struct arpt_entry *)
 417                                                (entry0 + pos);
 418                                } while (oldpos == pos + e->next_offset);
 419
 420                                /* Move along one */
 421                                size = e->next_offset;
 422                                e = (struct arpt_entry *)
 423                                        (entry0 + pos + size);
 424                                e->counters.pcnt = pos;
 425                                pos += size;
 426                        } else {
 427                                int newpos = t->verdict;
 428
 429                                if (strcmp(t->target.u.user.name,
 430                                           ARPT_STANDARD_TARGET) == 0
 431                                    && newpos >= 0) {
 432                                        if (newpos > newinfo->size -
 433                                                sizeof(struct arpt_entry)) {
 434                                                duprintf("mark_source_chains: "
 435                                                        "bad verdict (%i)\n",
 436                                                                newpos);
 437                                                return 0;
 438                                        }
 439
 440                                        /* This a jump; chase it. */
 441                                        duprintf("Jump rule %u -> %u\n",
 442                                                 pos, newpos);
 443                                } else {
 444                                        /* ... this is a fallthru */
 445                                        newpos = pos + e->next_offset;
 446                                }
 447                                e = (struct arpt_entry *)
 448                                        (entry0 + newpos);
 449                                e->counters.pcnt = pos;
 450                                pos = newpos;
 451                        }
 452                }
 453                next:
 454                duprintf("Finished chain %u\n", hook);
 455        }
 456        return 1;
 457}
 458
 459static inline int check_entry(struct arpt_entry *e, const char *name)
 460{
 461        const struct arpt_entry_target *t;
 462
 463        if (!arp_checkentry(&e->arp)) {
 464                duprintf("arp_tables: arp check failed %p %s.\n", e, name);
 465                return -EINVAL;
 466        }
 467
 468        if (e->target_offset + sizeof(struct arpt_entry_target) > e->next_offset)
 469                return -EINVAL;
 470
 471        t = arpt_get_target(e);
 472        if (e->target_offset + t->u.target_size > e->next_offset)
 473                return -EINVAL;
 474
 475        return 0;
 476}
 477
 478static inline int check_target(struct arpt_entry *e, const char *name)
 479{
 480        struct arpt_entry_target *t = arpt_get_target(e);
 481        int ret;
 482        struct xt_tgchk_param par = {
 483                .table     = name,
 484                .entryinfo = e,
 485                .target    = t->u.kernel.target,
 486                .targinfo  = t->data,
 487                .hook_mask = e->comefrom,
 488                .family    = NFPROTO_ARP,
 489        };
 490
 491        ret = xt_check_target(&par, t->u.target_size - sizeof(*t), 0, false);
 492        if (ret < 0) {
 493                duprintf("arp_tables: check failed for `%s'.\n",
 494                         t->u.kernel.target->name);
 495                return ret;
 496        }
 497        return 0;
 498}
 499
 500static inline int
 501find_check_entry(struct arpt_entry *e, const char *name, unsigned int size,
 502                 unsigned int *i)
 503{
 504        struct arpt_entry_target *t;
 505        struct xt_target *target;
 506        int ret;
 507
 508        ret = check_entry(e, name);
 509        if (ret)
 510                return ret;
 511
 512        t = arpt_get_target(e);
 513        target = try_then_request_module(xt_find_target(NFPROTO_ARP,
 514                                                        t->u.user.name,
 515                                                        t->u.user.revision),
 516                                         "arpt_%s", t->u.user.name);
 517        if (IS_ERR(target) || !target) {
 518                duprintf("find_check_entry: `%s' not found\n", t->u.user.name);
 519                ret = target ? PTR_ERR(target) : -ENOENT;
 520                goto out;
 521        }
 522        t->u.kernel.target = target;
 523
 524        ret = check_target(e, name);
 525        if (ret)
 526                goto err;
 527
 528        (*i)++;
 529        return 0;
 530err:
 531        module_put(t->u.kernel.target->me);
 532out:
 533        return ret;
 534}
 535
 536static bool check_underflow(struct arpt_entry *e)
 537{
 538        const struct arpt_entry_target *t;
 539        unsigned int verdict;
 540
 541        if (!unconditional(&e->arp))
 542                return false;
 543        t = arpt_get_target(e);
 544        if (strcmp(t->u.user.name, XT_STANDARD_TARGET) != 0)
 545                return false;
 546        verdict = ((struct arpt_standard_target *)t)->verdict;
 547        verdict = -verdict - 1;
 548        return verdict == NF_DROP || verdict == NF_ACCEPT;
 549}
 550
 551static inline int check_entry_size_and_hooks(struct arpt_entry *e,
 552                                             struct xt_table_info *newinfo,
 553                                             unsigned char *base,
 554                                             unsigned char *limit,
 555                                             const unsigned int *hook_entries,
 556                                             const unsigned int *underflows,
 557                                             unsigned int valid_hooks,
 558                                             unsigned int *i)
 559{
 560        unsigned int h;
 561
 562        if ((unsigned long)e % __alignof__(struct arpt_entry) != 0
 563            || (unsigned char *)e + sizeof(struct arpt_entry) >= limit) {
 564                duprintf("Bad offset %p\n", e);
 565                return -EINVAL;
 566        }
 567
 568        if (e->next_offset
 569            < sizeof(struct arpt_entry) + sizeof(struct arpt_entry_target)) {
 570                duprintf("checking: element %p size %u\n",
 571                         e, e->next_offset);
 572                return -EINVAL;
 573        }
 574
 575        /* Check hooks & underflows */
 576        for (h = 0; h < NF_ARP_NUMHOOKS; h++) {
 577                if (!(valid_hooks & (1 << h)))
 578                        continue;
 579                if ((unsigned char *)e - base == hook_entries[h])
 580                        newinfo->hook_entry[h] = hook_entries[h];
 581                if ((unsigned char *)e - base == underflows[h]) {
 582                        if (!check_underflow(e)) {
 583                                pr_err("Underflows must be unconditional and "
 584                                       "use the STANDARD target with "
 585                                       "ACCEPT/DROP\n");
 586                                return -EINVAL;
 587                        }
 588                        newinfo->underflow[h] = underflows[h];
 589                }
 590        }
 591
 592        /* Clear counters and comefrom */
 593        e->counters = ((struct xt_counters) { 0, 0 });
 594        e->comefrom = 0;
 595
 596        (*i)++;
 597        return 0;
 598}
 599
 600static inline int cleanup_entry(struct arpt_entry *e, unsigned int *i)
 601{
 602        struct xt_tgdtor_param par;
 603        struct arpt_entry_target *t;
 604
 605        if (i && (*i)-- == 0)
 606                return 1;
 607
 608        t = arpt_get_target(e);
 609        par.target   = t->u.kernel.target;
 610        par.targinfo = t->data;
 611        par.family   = NFPROTO_ARP;
 612        if (par.target->destroy != NULL)
 613                par.target->destroy(&par);
 614        module_put(par.target->me);
 615        return 0;
 616}
 617
 618/* Checks and translates the user-supplied table segment (held in
 619 * newinfo).
 620 */
 621static int translate_table(const char *name,
 622                           unsigned int valid_hooks,
 623                           struct xt_table_info *newinfo,
 624                           void *entry0,
 625                           unsigned int size,
 626                           unsigned int number,
 627                           const unsigned int *hook_entries,
 628                           const unsigned int *underflows)
 629{
 630        unsigned int i;
 631        int ret;
 632
 633        newinfo->size = size;
 634        newinfo->number = number;
 635
 636        /* Init all hooks to impossible value. */
 637        for (i = 0; i < NF_ARP_NUMHOOKS; i++) {
 638                newinfo->hook_entry[i] = 0xFFFFFFFF;
 639                newinfo->underflow[i] = 0xFFFFFFFF;
 640        }
 641
 642        duprintf("translate_table: size %u\n", newinfo->size);
 643        i = 0;
 644
 645        /* Walk through entries, checking offsets. */
 646        ret = ARPT_ENTRY_ITERATE(entry0, newinfo->size,
 647                                 check_entry_size_and_hooks,
 648                                 newinfo,
 649                                 entry0,
 650                                 entry0 + size,
 651                                 hook_entries, underflows, valid_hooks, &i);
 652        duprintf("translate_table: ARPT_ENTRY_ITERATE gives %d\n", ret);
 653        if (ret != 0)
 654                return ret;
 655
 656        if (i != number) {
 657                duprintf("translate_table: %u not %u entries\n",
 658                         i, number);
 659                return -EINVAL;
 660        }
 661
 662        /* Check hooks all assigned */
 663        for (i = 0; i < NF_ARP_NUMHOOKS; i++) {
 664                /* Only hooks which are valid */
 665                if (!(valid_hooks & (1 << i)))
 666                        continue;
 667                if (newinfo->hook_entry[i] == 0xFFFFFFFF) {
 668                        duprintf("Invalid hook entry %u %u\n",
 669                                 i, hook_entries[i]);
 670                        return -EINVAL;
 671                }
 672                if (newinfo->underflow[i] == 0xFFFFFFFF) {
 673                        duprintf("Invalid underflow %u %u\n",
 674                                 i, underflows[i]);
 675                        return -EINVAL;
 676                }
 677        }
 678
 679        if (!mark_source_chains(newinfo, valid_hooks, entry0)) {
 680                duprintf("Looping hook\n");
 681                return -ELOOP;
 682        }
 683
 684        /* Finally, each sanity check must pass */
 685        i = 0;
 686        ret = ARPT_ENTRY_ITERATE(entry0, newinfo->size,
 687                                 find_check_entry, name, size, &i);
 688
 689        if (ret != 0) {
 690                ARPT_ENTRY_ITERATE(entry0, newinfo->size,
 691                                cleanup_entry, &i);
 692                return ret;
 693        }
 694
 695        /* And one copy for every other CPU */
 696        for_each_possible_cpu(i) {
 697                if (newinfo->entries[i] && newinfo->entries[i] != entry0)
 698                        memcpy(newinfo->entries[i], entry0, newinfo->size);
 699        }
 700
 701        return ret;
 702}
 703
 704/* Gets counters. */
 705static inline int add_entry_to_counter(const struct arpt_entry *e,
 706                                       struct xt_counters total[],
 707                                       unsigned int *i)
 708{
 709        ADD_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);
 710
 711        (*i)++;
 712        return 0;
 713}
 714
 715static inline int set_entry_to_counter(const struct arpt_entry *e,
 716                                       struct xt_counters total[],
 717                                       unsigned int *i)
 718{
 719        SET_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);
 720
 721        (*i)++;
 722        return 0;
 723}
 724
 725static void get_counters(const struct xt_table_info *t,
 726                         struct xt_counters counters[])
 727{
 728        unsigned int cpu;
 729        unsigned int i;
 730        unsigned int curcpu;
 731
 732        /* Instead of clearing (by a previous call to memset())
 733         * the counters and using adds, we set the counters
 734         * with data used by 'current' CPU
 735         *
 736         * Bottom half has to be disabled to prevent deadlock
 737         * if new softirq were to run and call ipt_do_table
 738         */
 739        local_bh_disable();
 740        curcpu = smp_processor_id();
 741
 742        i = 0;
 743        ARPT_ENTRY_ITERATE(t->entries[curcpu],
 744                           t->size,
 745                           set_entry_to_counter,
 746                           counters,
 747                           &i);
 748
 749        for_each_possible_cpu(cpu) {
 750                if (cpu == curcpu)
 751                        continue;
 752                i = 0;
 753                xt_info_wrlock(cpu);
 754                ARPT_ENTRY_ITERATE(t->entries[cpu],
 755                                   t->size,
 756                                   add_entry_to_counter,
 757                                   counters,
 758                                   &i);
 759                xt_info_wrunlock(cpu);
 760        }
 761        local_bh_enable();
 762}
 763
 764static struct xt_counters *alloc_counters(struct xt_table *table)
 765{
 766        unsigned int countersize;
 767        struct xt_counters *counters;
 768        struct xt_table_info *private = table->private;
 769
 770        /* We need atomic snapshot of counters: rest doesn't change
 771         * (other than comefrom, which userspace doesn't care
 772         * about).
 773         */
 774        countersize = sizeof(struct xt_counters) * private->number;
 775        counters = vmalloc_node(countersize, numa_node_id());
 776
 777        if (counters == NULL)
 778                return ERR_PTR(-ENOMEM);
 779
 780        get_counters(private, counters);
 781
 782        return counters;
 783}
 784
 785static int copy_entries_to_user(unsigned int total_size,
 786                                struct xt_table *table,
 787                                void __user *userptr)
 788{
 789        unsigned int off, num;
 790        struct arpt_entry *e;
 791        struct xt_counters *counters;
 792        struct xt_table_info *private = table->private;
 793        int ret = 0;
 794        void *loc_cpu_entry;
 795
 796        counters = alloc_counters(table);
 797        if (IS_ERR(counters))
 798                return PTR_ERR(counters);
 799
 800        loc_cpu_entry = private->entries[raw_smp_processor_id()];
 801        /* ... then copy entire thing ... */
 802        if (copy_to_user(userptr, loc_cpu_entry, total_size) != 0) {
 803                ret = -EFAULT;
 804                goto free_counters;
 805        }
 806
 807        /* FIXME: use iterator macros --RR */
 808        /* ... then go back and fix counters and names */
 809        for (off = 0, num = 0; off < total_size; off += e->next_offset, num++){
 810                struct arpt_entry_target *t;
 811
 812                e = (struct arpt_entry *)(loc_cpu_entry + off);
 813                if (copy_to_user(userptr + off
 814                                 + offsetof(struct arpt_entry, counters),
 815                                 &counters[num],
 816                                 sizeof(counters[num])) != 0) {
 817                        ret = -EFAULT;
 818                        goto free_counters;
 819                }
 820
 821                t = arpt_get_target(e);
 822                if (copy_to_user(userptr + off + e->target_offset
 823                                 + offsetof(struct arpt_entry_target,
 824                                            u.user.name),
 825                                 t->u.kernel.target->name,
 826                                 strlen(t->u.kernel.target->name)+1) != 0) {
 827                        ret = -EFAULT;
 828                        goto free_counters;
 829                }
 830        }
 831
 832 free_counters:
 833        vfree(counters);
 834        return ret;
 835}
 836
 837#ifdef CONFIG_COMPAT
 838static void compat_standard_from_user(void *dst, void *src)
 839{
 840        int v = *(compat_int_t *)src;
 841
 842        if (v > 0)
 843                v += xt_compat_calc_jump(NFPROTO_ARP, v);
 844        memcpy(dst, &v, sizeof(v));
 845}
 846
 847static int compat_standard_to_user(void __user *dst, void *src)
 848{
 849        compat_int_t cv = *(int *)src;
 850
 851        if (cv > 0)
 852                cv -= xt_compat_calc_jump(NFPROTO_ARP, cv);
 853        return copy_to_user(dst, &cv, sizeof(cv)) ? -EFAULT : 0;
 854}
 855
 856static int compat_calc_entry(struct arpt_entry *e,
 857                             const struct xt_table_info *info,
 858                             void *base, struct xt_table_info *newinfo)
 859{
 860        struct arpt_entry_target *t;
 861        unsigned int entry_offset;
 862        int off, i, ret;
 863
 864        off = sizeof(struct arpt_entry) - sizeof(struct compat_arpt_entry);
 865        entry_offset = (void *)e - base;
 866
 867        t = arpt_get_target(e);
 868        off += xt_compat_target_offset(t->u.kernel.target);
 869        newinfo->size -= off;
 870        ret = xt_compat_add_offset(NFPROTO_ARP, entry_offset, off);
 871        if (ret)
 872                return ret;
 873
 874        for (i = 0; i < NF_ARP_NUMHOOKS; i++) {
 875                if (info->hook_entry[i] &&
 876                    (e < (struct arpt_entry *)(base + info->hook_entry[i])))
 877                        newinfo->hook_entry[i] -= off;
 878                if (info->underflow[i] &&
 879                    (e < (struct arpt_entry *)(base + info->underflow[i])))
 880                        newinfo->underflow[i] -= off;
 881        }
 882        return 0;
 883}
 884
 885static int compat_table_info(const struct xt_table_info *info,
 886                             struct xt_table_info *newinfo)
 887{
 888        void *loc_cpu_entry;
 889
 890        if (!newinfo || !info)
 891                return -EINVAL;
 892
 893        /* we dont care about newinfo->entries[] */
 894        memcpy(newinfo, info, offsetof(struct xt_table_info, entries));
 895        newinfo->initial_entries = 0;
 896        loc_cpu_entry = info->entries[raw_smp_processor_id()];
 897        return ARPT_ENTRY_ITERATE(loc_cpu_entry, info->size,
 898                                  compat_calc_entry, info, loc_cpu_entry,
 899                                  newinfo);
 900}
 901#endif
 902
 903static int get_info(struct net *net, void __user *user, int *len, int compat)
 904{
 905        char name[ARPT_TABLE_MAXNAMELEN];
 906        struct xt_table *t;
 907        int ret;
 908
 909        if (*len != sizeof(struct arpt_getinfo)) {
 910                duprintf("length %u != %Zu\n", *len,
 911                         sizeof(struct arpt_getinfo));
 912                return -EINVAL;
 913        }
 914
 915        if (copy_from_user(name, user, sizeof(name)) != 0)
 916                return -EFAULT;
 917
 918        name[ARPT_TABLE_MAXNAMELEN-1] = '\0';
 919#ifdef CONFIG_COMPAT
 920        if (compat)
 921                xt_compat_lock(NFPROTO_ARP);
 922#endif
 923        t = try_then_request_module(xt_find_table_lock(net, NFPROTO_ARP, name),
 924                                    "arptable_%s", name);
 925        if (t && !IS_ERR(t)) {
 926                struct arpt_getinfo info;
 927                const struct xt_table_info *private = t->private;
 928
 929#ifdef CONFIG_COMPAT
 930                if (compat) {
 931                        struct xt_table_info tmp;
 932                        ret = compat_table_info(private, &tmp);
 933                        xt_compat_flush_offsets(NFPROTO_ARP);
 934                        private = &tmp;
 935                }
 936#endif
 937                info.valid_hooks = t->valid_hooks;
 938                memcpy(info.hook_entry, private->hook_entry,
 939                       sizeof(info.hook_entry));
 940                memcpy(info.underflow, private->underflow,
 941                       sizeof(info.underflow));
 942                info.num_entries = private->number;
 943                info.size = private->size;
 944                strcpy(info.name, name);
 945
 946                if (copy_to_user(user, &info, *len) != 0)
 947                        ret = -EFAULT;
 948                else
 949                        ret = 0;
 950                xt_table_unlock(t);
 951                module_put(t->me);
 952        } else
 953                ret = t ? PTR_ERR(t) : -ENOENT;
 954#ifdef CONFIG_COMPAT
 955        if (compat)
 956                xt_compat_unlock(NFPROTO_ARP);
 957#endif
 958        return ret;
 959}
 960
 961static int get_entries(struct net *net, struct arpt_get_entries __user *uptr,
 962                       int *len)
 963{
 964        int ret;
 965        struct arpt_get_entries get;
 966        struct xt_table *t;
 967
 968        if (*len < sizeof(get)) {
 969                duprintf("get_entries: %u < %Zu\n", *len, sizeof(get));
 970                return -EINVAL;
 971        }
 972        if (copy_from_user(&get, uptr, sizeof(get)) != 0)
 973                return -EFAULT;
 974        if (*len != sizeof(struct arpt_get_entries) + get.size) {
 975                duprintf("get_entries: %u != %Zu\n", *len,
 976                         sizeof(struct arpt_get_entries) + get.size);
 977                return -EINVAL;
 978        }
 979
 980        t = xt_find_table_lock(net, NFPROTO_ARP, get.name);
 981        if (t && !IS_ERR(t)) {
 982                const struct xt_table_info *private = t->private;
 983
 984                duprintf("t->private->number = %u\n",
 985                         private->number);
 986                if (get.size == private->size)
 987                        ret = copy_entries_to_user(private->size,
 988                                                   t, uptr->entrytable);
 989                else {
 990                        duprintf("get_entries: I've got %u not %u!\n",
 991                                 private->size, get.size);
 992                        ret = -EAGAIN;
 993                }
 994                module_put(t->me);
 995                xt_table_unlock(t);
 996        } else
 997                ret = t ? PTR_ERR(t) : -ENOENT;
 998
 999        return ret;
1000}
1001
1002static int __do_replace(struct net *net, const char *name,
1003                        unsigned int valid_hooks,
1004                        struct xt_table_info *newinfo,
1005                        unsigned int num_counters,
1006                        void __user *counters_ptr)
1007{
1008        int ret;
1009        struct xt_table *t;
1010        struct xt_table_info *oldinfo;
1011        struct xt_counters *counters;
1012        void *loc_cpu_old_entry;
1013
1014        ret = 0;
1015        counters = vmalloc_node(num_counters * sizeof(struct xt_counters),
1016                                numa_node_id());
1017        if (!counters) {
1018                ret = -ENOMEM;
1019                goto out;
1020        }
1021
1022        t = try_then_request_module(xt_find_table_lock(net, NFPROTO_ARP, name),
1023                                    "arptable_%s", name);
1024        if (!t || IS_ERR(t)) {
1025                ret = t ? PTR_ERR(t) : -ENOENT;
1026                goto free_newinfo_counters_untrans;
1027        }
1028
1029        /* You lied! */
1030        if (valid_hooks != t->valid_hooks) {
1031                duprintf("Valid hook crap: %08X vs %08X\n",
1032                         valid_hooks, t->valid_hooks);
1033                ret = -EINVAL;
1034                goto put_module;
1035        }
1036
1037        oldinfo = xt_replace_table(t, num_counters, newinfo, &ret);
1038        if (!oldinfo)
1039                goto put_module;
1040
1041        /* Update module usage count based on number of rules */
1042        duprintf("do_replace: oldnum=%u, initnum=%u, newnum=%u\n",
1043                oldinfo->number, oldinfo->initial_entries, newinfo->number);
1044        if ((oldinfo->number > oldinfo->initial_entries) ||
1045            (newinfo->number <= oldinfo->initial_entries))
1046                module_put(t->me);
1047        if ((oldinfo->number > oldinfo->initial_entries) &&
1048            (newinfo->number <= oldinfo->initial_entries))
1049                module_put(t->me);
1050
1051        /* Get the old counters, and synchronize with replace */
1052        get_counters(oldinfo, counters);
1053
1054        /* Decrease module usage counts and free resource */
1055        loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()];
1056        ARPT_ENTRY_ITERATE(loc_cpu_old_entry, oldinfo->size, cleanup_entry,
1057                           NULL);
1058
1059        xt_free_table_info(oldinfo);
1060        if (copy_to_user(counters_ptr, counters,
1061                         sizeof(struct xt_counters) * num_counters) != 0)
1062                ret = -EFAULT;
1063        vfree(counters);
1064        xt_table_unlock(t);
1065        return ret;
1066
1067 put_module:
1068        module_put(t->me);
1069        xt_table_unlock(t);
1070 free_newinfo_counters_untrans:
1071        vfree(counters);
1072 out:
1073        return ret;
1074}
1075
1076static int do_replace(struct net *net, void __user *user, unsigned int len)
1077{
1078        int ret;
1079        struct arpt_replace tmp;
1080        struct xt_table_info *newinfo;
1081        void *loc_cpu_entry;
1082
1083        if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1084                return -EFAULT;
1085
1086        /* overflow check */
1087        if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
1088                return -ENOMEM;
1089
1090        newinfo = xt_alloc_table_info(tmp.size);
1091        if (!newinfo)
1092                return -ENOMEM;
1093
1094        /* choose the copy that is on our node/cpu */
1095        loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
1096        if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),
1097                           tmp.size) != 0) {
1098                ret = -EFAULT;
1099                goto free_newinfo;
1100        }
1101
1102        ret = translate_table(tmp.name, tmp.valid_hooks,
1103                              newinfo, loc_cpu_entry, tmp.size, tmp.num_entries,
1104                              tmp.hook_entry, tmp.underflow);
1105        if (ret != 0)
1106                goto free_newinfo;
1107
1108        duprintf("arp_tables: Translated table\n");
1109
1110        ret = __do_replace(net, tmp.name, tmp.valid_hooks, newinfo,
1111                           tmp.num_counters, tmp.counters);
1112        if (ret)
1113                goto free_newinfo_untrans;
1114        return 0;
1115
1116 free_newinfo_untrans:
1117        ARPT_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry, NULL);
1118 free_newinfo:
1119        xt_free_table_info(newinfo);
1120        return ret;
1121}
1122
1123/* We're lazy, and add to the first CPU; overflow works its fey magic
1124 * and everything is OK. */
1125static int
1126add_counter_to_entry(struct arpt_entry *e,
1127                     const struct xt_counters addme[],
1128                     unsigned int *i)
1129{
1130        ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);
1131
1132        (*i)++;
1133        return 0;
1134}
1135
1136static int do_add_counters(struct net *net, void __user *user, unsigned int len,
1137                           int compat)
1138{
1139        unsigned int i, curcpu;
1140        struct xt_counters_info tmp;
1141        struct xt_counters *paddc;
1142        unsigned int num_counters;
1143        const char *name;
1144        int size;
1145        void *ptmp;
1146        struct xt_table *t;
1147        const struct xt_table_info *private;
1148        int ret = 0;
1149        void *loc_cpu_entry;
1150#ifdef CONFIG_COMPAT
1151        struct compat_xt_counters_info compat_tmp;
1152
1153        if (compat) {
1154                ptmp = &compat_tmp;
1155                size = sizeof(struct compat_xt_counters_info);
1156        } else
1157#endif
1158        {
1159                ptmp = &tmp;
1160                size = sizeof(struct xt_counters_info);
1161        }
1162
1163        if (copy_from_user(ptmp, user, size) != 0)
1164                return -EFAULT;
1165
1166#ifdef CONFIG_COMPAT
1167        if (compat) {
1168                num_counters = compat_tmp.num_counters;
1169                name = compat_tmp.name;
1170        } else
1171#endif
1172        {
1173                num_counters = tmp.num_counters;
1174                name = tmp.name;
1175        }
1176
1177        if (len != size + num_counters * sizeof(struct xt_counters))
1178                return -EINVAL;
1179
1180        paddc = vmalloc_node(len - size, numa_node_id());
1181        if (!paddc)
1182                return -ENOMEM;
1183
1184        if (copy_from_user(paddc, user + size, len - size) != 0) {
1185                ret = -EFAULT;
1186                goto free;
1187        }
1188
1189        t = xt_find_table_lock(net, NFPROTO_ARP, name);
1190        if (!t || IS_ERR(t)) {
1191                ret = t ? PTR_ERR(t) : -ENOENT;
1192                goto free;
1193        }
1194
1195        local_bh_disable();
1196        private = t->private;
1197        if (private->number != num_counters) {
1198                ret = -EINVAL;
1199                goto unlock_up_free;
1200        }
1201
1202        i = 0;
1203        /* Choose the copy that is on our node */
1204        curcpu = smp_processor_id();
1205        loc_cpu_entry = private->entries[curcpu];
1206        xt_info_wrlock(curcpu);
1207        ARPT_ENTRY_ITERATE(loc_cpu_entry,
1208                           private->size,
1209                           add_counter_to_entry,
1210                           paddc,
1211                           &i);
1212        xt_info_wrunlock(curcpu);
1213 unlock_up_free:
1214        local_bh_enable();
1215        xt_table_unlock(t);
1216        module_put(t->me);
1217 free:
1218        vfree(paddc);
1219
1220        return ret;
1221}
1222
1223#ifdef CONFIG_COMPAT
1224static inline int
1225compat_release_entry(struct compat_arpt_entry *e, unsigned int *i)
1226{
1227        struct arpt_entry_target *t;
1228
1229        if (i && (*i)-- == 0)
1230                return 1;
1231
1232        t = compat_arpt_get_target(e);
1233        module_put(t->u.kernel.target->me);
1234        return 0;
1235}
1236
1237static inline int
1238check_compat_entry_size_and_hooks(struct compat_arpt_entry *e,
1239                                  struct xt_table_info *newinfo,
1240                                  unsigned int *size,
1241                                  unsigned char *base,
1242                                  unsigned char *limit,
1243                                  unsigned int *hook_entries,
1244                                  unsigned int *underflows,
1245                                  unsigned int *i,
1246                                  const char *name)
1247{
1248        struct arpt_entry_target *t;
1249        struct xt_target *target;
1250        unsigned int entry_offset;
1251        int ret, off, h;
1252
1253        duprintf("check_compat_entry_size_and_hooks %p\n", e);
1254        if ((unsigned long)e % __alignof__(struct compat_arpt_entry) != 0
1255            || (unsigned char *)e + sizeof(struct compat_arpt_entry) >= limit) {
1256                duprintf("Bad offset %p, limit = %p\n", e, limit);
1257                return -EINVAL;
1258        }
1259
1260        if (e->next_offset < sizeof(struct compat_arpt_entry) +
1261                             sizeof(struct compat_xt_entry_target)) {
1262                duprintf("checking: element %p size %u\n",
1263                         e, e->next_offset);
1264                return -EINVAL;
1265        }
1266
1267        /* For purposes of check_entry casting the compat entry is fine */
1268        ret = check_entry((struct arpt_entry *)e, name);
1269        if (ret)
1270                return ret;
1271
1272        off = sizeof(struct arpt_entry) - sizeof(struct compat_arpt_entry);
1273        entry_offset = (void *)e - (void *)base;
1274
1275        t = compat_arpt_get_target(e);
1276        target = try_then_request_module(xt_find_target(NFPROTO_ARP,
1277                                                        t->u.user.name,
1278                                                        t->u.user.revision),
1279                                         "arpt_%s", t->u.user.name);
1280        if (IS_ERR(target) || !target) {
1281                duprintf("check_compat_entry_size_and_hooks: `%s' not found\n",
1282                         t->u.user.name);
1283                ret = target ? PTR_ERR(target) : -ENOENT;
1284                goto out;
1285        }
1286        t->u.kernel.target = target;
1287
1288        off += xt_compat_target_offset(target);
1289        *size += off;
1290        ret = xt_compat_add_offset(NFPROTO_ARP, entry_offset, off);
1291        if (ret)
1292                goto release_target;
1293
1294        /* Check hooks & underflows */
1295        for (h = 0; h < NF_ARP_NUMHOOKS; h++) {
1296                if ((unsigned char *)e - base == hook_entries[h])
1297                        newinfo->hook_entry[h] = hook_entries[h];
1298                if ((unsigned char *)e - base == underflows[h])
1299                        newinfo->underflow[h] = underflows[h];
1300        }
1301
1302        /* Clear counters and comefrom */
1303        memset(&e->counters, 0, sizeof(e->counters));
1304        e->comefrom = 0;
1305
1306        (*i)++;
1307        return 0;
1308
1309release_target:
1310        module_put(t->u.kernel.target->me);
1311out:
1312        return ret;
1313}
1314
1315static int
1316compat_copy_entry_from_user(struct compat_arpt_entry *e, void **dstptr,
1317                            unsigned int *size, const char *name,
1318                            struct xt_table_info *newinfo, unsigned char *base)
1319{
1320        struct arpt_entry_target *t;
1321        struct xt_target *target;
1322        struct arpt_entry *de;
1323        unsigned int origsize;
1324        int ret, h;
1325
1326        ret = 0;
1327        origsize = *size;
1328        de = (struct arpt_entry *)*dstptr;
1329        memcpy(de, e, sizeof(struct arpt_entry));
1330        memcpy(&de->counters, &e->counters, sizeof(e->counters));
1331
1332        *dstptr += sizeof(struct arpt_entry);
1333        *size += sizeof(struct arpt_entry) - sizeof(struct compat_arpt_entry);
1334
1335        de->target_offset = e->target_offset - (origsize - *size);
1336        t = compat_arpt_get_target(e);
1337        target = t->u.kernel.target;
1338        xt_compat_target_from_user(t, dstptr, size);
1339
1340        de->next_offset = e->next_offset - (origsize - *size);
1341        for (h = 0; h < NF_ARP_NUMHOOKS; h++) {
1342                if ((unsigned char *)de - base < newinfo->hook_entry[h])
1343                        newinfo->hook_entry[h] -= origsize - *size;
1344                if ((unsigned char *)de - base < newinfo->underflow[h])
1345                        newinfo->underflow[h] -= origsize - *size;
1346        }
1347        return ret;
1348}
1349
1350static inline int compat_check_entry(struct arpt_entry *e, const char *name,
1351                                     unsigned int *i)
1352{
1353        int ret;
1354
1355        ret = check_target(e, name);
1356        if (ret)
1357                return ret;
1358
1359        (*i)++;
1360        return 0;
1361}
1362
1363static int translate_compat_table(const char *name,
1364                                  unsigned int valid_hooks,
1365                                  struct xt_table_info **pinfo,
1366                                  void **pentry0,
1367                                  unsigned int total_size,
1368                                  unsigned int number,
1369                                  unsigned int *hook_entries,
1370                                  unsigned int *underflows)
1371{
1372        unsigned int i, j;
1373        struct xt_table_info *newinfo, *info;
1374        void *pos, *entry0, *entry1;
1375        unsigned int size;
1376        int ret;
1377
1378        info = *pinfo;
1379        entry0 = *pentry0;
1380        size = total_size;
1381        info->number = number;
1382
1383        /* Init all hooks to impossible value. */
1384        for (i = 0; i < NF_ARP_NUMHOOKS; i++) {
1385                info->hook_entry[i] = 0xFFFFFFFF;
1386                info->underflow[i] = 0xFFFFFFFF;
1387        }
1388
1389        duprintf("translate_compat_table: size %u\n", info->size);
1390        j = 0;
1391        xt_compat_lock(NFPROTO_ARP);
1392        /* Walk through entries, checking offsets. */
1393        ret = COMPAT_ARPT_ENTRY_ITERATE(entry0, total_size,
1394                                        check_compat_entry_size_and_hooks,
1395                                        info, &size, entry0,
1396                                        entry0 + total_size,
1397                                        hook_entries, underflows, &j, name);
1398        if (ret != 0)
1399                goto out_unlock;
1400
1401        ret = -EINVAL;
1402        if (j != number) {
1403                duprintf("translate_compat_table: %u not %u entries\n",
1404                         j, number);
1405                goto out_unlock;
1406        }
1407
1408        /* Check hooks all assigned */
1409        for (i = 0; i < NF_ARP_NUMHOOKS; i++) {
1410                /* Only hooks which are valid */
1411                if (!(valid_hooks & (1 << i)))
1412                        continue;
1413                if (info->hook_entry[i] == 0xFFFFFFFF) {
1414                        duprintf("Invalid hook entry %u %u\n",
1415                                 i, hook_entries[i]);
1416                        goto out_unlock;
1417                }
1418                if (info->underflow[i] == 0xFFFFFFFF) {
1419                        duprintf("Invalid underflow %u %u\n",
1420                                 i, underflows[i]);
1421                        goto out_unlock;
1422                }
1423        }
1424
1425        ret = -ENOMEM;
1426        newinfo = xt_alloc_table_info(size);
1427        if (!newinfo)
1428                goto out_unlock;
1429
1430        newinfo->number = number;
1431        for (i = 0; i < NF_ARP_NUMHOOKS; i++) {
1432                newinfo->hook_entry[i] = info->hook_entry[i];
1433                newinfo->underflow[i] = info->underflow[i];
1434        }
1435        entry1 = newinfo->entries[raw_smp_processor_id()];
1436        pos = entry1;
1437        size = total_size;
1438        ret = COMPAT_ARPT_ENTRY_ITERATE(entry0, total_size,
1439                                        compat_copy_entry_from_user,
1440                                        &pos, &size, name, newinfo, entry1);
1441        xt_compat_flush_offsets(NFPROTO_ARP);
1442        xt_compat_unlock(NFPROTO_ARP);
1443        if (ret)
1444                goto free_newinfo;
1445
1446        ret = -ELOOP;
1447        if (!mark_source_chains(newinfo, valid_hooks, entry1))
1448                goto free_newinfo;
1449
1450        i = 0;
1451        ret = ARPT_ENTRY_ITERATE(entry1, newinfo->size, compat_check_entry,
1452                                 name, &i);
1453        if (ret) {
1454                j -= i;
1455                COMPAT_ARPT_ENTRY_ITERATE_CONTINUE(entry0, newinfo->size, i,
1456                                                   compat_release_entry, &j);
1457                ARPT_ENTRY_ITERATE(entry1, newinfo->size, cleanup_entry, &i);
1458                xt_free_table_info(newinfo);
1459                return ret;
1460        }
1461
1462        /* And one copy for every other CPU */
1463        for_each_possible_cpu(i)
1464                if (newinfo->entries[i] && newinfo->entries[i] != entry1)
1465                        memcpy(newinfo->entries[i], entry1, newinfo->size);
1466
1467        *pinfo = newinfo;
1468        *pentry0 = entry1;
1469        xt_free_table_info(info);
1470        return 0;
1471
1472free_newinfo:
1473        xt_free_table_info(newinfo);
1474out:
1475        COMPAT_ARPT_ENTRY_ITERATE(entry0, total_size, compat_release_entry, &j);
1476        return ret;
1477out_unlock:
1478        xt_compat_flush_offsets(NFPROTO_ARP);
1479        xt_compat_unlock(NFPROTO_ARP);
1480        goto out;
1481}
1482
1483struct compat_arpt_replace {
1484        char                            name[ARPT_TABLE_MAXNAMELEN];
1485        u32                             valid_hooks;
1486        u32                             num_entries;
1487        u32                             size;
1488        u32                             hook_entry[NF_ARP_NUMHOOKS];
1489        u32                             underflow[NF_ARP_NUMHOOKS];
1490        u32                             num_counters;
1491        compat_uptr_t                   counters;
1492        struct compat_arpt_entry        entries[0];
1493};
1494
1495static int compat_do_replace(struct net *net, void __user *user,
1496                             unsigned int len)
1497{
1498        int ret;
1499        struct compat_arpt_replace tmp;
1500        struct xt_table_info *newinfo;
1501        void *loc_cpu_entry;
1502
1503        if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1504                return -EFAULT;
1505
1506        /* overflow check */
1507        if (tmp.size >= INT_MAX / num_possible_cpus())
1508                return -ENOMEM;
1509        if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
1510                return -ENOMEM;
1511
1512        newinfo = xt_alloc_table_info(tmp.size);
1513        if (!newinfo)
1514                return -ENOMEM;
1515
1516        /* choose the copy that is on our node/cpu */
1517        loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
1518        if (copy_from_user(loc_cpu_entry, user + sizeof(tmp), tmp.size) != 0) {
1519                ret = -EFAULT;
1520                goto free_newinfo;
1521        }
1522
1523        ret = translate_compat_table(tmp.name, tmp.valid_hooks,
1524                                     &newinfo, &loc_cpu_entry, tmp.size,
1525                                     tmp.num_entries, tmp.hook_entry,
1526                                     tmp.underflow);
1527        if (ret != 0)
1528                goto free_newinfo;
1529
1530        duprintf("compat_do_replace: Translated table\n");
1531
1532        ret = __do_replace(net, tmp.name, tmp.valid_hooks, newinfo,
1533                           tmp.num_counters, compat_ptr(tmp.counters));
1534        if (ret)
1535                goto free_newinfo_untrans;
1536        return 0;
1537
1538 free_newinfo_untrans:
1539        ARPT_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry, NULL);
1540 free_newinfo:
1541        xt_free_table_info(newinfo);
1542        return ret;
1543}
1544
1545static int compat_do_arpt_set_ctl(struct sock *sk, int cmd, void __user *user,
1546                                  unsigned int len)
1547{
1548        int ret;
1549
1550        if (!capable(CAP_NET_ADMIN))
1551                return -EPERM;
1552
1553        switch (cmd) {
1554        case ARPT_SO_SET_REPLACE:
1555                ret = compat_do_replace(sock_net(sk), user, len);
1556                break;
1557
1558        case ARPT_SO_SET_ADD_COUNTERS:
1559                ret = do_add_counters(sock_net(sk), user, len, 1);
1560                break;
1561
1562        default:
1563                duprintf("do_arpt_set_ctl:  unknown request %i\n", cmd);
1564                ret = -EINVAL;
1565        }
1566
1567        return ret;
1568}
1569
1570static int compat_copy_entry_to_user(struct arpt_entry *e, void __user **dstptr,
1571                                     compat_uint_t *size,
1572                                     struct xt_counters *counters,
1573                                     unsigned int *i)
1574{
1575        struct arpt_entry_target *t;
1576        struct compat_arpt_entry __user *ce;
1577        u_int16_t target_offset, next_offset;
1578        compat_uint_t origsize;
1579        int ret;
1580
1581        ret = -EFAULT;
1582        origsize = *size;
1583        ce = (struct compat_arpt_entry __user *)*dstptr;
1584        if (copy_to_user(ce, e, sizeof(struct arpt_entry)))
1585                goto out;
1586
1587        if (copy_to_user(&ce->counters, &counters[*i], sizeof(counters[*i])))
1588                goto out;
1589
1590        *dstptr += sizeof(struct compat_arpt_entry);
1591        *size -= sizeof(struct arpt_entry) - sizeof(struct compat_arpt_entry);
1592
1593        target_offset = e->target_offset - (origsize - *size);
1594
1595        t = arpt_get_target(e);
1596        ret = xt_compat_target_to_user(t, dstptr, size);
1597        if (ret)
1598                goto out;
1599        ret = -EFAULT;
1600        next_offset = e->next_offset - (origsize - *size);
1601        if (put_user(target_offset, &ce->target_offset))
1602                goto out;
1603        if (put_user(next_offset, &ce->next_offset))
1604                goto out;
1605
1606        (*i)++;
1607        return 0;
1608out:
1609        return ret;
1610}
1611
1612static int compat_copy_entries_to_user(unsigned int total_size,
1613                                       struct xt_table *table,
1614                                       void __user *userptr)
1615{
1616        struct xt_counters *counters;
1617        const struct xt_table_info *private = table->private;
1618        void __user *pos;
1619        unsigned int size;
1620        int ret = 0;
1621        void *loc_cpu_entry;
1622        unsigned int i = 0;
1623
1624        counters = alloc_counters(table);
1625        if (IS_ERR(counters))
1626                return PTR_ERR(counters);
1627
1628        /* choose the copy on our node/cpu */
1629        loc_cpu_entry = private->entries[raw_smp_processor_id()];
1630        pos = userptr;
1631        size = total_size;
1632        ret = ARPT_ENTRY_ITERATE(loc_cpu_entry, total_size,
1633                                 compat_copy_entry_to_user,
1634                                 &pos, &size, counters, &i);
1635        vfree(counters);
1636        return ret;
1637}
1638
1639struct compat_arpt_get_entries {
1640        char name[ARPT_TABLE_MAXNAMELEN];
1641        compat_uint_t size;
1642        struct compat_arpt_entry entrytable[0];
1643};
1644
1645static int compat_get_entries(struct net *net,
1646                              struct compat_arpt_get_entries __user *uptr,
1647                              int *len)
1648{
1649        int ret;
1650        struct compat_arpt_get_entries get;
1651        struct xt_table *t;
1652
1653        if (*len < sizeof(get)) {
1654                duprintf("compat_get_entries: %u < %zu\n", *len, sizeof(get));
1655                return -EINVAL;
1656        }
1657        if (copy_from_user(&get, uptr, sizeof(get)) != 0)
1658                return -EFAULT;
1659        if (*len != sizeof(struct compat_arpt_get_entries) + get.size) {
1660                duprintf("compat_get_entries: %u != %zu\n",
1661                         *len, sizeof(get) + get.size);
1662                return -EINVAL;
1663        }
1664
1665        xt_compat_lock(NFPROTO_ARP);
1666        t = xt_find_table_lock(net, NFPROTO_ARP, get.name);
1667        if (t && !IS_ERR(t)) {
1668                const struct xt_table_info *private = t->private;
1669                struct xt_table_info info;
1670
1671                duprintf("t->private->number = %u\n", private->number);
1672                ret = compat_table_info(private, &info);
1673                if (!ret && get.size == info.size) {
1674                        ret = compat_copy_entries_to_user(private->size,
1675                                                          t, uptr->entrytable);
1676                } else if (!ret) {
1677                        duprintf("compat_get_entries: I've got %u not %u!\n",
1678                                 private->size, get.size);
1679                        ret = -EAGAIN;
1680                }
1681                xt_compat_flush_offsets(NFPROTO_ARP);
1682                module_put(t->me);
1683                xt_table_unlock(t);
1684        } else
1685                ret = t ? PTR_ERR(t) : -ENOENT;
1686
1687        xt_compat_unlock(NFPROTO_ARP);
1688        return ret;
1689}
1690
1691static int do_arpt_get_ctl(struct sock *, int, void __user *, int *);
1692
1693static int compat_do_arpt_get_ctl(struct sock *sk, int cmd, void __user *user,
1694                                  int *len)
1695{
1696        int ret;
1697
1698        if (!capable(CAP_NET_ADMIN))
1699                return -EPERM;
1700
1701        switch (cmd) {
1702        case ARPT_SO_GET_INFO:
1703                ret = get_info(sock_net(sk), user, len, 1);
1704                break;
1705        case ARPT_SO_GET_ENTRIES:
1706                ret = compat_get_entries(sock_net(sk), user, len);
1707                break;
1708        default:
1709                ret = do_arpt_get_ctl(sk, cmd, user, len);
1710        }
1711        return ret;
1712}
1713#endif
1714
1715static int do_arpt_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
1716{
1717        int ret;
1718
1719        if (!capable(CAP_NET_ADMIN))
1720                return -EPERM;
1721
1722        switch (cmd) {
1723        case ARPT_SO_SET_REPLACE:
1724                ret = do_replace(sock_net(sk), user, len);
1725                break;
1726
1727        case ARPT_SO_SET_ADD_COUNTERS:
1728                ret = do_add_counters(sock_net(sk), user, len, 0);
1729                break;
1730
1731        default:
1732                duprintf("do_arpt_set_ctl:  unknown request %i\n", cmd);
1733                ret = -EINVAL;
1734        }
1735
1736        return ret;
1737}
1738
1739static int do_arpt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1740{
1741        int ret;
1742
1743        if (!capable(CAP_NET_ADMIN))
1744                return -EPERM;
1745
1746        switch (cmd) {
1747        case ARPT_SO_GET_INFO:
1748                ret = get_info(sock_net(sk), user, len, 0);
1749                break;
1750
1751        case ARPT_SO_GET_ENTRIES:
1752                ret = get_entries(sock_net(sk), user, len);
1753                break;
1754
1755        case ARPT_SO_GET_REVISION_TARGET: {
1756                struct xt_get_revision rev;
1757
1758                if (*len != sizeof(rev)) {
1759                        ret = -EINVAL;
1760                        break;
1761                }
1762                if (copy_from_user(&rev, user, sizeof(rev)) != 0) {
1763                        ret = -EFAULT;
1764                        break;
1765                }
1766
1767                try_then_request_module(xt_find_revision(NFPROTO_ARP, rev.name,
1768                                                         rev.revision, 1, &ret),
1769                                        "arpt_%s", rev.name);
1770                break;
1771        }
1772
1773        default:
1774                duprintf("do_arpt_get_ctl: unknown request %i\n", cmd);
1775                ret = -EINVAL;
1776        }
1777
1778        return ret;
1779}
1780
1781struct xt_table *arpt_register_table(struct net *net,
1782                                     const struct xt_table *table,
1783                                     const struct arpt_replace *repl)
1784{
1785        int ret;
1786        struct xt_table_info *newinfo;
1787        struct xt_table_info bootstrap
1788                = { 0, 0, 0, { 0 }, { 0 }, { } };
1789        void *loc_cpu_entry;
1790        struct xt_table *new_table;
1791
1792        newinfo = xt_alloc_table_info(repl->size);
1793        if (!newinfo) {
1794                ret = -ENOMEM;
1795                goto out;
1796        }
1797
1798        /* choose the copy on our node/cpu */
1799        loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
1800        memcpy(loc_cpu_entry, repl->entries, repl->size);
1801
1802        ret = translate_table(table->name, table->valid_hooks,
1803                              newinfo, loc_cpu_entry, repl->size,
1804                              repl->num_entries,
1805                              repl->hook_entry,
1806                              repl->underflow);
1807
1808        duprintf("arpt_register_table: translate table gives %d\n", ret);
1809        if (ret != 0)
1810                goto out_free;
1811
1812        new_table = xt_register_table(net, table, &bootstrap, newinfo);
1813        if (IS_ERR(new_table)) {
1814                ret = PTR_ERR(new_table);
1815                goto out_free;
1816        }
1817        return new_table;
1818
1819out_free:
1820        xt_free_table_info(newinfo);
1821out:
1822        return ERR_PTR(ret);
1823}
1824
1825void arpt_unregister_table(struct xt_table *table)
1826{
1827        struct xt_table_info *private;
1828        void *loc_cpu_entry;
1829        struct module *table_owner = table->me;
1830
1831        private = xt_unregister_table(table);
1832
1833        /* Decrease module usage counts and free resources */
1834        loc_cpu_entry = private->entries[raw_smp_processor_id()];
1835        ARPT_ENTRY_ITERATE(loc_cpu_entry, private->size,
1836                           cleanup_entry, NULL);
1837        if (private->number > private->initial_entries)
1838                module_put(table_owner);
1839        xt_free_table_info(private);
1840}
1841
1842/* The built-in targets: standard (NULL) and error. */
1843static struct xt_target arpt_standard_target __read_mostly = {
1844        .name           = ARPT_STANDARD_TARGET,
1845        .targetsize     = sizeof(int),
1846        .family         = NFPROTO_ARP,
1847#ifdef CONFIG_COMPAT
1848        .compatsize     = sizeof(compat_int_t),
1849        .compat_from_user = compat_standard_from_user,
1850        .compat_to_user = compat_standard_to_user,
1851#endif
1852};
1853
1854static struct xt_target arpt_error_target __read_mostly = {
1855        .name           = ARPT_ERROR_TARGET,
1856        .target         = arpt_error,
1857        .targetsize     = ARPT_FUNCTION_MAXNAMELEN,
1858        .family         = NFPROTO_ARP,
1859};
1860
1861static struct nf_sockopt_ops arpt_sockopts = {
1862        .pf             = PF_INET,
1863        .set_optmin     = ARPT_BASE_CTL,
1864        .set_optmax     = ARPT_SO_SET_MAX+1,
1865        .set            = do_arpt_set_ctl,
1866#ifdef CONFIG_COMPAT
1867        .compat_set     = compat_do_arpt_set_ctl,
1868#endif
1869        .get_optmin     = ARPT_BASE_CTL,
1870        .get_optmax     = ARPT_SO_GET_MAX+1,
1871        .get            = do_arpt_get_ctl,
1872#ifdef CONFIG_COMPAT
1873        .compat_get     = compat_do_arpt_get_ctl,
1874#endif
1875        .owner          = THIS_MODULE,
1876};
1877
1878static int __net_init arp_tables_net_init(struct net *net)
1879{
1880        return xt_proto_init(net, NFPROTO_ARP);
1881}
1882
1883static void __net_exit arp_tables_net_exit(struct net *net)
1884{
1885        xt_proto_fini(net, NFPROTO_ARP);
1886}
1887
1888static struct pernet_operations arp_tables_net_ops = {
1889        .init = arp_tables_net_init,
1890        .exit = arp_tables_net_exit,
1891};
1892
1893static int __init arp_tables_init(void)
1894{
1895        int ret;
1896
1897        ret = register_pernet_subsys(&arp_tables_net_ops);
1898        if (ret < 0)
1899                goto err1;
1900
1901        /* Noone else will be downing sem now, so we won't sleep */
1902        ret = xt_register_target(&arpt_standard_target);
1903        if (ret < 0)
1904                goto err2;
1905        ret = xt_register_target(&arpt_error_target);
1906        if (ret < 0)
1907                goto err3;
1908
1909        /* Register setsockopt */
1910        ret = nf_register_sockopt(&arpt_sockopts);
1911        if (ret < 0)
1912                goto err4;
1913
1914        printk(KERN_INFO "arp_tables: (C) 2002 David S. Miller\n");
1915        return 0;
1916
1917err4:
1918        xt_unregister_target(&arpt_error_target);
1919err3:
1920        xt_unregister_target(&arpt_standard_target);
1921err2:
1922        unregister_pernet_subsys(&arp_tables_net_ops);
1923err1:
1924        return ret;
1925}
1926
1927static void __exit arp_tables_fini(void)
1928{
1929        nf_unregister_sockopt(&arpt_sockopts);
1930        xt_unregister_target(&arpt_error_target);
1931        xt_unregister_target(&arpt_standard_target);
1932        unregister_pernet_subsys(&arp_tables_net_ops);
1933}
1934
1935EXPORT_SYMBOL(arpt_register_table);
1936EXPORT_SYMBOL(arpt_unregister_table);
1937EXPORT_SYMBOL(arpt_do_table);
1938
1939module_init(arp_tables_init);
1940module_exit(arp_tables_fini);
1941