summaryrefslogtreecommitdiffstats
path: root/zebra/ioctl.c
diff options
context:
space:
mode:
Diffstat (limited to 'zebra/ioctl.c')
-rw-r--r--zebra/ioctl.c63
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;