#define __CONNMAN_INET_H
#include <arpa/inet.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
#include <connman/device.h>
#include <connman/ipconfig.h>
connman_bool_t connman_inet_is_cfg80211(int index);
int connman_inet_set_address(int index, struct connman_ipaddress *ipaddress);
-int connman_inet_clear_address(int index);
+int connman_inet_clear_address(int index, struct connman_ipaddress *ipaddress);
int connman_inet_add_host_route(int index, const char *host, const char *gateway);
int connman_inet_del_host_route(int index, const char *host);
int connman_inet_set_gateway_address(int index, const char *gateway);
#include <connman/inet.h>
+int __connman_inet_modify_address(int cmd, int flags, int index, int family,
+ const char *address,
+ unsigned char prefixlen,
+ const char *broadcast);
+
#include <connman/wifi.h>
#include <connman/rfkill.h>
struct connman_element *parent);
int __connman_ipconfig_set_address(struct connman_ipconfig *ipconfig);
int __connman_ipconfig_clear_address(struct connman_ipconfig *ipconfig);
+unsigned char __connman_ipconfig_netmask_prefix_len(const char *netmask);
int __connman_ipconfig_set_proxy_autoconfig(struct connman_ipconfig *ipconfig,
const char *url);
#include "connman.h"
+#define NLMSG_TAIL(nmsg) \
+ ((struct rtattr *) (((uint8_t*) (nmsg)) + \
+ NLMSG_ALIGN((nmsg)->nlmsg_len)))
+
+static int add_rtattr(struct nlmsghdr *n, size_t max_length, int type,
+ const void *data, size_t data_length)
+{
+ size_t length;
+ struct rtattr *rta;
+
+ length = RTA_LENGTH(data_length);
+
+ if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(length) > max_length)
+ return -E2BIG;
+
+ rta = NLMSG_TAIL(n);
+ rta->rta_type = type;
+ rta->rta_len = length;
+ memcpy(RTA_DATA(rta), data, data_length);
+ n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(length);
+
+ return 0;
+}
+
+int __connman_inet_modify_address(int cmd, int flags,
+ int index, int family,
+ const char *address,
+ unsigned char prefixlen,
+ const char *broadcast)
+{
+ uint8_t request[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
+ NLMSG_ALIGN(sizeof(struct ifaddrmsg)) +
+ RTA_LENGTH(sizeof(struct in6_addr))];
+
+ struct nlmsghdr *header;
+ struct sockaddr_nl nl_addr;
+ struct ifaddrmsg *ifaddrmsg;
+ struct in_addr ipv4_addr, ipv4_bcast;
+ int sk, err;
+
+ DBG("");
+
+ if (address == NULL)
+ return -1;
+
+ memset(&request, 0, sizeof(request));
+
+ header = (struct nlmsghdr *)request;
+ header->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
+ header->nlmsg_type = cmd;
+ header->nlmsg_flags = NLM_F_REQUEST | flags;
+ header->nlmsg_seq = 1;
+
+ ifaddrmsg = NLMSG_DATA(header);
+ ifaddrmsg->ifa_family = family;
+ ifaddrmsg->ifa_prefixlen = prefixlen;
+ ifaddrmsg->ifa_flags = IFA_F_PERMANENT;
+ ifaddrmsg->ifa_scope = RT_SCOPE_UNIVERSE;
+ ifaddrmsg->ifa_index = index;
+
+ if (family == AF_INET) {
+ if (inet_pton(AF_INET, address, &ipv4_addr) < 1)
+ return -1;
+
+ if (broadcast != NULL)
+ inet_pton(AF_INET, broadcast, &ipv4_bcast);
+ else
+ ipv4_bcast.s_addr = ipv4_addr.s_addr |
+ htonl(0xfffffffflu >> prefixlen);
+
+ if ((err = add_rtattr(header, sizeof(request), IFA_LOCAL,
+ &ipv4_addr, sizeof(ipv4_addr))) < 0)
+ return err;
+
+ if ((err = add_rtattr(header, sizeof(request), IFA_BROADCAST,
+ &ipv4_bcast, sizeof(ipv4_bcast))) < 0)
+ return err;
+ } else {
+ return -1;
+ }
+
+ sk = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
+ if (sk < 0)
+ return -1;
+
+ memset(&nl_addr, 0, sizeof(nl_addr));
+ nl_addr.nl_family = AF_NETLINK;
+
+ if ((err = sendto(sk, request, header->nlmsg_len, 0,
+ (struct sockaddr *) &nl_addr, sizeof(nl_addr))) < 0)
+ goto done;
+
+ err = 0;
+
+done:
+ close(sk);
+
+ return err;
+}
+
int connman_inet_ifindex(const char *name)
{
struct ifreq ifr;
int connman_inet_set_address(int index, struct connman_ipaddress *ipaddress)
{
- struct ifreq ifr;
- struct sockaddr_in addr;
- int sk, err;
+ unsigned char prefix_len;
+ const char *address, *broadcast;
- sk = socket(PF_INET, SOCK_DGRAM, 0);
- if (sk < 0)
+ if (ipaddress->local == NULL)
return -1;
- memset(&ifr, 0, sizeof(ifr));
- ifr.ifr_ifindex = index;
-
- if (ioctl(sk, SIOCGIFNAME, &ifr) < 0) {
- close(sk);
- return -1;
- }
+ prefix_len = ipaddress->prefixlen;
+ address = ipaddress->local;
+ broadcast = ipaddress->broadcast;
- DBG("ifname %s", ifr.ifr_name);
+ DBG("index %d address %s prefix_len %d", index, address, prefix_len);
- if (ipaddress->local == NULL) {
- close(sk);
+ if ((__connman_inet_modify_address(RTM_NEWADDR,
+ NLM_F_REPLACE | NLM_F_ACK, index, AF_INET,
+ address, prefix_len, broadcast)) < 0) {
+ DBG("address setting failed");
return -1;
}
- memset(&addr, 0, sizeof(addr));
- addr.sin_family = AF_INET;
- addr.sin_addr.s_addr = inet_addr(ipaddress->local);
- memcpy(&ifr.ifr_addr, &addr, sizeof(ifr.ifr_addr));
-
- err = ioctl(sk, SIOCSIFADDR, &ifr);
-
- if (err < 0)
- DBG("address setting failed (%s)", strerror(errno));
-
- memset(&addr, 0, sizeof(addr));
- addr.sin_family = AF_INET;
- addr.sin_addr.s_addr = htonl(~(0xfffffffflu >> ipaddress->prefixlen));
- memcpy(&ifr.ifr_netmask, &addr, sizeof(ifr.ifr_netmask));
-
- err = ioctl(sk, SIOCSIFNETMASK, &ifr);
-
- if (err < 0)
- DBG("netmask setting failed (%s)", strerror(errno));
-
- memset(&addr, 0, sizeof(addr));
- addr.sin_family = AF_INET;
-
- if (ipaddress->broadcast != NULL)
- addr.sin_addr.s_addr = inet_addr(ipaddress->broadcast);
- else
- addr.sin_addr.s_addr = inet_addr(ipaddress->local) |
- htonl(0xfffffffflu >> ipaddress->prefixlen);
-
- memcpy(&ifr.ifr_broadaddr, &addr, sizeof(ifr.ifr_broadaddr));
-
- err = ioctl(sk, SIOCSIFBRDADDR, &ifr);
-
- if (err < 0)
- DBG("broadcast setting failed (%s)", strerror(errno));
-
- close(sk);
-
return 0;
}
return err;
}
-int connman_inet_clear_address(int index)
+int connman_inet_clear_address(int index, struct connman_ipaddress *ipaddress)
{
+ unsigned char prefix_len;
+ const char *address, *broadcast;
+ prefix_len = ipaddress->prefixlen;
+ address = ipaddress->local;
+ broadcast = ipaddress->broadcast;
- struct ifreq ifr;
- struct sockaddr_in addr;
- int sk, err;
-
- sk = socket(PF_INET, SOCK_DGRAM, 0);
- if (sk < 0)
- return -1;
-
- memset(&ifr, 0, sizeof(ifr));
- ifr.ifr_ifindex = index;
-
- if (ioctl(sk, SIOCGIFNAME, &ifr) < 0) {
- close(sk);
- return -1;
- }
-
- DBG("ifname %s", ifr.ifr_name);
-
- memset(&addr, 0, sizeof(addr));
- addr.sin_family = AF_INET;
- addr.sin_addr.s_addr = INADDR_ANY;
- memcpy(&ifr.ifr_addr, &addr, sizeof(ifr.ifr_addr));
-
- //err = ioctl(sk, SIOCDIFADDR, &ifr);
- err = ioctl(sk, SIOCSIFADDR, &ifr);
-
- close(sk);
+ DBG("index %d address %s prefix_len %d", index, address, prefix_len);
- if (err < 0 && errno != EADDRNOTAVAIL) {
- DBG("address removal failed (%s)", strerror(errno));
+ if ((__connman_inet_modify_address(RTM_DELADDR, 0, index, AF_INET,
+ address, prefix_len, broadcast)) < 0) {
+ DBG("address removal failed");
return -1;
}
g_free(ipaddress);
}
-static unsigned char netmask2prefixlen(const char *netmask)
+unsigned char __connman_ipconfig_netmask_prefix_len(const char *netmask)
{
unsigned char bits = 0;
in_addr_t mask = inet_network(netmask);
return;
if (netmask != NULL)
- ipaddress->prefixlen = netmask2prefixlen(netmask);
+ ipaddress->prefixlen =
+ __connman_ipconfig_netmask_prefix_len(netmask);
else
ipaddress->prefixlen = 32;
connman_ipconfig_unref(ipdevice->driver_config);
ipdevice->driver_config = NULL;
- connman_inet_clear_address(ipdevice->index);
+ connman_inet_clear_address(ipdevice->index, ipdevice->config->address);
connman_inet_clear_ipv6_address(ipdevice->index,
ipdevice->driver_config->address->local,
ipdevice->driver_config->address->prefixlen);
break;
case CONNMAN_IPCONFIG_METHOD_MANUAL:
if (ipconfig->type == CONNMAN_IPCONFIG_TYPE_IPV4)
- return connman_inet_clear_address(ipconfig->index);
+ return connman_inet_clear_address(ipconfig->index,
+ ipconfig->address);
else if (ipconfig->type == CONNMAN_IPCONFIG_TYPE_IPV6)
return connman_inet_clear_ipv6_address(
ipconfig->index,
#include <netinet/in.h>
#include <arpa/inet.h>
#include <net/if.h>
+#include <asm/types.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
#include "connman.h"
-struct connman_ipv4 {
- enum connman_ipconfig_method method;
- struct in_addr address;
- struct in_addr netmask;
- struct in_addr broadcast;
-};
-
-static int set_ipv4(struct connman_element *element, struct connman_ipv4 *ipv4)
-{
- struct ifreq ifr;
- struct sockaddr_in addr;
- int sk, err;
-
- DBG("element %p ipv4 %p", element, ipv4);
-
- sk = socket(PF_INET, SOCK_DGRAM, 0);
- if (sk < 0)
- return -1;
-
- memset(&ifr, 0, sizeof(ifr));
- ifr.ifr_ifindex = element->index;
-
- if (ioctl(sk, SIOCGIFNAME, &ifr) < 0) {
- close(sk);
- return -1;
- }
-
- DBG("ifname %s", ifr.ifr_name);
-
- memset(&addr, 0, sizeof(addr));
- addr.sin_family = AF_INET;
- addr.sin_addr = ipv4->address;
- memcpy(&ifr.ifr_addr, &addr, sizeof(ifr.ifr_addr));
-
- err = ioctl(sk, SIOCSIFADDR, &ifr);
-
- if (err < 0)
- DBG("address setting failed (%s)", strerror(errno));
-
- memset(&addr, 0, sizeof(addr));
- addr.sin_family = AF_INET;
- addr.sin_addr = ipv4->netmask;
- memcpy(&ifr.ifr_netmask, &addr, sizeof(ifr.ifr_netmask));
-
- err = ioctl(sk, SIOCSIFNETMASK, &ifr);
-
- if (err < 0)
- DBG("netmask setting failed (%s)", strerror(errno));
-
- memset(&addr, 0, sizeof(addr));
- addr.sin_family = AF_INET;
- addr.sin_addr = ipv4->broadcast;
- memcpy(&ifr.ifr_broadaddr, &addr, sizeof(ifr.ifr_broadaddr));
-
- err = ioctl(sk, SIOCSIFBRDADDR, &ifr);
-
- if (err < 0)
- DBG("broadcast setting failed (%s)", strerror(errno));
-
- close(sk);
-
- return 0;
-}
-
-static int clear_ipv4(struct connman_element *element)
-{
- struct ifreq ifr;
- struct sockaddr_in addr;
- int sk, err;
-
- DBG("element %p", element);
-
- sk = socket(PF_INET, SOCK_DGRAM, 0);
- if (sk < 0)
- return -1;
-
- memset(&ifr, 0, sizeof(ifr));
- ifr.ifr_ifindex = element->index;
-
- if (ioctl(sk, SIOCGIFNAME, &ifr) < 0) {
- close(sk);
- return -1;
- }
-
- DBG("ifname %s", ifr.ifr_name);
-
- memset(&addr, 0, sizeof(addr));
- addr.sin_family = AF_INET;
- addr.sin_addr.s_addr = INADDR_ANY;
- memcpy(&ifr.ifr_addr, &addr, sizeof(ifr.ifr_addr));
-
- //err = ioctl(sk, SIOCDIFADDR, &ifr);
- err = ioctl(sk, SIOCSIFADDR, &ifr);
-
- close(sk);
-
- if (err < 0 && errno != EADDRNOTAVAIL) {
- DBG("address removal failed (%s)", strerror(errno));
- return -1;
- }
-
- return 0;
-}
-
static char *index2name(int index)
{
struct ifreq ifr;
struct connman_service *service;
struct connman_ipconfig *ipconfig;
struct connman_element *connection;
- struct connman_ipv4 ipv4;
const char *address = NULL, *netmask = NULL, *broadcast = NULL;
const char *nameserver = NULL, *pac = NULL;
char *timeserver = NULL;
+ unsigned char prefixlen;
DBG("element %p name %s", element, element->name);
-
connman_element_get_value(element,
CONNMAN_PROPERTY_ID_IPV4_ADDRESS, &address);
connman_element_get_value(element,
if (address == NULL || netmask == NULL)
return -EINVAL;
- memset(&ipv4, 0, sizeof(ipv4));
- ipv4.address.s_addr = inet_addr(address);
- ipv4.netmask.s_addr = inet_addr(netmask);
- if (broadcast)
- ipv4.broadcast.s_addr = inet_addr(broadcast);
- else
- ipv4.broadcast.s_addr = ipv4.address.s_addr |
- ~ipv4.netmask.s_addr;
+ prefixlen = __connman_ipconfig_netmask_prefix_len(netmask);
- set_ipv4(element, &ipv4);
+ if ((__connman_inet_modify_address(RTM_NEWADDR,
+ NLM_F_REPLACE | NLM_F_ACK, element->index,
+ AF_INET, address, prefixlen, broadcast)) < 0)
+ DBG("address setting failed");
service = __connman_element_get_service(element);
static void ipv4_remove(struct connman_element *element)
{
+ const char *address = NULL, *netmask = NULL, *broadcast = NULL;
const char *nameserver = NULL;
char *timeserver = NULL;
+ unsigned char prefixlen;
DBG("element %p name %s", element, element->name);
connman_element_get_value(element,
+ CONNMAN_PROPERTY_ID_IPV4_ADDRESS, &address);
+ connman_element_get_value(element,
+ CONNMAN_PROPERTY_ID_IPV4_NETMASK, &netmask);
+ connman_element_get_value(element,
+ CONNMAN_PROPERTY_ID_IPV4_BROADCAST, &broadcast);
+
+ connman_element_get_value(element,
CONNMAN_PROPERTY_ID_IPV4_NAMESERVER, &nameserver);
connman_element_get_value(element,
CONNMAN_PROPERTY_ID_IPV4_TIMESERVER, ×erver);
connman_timeserver_remove(timeserver);
+ DBG("address %s", address);
+ DBG("netmask %s", netmask);
+ DBG("broadcast %s", broadcast);
+
if (nameserver != NULL) {
struct connman_service *service;
__connman_service_remove_nameserver(service, nameserver);
}
- clear_ipv4(element);
+ prefixlen = __connman_ipconfig_netmask_prefix_len(netmask);
+
+ if ((__connman_inet_modify_address(RTM_DELADDR, 0, element->index,
+ AF_INET, address, prefixlen, broadcast) < 0))
+ DBG("address removal failed");
}
static struct connman_driver ipv4_driver = {