diff options
author | Thomas Graf <tgraf@suug.ch> | 2013-03-21 03:45:28 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-03-22 10:31:16 -0400 |
commit | 58d7d8f9b20ee6f883532b952f246e4289fe06eb (patch) | |
tree | 9d57be6839dd056ab37a63043ae871d36e0cf548 | |
parent | 9b924dbd5e903aa6394ff6feee8275b9bde313d1 (diff) |
decnet: Parse netlink attributes on our own
decnet is the only subsystem left that is relying on the global
netlink attribute buffer rta_buf. It's horrible design and we
want to get rid of it.
This converts all of decnet to do implicit attribute parsing. It
also gets rid of the error prone struct dn_kern_rta.
Yes, the fib_magic() stuff is not pretty.
It's compiled tested but I need someone with appropriate hardware
to test the patch since I don't have access to it.
Cc: linux-decnet-user@lists.sourceforge.net
Signed-off-by: Thomas Graf <tgraf@suug.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/net/dn_fib.h | 28 | ||||
-rw-r--r-- | net/decnet/dn_fib.c | 211 | ||||
-rw-r--r-- | net/decnet/dn_route.c | 27 | ||||
-rw-r--r-- | net/decnet/dn_table.c | 42 |
4 files changed, 160 insertions, 148 deletions
diff --git a/include/net/dn_fib.h b/include/net/dn_fib.h index 1ee9d4bda30d..74004af31c48 100644 --- a/include/net/dn_fib.h +++ b/include/net/dn_fib.h | |||
@@ -1,24 +1,9 @@ | |||
1 | #ifndef _NET_DN_FIB_H | 1 | #ifndef _NET_DN_FIB_H |
2 | #define _NET_DN_FIB_H | 2 | #define _NET_DN_FIB_H |
3 | 3 | ||
4 | /* WARNING: The ordering of these elements must match ordering | 4 | #include <linux/netlink.h> |
5 | * of RTA_* rtnetlink attribute numbers. | 5 | |
6 | */ | 6 | extern const struct nla_policy rtm_dn_policy[]; |
7 | struct dn_kern_rta { | ||
8 | void *rta_dst; | ||
9 | void *rta_src; | ||
10 | int *rta_iif; | ||
11 | int *rta_oif; | ||
12 | void *rta_gw; | ||
13 | u32 *rta_priority; | ||
14 | void *rta_prefsrc; | ||
15 | struct rtattr *rta_mx; | ||
16 | struct rtattr *rta_mp; | ||
17 | unsigned char *rta_protoinfo; | ||
18 | u32 *rta_flow; | ||
19 | struct rta_cacheinfo *rta_ci; | ||
20 | struct rta_session *rta_sess; | ||
21 | }; | ||
22 | 7 | ||
23 | struct dn_fib_res { | 8 | struct dn_fib_res { |
24 | struct fib_rule *r; | 9 | struct fib_rule *r; |
@@ -93,10 +78,10 @@ struct dn_fib_table { | |||
93 | u32 n; | 78 | u32 n; |
94 | 79 | ||
95 | int (*insert)(struct dn_fib_table *t, struct rtmsg *r, | 80 | int (*insert)(struct dn_fib_table *t, struct rtmsg *r, |
96 | struct dn_kern_rta *rta, struct nlmsghdr *n, | 81 | struct nlattr *attrs[], struct nlmsghdr *n, |
97 | struct netlink_skb_parms *req); | 82 | struct netlink_skb_parms *req); |
98 | int (*delete)(struct dn_fib_table *t, struct rtmsg *r, | 83 | int (*delete)(struct dn_fib_table *t, struct rtmsg *r, |
99 | struct dn_kern_rta *rta, struct nlmsghdr *n, | 84 | struct nlattr *attrs[], struct nlmsghdr *n, |
100 | struct netlink_skb_parms *req); | 85 | struct netlink_skb_parms *req); |
101 | int (*lookup)(struct dn_fib_table *t, const struct flowidn *fld, | 86 | int (*lookup)(struct dn_fib_table *t, const struct flowidn *fld, |
102 | struct dn_fib_res *res); | 87 | struct dn_fib_res *res); |
@@ -116,13 +101,12 @@ extern void dn_fib_cleanup(void); | |||
116 | extern int dn_fib_ioctl(struct socket *sock, unsigned int cmd, | 101 | extern int dn_fib_ioctl(struct socket *sock, unsigned int cmd, |
117 | unsigned long arg); | 102 | unsigned long arg); |
118 | extern struct dn_fib_info *dn_fib_create_info(const struct rtmsg *r, | 103 | extern struct dn_fib_info *dn_fib_create_info(const struct rtmsg *r, |
119 | struct dn_kern_rta *rta, | 104 | struct nlattr *attrs[], |
120 | const struct nlmsghdr *nlh, int *errp); | 105 | const struct nlmsghdr *nlh, int *errp); |
121 | extern int dn_fib_semantic_match(int type, struct dn_fib_info *fi, | 106 | extern int dn_fib_semantic_match(int type, struct dn_fib_info *fi, |
122 | const struct flowidn *fld, | 107 | const struct flowidn *fld, |
123 | struct dn_fib_res *res); | 108 | struct dn_fib_res *res); |
124 | extern void dn_fib_release_info(struct dn_fib_info *fi); | 109 | extern void dn_fib_release_info(struct dn_fib_info *fi); |
125 | extern __le16 dn_fib_get_attr16(struct rtattr *attr, int attrlen, int type); | ||
126 | extern void dn_fib_flush(void); | 110 | extern void dn_fib_flush(void); |
127 | extern void dn_fib_select_multipath(const struct flowidn *fld, | 111 | extern void dn_fib_select_multipath(const struct flowidn *fld, |
128 | struct dn_fib_res *res); | 112 | struct dn_fib_res *res); |
diff --git a/net/decnet/dn_fib.c b/net/decnet/dn_fib.c index e36614eccc04..42a8048fe725 100644 --- a/net/decnet/dn_fib.c +++ b/net/decnet/dn_fib.c | |||
@@ -145,22 +145,10 @@ static inline struct dn_fib_info *dn_fib_find_info(const struct dn_fib_info *nfi | |||
145 | return NULL; | 145 | return NULL; |
146 | } | 146 | } |
147 | 147 | ||
148 | __le16 dn_fib_get_attr16(struct rtattr *attr, int attrlen, int type) | 148 | static int dn_fib_count_nhs(const struct nlattr *attr) |
149 | { | 149 | { |
150 | while(RTA_OK(attr,attrlen)) { | 150 | struct rtnexthop *nhp = nla_data(attr); |
151 | if (attr->rta_type == type) | 151 | int nhs = 0, nhlen = nla_len(attr); |
152 | return *(__le16*)RTA_DATA(attr); | ||
153 | attr = RTA_NEXT(attr, attrlen); | ||
154 | } | ||
155 | |||
156 | return 0; | ||
157 | } | ||
158 | |||
159 | static int dn_fib_count_nhs(struct rtattr *rta) | ||
160 | { | ||
161 | int nhs = 0; | ||
162 | struct rtnexthop *nhp = RTA_DATA(rta); | ||
163 | int nhlen = RTA_PAYLOAD(rta); | ||
164 | 152 | ||
165 | while(nhlen >= (int)sizeof(struct rtnexthop)) { | 153 | while(nhlen >= (int)sizeof(struct rtnexthop)) { |
166 | if ((nhlen -= nhp->rtnh_len) < 0) | 154 | if ((nhlen -= nhp->rtnh_len) < 0) |
@@ -172,10 +160,11 @@ static int dn_fib_count_nhs(struct rtattr *rta) | |||
172 | return nhs; | 160 | return nhs; |
173 | } | 161 | } |
174 | 162 | ||
175 | static int dn_fib_get_nhs(struct dn_fib_info *fi, const struct rtattr *rta, const struct rtmsg *r) | 163 | static int dn_fib_get_nhs(struct dn_fib_info *fi, const struct nlattr *attr, |
164 | const struct rtmsg *r) | ||
176 | { | 165 | { |
177 | struct rtnexthop *nhp = RTA_DATA(rta); | 166 | struct rtnexthop *nhp = nla_data(attr); |
178 | int nhlen = RTA_PAYLOAD(rta); | 167 | int nhlen = nla_len(attr); |
179 | 168 | ||
180 | change_nexthops(fi) { | 169 | change_nexthops(fi) { |
181 | int attrlen = nhlen - sizeof(struct rtnexthop); | 170 | int attrlen = nhlen - sizeof(struct rtnexthop); |
@@ -187,7 +176,10 @@ static int dn_fib_get_nhs(struct dn_fib_info *fi, const struct rtattr *rta, cons | |||
187 | nh->nh_weight = nhp->rtnh_hops + 1; | 176 | nh->nh_weight = nhp->rtnh_hops + 1; |
188 | 177 | ||
189 | if (attrlen) { | 178 | if (attrlen) { |
190 | nh->nh_gw = dn_fib_get_attr16(RTNH_DATA(nhp), attrlen, RTA_GATEWAY); | 179 | struct nlattr *gw_attr; |
180 | |||
181 | gw_attr = nla_find((struct nlattr *) (nhp + 1), attrlen, RTA_GATEWAY); | ||
182 | nh->nh_gw = gw_attr ? nla_get_le16(gw_attr) : 0; | ||
191 | } | 183 | } |
192 | nhp = RTNH_NEXT(nhp); | 184 | nhp = RTNH_NEXT(nhp); |
193 | } endfor_nexthops(fi); | 185 | } endfor_nexthops(fi); |
@@ -268,7 +260,8 @@ out: | |||
268 | } | 260 | } |
269 | 261 | ||
270 | 262 | ||
271 | struct dn_fib_info *dn_fib_create_info(const struct rtmsg *r, struct dn_kern_rta *rta, const struct nlmsghdr *nlh, int *errp) | 263 | struct dn_fib_info *dn_fib_create_info(const struct rtmsg *r, struct nlattr *attrs[], |
264 | const struct nlmsghdr *nlh, int *errp) | ||
272 | { | 265 | { |
273 | int err; | 266 | int err; |
274 | struct dn_fib_info *fi = NULL; | 267 | struct dn_fib_info *fi = NULL; |
@@ -281,11 +274,9 @@ struct dn_fib_info *dn_fib_create_info(const struct rtmsg *r, struct dn_kern_rta | |||
281 | if (dn_fib_props[r->rtm_type].scope > r->rtm_scope) | 274 | if (dn_fib_props[r->rtm_type].scope > r->rtm_scope) |
282 | goto err_inval; | 275 | goto err_inval; |
283 | 276 | ||
284 | if (rta->rta_mp) { | 277 | if (attrs[RTA_MULTIPATH] && |
285 | nhs = dn_fib_count_nhs(rta->rta_mp); | 278 | (nhs = dn_fib_count_nhs(attrs[RTA_MULTIPATH])) == 0) |
286 | if (nhs == 0) | 279 | goto err_inval; |
287 | goto err_inval; | ||
288 | } | ||
289 | 280 | ||
290 | fi = kzalloc(sizeof(*fi)+nhs*sizeof(struct dn_fib_nh), GFP_KERNEL); | 281 | fi = kzalloc(sizeof(*fi)+nhs*sizeof(struct dn_fib_nh), GFP_KERNEL); |
291 | err = -ENOBUFS; | 282 | err = -ENOBUFS; |
@@ -295,53 +286,65 @@ struct dn_fib_info *dn_fib_create_info(const struct rtmsg *r, struct dn_kern_rta | |||
295 | fi->fib_protocol = r->rtm_protocol; | 286 | fi->fib_protocol = r->rtm_protocol; |
296 | fi->fib_nhs = nhs; | 287 | fi->fib_nhs = nhs; |
297 | fi->fib_flags = r->rtm_flags; | 288 | fi->fib_flags = r->rtm_flags; |
298 | if (rta->rta_priority) | ||
299 | fi->fib_priority = *rta->rta_priority; | ||
300 | if (rta->rta_mx) { | ||
301 | int attrlen = RTA_PAYLOAD(rta->rta_mx); | ||
302 | struct rtattr *attr = RTA_DATA(rta->rta_mx); | ||
303 | 289 | ||
304 | while(RTA_OK(attr, attrlen)) { | 290 | if (attrs[RTA_PRIORITY]) |
305 | unsigned int flavour = attr->rta_type; | 291 | fi->fib_priority = nla_get_u32(attrs[RTA_PRIORITY]); |
292 | |||
293 | if (attrs[RTA_METRICS]) { | ||
294 | struct nlattr *attr; | ||
295 | int rem; | ||
306 | 296 | ||
307 | if (flavour) { | 297 | nla_for_each_nested(attr, attrs[RTA_METRICS], rem) { |
308 | if (flavour > RTAX_MAX) | 298 | int type = nla_type(attr); |
299 | |||
300 | if (type) { | ||
301 | if (type > RTAX_MAX || nla_len(attr) < 4) | ||
309 | goto err_inval; | 302 | goto err_inval; |
310 | fi->fib_metrics[flavour-1] = *(unsigned int *)RTA_DATA(attr); | 303 | |
304 | fi->fib_metrics[type-1] = nla_get_u32(attr); | ||
311 | } | 305 | } |
312 | attr = RTA_NEXT(attr, attrlen); | ||
313 | } | 306 | } |
314 | } | 307 | } |
315 | if (rta->rta_prefsrc) | ||
316 | memcpy(&fi->fib_prefsrc, rta->rta_prefsrc, 2); | ||
317 | 308 | ||
318 | if (rta->rta_mp) { | 309 | if (attrs[RTA_PREFSRC]) |
319 | if ((err = dn_fib_get_nhs(fi, rta->rta_mp, r)) != 0) | 310 | fi->fib_prefsrc = nla_get_le16(attrs[RTA_PREFSRC]); |
311 | |||
312 | if (attrs[RTA_MULTIPATH]) { | ||
313 | if ((err = dn_fib_get_nhs(fi, attrs[RTA_MULTIPATH], r)) != 0) | ||
320 | goto failure; | 314 | goto failure; |
321 | if (rta->rta_oif && fi->fib_nh->nh_oif != *rta->rta_oif) | 315 | |
316 | if (attrs[RTA_OIF] && | ||
317 | fi->fib_nh->nh_oif != nla_get_u32(attrs[RTA_OIF])) | ||
322 | goto err_inval; | 318 | goto err_inval; |
323 | if (rta->rta_gw && memcmp(&fi->fib_nh->nh_gw, rta->rta_gw, 2)) | 319 | |
320 | if (attrs[RTA_GATEWAY] && | ||
321 | fi->fib_nh->nh_gw != nla_get_le16(attrs[RTA_GATEWAY])) | ||
324 | goto err_inval; | 322 | goto err_inval; |
325 | } else { | 323 | } else { |
326 | struct dn_fib_nh *nh = fi->fib_nh; | 324 | struct dn_fib_nh *nh = fi->fib_nh; |
327 | if (rta->rta_oif) | 325 | |
328 | nh->nh_oif = *rta->rta_oif; | 326 | if (attrs[RTA_OIF]) |
329 | if (rta->rta_gw) | 327 | nh->nh_oif = nla_get_u32(attrs[RTA_OIF]); |
330 | memcpy(&nh->nh_gw, rta->rta_gw, 2); | 328 | |
329 | if (attrs[RTA_GATEWAY]) | ||
330 | nh->nh_gw = nla_get_le16(attrs[RTA_GATEWAY]); | ||
331 | |||
331 | nh->nh_flags = r->rtm_flags; | 332 | nh->nh_flags = r->rtm_flags; |
332 | nh->nh_weight = 1; | 333 | nh->nh_weight = 1; |
333 | } | 334 | } |
334 | 335 | ||
335 | if (r->rtm_type == RTN_NAT) { | 336 | if (r->rtm_type == RTN_NAT) { |
336 | if (rta->rta_gw == NULL || nhs != 1 || rta->rta_oif) | 337 | if (!attrs[RTA_GATEWAY] || nhs != 1 || attrs[RTA_OIF]) |
337 | goto err_inval; | 338 | goto err_inval; |
338 | memcpy(&fi->fib_nh->nh_gw, rta->rta_gw, 2); | 339 | |
340 | fi->fib_nh->nh_gw = nla_get_le16(attrs[RTA_GATEWAY]); | ||
339 | goto link_it; | 341 | goto link_it; |
340 | } | 342 | } |
341 | 343 | ||
342 | if (dn_fib_props[r->rtm_type].error) { | 344 | if (dn_fib_props[r->rtm_type].error) { |
343 | if (rta->rta_gw || rta->rta_oif || rta->rta_mp) | 345 | if (attrs[RTA_GATEWAY] || attrs[RTA_OIF] || attrs[RTA_MULTIPATH]) |
344 | goto err_inval; | 346 | goto err_inval; |
347 | |||
345 | goto link_it; | 348 | goto link_it; |
346 | } | 349 | } |
347 | 350 | ||
@@ -367,8 +370,8 @@ struct dn_fib_info *dn_fib_create_info(const struct rtmsg *r, struct dn_kern_rta | |||
367 | } | 370 | } |
368 | 371 | ||
369 | if (fi->fib_prefsrc) { | 372 | if (fi->fib_prefsrc) { |
370 | if (r->rtm_type != RTN_LOCAL || rta->rta_dst == NULL || | 373 | if (r->rtm_type != RTN_LOCAL || !attrs[RTA_DST] || |
371 | memcmp(&fi->fib_prefsrc, rta->rta_dst, 2)) | 374 | fi->fib_prefsrc != nla_get_le16(attrs[RTA_DST])) |
372 | if (dnet_addr_type(fi->fib_prefsrc) != RTN_LOCAL) | 375 | if (dnet_addr_type(fi->fib_prefsrc) != RTN_LOCAL) |
373 | goto err_inval; | 376 | goto err_inval; |
374 | } | 377 | } |
@@ -486,29 +489,24 @@ void dn_fib_select_multipath(const struct flowidn *fld, struct dn_fib_res *res) | |||
486 | spin_unlock_bh(&dn_fib_multipath_lock); | 489 | spin_unlock_bh(&dn_fib_multipath_lock); |
487 | } | 490 | } |
488 | 491 | ||
492 | const struct nla_policy rtm_dn_policy[RTA_MAX + 1] = { | ||
493 | [RTA_DST] = { .type = NLA_U16 }, | ||
494 | [RTA_SRC] = { .type = NLA_U16 }, | ||
495 | [RTA_IIF] = { .type = NLA_U32 }, | ||
496 | [RTA_OIF] = { .type = NLA_U32 }, | ||
497 | [RTA_GATEWAY] = { .type = NLA_U16 }, | ||
498 | [RTA_PRIORITY] = { .type = NLA_U32 }, | ||
499 | [RTA_PREFSRC] = { .type = NLA_U16 }, | ||
500 | [RTA_METRICS] = { .type = NLA_NESTED }, | ||
501 | [RTA_MULTIPATH] = { .type = NLA_NESTED }, | ||
502 | [RTA_TABLE] = { .type = NLA_U32 }, | ||
503 | [RTA_MARK] = { .type = NLA_U32 }, | ||
504 | }; | ||
489 | 505 | ||
490 | static int dn_fib_check_attr(struct rtmsg *r, struct rtattr **rta) | 506 | static inline u32 rtm_get_table(struct nlattr *attrs[], u8 table) |
491 | { | ||
492 | int i; | ||
493 | |||
494 | for(i = 1; i <= RTA_MAX; i++) { | ||
495 | struct rtattr *attr = rta[i-1]; | ||
496 | if (attr) { | ||
497 | if (RTA_PAYLOAD(attr) < 4 && RTA_PAYLOAD(attr) != 2) | ||
498 | return -EINVAL; | ||
499 | if (i != RTA_MULTIPATH && i != RTA_METRICS && | ||
500 | i != RTA_TABLE) | ||
501 | rta[i-1] = (struct rtattr *)RTA_DATA(attr); | ||
502 | } | ||
503 | } | ||
504 | |||
505 | return 0; | ||
506 | } | ||
507 | |||
508 | static inline u32 rtm_get_table(struct rtattr **rta, u8 table) | ||
509 | { | 507 | { |
510 | if (rta[RTA_TABLE - 1]) | 508 | if (attrs[RTA_TABLE]) |
511 | table = nla_get_u32((struct nlattr *) rta[RTA_TABLE - 1]); | 509 | table = nla_get_u32(attrs[RTA_TABLE]); |
512 | 510 | ||
513 | return table; | 511 | return table; |
514 | } | 512 | } |
@@ -517,8 +515,9 @@ static int dn_fib_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh, void * | |||
517 | { | 515 | { |
518 | struct net *net = sock_net(skb->sk); | 516 | struct net *net = sock_net(skb->sk); |
519 | struct dn_fib_table *tb; | 517 | struct dn_fib_table *tb; |
520 | struct rtattr **rta = arg; | 518 | struct rtmsg *r = nlmsg_data(nlh); |
521 | struct rtmsg *r = NLMSG_DATA(nlh); | 519 | struct nlattr *attrs[RTA_MAX+1]; |
520 | int err; | ||
522 | 521 | ||
523 | if (!capable(CAP_NET_ADMIN)) | 522 | if (!capable(CAP_NET_ADMIN)) |
524 | return -EPERM; | 523 | return -EPERM; |
@@ -526,22 +525,24 @@ static int dn_fib_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh, void * | |||
526 | if (!net_eq(net, &init_net)) | 525 | if (!net_eq(net, &init_net)) |
527 | return -EINVAL; | 526 | return -EINVAL; |
528 | 527 | ||
529 | if (dn_fib_check_attr(r, rta)) | 528 | err = nlmsg_parse(nlh, sizeof(*r), attrs, RTA_MAX, rtm_dn_policy); |
530 | return -EINVAL; | 529 | if (err < 0) |
530 | return err; | ||
531 | 531 | ||
532 | tb = dn_fib_get_table(rtm_get_table(rta, r->rtm_table), 0); | 532 | tb = dn_fib_get_table(rtm_get_table(attrs, r->rtm_table), 0); |
533 | if (tb) | 533 | if (!tb) |
534 | return tb->delete(tb, r, (struct dn_kern_rta *)rta, nlh, &NETLINK_CB(skb)); | 534 | return -ESRCH; |
535 | 535 | ||
536 | return -ESRCH; | 536 | return tb->delete(tb, r, attrs, nlh, &NETLINK_CB(skb)); |
537 | } | 537 | } |
538 | 538 | ||
539 | static int dn_fib_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | 539 | static int dn_fib_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) |
540 | { | 540 | { |
541 | struct net *net = sock_net(skb->sk); | 541 | struct net *net = sock_net(skb->sk); |
542 | struct dn_fib_table *tb; | 542 | struct dn_fib_table *tb; |
543 | struct rtattr **rta = arg; | 543 | struct rtmsg *r = nlmsg_data(nlh); |
544 | struct rtmsg *r = NLMSG_DATA(nlh); | 544 | struct nlattr *attrs[RTA_MAX+1]; |
545 | int err; | ||
545 | 546 | ||
546 | if (!capable(CAP_NET_ADMIN)) | 547 | if (!capable(CAP_NET_ADMIN)) |
547 | return -EPERM; | 548 | return -EPERM; |
@@ -549,14 +550,15 @@ static int dn_fib_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh, void * | |||
549 | if (!net_eq(net, &init_net)) | 550 | if (!net_eq(net, &init_net)) |
550 | return -EINVAL; | 551 | return -EINVAL; |
551 | 552 | ||
552 | if (dn_fib_check_attr(r, rta)) | 553 | err = nlmsg_parse(nlh, sizeof(*r), attrs, RTA_MAX, rtm_dn_policy); |
553 | return -EINVAL; | 554 | if (err < 0) |
555 | return err; | ||
554 | 556 | ||
555 | tb = dn_fib_get_table(rtm_get_table(rta, r->rtm_table), 1); | 557 | tb = dn_fib_get_table(rtm_get_table(attrs, r->rtm_table), 1); |
556 | if (tb) | 558 | if (!tb) |
557 | return tb->insert(tb, r, (struct dn_kern_rta *)rta, nlh, &NETLINK_CB(skb)); | 559 | return -ENOBUFS; |
558 | 560 | ||
559 | return -ENOBUFS; | 561 | return tb->insert(tb, r, attrs, nlh, &NETLINK_CB(skb)); |
560 | } | 562 | } |
561 | 563 | ||
562 | static void fib_magic(int cmd, int type, __le16 dst, int dst_len, struct dn_ifaddr *ifa) | 564 | static void fib_magic(int cmd, int type, __le16 dst, int dst_len, struct dn_ifaddr *ifa) |
@@ -566,10 +568,31 @@ static void fib_magic(int cmd, int type, __le16 dst, int dst_len, struct dn_ifad | |||
566 | struct nlmsghdr nlh; | 568 | struct nlmsghdr nlh; |
567 | struct rtmsg rtm; | 569 | struct rtmsg rtm; |
568 | } req; | 570 | } req; |
569 | struct dn_kern_rta rta; | 571 | struct { |
572 | struct nlattr hdr; | ||
573 | __le16 dst; | ||
574 | } dst_attr = { | ||
575 | .dst = dst, | ||
576 | }; | ||
577 | struct { | ||
578 | struct nlattr hdr; | ||
579 | __le16 prefsrc; | ||
580 | } prefsrc_attr = { | ||
581 | .prefsrc = ifa->ifa_local, | ||
582 | }; | ||
583 | struct { | ||
584 | struct nlattr hdr; | ||
585 | u32 oif; | ||
586 | } oif_attr = { | ||
587 | .oif = ifa->ifa_dev->dev->ifindex, | ||
588 | }; | ||
589 | struct nlattr *attrs[RTA_MAX+1] = { | ||
590 | [RTA_DST] = (struct nlattr *) &dst_attr, | ||
591 | [RTA_PREFSRC] = (struct nlattr * ) &prefsrc_attr, | ||
592 | [RTA_OIF] = (struct nlattr *) &oif_attr, | ||
593 | }; | ||
570 | 594 | ||
571 | memset(&req.rtm, 0, sizeof(req.rtm)); | 595 | memset(&req.rtm, 0, sizeof(req.rtm)); |
572 | memset(&rta, 0, sizeof(rta)); | ||
573 | 596 | ||
574 | if (type == RTN_UNICAST) | 597 | if (type == RTN_UNICAST) |
575 | tb = dn_fib_get_table(RT_MIN_TABLE, 1); | 598 | tb = dn_fib_get_table(RT_MIN_TABLE, 1); |
@@ -591,14 +614,10 @@ static void fib_magic(int cmd, int type, __le16 dst, int dst_len, struct dn_ifad | |||
591 | req.rtm.rtm_scope = (type != RTN_LOCAL ? RT_SCOPE_LINK : RT_SCOPE_HOST); | 614 | req.rtm.rtm_scope = (type != RTN_LOCAL ? RT_SCOPE_LINK : RT_SCOPE_HOST); |
592 | req.rtm.rtm_type = type; | 615 | req.rtm.rtm_type = type; |
593 | 616 | ||
594 | rta.rta_dst = &dst; | ||
595 | rta.rta_prefsrc = &ifa->ifa_local; | ||
596 | rta.rta_oif = &ifa->ifa_dev->dev->ifindex; | ||
597 | |||
598 | if (cmd == RTM_NEWROUTE) | 617 | if (cmd == RTM_NEWROUTE) |
599 | tb->insert(tb, &req.rtm, &rta, &req.nlh, NULL); | 618 | tb->insert(tb, &req.rtm, attrs, &req.nlh, NULL); |
600 | else | 619 | else |
601 | tb->delete(tb, &req.rtm, &rta, &req.nlh, NULL); | 620 | tb->delete(tb, &req.rtm, attrs, &req.nlh, NULL); |
602 | } | 621 | } |
603 | 622 | ||
604 | static void dn_fib_add_ifaddr(struct dn_ifaddr *ifa) | 623 | static void dn_fib_add_ifaddr(struct dn_ifaddr *ifa) |
diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c index 5ac0e153ef83..b4b3508e77f0 100644 --- a/net/decnet/dn_route.c +++ b/net/decnet/dn_route.c | |||
@@ -1619,17 +1619,21 @@ errout: | |||
1619 | static int dn_cache_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh, void *arg) | 1619 | static int dn_cache_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh, void *arg) |
1620 | { | 1620 | { |
1621 | struct net *net = sock_net(in_skb->sk); | 1621 | struct net *net = sock_net(in_skb->sk); |
1622 | struct rtattr **rta = arg; | ||
1623 | struct rtmsg *rtm = nlmsg_data(nlh); | 1622 | struct rtmsg *rtm = nlmsg_data(nlh); |
1624 | struct dn_route *rt = NULL; | 1623 | struct dn_route *rt = NULL; |
1625 | struct dn_skb_cb *cb; | 1624 | struct dn_skb_cb *cb; |
1626 | int err; | 1625 | int err; |
1627 | struct sk_buff *skb; | 1626 | struct sk_buff *skb; |
1628 | struct flowidn fld; | 1627 | struct flowidn fld; |
1628 | struct nlattr *tb[RTA_MAX+1]; | ||
1629 | 1629 | ||
1630 | if (!net_eq(net, &init_net)) | 1630 | if (!net_eq(net, &init_net)) |
1631 | return -EINVAL; | 1631 | return -EINVAL; |
1632 | 1632 | ||
1633 | err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_dn_policy); | ||
1634 | if (err < 0) | ||
1635 | return err; | ||
1636 | |||
1633 | memset(&fld, 0, sizeof(fld)); | 1637 | memset(&fld, 0, sizeof(fld)); |
1634 | fld.flowidn_proto = DNPROTO_NSP; | 1638 | fld.flowidn_proto = DNPROTO_NSP; |
1635 | 1639 | ||
@@ -1639,12 +1643,14 @@ static int dn_cache_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh, void | |||
1639 | skb_reset_mac_header(skb); | 1643 | skb_reset_mac_header(skb); |
1640 | cb = DN_SKB_CB(skb); | 1644 | cb = DN_SKB_CB(skb); |
1641 | 1645 | ||
1642 | if (rta[RTA_SRC-1]) | 1646 | if (tb[RTA_SRC]) |
1643 | memcpy(&fld.saddr, RTA_DATA(rta[RTA_SRC-1]), 2); | 1647 | fld.saddr = nla_get_le16(tb[RTA_SRC]); |
1644 | if (rta[RTA_DST-1]) | 1648 | |
1645 | memcpy(&fld.daddr, RTA_DATA(rta[RTA_DST-1]), 2); | 1649 | if (tb[RTA_DST]) |
1646 | if (rta[RTA_IIF-1]) | 1650 | fld.daddr = nla_get_le16(tb[RTA_DST]); |
1647 | memcpy(&fld.flowidn_iif, RTA_DATA(rta[RTA_IIF-1]), sizeof(int)); | 1651 | |
1652 | if (tb[RTA_IIF]) | ||
1653 | fld.flowidn_iif = nla_get_u32(tb[RTA_IIF]); | ||
1648 | 1654 | ||
1649 | if (fld.flowidn_iif) { | 1655 | if (fld.flowidn_iif) { |
1650 | struct net_device *dev; | 1656 | struct net_device *dev; |
@@ -1669,10 +1675,9 @@ static int dn_cache_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh, void | |||
1669 | if (!err && -rt->dst.error) | 1675 | if (!err && -rt->dst.error) |
1670 | err = rt->dst.error; | 1676 | err = rt->dst.error; |
1671 | } else { | 1677 | } else { |
1672 | int oif = 0; | 1678 | if (tb[RTA_OIF]) |
1673 | if (rta[RTA_OIF - 1]) | 1679 | fld.flowidn_oif = nla_get_u32(tb[RTA_OIF]); |
1674 | memcpy(&oif, RTA_DATA(rta[RTA_OIF - 1]), sizeof(int)); | 1680 | |
1675 | fld.flowidn_oif = oif; | ||
1676 | err = dn_route_output_key((struct dst_entry **)&rt, &fld, 0); | 1681 | err = dn_route_output_key((struct dst_entry **)&rt, &fld, 0); |
1677 | } | 1682 | } |
1678 | 1683 | ||
diff --git a/net/decnet/dn_table.c b/net/decnet/dn_table.c index 6c2445bcaba1..fc42a0afd306 100644 --- a/net/decnet/dn_table.c +++ b/net/decnet/dn_table.c | |||
@@ -224,26 +224,27 @@ static struct dn_zone *dn_new_zone(struct dn_hash *table, int z) | |||
224 | } | 224 | } |
225 | 225 | ||
226 | 226 | ||
227 | static int dn_fib_nh_match(struct rtmsg *r, struct nlmsghdr *nlh, struct dn_kern_rta *rta, struct dn_fib_info *fi) | 227 | static int dn_fib_nh_match(struct rtmsg *r, struct nlmsghdr *nlh, struct nlattr *attrs[], struct dn_fib_info *fi) |
228 | { | 228 | { |
229 | struct rtnexthop *nhp; | 229 | struct rtnexthop *nhp; |
230 | int nhlen; | 230 | int nhlen; |
231 | 231 | ||
232 | if (rta->rta_priority && *rta->rta_priority != fi->fib_priority) | 232 | if (attrs[RTA_PRIORITY] && |
233 | nla_get_u32(attrs[RTA_PRIORITY]) != fi->fib_priority) | ||
233 | return 1; | 234 | return 1; |
234 | 235 | ||
235 | if (rta->rta_oif || rta->rta_gw) { | 236 | if (attrs[RTA_OIF] || attrs[RTA_GATEWAY]) { |
236 | if ((!rta->rta_oif || *rta->rta_oif == fi->fib_nh->nh_oif) && | 237 | if ((!attrs[RTA_OIF] || nla_get_u32(attrs[RTA_OIF]) == fi->fib_nh->nh_oif) && |
237 | (!rta->rta_gw || memcmp(rta->rta_gw, &fi->fib_nh->nh_gw, 2) == 0)) | 238 | (!attrs[RTA_GATEWAY] || nla_get_le16(attrs[RTA_GATEWAY]) != fi->fib_nh->nh_gw)) |
238 | return 0; | 239 | return 0; |
239 | return 1; | 240 | return 1; |
240 | } | 241 | } |
241 | 242 | ||
242 | if (rta->rta_mp == NULL) | 243 | if (!attrs[RTA_MULTIPATH]) |
243 | return 0; | 244 | return 0; |
244 | 245 | ||
245 | nhp = RTA_DATA(rta->rta_mp); | 246 | nhp = nla_data(attrs[RTA_MULTIPATH]); |
246 | nhlen = RTA_PAYLOAD(rta->rta_mp); | 247 | nhlen = nla_len(attrs[RTA_MULTIPATH]); |
247 | 248 | ||
248 | for_nexthops(fi) { | 249 | for_nexthops(fi) { |
249 | int attrlen = nhlen - sizeof(struct rtnexthop); | 250 | int attrlen = nhlen - sizeof(struct rtnexthop); |
@@ -254,7 +255,10 @@ static int dn_fib_nh_match(struct rtmsg *r, struct nlmsghdr *nlh, struct dn_kern | |||
254 | if (nhp->rtnh_ifindex && nhp->rtnh_ifindex != nh->nh_oif) | 255 | if (nhp->rtnh_ifindex && nhp->rtnh_ifindex != nh->nh_oif) |
255 | return 1; | 256 | return 1; |
256 | if (attrlen) { | 257 | if (attrlen) { |
257 | gw = dn_fib_get_attr16(RTNH_DATA(nhp), attrlen, RTA_GATEWAY); | 258 | struct nlattr *gw_attr; |
259 | |||
260 | gw_attr = nla_find((struct nlattr *) (nhp + 1), attrlen, RTA_GATEWAY); | ||
261 | gw = gw_attr ? nla_get_le16(gw_attr) : 0; | ||
258 | 262 | ||
259 | if (gw && gw != nh->nh_gw) | 263 | if (gw && gw != nh->nh_gw) |
260 | return 1; | 264 | return 1; |
@@ -517,7 +521,8 @@ out: | |||
517 | return skb->len; | 521 | return skb->len; |
518 | } | 522 | } |
519 | 523 | ||
520 | static int dn_fib_table_insert(struct dn_fib_table *tb, struct rtmsg *r, struct dn_kern_rta *rta, struct nlmsghdr *n, struct netlink_skb_parms *req) | 524 | static int dn_fib_table_insert(struct dn_fib_table *tb, struct rtmsg *r, struct nlattr *attrs[], |
525 | struct nlmsghdr *n, struct netlink_skb_parms *req) | ||
521 | { | 526 | { |
522 | struct dn_hash *table = (struct dn_hash *)tb->data; | 527 | struct dn_hash *table = (struct dn_hash *)tb->data; |
523 | struct dn_fib_node *new_f, *f, **fp, **del_fp; | 528 | struct dn_fib_node *new_f, *f, **fp, **del_fp; |
@@ -536,15 +541,14 @@ static int dn_fib_table_insert(struct dn_fib_table *tb, struct rtmsg *r, struct | |||
536 | return -ENOBUFS; | 541 | return -ENOBUFS; |
537 | 542 | ||
538 | dz_key_0(key); | 543 | dz_key_0(key); |
539 | if (rta->rta_dst) { | 544 | if (attrs[RTA_DST]) { |
540 | __le16 dst; | 545 | __le16 dst = nla_get_le16(attrs[RTA_DST]); |
541 | memcpy(&dst, rta->rta_dst, 2); | ||
542 | if (dst & ~DZ_MASK(dz)) | 546 | if (dst & ~DZ_MASK(dz)) |
543 | return -EINVAL; | 547 | return -EINVAL; |
544 | key = dz_key(dst, dz); | 548 | key = dz_key(dst, dz); |
545 | } | 549 | } |
546 | 550 | ||
547 | if ((fi = dn_fib_create_info(r, rta, n, &err)) == NULL) | 551 | if ((fi = dn_fib_create_info(r, attrs, n, &err)) == NULL) |
548 | return err; | 552 | return err; |
549 | 553 | ||
550 | if (dz->dz_nent > (dz->dz_divisor << 2) && | 554 | if (dz->dz_nent > (dz->dz_divisor << 2) && |
@@ -654,7 +658,8 @@ out: | |||
654 | } | 658 | } |
655 | 659 | ||
656 | 660 | ||
657 | static int dn_fib_table_delete(struct dn_fib_table *tb, struct rtmsg *r, struct dn_kern_rta *rta, struct nlmsghdr *n, struct netlink_skb_parms *req) | 661 | static int dn_fib_table_delete(struct dn_fib_table *tb, struct rtmsg *r, struct nlattr *attrs[], |
662 | struct nlmsghdr *n, struct netlink_skb_parms *req) | ||
658 | { | 663 | { |
659 | struct dn_hash *table = (struct dn_hash*)tb->data; | 664 | struct dn_hash *table = (struct dn_hash*)tb->data; |
660 | struct dn_fib_node **fp, **del_fp, *f; | 665 | struct dn_fib_node **fp, **del_fp, *f; |
@@ -671,9 +676,8 @@ static int dn_fib_table_delete(struct dn_fib_table *tb, struct rtmsg *r, struct | |||
671 | return -ESRCH; | 676 | return -ESRCH; |
672 | 677 | ||
673 | dz_key_0(key); | 678 | dz_key_0(key); |
674 | if (rta->rta_dst) { | 679 | if (attrs[RTA_DST]) { |
675 | __le16 dst; | 680 | __le16 dst = nla_get_le16(attrs[RTA_DST]); |
676 | memcpy(&dst, rta->rta_dst, 2); | ||
677 | if (dst & ~DZ_MASK(dz)) | 681 | if (dst & ~DZ_MASK(dz)) |
678 | return -EINVAL; | 682 | return -EINVAL; |
679 | key = dz_key(dst, dz); | 683 | key = dz_key(dst, dz); |
@@ -703,7 +707,7 @@ static int dn_fib_table_delete(struct dn_fib_table *tb, struct rtmsg *r, struct | |||
703 | (r->rtm_scope == RT_SCOPE_NOWHERE || f->fn_scope == r->rtm_scope) && | 707 | (r->rtm_scope == RT_SCOPE_NOWHERE || f->fn_scope == r->rtm_scope) && |
704 | (!r->rtm_protocol || | 708 | (!r->rtm_protocol || |
705 | fi->fib_protocol == r->rtm_protocol) && | 709 | fi->fib_protocol == r->rtm_protocol) && |
706 | dn_fib_nh_match(r, n, rta, fi) == 0) | 710 | dn_fib_nh_match(r, n, attrs, fi) == 0) |
707 | del_fp = fp; | 711 | del_fp = fp; |
708 | } | 712 | } |
709 | 713 | ||