Allow pre-processor pasting of plugin name
[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/log.h>
41
42 enum connman_ipv4_method {
43         CONNMAN_IPV4_METHOD_UNKNOWN = 0,
44         CONNMAN_IPV4_METHOD_OFF     = 1,
45         CONNMAN_IPV4_METHOD_STATIC  = 2,
46         CONNMAN_IPV4_METHOD_DHCP    = 3,
47 };
48
49 struct connman_ipv4 {
50         enum connman_ipv4_method method;
51         struct in_addr address;
52         struct in_addr netmask;
53         struct in_addr gateway;
54         struct in_addr network;
55         struct in_addr broadcast;
56         struct in_addr nameserver;
57 };
58
59 static int set_ipv4(struct connman_element *element,
60                                                 struct connman_ipv4 *ipv4)
61 {
62         struct ifreq ifr;
63         struct rtentry rt;
64         struct sockaddr_in *addr;
65         int sk, err;
66
67         DBG("element %p ipv4 %p", element, ipv4);
68
69         sk = socket(PF_INET, SOCK_DGRAM, 0);
70         if (sk < 0)
71                 return -1;
72
73         memset(&ifr, 0, sizeof(ifr));
74         ifr.ifr_ifindex = element->index;
75
76         if (ioctl(sk, SIOCGIFNAME, &ifr) < 0) {
77                 close(sk);
78                 return -1;
79         }
80
81         DBG("ifname %s", ifr.ifr_name);
82
83         addr = (struct sockaddr_in *) &ifr.ifr_addr;
84         addr->sin_family = AF_INET;
85         addr->sin_addr = ipv4->address;
86
87         err = ioctl(sk, SIOCSIFADDR, &ifr);
88
89         if (err < 0)
90                 DBG("address setting failed (%s)", strerror(errno));
91
92         addr = (struct sockaddr_in *) &ifr.ifr_netmask;
93         addr->sin_family = AF_INET;
94         addr->sin_addr = ipv4->netmask;
95
96         err = ioctl(sk, SIOCSIFNETMASK, &ifr);
97
98         if (err < 0)
99                 DBG("netmask setting failed (%s)", strerror(errno));
100
101         addr = (struct sockaddr_in *) &ifr.ifr_broadaddr;
102         addr->sin_family = AF_INET;
103         addr->sin_addr = ipv4->broadcast;
104
105         err = ioctl(sk, SIOCSIFBRDADDR, &ifr);
106
107         if (err < 0)
108                 DBG("broadcast setting failed (%s)", strerror(errno));
109
110         memset(&rt, 0, sizeof(rt));
111         rt.rt_flags = RTF_UP | RTF_GATEWAY;
112
113         addr = (struct sockaddr_in *) &rt.rt_dst;
114         addr->sin_family = AF_INET;
115         addr->sin_addr.s_addr = INADDR_ANY;
116
117         addr = (struct sockaddr_in *) &rt.rt_gateway;
118         addr->sin_family = AF_INET;
119         addr->sin_addr = ipv4->gateway;
120
121         addr = (struct sockaddr_in *) &rt.rt_genmask;
122         addr->sin_family = AF_INET;
123         addr->sin_addr.s_addr = INADDR_ANY;
124
125         err = ioctl(sk, SIOCADDRT, &rt);
126
127         close(sk);
128
129         if (err < 0) {
130                 DBG("default route failed (%s)", strerror(errno));
131                 return -1;
132         }
133
134         return 0;
135 }
136
137 static int clear_ipv4(struct connman_element *element)
138 {
139         struct ifreq ifr;
140         struct sockaddr_in *addr;
141         int sk, err;
142
143         DBG("element %p", element);
144
145         sk = socket(PF_INET, SOCK_DGRAM, 0);
146         if (sk < 0)
147                 return -1;
148
149         memset(&ifr, 0, sizeof(ifr));
150         ifr.ifr_ifindex = element->index;
151
152         if (ioctl(sk, SIOCGIFNAME, &ifr) < 0) {
153                 close(sk);
154                 return -1;
155         }
156
157         DBG("ifname %s", ifr.ifr_name);
158
159         addr = (struct sockaddr_in *) &ifr.ifr_addr;
160         addr->sin_family = AF_INET;
161         addr->sin_addr.s_addr = INADDR_ANY;
162
163         //err = ioctl(sk, SIOCDIFADDR, &ifr);
164         err = ioctl(sk, SIOCSIFADDR, &ifr);
165
166         close(sk);
167
168         if (err < 0 && errno != EADDRNOTAVAIL) {
169                 DBG("address removal failed (%s)", strerror(errno));
170                 return -1;
171         }
172
173         return 0;
174 }
175
176 static int ipv4_probe(struct connman_element *element)
177 {
178         struct connman_element *resolver;
179         struct connman_ipv4 ipv4;
180         const char *address = NULL, *netmask = NULL, *gateway = NULL;
181
182         DBG("element %p name %s", element, element->name);
183
184         connman_element_get_value(element,
185                                 CONNMAN_PROPERTY_ID_IPV4_ADDRESS, &address);
186         connman_element_get_value(element,
187                                 CONNMAN_PROPERTY_ID_IPV4_NETMASK, &netmask);
188         connman_element_get_value(element,
189                                 CONNMAN_PROPERTY_ID_IPV4_GATEWAY, &gateway);
190
191         DBG("address %s", address);
192         DBG("netmask %s", netmask);
193         DBG("gateway %s", gateway);
194
195         if (address == NULL || netmask == NULL || gateway == NULL)
196                 return -EINVAL;
197
198         memset(&ipv4, 0, sizeof(ipv4));
199         ipv4.address.s_addr = inet_addr(address);
200         ipv4.netmask.s_addr = inet_addr(netmask);
201         ipv4.gateway.s_addr = inet_addr(gateway);
202
203         set_ipv4(element, &ipv4);
204
205         resolver = connman_element_create(NULL);
206
207         resolver->type = CONNMAN_ELEMENT_TYPE_RESOLVER;
208         resolver->index = element->index;
209
210         connman_element_register(resolver, element);
211
212         return 0;
213 }
214
215 static void ipv4_remove(struct connman_element *element)
216 {
217         DBG("element %p name %s", element, element->name);
218
219         clear_ipv4(element);
220 }
221
222 static struct connman_driver ipv4_driver = {
223         .name           = "ipv4",
224         .type           = CONNMAN_ELEMENT_TYPE_IPV4,
225         .probe          = ipv4_probe,
226         .remove         = ipv4_remove,
227 };
228
229 static int ipv4_init(void)
230 {
231         return connman_driver_register(&ipv4_driver);
232 }
233
234 static void ipv4_exit(void)
235 {
236         connman_driver_unregister(&ipv4_driver);
237 }
238
239 CONNMAN_PLUGIN_DEFINE(ipv4, "IPv4 configuration plugin", VERSION,
240                                                         ipv4_init, ipv4_exit)