From ea79a762886a6b723e70686c5db0ec4d8bf707a6 Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Mon, 12 Nov 2012 23:48:02 +0100 Subject: addr: Support setting local/peer/anycast/multicast/broadcast address to NULL Signed-off-by: Thomas Graf --- lib/route/addr.c | 60 +++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 40 insertions(+), 20 deletions(-) diff --git a/lib/route/addr.c b/lib/route/addr.c index d9c1b50..7e29529 100644 --- a/lib/route/addr.c +++ b/lib/route/addr.c @@ -855,17 +855,25 @@ unsigned int rtnl_addr_get_flags(struct rtnl_addr *addr) static inline int __assign_addr(struct rtnl_addr *addr, struct nl_addr **pos, struct nl_addr *new, int flag) { - if (addr->ce_mask & ADDR_ATTR_FAMILY) { - if (new->a_family != addr->a_family) - return -NLE_AF_MISMATCH; - } else - addr->a_family = new->a_family; - - if (*pos) - nl_addr_put(*pos); - - *pos = nl_addr_get(new); - addr->ce_mask |= (flag | ADDR_ATTR_FAMILY); + if (new) { + if (addr->ce_mask & ADDR_ATTR_FAMILY) { + if (new->a_family != addr->a_family) + return -NLE_AF_MISMATCH; + } else + addr->a_family = new->a_family; + + if (*pos) + nl_addr_put(*pos); + + *pos = nl_addr_get(new); + addr->ce_mask |= (flag | ADDR_ATTR_FAMILY); + } else { + if (*pos) + nl_addr_put(*pos); + + *pos = NULL; + addr->ce_mask &= ~flag; + } return 0; } @@ -874,14 +882,18 @@ int rtnl_addr_set_local(struct rtnl_addr *addr, struct nl_addr *local) { int err; + /* Prohibit local address with prefix length if peer address is present */ + if ((addr->ce_mask & ADDR_ATTR_PEER) && local && + nl_addr_get_prefixlen(local)) + return -NLE_INVAL; + err = __assign_addr(addr, &addr->a_local, local, ADDR_ATTR_LOCAL); if (err < 0) return err; - if (!(addr->ce_mask & ADDR_ATTR_PEER)) { - addr->a_prefixlen = nl_addr_get_prefixlen(addr->a_local); - addr->ce_mask |= ADDR_ATTR_PREFIXLEN; - } + /* Never overwrite the prefix length if a peer address is present */ + if (!(addr->ce_mask & ADDR_ATTR_PEER)) + rtnl_addr_set_prefixlen(addr, local ? nl_addr_get_prefixlen(local) : 0); return 0; } @@ -893,10 +905,18 @@ struct nl_addr *rtnl_addr_get_local(struct rtnl_addr *addr) int rtnl_addr_set_peer(struct rtnl_addr *addr, struct nl_addr *peer) { - if (peer->a_family != AF_INET) + int err; + + if (peer && peer->a_family != AF_INET) return -NLE_AF_NOSUPPORT; - return __assign_addr(addr, &addr->a_peer, peer, ADDR_ATTR_PEER); + err = __assign_addr(addr, &addr->a_peer, peer, ADDR_ATTR_PEER); + if (err < 0) + return err; + + rtnl_addr_set_prefixlen(addr, peer ? nl_addr_get_prefixlen(peer) : 0); + + return 0; } struct nl_addr *rtnl_addr_get_peer(struct rtnl_addr *addr) @@ -906,7 +926,7 @@ struct nl_addr *rtnl_addr_get_peer(struct rtnl_addr *addr) int rtnl_addr_set_broadcast(struct rtnl_addr *addr, struct nl_addr *bcast) { - if (bcast->a_family != AF_INET) + if (bcast && bcast->a_family != AF_INET) return -NLE_AF_NOSUPPORT; return __assign_addr(addr, &addr->a_bcast, bcast, ADDR_ATTR_BROADCAST); @@ -919,7 +939,7 @@ struct nl_addr *rtnl_addr_get_broadcast(struct rtnl_addr *addr) int rtnl_addr_set_multicast(struct rtnl_addr *addr, struct nl_addr *multicast) { - if (multicast->a_family != AF_INET6) + if (multicast && multicast->a_family != AF_INET6) return -NLE_AF_NOSUPPORT; return __assign_addr(addr, &addr->a_multicast, multicast, @@ -933,7 +953,7 @@ struct nl_addr *rtnl_addr_get_multicast(struct rtnl_addr *addr) int rtnl_addr_set_anycast(struct rtnl_addr *addr, struct nl_addr *anycast) { - if (anycast->a_family != AF_INET6) + if (anycast && anycast->a_family != AF_INET6) return -NLE_AF_NOSUPPORT; return __assign_addr(addr, &addr->a_anycast, anycast, -- cgit v1.2.1