From bc286c00ea02ab53cc8b6001da79d01735bd9f07 Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Mon, 14 Jul 2008 13:02:27 -0700 Subject: [PATCH] netdev: add ability to set IPv4 addresses and add a default gateway. --- include/netdev.h | 2 ++ lib/netdev.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+) diff --git a/include/netdev.h b/include/netdev.h index 33f549a4..e58a90dd 100644 --- a/include/netdev.h +++ b/include/netdev.h @@ -71,6 +71,8 @@ int netdev_get_mtu(const struct netdev *); int netdev_get_speed(const struct netdev *); uint32_t netdev_get_features(const struct netdev *); bool netdev_get_in4(const struct netdev *, struct in_addr *); +int netdev_set_in4(struct netdev *, struct in_addr addr, struct in_addr mask); +int netdev_add_router(struct netdev *, struct in_addr router); bool netdev_get_in6(const struct netdev *, struct in6_addr *); int netdev_get_flags(const struct netdev *, enum netdev_flags *); int netdev_set_flags(struct netdev *, enum netdev_flags, bool permanent); diff --git a/lib/netdev.c b/lib/netdev.c index b6195940..34c7747d 100644 --- a/lib/netdev.c +++ b/lib/netdev.c @@ -538,6 +538,75 @@ netdev_get_in4(const struct netdev *netdev, struct in_addr *in4) return in4->s_addr != INADDR_ANY; } +static void +make_in4_sockaddr(struct sockaddr *sa, struct in_addr addr) +{ + struct sockaddr_in sin; + memset(&sin, 0, sizeof sin); + sin.sin_family = AF_INET; + sin.sin_addr = addr; + sin.sin_port = 0; + + memset(sa, 0, sizeof *sa); + memcpy(sa, &sin, sizeof sin); +} + +static int +do_set_addr(struct netdev *netdev, int sock, + int ioctl_nr, const char *ioctl_name, struct in_addr addr) +{ + struct ifreq ifr; + int error; + + strncpy(ifr.ifr_name, netdev->name, sizeof ifr.ifr_name); + make_in4_sockaddr(&ifr.ifr_addr, addr); + error = ioctl(sock, ioctl_nr, &ifr) < 0 ? errno : 0; + if (error) { + VLOG_WARN("ioctl(%s): %s", ioctl_name, strerror(error)); + } + return error; +} + +/* Assigns 'addr' as 'netdev''s IPv4 address and 'mask' as its netmask. If + * 'addr' is INADDR_ANY, 'netdev''s IPv4 address is cleared. Returns a + * positive errno value. */ +int +netdev_set_in4(struct netdev *netdev, struct in_addr addr, struct in_addr mask) +{ + int error; + + error = do_set_addr(netdev, af_inet_sock, + SIOCSIFADDR, "SIOCSIFADDR", addr); + if (!error) { + netdev->in4 = addr; + if (addr.s_addr != INADDR_ANY) { + error = do_set_addr(netdev, af_inet_sock, + SIOCSIFNETMASK, "SIOCSIFNETMASK", mask); + } + } + return error; +} + +/* Adds 'router' as a default gateway for 'netdev''s IP address. */ +int +netdev_add_router(struct netdev *netdev, struct in_addr router) +{ + struct in_addr any = { INADDR_ANY }; + struct rtentry rt; + int error; + + memset(&rt, 0, sizeof rt); + make_in4_sockaddr(&rt.rt_dst, any); + make_in4_sockaddr(&rt.rt_gateway, router); + make_in4_sockaddr(&rt.rt_genmask, any); + rt.rt_flags = RTF_UP | RTF_GATEWAY; + error = ioctl(af_inet_sock, SIOCADDRT, &rt) < 0 ? errno : 0; + if (error) { + VLOG_WARN("ioctl(SIOCADDRT): %s", strerror(error)); + } + return error; +} + /* If 'netdev' has an assigned IPv6 address, sets '*in6' to that address and * returns true. Otherwise, returns false. */ bool -- 2.30.2