diff options
-rw-r--r-- | net/decnet/dn_rules.c | 20 |
1 files changed, 18 insertions, 2 deletions
diff --git a/net/decnet/dn_rules.c b/net/decnet/dn_rules.c index 50e819edf8c7..63ad63dfd252 100644 --- a/net/decnet/dn_rules.c +++ b/net/decnet/dn_rules.c | |||
@@ -47,6 +47,7 @@ struct dn_fib_rule | |||
47 | u8 flags; | 47 | u8 flags; |
48 | #ifdef CONFIG_DECNET_ROUTE_FWMARK | 48 | #ifdef CONFIG_DECNET_ROUTE_FWMARK |
49 | u32 fwmark; | 49 | u32 fwmark; |
50 | u32 fwmask; | ||
50 | #endif | 51 | #endif |
51 | }; | 52 | }; |
52 | 53 | ||
@@ -116,6 +117,7 @@ static struct nla_policy dn_fib_rule_policy[FRA_MAX+1] __read_mostly = { | |||
116 | [FRA_SRC] = { .type = NLA_U16 }, | 117 | [FRA_SRC] = { .type = NLA_U16 }, |
117 | [FRA_DST] = { .type = NLA_U16 }, | 118 | [FRA_DST] = { .type = NLA_U16 }, |
118 | [FRA_FWMARK] = { .type = NLA_U32 }, | 119 | [FRA_FWMARK] = { .type = NLA_U32 }, |
120 | [FRA_FWMASK] = { .type = NLA_U32 }, | ||
119 | [FRA_TABLE] = { .type = NLA_U32 }, | 121 | [FRA_TABLE] = { .type = NLA_U32 }, |
120 | }; | 122 | }; |
121 | 123 | ||
@@ -130,7 +132,7 @@ static int dn_fib_rule_match(struct fib_rule *rule, struct flowi *fl, int flags) | |||
130 | return 0; | 132 | return 0; |
131 | 133 | ||
132 | #ifdef CONFIG_DECNET_ROUTE_FWMARK | 134 | #ifdef CONFIG_DECNET_ROUTE_FWMARK |
133 | if (r->fwmark && (r->fwmark != fl->fld_fwmark)) | 135 | if ((r->fwmark ^ fl->fld_fwmark) & r->fwmask) |
134 | return 0; | 136 | return 0; |
135 | #endif | 137 | #endif |
136 | 138 | ||
@@ -168,8 +170,17 @@ static int dn_fib_rule_configure(struct fib_rule *rule, struct sk_buff *skb, | |||
168 | r->dst = nla_get_u16(tb[FRA_DST]); | 170 | r->dst = nla_get_u16(tb[FRA_DST]); |
169 | 171 | ||
170 | #ifdef CONFIG_DECNET_ROUTE_FWMARK | 172 | #ifdef CONFIG_DECNET_ROUTE_FWMARK |
171 | if (tb[FRA_FWMARK]) | 173 | if (tb[FRA_FWMARK]) { |
172 | r->fwmark = nla_get_u32(tb[FRA_FWMARK]); | 174 | r->fwmark = nla_get_u32(tb[FRA_FWMARK]); |
175 | if (r->fwmark) | ||
176 | /* compatibility: if the mark value is non-zero all bits | ||
177 | * are compared unless a mask is explicitly specified. | ||
178 | */ | ||
179 | r->fwmask = 0xFFFFFFFF; | ||
180 | } | ||
181 | |||
182 | if (tb[FRA_FWMASK]) | ||
183 | r->fwmask = nla_get_u32(tb[FRA_FWMASK]); | ||
173 | #endif | 184 | #endif |
174 | 185 | ||
175 | r->src_len = frh->src_len; | 186 | r->src_len = frh->src_len; |
@@ -195,6 +206,9 @@ static int dn_fib_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh, | |||
195 | #ifdef CONFIG_DECNET_ROUTE_FWMARK | 206 | #ifdef CONFIG_DECNET_ROUTE_FWMARK |
196 | if (tb[FRA_FWMARK] && (r->fwmark != nla_get_u32(tb[FRA_FWMARK]))) | 207 | if (tb[FRA_FWMARK] && (r->fwmark != nla_get_u32(tb[FRA_FWMARK]))) |
197 | return 0; | 208 | return 0; |
209 | |||
210 | if (tb[FRA_FWMASK] && (r->fwmask != nla_get_u32(tb[FRA_FWMASK]))) | ||
211 | return 0; | ||
198 | #endif | 212 | #endif |
199 | 213 | ||
200 | if (tb[FRA_SRC] && (r->src != nla_get_u16(tb[FRA_SRC]))) | 214 | if (tb[FRA_SRC] && (r->src != nla_get_u16(tb[FRA_SRC]))) |
@@ -237,6 +251,8 @@ static int dn_fib_rule_fill(struct fib_rule *rule, struct sk_buff *skb, | |||
237 | #ifdef CONFIG_DECNET_ROUTE_FWMARK | 251 | #ifdef CONFIG_DECNET_ROUTE_FWMARK |
238 | if (r->fwmark) | 252 | if (r->fwmark) |
239 | NLA_PUT_U32(skb, FRA_FWMARK, r->fwmark); | 253 | NLA_PUT_U32(skb, FRA_FWMARK, r->fwmark); |
254 | if (r->fwmask || r->fwmark) | ||
255 | NLA_PUT_U32(skb, FRA_FWMASK, r->fwmask); | ||
240 | #endif | 256 | #endif |
241 | if (r->dst_len) | 257 | if (r->dst_len) |
242 | NLA_PUT_U16(skb, FRA_DST, r->dst); | 258 | NLA_PUT_U16(skb, FRA_DST, r->dst); |