diff options
Diffstat (limited to 'zebra/ioctl.c')
-rw-r--r-- | zebra/ioctl.c | 63 |
1 files changed, 58 insertions, 5 deletions
diff --git a/zebra/ioctl.c b/zebra/ioctl.c index d783b0a3..6cb428a7 100644 --- a/zebra/ioctl.c +++ b/zebra/ioctl.c @@ -191,10 +191,16 @@ if_set_prefix (struct interface *ifp, struct connected *ifc) { int ret; struct ifaliasreq addreq; - struct sockaddr_in addr; - struct sockaddr_in mask; + struct sockaddr_in addr, mask, peer; struct prefix_ipv4 *p; + /* don't configure PtP addresses on broadcast ifs or reverse */ + if (!(ifp->flags & IFF_POINTOPOINT) != !CONNECTED_PEER (ifc)) + { + errno = EINVAL; + return -1; + } + p = (struct prefix_ipv4 *) ifc->address; rib_lookup_and_pushup (p); @@ -209,6 +215,18 @@ if_set_prefix (struct interface *ifp, struct connected *ifc) #endif memcpy (&addreq.ifra_addr, &addr, sizeof (struct sockaddr_in)); + if (CONNECTED_PEER (ifc)) + { + p = (struct prefix_ipv4 *) ifc->destination; + memset (&mask, 0, sizeof (struct sockaddr_in)); + peer.sin_addr = p->prefix; + peer.sin_family = p->family; +#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN + peer.sin_len = sizeof (struct sockaddr_in); +#endif + memcpy (&addreq.ifra_broadaddr, &peer, sizeof (struct sockaddr_in)); + } + memset (&mask, 0, sizeof (struct sockaddr_in)); masklen2ip (p->prefixlen, &mask.sin_addr); mask.sin_family = p->family; @@ -216,10 +234,27 @@ if_set_prefix (struct interface *ifp, struct connected *ifc) mask.sin_len = sizeof (struct sockaddr_in); #endif memcpy (&addreq.ifra_mask, &mask, sizeof (struct sockaddr_in)); - + ret = if_ioctl (SIOCAIFADDR, (caddr_t) &addreq); if (ret < 0) return ret; + +#ifdef SIOCSIFADDRPREF + if (ifc->preference != 0) + { + struct if_addrprefreq ifapr; + + memset (&ifapr, 0, sizeof ifapr); + strncpy ((char *)&ifapr.ifap_name, ifp->name, sizeof ifapr.ifap_name); + ifapr.ifap_preference = ifc->preference; + memcpy (&ifapr.ifap_addr, &addr, sizeof (struct sockaddr_in)); + + ret = if_ioctl (SIOCSIFADDRPREF, (caddr_t) &ifapr); + if (ret < 0) + zlog_err("if_ioctl(SIOCSIFADDRPREF) failed: %s", + safe_strerror(errno)); + } +#endif return 0; } @@ -230,10 +265,16 @@ if_unset_prefix (struct interface *ifp, struct connected *ifc) { int ret; struct ifaliasreq addreq; - struct sockaddr_in addr; - struct sockaddr_in mask; + struct sockaddr_in addr, mask, peer; struct prefix_ipv4 *p; + /* this would probably wreak havoc */ + if (!(ifp->flags & IFF_POINTOPOINT) != !CONNECTED_PEER (ifc)) + { + errno = EINVAL; + return -1; + } + p = (struct prefix_ipv4 *)ifc->address; memset (&addreq, 0, sizeof addreq); @@ -247,6 +288,18 @@ if_unset_prefix (struct interface *ifp, struct connected *ifc) #endif memcpy (&addreq.ifra_addr, &addr, sizeof (struct sockaddr_in)); + if (CONNECTED_PEER (ifc)) + { + p = (struct prefix_ipv4 *) ifc->destination; + memset (&mask, 0, sizeof (struct sockaddr_in)); + peer.sin_addr = p->prefix; + peer.sin_family = p->family; +#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN + peer.sin_len = sizeof (struct sockaddr_in); +#endif + memcpy (&addreq.ifra_broadaddr, &peer, sizeof (struct sockaddr_in)); + } + memset (&mask, 0, sizeof (struct sockaddr_in)); masklen2ip (p->prefixlen, &mask.sin_addr); mask.sin_family = p->family; |