/* * 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; }