Convert IPv4 setting to use new resolver framework
[connman] / plugins / ipv4.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2008  Intel Corporation. All rights reserved.
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License version 2 as
9  *  published by the Free Software Foundation.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <unistd.h>
27 #include <string.h>
28 #include <sys/ioctl.h>
29 #include <sys/socket.h>
30 #include <netinet/in.h>
31 #include <arpa/inet.h>
32 #include <net/if.h>
33 #include <net/route.h>
34
35 #include <linux/netlink.h>
36 #include <linux/rtnetlink.h>
37
38 #include <connman/plugin.h>
39 #include <connman/driver.h>
40 #include <connman/resolver.h>
41 #include <connman/log.h>
42
43 #include "inet.h"
44
45 enum connman_ipv4_method {
46         CONNMAN_IPV4_METHOD_UNKNOWN = 0,
47         CONNMAN_IPV4_METHOD_OFF     = 1,
48         CONNMAN_IPV4_METHOD_STATIC  = 2,
49         CONNMAN_IPV4_METHOD_DHCP    = 3,
50 };
51
52 struct connman_ipv4 {
53         enum connman_ipv4_method method;
54         struct in_addr address;
55         struct in_addr netmask;
56         struct in_addr gateway;
57         struct in_addr network;
58         struct in_addr broadcast;
59         struct in_addr nameserver;
60 };
61
62 static int set_ipv4(struct connman_element *element,
63                         struct connman_ipv4 *ipv4, const char *nameserver)
64 {
65         struct ifreq ifr;
66         struct rtentry rt;
67         struct sockaddr_in *addr;
68         int sk, err;
69
70         DBG("element %p ipv4 %p", element, ipv4);
71
72         sk = socket(PF_INET, SOCK_DGRAM, 0);
73         if (sk < 0)
74                 return -1;
75
76         memset(&ifr, 0, sizeof(ifr));
77         ifr.ifr_ifindex = element->index;
78
79         if (ioctl(sk, SIOCGIFNAME, &ifr) < 0) {
80                 close(sk);
81                 return -1;
82         }
83
84         DBG("ifname %s", ifr.ifr_name);
85
86         addr = (struct sockaddr_in *) &ifr.ifr_addr;
87         addr->sin_family = AF_INET;
88         addr->sin_addr = ipv4->address;
89
90         err = ioctl(sk, SIOCSIFADDR, &ifr);
91
92         if (err < 0)
93                 DBG("address setting failed (%s)", strerror(errno));
94
95         addr = (struct sockaddr_in *) &ifr.ifr_netmask;
96         addr->sin_family = AF_INET;
97         addr->sin_addr = ipv4->netmask;
98
99         err = ioctl(sk, SIOCSIFNETMASK, &ifr);
100
101         if (err < 0)
102                 DBG("netmask setting failed (%s)", strerror(errno));
103
104         addr = (struct sockaddr_in *) &ifr.ifr_broadaddr;
105         addr->sin_family = AF_INET;
106         addr->sin_addr = ipv4->broadcast;
107
108         err = ioctl(sk, SIOCSIFBRDADDR, &ifr);
109
110         if (err < 0)
111                 DBG("broadcast setting failed (%s)", strerror(errno));
112
113         memset(&rt, 0, sizeof(rt));
114         rt.rt_flags = RTF_UP | RTF_GATEWAY;
115
116         addr = (struct sockaddr_in *) &rt.rt_dst;
117         addr->sin_family = AF_INET;
118         addr->sin_addr.s_addr = INADDR_ANY;
119
120         addr = (struct sockaddr_in *) &rt.rt_gateway;
121         addr->sin_family = AF_INET;
122         addr->sin_addr = ipv4->gateway;
123
124         addr = (struct sockaddr_in *) &rt.rt_genmask;
125         addr->sin_family = AF_INET;
126         addr->sin_addr.s_addr = INADDR_ANY;
127
128         err = ioctl(sk, SIOCADDRT, &rt);
129
130         close(sk);
131
132         if (err < 0) {
133                 DBG("default route failed (%s)", strerror(errno));
134                 return -1;
135         }
136
137         connman_resolver_append(ifr.ifr_name, NULL, nameserver);
138
139         return 0;
140 }
141
142 static int clear_ipv4(struct connman_element *element)
143 {
144         struct ifreq ifr;
145         struct sockaddr_in *addr;
146         int sk, err;
147
148         DBG("element %p", element);
149
150         sk = socket(PF_INET, SOCK_DGRAM, 0);
151         if (sk < 0)
152                 return -1;
153
154         memset(&ifr, 0, sizeof(ifr));
155         ifr.ifr_ifindex = element->index;
156
157         if (ioctl(sk, SIOCGIFNAME, &ifr) < 0) {
158                 close(sk);
159                 return -1;
160         }
161
162         DBG("ifname %s", ifr.ifr_name);
163
164         connman_resolver_remove_all(ifr.ifr_name);
165
166         addr = (struct sockaddr_in *) &ifr.ifr_addr;
167         addr->sin_family = AF_INET;
168         addr->sin_addr.s_addr = INADDR_ANY;
169
170         //err = ioctl(sk, SIOCDIFADDR, &ifr);
171         err = ioctl(sk, SIOCSIFADDR, &ifr);
172
173         close(sk);
174
175         if (err < 0 && errno != EADDRNOTAVAIL) {
176                 DBG("address removal failed (%s)", strerror(errno));
177                 return -1;
178         }
179
180         return 0;
181 }
182
183 static int ipv4_probe(struct connman_element *element)
184 {
185         struct connman_element *connection;
186         struct connman_ipv4 ipv4;
187         const char *address = NULL, *netmask = NULL, *gateway = NULL;
188         const char *nameserver = NULL;
189
190         DBG("element %p name %s", element, element->name);
191
192         connman_element_get_value(element,
193                                 CONNMAN_PROPERTY_ID_IPV4_ADDRESS, &address);
194         connman_element_get_value(element,
195                                 CONNMAN_PROPERTY_ID_IPV4_NETMASK, &netmask);
196         connman_element_get_value(element,
197                                 CONNMAN_PROPERTY_ID_IPV4_GATEWAY, &gateway);
198
199         connman_element_get_value(element,
200                         CONNMAN_PROPERTY_ID_IPV4_NAMESERVER, &nameserver);
201
202         DBG("address %s", address);
203         DBG("netmask %s", netmask);
204         DBG("gateway %s", gateway);
205
206         if (address == NULL || netmask == NULL || gateway == NULL)
207                 return -EINVAL;
208
209         memset(&ipv4, 0, sizeof(ipv4));
210         ipv4.address.s_addr = inet_addr(address);
211         ipv4.netmask.s_addr = inet_addr(netmask);
212         ipv4.gateway.s_addr = inet_addr(gateway);
213
214         set_ipv4(element, &ipv4, nameserver);
215
216         connection = connman_element_create(NULL);
217
218         connection->type = CONNMAN_ELEMENT_TYPE_CONNECTION;
219         connection->index = element->index;
220
221         connman_element_register(connection, element);
222
223         return 0;
224 }
225
226 static void ipv4_remove(struct connman_element *element)
227 {
228         DBG("element %p name %s", element, element->name);
229
230         clear_ipv4(element);
231 }
232
233 static struct connman_driver ipv4_driver = {
234         .name           = "ipv4",
235         .type           = CONNMAN_ELEMENT_TYPE_IPV4,
236         .probe          = ipv4_probe,
237         .remove         = ipv4_remove,
238 };
239
240 static int ipv4_init(void)
241 {
242         return connman_driver_register(&ipv4_driver);
243 }
244
245 static void ipv4_exit(void)
246 {
247         connman_driver_unregister(&ipv4_driver);
248 }
249
250 CONNMAN_PLUGIN_DEFINE(ipv4, "IPv4 configuration plugin", VERSION,
251                                                         ipv4_init, ipv4_exit)