diff options
Diffstat (limited to 'setif.c')
-rw-r--r-- | setif.c | 129 |
1 files changed, 129 insertions, 0 deletions
@@ -0,0 +1,129 @@ +/* + * Copyright 2012 Daniel Drown <dan-android@drown.org> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * setif.c - network interface configuration + */ +#include <errno.h> +#include <netinet/in.h> +#include <net/if.h> + +#include <linux/rtnetlink.h> +#include <netlink/handlers.h> +#include <netlink/msg.h> + +#include "netlink_msg.h" + +/* function: add_address + * adds an IP address to/from an interface, returns 0 on success and <0 on failure + * ifname - name of interface to change + * family - address family (AF_INET, AF_INET6) + * address - pointer to a struct in_addr or in6_addr + * prefixlen - bitlength of network (example: 24 for AF_INET's 255.255.255.0) + * broadcast - broadcast address (only for AF_INET, ignored for AF_INET6) + */ +int add_address(const char *ifname, int family, const void *address, int prefixlen, const void *broadcast) { + int retval; + size_t addr_size; + struct ifaddrmsg ifa; + struct nl_msg *msg = NULL; + + addr_size = inet_family_size(family); + if(addr_size == 0) { + retval = -EAFNOSUPPORT; + goto cleanup; + } + + memset(&ifa, 0, sizeof(ifa)); + if (!(ifa.ifa_index = if_nametoindex(ifname))) { + retval = -ENODEV; + goto cleanup; + } + ifa.ifa_family = family; + ifa.ifa_prefixlen = prefixlen; + ifa.ifa_scope = RT_SCOPE_UNIVERSE; + + msg = nlmsg_alloc_ifaddr(RTM_NEWADDR, NLM_F_ACK | NLM_F_REQUEST | NLM_F_CREATE | NLM_F_REPLACE, &ifa); + if(!msg) { + retval = -ENOMEM; + goto cleanup; + } + + if(nla_put(msg, IFA_LOCAL, addr_size, address) < 0) { + retval = -ENOMEM; + goto cleanup; + } + if(family == AF_INET6) { + // AF_INET6 gets IFA_LOCAL + IFA_ADDRESS + if(nla_put(msg, IFA_ADDRESS, addr_size, address) < 0) { + retval = -ENOMEM; + goto cleanup; + } + } else if(family == AF_INET) { + // AF_INET gets IFA_LOCAL + IFA_BROADCAST + if(nla_put(msg, IFA_BROADCAST, addr_size, broadcast) < 0) { + retval = -ENOMEM; + goto cleanup; + } + } else { + retval = -EAFNOSUPPORT; + goto cleanup; + } + + retval = netlink_sendrecv(msg); + +cleanup: + if(msg) + nlmsg_free(msg); + + return retval; +} + +/* function: if_up + * sets interface link state to up and sets mtu, returns 0 on success and <0 on failure + * ifname - interface name to change + * mtu - new mtu + */ +int if_up(const char *ifname, int mtu) { + int retval = -1; + struct ifinfomsg ifi; + struct nl_msg *msg = NULL; + + memset(&ifi, 0, sizeof(ifi)); + if (!(ifi.ifi_index = if_nametoindex(ifname))) { + retval = -ENODEV; + goto cleanup; + } + ifi.ifi_change = IFF_UP; + ifi.ifi_flags = IFF_UP; + + msg = nlmsg_alloc_ifinfo(RTM_SETLINK, NLM_F_ACK | NLM_F_REQUEST | NLM_F_ROOT, &ifi); + if(!msg) { + retval = -ENOMEM; + goto cleanup; + } + + if(nla_put(msg, IFLA_MTU, 4, &mtu) < 0) { + retval = -ENOMEM; + goto cleanup; + } + + retval = netlink_sendrecv(msg); + +cleanup: + if(msg) + nlmsg_free(msg); + + return retval; +} |