Merge branch 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux-2.6
[linux-2.6] / net / bridge / netfilter / ebt_arp.c
1 /*
2  *  ebt_arp
3  *
4  *      Authors:
5  *      Bart De Schuymer <bdschuym@pandora.be>
6  *      Tim Gardner <timg@tpi.com>
7  *
8  *  April, 2002
9  *
10  */
11
12 #include <linux/netfilter_bridge/ebtables.h>
13 #include <linux/netfilter_bridge/ebt_arp.h>
14 #include <linux/if_arp.h>
15 #include <linux/if_ether.h>
16 #include <linux/module.h>
17
18 static int ebt_filter_arp(const struct sk_buff *skb, const struct net_device *in,
19    const struct net_device *out, const void *data, unsigned int datalen)
20 {
21         struct ebt_arp_info *info = (struct ebt_arp_info *)data;
22         struct arphdr _arph, *ah;
23
24         ah = skb_header_pointer(skb, 0, sizeof(_arph), &_arph);
25         if (ah == NULL)
26                 return EBT_NOMATCH;
27         if (info->bitmask & EBT_ARP_OPCODE && FWINV(info->opcode !=
28            ah->ar_op, EBT_ARP_OPCODE))
29                 return EBT_NOMATCH;
30         if (info->bitmask & EBT_ARP_HTYPE && FWINV(info->htype !=
31            ah->ar_hrd, EBT_ARP_HTYPE))
32                 return EBT_NOMATCH;
33         if (info->bitmask & EBT_ARP_PTYPE && FWINV(info->ptype !=
34            ah->ar_pro, EBT_ARP_PTYPE))
35                 return EBT_NOMATCH;
36
37         if (info->bitmask & (EBT_ARP_SRC_IP | EBT_ARP_DST_IP)) {
38                 uint32_t _addr, *ap;
39
40                 /* IPv4 addresses are always 4 bytes */
41                 if (ah->ar_pln != sizeof(uint32_t))
42                         return EBT_NOMATCH;
43                 if (info->bitmask & EBT_ARP_SRC_IP) {
44                         ap = skb_header_pointer(skb, sizeof(struct arphdr) +
45                                                 ah->ar_hln, sizeof(_addr),
46                                                 &_addr);
47                         if (ap == NULL)
48                                 return EBT_NOMATCH;
49                         if (FWINV(info->saddr != (*ap & info->smsk),
50                            EBT_ARP_SRC_IP))
51                                 return EBT_NOMATCH;
52                 }
53
54                 if (info->bitmask & EBT_ARP_DST_IP) {
55                         ap = skb_header_pointer(skb, sizeof(struct arphdr) +
56                                                 2*ah->ar_hln+sizeof(uint32_t),
57                                                 sizeof(_addr), &_addr);
58                         if (ap == NULL)
59                                 return EBT_NOMATCH;
60                         if (FWINV(info->daddr != (*ap & info->dmsk),
61                            EBT_ARP_DST_IP))
62                                 return EBT_NOMATCH;
63                 }
64         }
65
66         if (info->bitmask & (EBT_ARP_SRC_MAC | EBT_ARP_DST_MAC)) {
67                 unsigned char _mac[ETH_ALEN], *mp;
68                 uint8_t verdict, i;
69
70                 /* MAC addresses are 6 bytes */
71                 if (ah->ar_hln != ETH_ALEN)
72                         return EBT_NOMATCH;
73                 if (info->bitmask & EBT_ARP_SRC_MAC) {
74                         mp = skb_header_pointer(skb, sizeof(struct arphdr),
75                                                 sizeof(_mac), &_mac);
76                         if (mp == NULL)
77                                 return EBT_NOMATCH;
78                         verdict = 0;
79                         for (i = 0; i < 6; i++)
80                                 verdict |= (mp[i] ^ info->smaddr[i]) &
81                                        info->smmsk[i];
82                         if (FWINV(verdict != 0, EBT_ARP_SRC_MAC))
83                                 return EBT_NOMATCH;
84                 }
85
86                 if (info->bitmask & EBT_ARP_DST_MAC) {
87                         mp = skb_header_pointer(skb, sizeof(struct arphdr) +
88                                                 ah->ar_hln + ah->ar_pln,
89                                                 sizeof(_mac), &_mac);
90                         if (mp == NULL)
91                                 return EBT_NOMATCH;
92                         verdict = 0;
93                         for (i = 0; i < 6; i++)
94                                 verdict |= (mp[i] ^ info->dmaddr[i]) &
95                                         info->dmmsk[i];
96                         if (FWINV(verdict != 0, EBT_ARP_DST_MAC))
97                                 return EBT_NOMATCH;
98                 }
99         }
100
101         return EBT_MATCH;
102 }
103
104 static int ebt_arp_check(const char *tablename, unsigned int hookmask,
105    const struct ebt_entry *e, void *data, unsigned int datalen)
106 {
107         struct ebt_arp_info *info = (struct ebt_arp_info *)data;
108
109         if (datalen != EBT_ALIGN(sizeof(struct ebt_arp_info)))
110                 return -EINVAL;
111         if ((e->ethproto != htons(ETH_P_ARP) &&
112            e->ethproto != htons(ETH_P_RARP)) ||
113            e->invflags & EBT_IPROTO)
114                 return -EINVAL;
115         if (info->bitmask & ~EBT_ARP_MASK || info->invflags & ~EBT_ARP_MASK)
116                 return -EINVAL;
117         return 0;
118 }
119
120 static struct ebt_match filter_arp =
121 {
122         .name           = EBT_ARP_MATCH,
123         .match          = ebt_filter_arp,
124         .check          = ebt_arp_check,
125         .me             = THIS_MODULE,
126 };
127
128 static int __init init(void)
129 {
130         return ebt_register_match(&filter_arp);
131 }
132
133 static void __exit fini(void)
134 {
135         ebt_unregister_match(&filter_arp);
136 }
137
138 module_init(init);
139 module_exit(fini);
140 MODULE_LICENSE("GPL");