|
@@ -44,6 +44,7 @@
|
|
|
#include <net/ip_fib.h>
|
|
|
#include <net/ip_mp_alg.h>
|
|
|
#include <net/netlink.h>
|
|
|
+#include <net/nexthop.h>
|
|
|
|
|
|
#include "fib_lookup.h"
|
|
|
|
|
@@ -273,27 +274,27 @@ int ip_fib_check_default(u32 gw, struct net_device *dev)
|
|
|
}
|
|
|
|
|
|
void rtmsg_fib(int event, u32 key, struct fib_alias *fa,
|
|
|
- int z, u32 tb_id,
|
|
|
- struct nlmsghdr *n, struct netlink_skb_parms *req)
|
|
|
+ int dst_len, u32 tb_id, struct nl_info *info)
|
|
|
{
|
|
|
struct sk_buff *skb;
|
|
|
- u32 pid = req ? req->pid : n->nlmsg_pid;
|
|
|
int payload = sizeof(struct rtmsg) + 256;
|
|
|
+ u32 seq = info->nlh ? info->nlh->nlmsg_seq : 0;
|
|
|
int err = -ENOBUFS;
|
|
|
|
|
|
skb = nlmsg_new(nlmsg_total_size(payload), GFP_KERNEL);
|
|
|
if (skb == NULL)
|
|
|
goto errout;
|
|
|
|
|
|
- err = fib_dump_info(skb, pid, n->nlmsg_seq, event, tb_id,
|
|
|
- fa->fa_type, fa->fa_scope, &key, z, fa->fa_tos,
|
|
|
- fa->fa_info, 0);
|
|
|
+ err = fib_dump_info(skb, info->pid, seq, event, tb_id,
|
|
|
+ fa->fa_type, fa->fa_scope, &key, dst_len,
|
|
|
+ fa->fa_tos, fa->fa_info, 0);
|
|
|
if (err < 0) {
|
|
|
kfree_skb(skb);
|
|
|
goto errout;
|
|
|
}
|
|
|
|
|
|
- err = rtnl_notify(skb, pid, RTNLGRP_IPV4_ROUTE, n, GFP_KERNEL);
|
|
|
+ err = rtnl_notify(skb, info->pid, RTNLGRP_IPV4_ROUTE,
|
|
|
+ info->nlh, GFP_KERNEL);
|
|
|
errout:
|
|
|
if (err < 0)
|
|
|
rtnl_set_sk_err(RTNLGRP_IPV4_ROUTE, err);
|
|
@@ -342,102 +343,100 @@ int fib_detect_death(struct fib_info *fi, int order,
|
|
|
|
|
|
#ifdef CONFIG_IP_ROUTE_MULTIPATH
|
|
|
|
|
|
-static u32 fib_get_attr32(struct rtattr *attr, int attrlen, int type)
|
|
|
-{
|
|
|
- while (RTA_OK(attr,attrlen)) {
|
|
|
- if (attr->rta_type == type)
|
|
|
- return *(u32*)RTA_DATA(attr);
|
|
|
- attr = RTA_NEXT(attr, attrlen);
|
|
|
- }
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-static int
|
|
|
-fib_count_nexthops(struct rtattr *rta)
|
|
|
+static int fib_count_nexthops(struct rtnexthop *rtnh, int remaining)
|
|
|
{
|
|
|
int nhs = 0;
|
|
|
- struct rtnexthop *nhp = RTA_DATA(rta);
|
|
|
- int nhlen = RTA_PAYLOAD(rta);
|
|
|
|
|
|
- while (nhlen >= (int)sizeof(struct rtnexthop)) {
|
|
|
- if ((nhlen -= nhp->rtnh_len) < 0)
|
|
|
- return 0;
|
|
|
+ while (rtnh_ok(rtnh, remaining)) {
|
|
|
nhs++;
|
|
|
- nhp = RTNH_NEXT(nhp);
|
|
|
- };
|
|
|
- return nhs;
|
|
|
+ rtnh = rtnh_next(rtnh, &remaining);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* leftover implies invalid nexthop configuration, discard it */
|
|
|
+ return remaining > 0 ? 0 : nhs;
|
|
|
}
|
|
|
|
|
|
-static int
|
|
|
-fib_get_nhs(struct fib_info *fi, const struct rtattr *rta, const struct rtmsg *r)
|
|
|
+static int fib_get_nhs(struct fib_info *fi, struct rtnexthop *rtnh,
|
|
|
+ int remaining, struct fib_config *cfg)
|
|
|
{
|
|
|
- struct rtnexthop *nhp = RTA_DATA(rta);
|
|
|
- int nhlen = RTA_PAYLOAD(rta);
|
|
|
-
|
|
|
change_nexthops(fi) {
|
|
|
- int attrlen = nhlen - sizeof(struct rtnexthop);
|
|
|
- if (attrlen < 0 || (nhlen -= nhp->rtnh_len) < 0)
|
|
|
+ int attrlen;
|
|
|
+
|
|
|
+ if (!rtnh_ok(rtnh, remaining))
|
|
|
return -EINVAL;
|
|
|
- nh->nh_flags = (r->rtm_flags&~0xFF) | nhp->rtnh_flags;
|
|
|
- nh->nh_oif = nhp->rtnh_ifindex;
|
|
|
- nh->nh_weight = nhp->rtnh_hops + 1;
|
|
|
- if (attrlen) {
|
|
|
- nh->nh_gw = fib_get_attr32(RTNH_DATA(nhp), attrlen, RTA_GATEWAY);
|
|
|
+
|
|
|
+ nh->nh_flags = (cfg->fc_flags & ~0xFF) | rtnh->rtnh_flags;
|
|
|
+ nh->nh_oif = rtnh->rtnh_ifindex;
|
|
|
+ nh->nh_weight = rtnh->rtnh_hops + 1;
|
|
|
+
|
|
|
+ attrlen = rtnh_attrlen(rtnh);
|
|
|
+ if (attrlen > 0) {
|
|
|
+ struct nlattr *nla, *attrs = rtnh_attrs(rtnh);
|
|
|
+
|
|
|
+ nla = nla_find(attrs, attrlen, RTA_GATEWAY);
|
|
|
+ nh->nh_gw = nla ? nla_get_u32(nla) : 0;
|
|
|
#ifdef CONFIG_NET_CLS_ROUTE
|
|
|
- nh->nh_tclassid = fib_get_attr32(RTNH_DATA(nhp), attrlen, RTA_FLOW);
|
|
|
+ nla = nla_find(attrs, attrlen, RTA_FLOW);
|
|
|
+ nh->nh_tclassid = nla ? nla_get_u32(nla) : 0;
|
|
|
#endif
|
|
|
}
|
|
|
- nhp = RTNH_NEXT(nhp);
|
|
|
+
|
|
|
+ rtnh = rtnh_next(rtnh, &remaining);
|
|
|
} endfor_nexthops(fi);
|
|
|
+
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
#endif
|
|
|
|
|
|
-int fib_nh_match(struct rtmsg *r, struct nlmsghdr *nlh, struct kern_rta *rta,
|
|
|
- struct fib_info *fi)
|
|
|
+int fib_nh_match(struct fib_config *cfg, struct fib_info *fi)
|
|
|
{
|
|
|
#ifdef CONFIG_IP_ROUTE_MULTIPATH
|
|
|
- struct rtnexthop *nhp;
|
|
|
- int nhlen;
|
|
|
+ struct rtnexthop *rtnh;
|
|
|
+ int remaining;
|
|
|
#endif
|
|
|
|
|
|
- if (rta->rta_priority &&
|
|
|
- *rta->rta_priority != fi->fib_priority)
|
|
|
+ if (cfg->fc_priority && cfg->fc_priority != fi->fib_priority)
|
|
|
return 1;
|
|
|
|
|
|
- if (rta->rta_oif || rta->rta_gw) {
|
|
|
- if ((!rta->rta_oif || *rta->rta_oif == fi->fib_nh->nh_oif) &&
|
|
|
- (!rta->rta_gw || memcmp(rta->rta_gw, &fi->fib_nh->nh_gw, 4) == 0))
|
|
|
+ if (cfg->fc_oif || cfg->fc_gw) {
|
|
|
+ if ((!cfg->fc_oif || cfg->fc_oif == fi->fib_nh->nh_oif) &&
|
|
|
+ (!cfg->fc_gw || cfg->fc_gw == fi->fib_nh->nh_gw))
|
|
|
return 0;
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
|
#ifdef CONFIG_IP_ROUTE_MULTIPATH
|
|
|
- if (rta->rta_mp == NULL)
|
|
|
+ if (cfg->fc_mp == NULL)
|
|
|
return 0;
|
|
|
- nhp = RTA_DATA(rta->rta_mp);
|
|
|
- nhlen = RTA_PAYLOAD(rta->rta_mp);
|
|
|
+
|
|
|
+ rtnh = cfg->fc_mp;
|
|
|
+ remaining = cfg->fc_mp_len;
|
|
|
|
|
|
for_nexthops(fi) {
|
|
|
- int attrlen = nhlen - sizeof(struct rtnexthop);
|
|
|
- u32 gw;
|
|
|
+ int attrlen;
|
|
|
|
|
|
- if (attrlen < 0 || (nhlen -= nhp->rtnh_len) < 0)
|
|
|
+ if (!rtnh_ok(rtnh, remaining))
|
|
|
return -EINVAL;
|
|
|
- if (nhp->rtnh_ifindex && nhp->rtnh_ifindex != nh->nh_oif)
|
|
|
+
|
|
|
+ if (rtnh->rtnh_ifindex && rtnh->rtnh_ifindex != nh->nh_oif)
|
|
|
return 1;
|
|
|
- if (attrlen) {
|
|
|
- gw = fib_get_attr32(RTNH_DATA(nhp), attrlen, RTA_GATEWAY);
|
|
|
- if (gw && gw != nh->nh_gw)
|
|
|
+
|
|
|
+ attrlen = rtnh_attrlen(rtnh);
|
|
|
+ if (attrlen < 0) {
|
|
|
+ struct nlattr *nla, *attrs = rtnh_attrs(rtnh);
|
|
|
+
|
|
|
+ nla = nla_find(attrs, attrlen, RTA_GATEWAY);
|
|
|
+ if (nla && nla_get_u32(nla) != nh->nh_gw)
|
|
|
return 1;
|
|
|
#ifdef CONFIG_NET_CLS_ROUTE
|
|
|
- gw = fib_get_attr32(RTNH_DATA(nhp), attrlen, RTA_FLOW);
|
|
|
- if (gw && gw != nh->nh_tclassid)
|
|
|
+ nla = nla_find(attrs, attrlen, RTA_FLOW);
|
|
|
+ if (nla && nla_get_u32(nla) != nh->nh_tclassid)
|
|
|
return 1;
|
|
|
#endif
|
|
|
}
|
|
|
- nhp = RTNH_NEXT(nhp);
|
|
|
+
|
|
|
+ rtnh = rtnh_next(rtnh, &remaining);
|
|
|
} endfor_nexthops(fi);
|
|
|
#endif
|
|
|
return 0;
|
|
@@ -488,7 +487,8 @@ int fib_nh_match(struct rtmsg *r, struct nlmsghdr *nlh, struct kern_rta *rta,
|
|
|
|-> {local prefix} (terminal node)
|
|
|
*/
|
|
|
|
|
|
-static int fib_check_nh(const struct rtmsg *r, struct fib_info *fi, struct fib_nh *nh)
|
|
|
+static int fib_check_nh(struct fib_config *cfg, struct fib_info *fi,
|
|
|
+ struct fib_nh *nh)
|
|
|
{
|
|
|
int err;
|
|
|
|
|
@@ -502,7 +502,7 @@ static int fib_check_nh(const struct rtmsg *r, struct fib_info *fi, struct fib_n
|
|
|
if (nh->nh_flags&RTNH_F_ONLINK) {
|
|
|
struct net_device *dev;
|
|
|
|
|
|
- if (r->rtm_scope >= RT_SCOPE_LINK)
|
|
|
+ if (cfg->fc_scope >= RT_SCOPE_LINK)
|
|
|
return -EINVAL;
|
|
|
if (inet_addr_type(nh->nh_gw) != RTN_UNICAST)
|
|
|
return -EINVAL;
|
|
@@ -516,10 +516,15 @@ static int fib_check_nh(const struct rtmsg *r, struct fib_info *fi, struct fib_n
|
|
|
return 0;
|
|
|
}
|
|
|
{
|
|
|
- struct flowi fl = { .nl_u = { .ip4_u =
|
|
|
- { .daddr = nh->nh_gw,
|
|
|
- .scope = r->rtm_scope + 1 } },
|
|
|
- .oif = nh->nh_oif };
|
|
|
+ struct flowi fl = {
|
|
|
+ .nl_u = {
|
|
|
+ .ip4_u = {
|
|
|
+ .daddr = nh->nh_gw,
|
|
|
+ .scope = cfg->fc_scope + 1,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ .oif = nh->nh_oif,
|
|
|
+ };
|
|
|
|
|
|
/* It is not necessary, but requires a bit of thinking */
|
|
|
if (fl.fl4_scope < RT_SCOPE_LINK)
|
|
@@ -646,39 +651,28 @@ static void fib_hash_move(struct hlist_head *new_info_hash,
|
|
|
fib_hash_free(old_laddrhash, bytes);
|
|
|
}
|
|
|
|
|
|
-struct fib_info *
|
|
|
-fib_create_info(const struct rtmsg *r, struct kern_rta *rta,
|
|
|
- const struct nlmsghdr *nlh, int *errp)
|
|
|
+struct fib_info *fib_create_info(struct fib_config *cfg)
|
|
|
{
|
|
|
int err;
|
|
|
struct fib_info *fi = NULL;
|
|
|
struct fib_info *ofi;
|
|
|
-#ifdef CONFIG_IP_ROUTE_MULTIPATH
|
|
|
int nhs = 1;
|
|
|
-#else
|
|
|
- const int nhs = 1;
|
|
|
-#endif
|
|
|
-#ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
|
|
|
- u32 mp_alg = IP_MP_ALG_NONE;
|
|
|
-#endif
|
|
|
|
|
|
/* Fast check to catch the most weird cases */
|
|
|
- if (fib_props[r->rtm_type].scope > r->rtm_scope)
|
|
|
+ if (fib_props[cfg->fc_type].scope > cfg->fc_scope)
|
|
|
goto err_inval;
|
|
|
|
|
|
#ifdef CONFIG_IP_ROUTE_MULTIPATH
|
|
|
- if (rta->rta_mp) {
|
|
|
- nhs = fib_count_nexthops(rta->rta_mp);
|
|
|
+ if (cfg->fc_mp) {
|
|
|
+ nhs = fib_count_nexthops(cfg->fc_mp, cfg->fc_mp_len);
|
|
|
if (nhs == 0)
|
|
|
goto err_inval;
|
|
|
}
|
|
|
#endif
|
|
|
#ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
|
|
|
- if (rta->rta_mp_alg) {
|
|
|
- mp_alg = *rta->rta_mp_alg;
|
|
|
-
|
|
|
- if (mp_alg < IP_MP_ALG_NONE ||
|
|
|
- mp_alg > IP_MP_ALG_MAX)
|
|
|
+ if (cfg->fc_mp_alg) {
|
|
|
+ if (cfg->fc_mp_alg < IP_MP_ALG_NONE ||
|
|
|
+ cfg->fc_mp_alg > IP_MP_ALG_MAX)
|
|
|
goto err_inval;
|
|
|
}
|
|
|
#endif
|
|
@@ -714,43 +708,42 @@ fib_create_info(const struct rtmsg *r, struct kern_rta *rta,
|
|
|
goto failure;
|
|
|
fib_info_cnt++;
|
|
|
|
|
|
- fi->fib_protocol = r->rtm_protocol;
|
|
|
+ fi->fib_protocol = cfg->fc_protocol;
|
|
|
+ fi->fib_flags = cfg->fc_flags;
|
|
|
+ fi->fib_priority = cfg->fc_priority;
|
|
|
+ fi->fib_prefsrc = cfg->fc_prefsrc;
|
|
|
|
|
|
fi->fib_nhs = nhs;
|
|
|
change_nexthops(fi) {
|
|
|
nh->nh_parent = fi;
|
|
|
} endfor_nexthops(fi)
|
|
|
|
|
|
- fi->fib_flags = r->rtm_flags;
|
|
|
- if (rta->rta_priority)
|
|
|
- fi->fib_priority = *rta->rta_priority;
|
|
|
- if (rta->rta_mx) {
|
|
|
- int attrlen = RTA_PAYLOAD(rta->rta_mx);
|
|
|
- struct rtattr *attr = RTA_DATA(rta->rta_mx);
|
|
|
-
|
|
|
- while (RTA_OK(attr, attrlen)) {
|
|
|
- unsigned flavor = attr->rta_type;
|
|
|
- if (flavor) {
|
|
|
- if (flavor > RTAX_MAX)
|
|
|
+ if (cfg->fc_mx) {
|
|
|
+ struct nlattr *nla;
|
|
|
+ int remaining;
|
|
|
+
|
|
|
+ nla_for_each_attr(nla, cfg->fc_mx, cfg->fc_mx_len, remaining) {
|
|
|
+ int type = nla->nla_type;
|
|
|
+
|
|
|
+ if (type) {
|
|
|
+ if (type > RTAX_MAX)
|
|
|
goto err_inval;
|
|
|
- fi->fib_metrics[flavor-1] = *(unsigned*)RTA_DATA(attr);
|
|
|
+ fi->fib_metrics[type - 1] = nla_get_u32(nla);
|
|
|
}
|
|
|
- attr = RTA_NEXT(attr, attrlen);
|
|
|
}
|
|
|
}
|
|
|
- if (rta->rta_prefsrc)
|
|
|
- memcpy(&fi->fib_prefsrc, rta->rta_prefsrc, 4);
|
|
|
|
|
|
- if (rta->rta_mp) {
|
|
|
+ if (cfg->fc_mp) {
|
|
|
#ifdef CONFIG_IP_ROUTE_MULTIPATH
|
|
|
- if ((err = fib_get_nhs(fi, rta->rta_mp, r)) != 0)
|
|
|
+ err = fib_get_nhs(fi, cfg->fc_mp, cfg->fc_mp_len, cfg);
|
|
|
+ if (err != 0)
|
|
|
goto failure;
|
|
|
- if (rta->rta_oif && fi->fib_nh->nh_oif != *rta->rta_oif)
|
|
|
+ if (cfg->fc_oif && fi->fib_nh->nh_oif != cfg->fc_oif)
|
|
|
goto err_inval;
|
|
|
- if (rta->rta_gw && memcmp(&fi->fib_nh->nh_gw, rta->rta_gw, 4))
|
|
|
+ if (cfg->fc_gw && fi->fib_nh->nh_gw != cfg->fc_gw)
|
|
|
goto err_inval;
|
|
|
#ifdef CONFIG_NET_CLS_ROUTE
|
|
|
- if (rta->rta_flow && memcmp(&fi->fib_nh->nh_tclassid, rta->rta_flow, 4))
|
|
|
+ if (cfg->fc_flow && fi->fib_nh->nh_tclassid != cfg->fc_flow)
|
|
|
goto err_inval;
|
|
|
#endif
|
|
|
#else
|
|
@@ -758,34 +751,32 @@ fib_create_info(const struct rtmsg *r, struct kern_rta *rta,
|
|
|
#endif
|
|
|
} else {
|
|
|
struct fib_nh *nh = fi->fib_nh;
|
|
|
- if (rta->rta_oif)
|
|
|
- nh->nh_oif = *rta->rta_oif;
|
|
|
- if (rta->rta_gw)
|
|
|
- memcpy(&nh->nh_gw, rta->rta_gw, 4);
|
|
|
+
|
|
|
+ nh->nh_oif = cfg->fc_oif;
|
|
|
+ nh->nh_gw = cfg->fc_gw;
|
|
|
+ nh->nh_flags = cfg->fc_flags;
|
|
|
#ifdef CONFIG_NET_CLS_ROUTE
|
|
|
- if (rta->rta_flow)
|
|
|
- memcpy(&nh->nh_tclassid, rta->rta_flow, 4);
|
|
|
+ nh->nh_tclassid = cfg->fc_flow;
|
|
|
#endif
|
|
|
- nh->nh_flags = r->rtm_flags;
|
|
|
#ifdef CONFIG_IP_ROUTE_MULTIPATH
|
|
|
nh->nh_weight = 1;
|
|
|
#endif
|
|
|
}
|
|
|
|
|
|
#ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
|
|
|
- fi->fib_mp_alg = mp_alg;
|
|
|
+ fi->fib_mp_alg = cfg->fc_mp_alg;
|
|
|
#endif
|
|
|
|
|
|
- if (fib_props[r->rtm_type].error) {
|
|
|
- if (rta->rta_gw || rta->rta_oif || rta->rta_mp)
|
|
|
+ if (fib_props[cfg->fc_type].error) {
|
|
|
+ if (cfg->fc_gw || cfg->fc_oif || cfg->fc_mp)
|
|
|
goto err_inval;
|
|
|
goto link_it;
|
|
|
}
|
|
|
|
|
|
- if (r->rtm_scope > RT_SCOPE_HOST)
|
|
|
+ if (cfg->fc_scope > RT_SCOPE_HOST)
|
|
|
goto err_inval;
|
|
|
|
|
|
- if (r->rtm_scope == RT_SCOPE_HOST) {
|
|
|
+ if (cfg->fc_scope == RT_SCOPE_HOST) {
|
|
|
struct fib_nh *nh = fi->fib_nh;
|
|
|
|
|
|
/* Local address is added. */
|
|
@@ -798,14 +789,14 @@ fib_create_info(const struct rtmsg *r, struct kern_rta *rta,
|
|
|
goto failure;
|
|
|
} else {
|
|
|
change_nexthops(fi) {
|
|
|
- if ((err = fib_check_nh(r, fi, nh)) != 0)
|
|
|
+ if ((err = fib_check_nh(cfg, fi, nh)) != 0)
|
|
|
goto failure;
|
|
|
} endfor_nexthops(fi)
|
|
|
}
|
|
|
|
|
|
if (fi->fib_prefsrc) {
|
|
|
- if (r->rtm_type != RTN_LOCAL || rta->rta_dst == NULL ||
|
|
|
- memcmp(&fi->fib_prefsrc, rta->rta_dst, 4))
|
|
|
+ if (cfg->fc_type != RTN_LOCAL || !cfg->fc_dst ||
|
|
|
+ fi->fib_prefsrc != cfg->fc_dst)
|
|
|
if (inet_addr_type(fi->fib_prefsrc) != RTN_LOCAL)
|
|
|
goto err_inval;
|
|
|
}
|
|
@@ -846,12 +837,12 @@ err_inval:
|
|
|
err = -EINVAL;
|
|
|
|
|
|
failure:
|
|
|
- *errp = err;
|
|
|
if (fi) {
|
|
|
fi->fib_dead = 1;
|
|
|
free_fib_info(fi);
|
|
|
}
|
|
|
- return NULL;
|
|
|
+
|
|
|
+ return ERR_PTR(err);
|
|
|
}
|
|
|
|
|
|
/* Note! fib_semantic_match intentionally uses RCU list functions. */
|
|
@@ -1012,150 +1003,6 @@ rtattr_failure:
|
|
|
return -1;
|
|
|
}
|
|
|
|
|
|
-#ifndef CONFIG_IP_NOSIOCRT
|
|
|
-
|
|
|
-int
|
|
|
-fib_convert_rtentry(int cmd, struct nlmsghdr *nl, struct rtmsg *rtm,
|
|
|
- struct kern_rta *rta, struct rtentry *r)
|
|
|
-{
|
|
|
- int plen;
|
|
|
- u32 *ptr;
|
|
|
-
|
|
|
- memset(rtm, 0, sizeof(*rtm));
|
|
|
- memset(rta, 0, sizeof(*rta));
|
|
|
-
|
|
|
- if (r->rt_dst.sa_family != AF_INET)
|
|
|
- return -EAFNOSUPPORT;
|
|
|
-
|
|
|
- /* Check mask for validity:
|
|
|
- a) it must be contiguous.
|
|
|
- b) destination must have all host bits clear.
|
|
|
- c) if application forgot to set correct family (AF_INET),
|
|
|
- reject request unless it is absolutely clear i.e.
|
|
|
- both family and mask are zero.
|
|
|
- */
|
|
|
- plen = 32;
|
|
|
- ptr = &((struct sockaddr_in*)&r->rt_dst)->sin_addr.s_addr;
|
|
|
- if (!(r->rt_flags&RTF_HOST)) {
|
|
|
- u32 mask = ((struct sockaddr_in*)&r->rt_genmask)->sin_addr.s_addr;
|
|
|
- if (r->rt_genmask.sa_family != AF_INET) {
|
|
|
- if (mask || r->rt_genmask.sa_family)
|
|
|
- return -EAFNOSUPPORT;
|
|
|
- }
|
|
|
- if (bad_mask(mask, *ptr))
|
|
|
- return -EINVAL;
|
|
|
- plen = inet_mask_len(mask);
|
|
|
- }
|
|
|
-
|
|
|
- nl->nlmsg_flags = NLM_F_REQUEST;
|
|
|
- nl->nlmsg_pid = 0;
|
|
|
- nl->nlmsg_seq = 0;
|
|
|
- nl->nlmsg_len = NLMSG_LENGTH(sizeof(*rtm));
|
|
|
- if (cmd == SIOCDELRT) {
|
|
|
- nl->nlmsg_type = RTM_DELROUTE;
|
|
|
- nl->nlmsg_flags = 0;
|
|
|
- } else {
|
|
|
- nl->nlmsg_type = RTM_NEWROUTE;
|
|
|
- nl->nlmsg_flags = NLM_F_REQUEST|NLM_F_CREATE;
|
|
|
- rtm->rtm_protocol = RTPROT_BOOT;
|
|
|
- }
|
|
|
-
|
|
|
- rtm->rtm_dst_len = plen;
|
|
|
- rta->rta_dst = ptr;
|
|
|
-
|
|
|
- if (r->rt_metric) {
|
|
|
- *(u32*)&r->rt_pad3 = r->rt_metric - 1;
|
|
|
- rta->rta_priority = (u32*)&r->rt_pad3;
|
|
|
- }
|
|
|
- if (r->rt_flags&RTF_REJECT) {
|
|
|
- rtm->rtm_scope = RT_SCOPE_HOST;
|
|
|
- rtm->rtm_type = RTN_UNREACHABLE;
|
|
|
- return 0;
|
|
|
- }
|
|
|
- rtm->rtm_scope = RT_SCOPE_NOWHERE;
|
|
|
- rtm->rtm_type = RTN_UNICAST;
|
|
|
-
|
|
|
- if (r->rt_dev) {
|
|
|
- char *colon;
|
|
|
- struct net_device *dev;
|
|
|
- char devname[IFNAMSIZ];
|
|
|
-
|
|
|
- if (copy_from_user(devname, r->rt_dev, IFNAMSIZ-1))
|
|
|
- return -EFAULT;
|
|
|
- devname[IFNAMSIZ-1] = 0;
|
|
|
- colon = strchr(devname, ':');
|
|
|
- if (colon)
|
|
|
- *colon = 0;
|
|
|
- dev = __dev_get_by_name(devname);
|
|
|
- if (!dev)
|
|
|
- return -ENODEV;
|
|
|
- rta->rta_oif = &dev->ifindex;
|
|
|
- if (colon) {
|
|
|
- struct in_ifaddr *ifa;
|
|
|
- struct in_device *in_dev = __in_dev_get_rtnl(dev);
|
|
|
- if (!in_dev)
|
|
|
- return -ENODEV;
|
|
|
- *colon = ':';
|
|
|
- for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next)
|
|
|
- if (strcmp(ifa->ifa_label, devname) == 0)
|
|
|
- break;
|
|
|
- if (ifa == NULL)
|
|
|
- return -ENODEV;
|
|
|
- rta->rta_prefsrc = &ifa->ifa_local;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- ptr = &((struct sockaddr_in*)&r->rt_gateway)->sin_addr.s_addr;
|
|
|
- if (r->rt_gateway.sa_family == AF_INET && *ptr) {
|
|
|
- rta->rta_gw = ptr;
|
|
|
- if (r->rt_flags&RTF_GATEWAY && inet_addr_type(*ptr) == RTN_UNICAST)
|
|
|
- rtm->rtm_scope = RT_SCOPE_UNIVERSE;
|
|
|
- }
|
|
|
-
|
|
|
- if (cmd == SIOCDELRT)
|
|
|
- return 0;
|
|
|
-
|
|
|
- if (r->rt_flags&RTF_GATEWAY && rta->rta_gw == NULL)
|
|
|
- return -EINVAL;
|
|
|
-
|
|
|
- if (rtm->rtm_scope == RT_SCOPE_NOWHERE)
|
|
|
- rtm->rtm_scope = RT_SCOPE_LINK;
|
|
|
-
|
|
|
- if (r->rt_flags&(RTF_MTU|RTF_WINDOW|RTF_IRTT)) {
|
|
|
- struct rtattr *rec;
|
|
|
- struct rtattr *mx = kmalloc(RTA_LENGTH(3*RTA_LENGTH(4)), GFP_KERNEL);
|
|
|
- if (mx == NULL)
|
|
|
- return -ENOMEM;
|
|
|
- rta->rta_mx = mx;
|
|
|
- mx->rta_type = RTA_METRICS;
|
|
|
- mx->rta_len = RTA_LENGTH(0);
|
|
|
- if (r->rt_flags&RTF_MTU) {
|
|
|
- rec = (void*)((char*)mx + RTA_ALIGN(mx->rta_len));
|
|
|
- rec->rta_type = RTAX_ADVMSS;
|
|
|
- rec->rta_len = RTA_LENGTH(4);
|
|
|
- mx->rta_len += RTA_LENGTH(4);
|
|
|
- *(u32*)RTA_DATA(rec) = r->rt_mtu - 40;
|
|
|
- }
|
|
|
- if (r->rt_flags&RTF_WINDOW) {
|
|
|
- rec = (void*)((char*)mx + RTA_ALIGN(mx->rta_len));
|
|
|
- rec->rta_type = RTAX_WINDOW;
|
|
|
- rec->rta_len = RTA_LENGTH(4);
|
|
|
- mx->rta_len += RTA_LENGTH(4);
|
|
|
- *(u32*)RTA_DATA(rec) = r->rt_window;
|
|
|
- }
|
|
|
- if (r->rt_flags&RTF_IRTT) {
|
|
|
- rec = (void*)((char*)mx + RTA_ALIGN(mx->rta_len));
|
|
|
- rec->rta_type = RTAX_RTT;
|
|
|
- rec->rta_len = RTA_LENGTH(4);
|
|
|
- mx->rta_len += RTA_LENGTH(4);
|
|
|
- *(u32*)RTA_DATA(rec) = r->rt_irtt<<3;
|
|
|
- }
|
|
|
- }
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-#endif
|
|
|
-
|
|
|
/*
|
|
|
Update FIB if:
|
|
|
- local address disappeared -> we must delete all the entries
|