dhcp: Add IPv4LL support
[framework/connectivity/connman.git] / plugins / dhcp.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2010  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 <stdio.h>
27 #include <errno.h>
28 #include <string.h>
29 #include <stdlib.h>
30
31 #define CONNMAN_API_SUBJECT_TO_CHANGE
32 #include <connman/plugin.h>
33 #include <connman/dhcp.h>
34 #include <connman/utsname.h>
35 #include <connman/log.h>
36
37 #include <gdhcp/gdhcp.h>
38
39 static void dhcp_debug(const char *str, void *data)
40 {
41         connman_info("%s: %s\n", (const char *) data, str);
42 }
43
44 static void no_lease_cb(GDHCPClient *dhcp_client, gpointer user_data)
45 {
46         struct connman_dhcp *dhcp = user_data;
47
48         DBG("No lease available");
49
50         connman_dhcp_fail(dhcp);
51 }
52
53 static void lease_lost_cb(GDHCPClient *dhcp_client, gpointer user_data)
54 {
55         DBG("Lease lost");
56 }
57
58 static void ipv4ll_lost_cb(GDHCPClient *dhcp_client, gpointer user_data)
59 {
60         struct connman_dhcp *dhcp = user_data;
61
62         DBG("Lease lost");
63
64         connman_dhcp_release(dhcp);
65 }
66
67 static void lease_available_cb(GDHCPClient *dhcp_client, gpointer user_data)
68 {
69         struct connman_dhcp *dhcp = user_data;
70         GList *list, *option = NULL;
71         char *address, *nameservers;
72         size_t ns_strlen = 0;
73
74         DBG("Lease available");
75
76         address = g_dhcp_client_get_address(dhcp_client);
77         if (address != NULL)
78                 connman_dhcp_set_value(dhcp, "Address", address);
79
80         option = g_dhcp_client_get_option(dhcp_client, G_DHCP_SUBNET);
81         if (option != NULL)
82                 connman_dhcp_set_value(dhcp, "Netmask", option->data);
83
84         option = g_dhcp_client_get_option(dhcp_client, G_DHCP_DNS_SERVER);
85         for (list = option; list; list = list->next)
86                 ns_strlen += strlen((char *) list->data) + 2;
87         nameservers = g_try_malloc0(ns_strlen);
88         if (nameservers) {
89                 char *ns_index = nameservers;
90
91                 for (list = option; list; list = list->next) {
92                         sprintf(ns_index, "%s ", (char *) list->data);
93                         ns_index += strlen((char *) list->data) + 1;
94                 }
95
96                 connman_dhcp_set_value(dhcp, "Nameserver", nameservers);
97         }
98         g_free(nameservers);
99
100         option = g_dhcp_client_get_option(dhcp_client, G_DHCP_DOMAIN_NAME);
101         if (option != NULL)
102                 connman_dhcp_set_value(dhcp, "Domainname", option->data);
103
104         option = g_dhcp_client_get_option(dhcp_client, G_DHCP_ROUTER);
105         if (option != NULL)
106                 connman_dhcp_set_value(dhcp, "Gateway", option->data);
107
108         option = g_dhcp_client_get_option(dhcp_client, G_DHCP_HOST_NAME);
109         if (option != NULL)
110                 connman_dhcp_set_value(dhcp, "Hostname", option->data);
111
112         option = g_dhcp_client_get_option(dhcp_client, G_DHCP_NTP_SERVER);
113         if (option != NULL)
114                 connman_dhcp_set_value(dhcp, "Timeserver", option->data);
115
116         option = g_dhcp_client_get_option(dhcp_client, 252);
117         if (option != NULL)
118                 connman_dhcp_set_value(dhcp, "PAC", option->data);
119
120         connman_dhcp_bound(dhcp);
121 }
122
123 static void ipv4ll_available_cb(GDHCPClient *dhcp_client, gpointer user_data)
124 {
125         struct connman_dhcp *dhcp = user_data;
126         char *address, *netmask;
127
128         DBG("IPV4LL available");
129
130         address = g_dhcp_client_get_address(dhcp_client);
131         if (address != NULL)
132                 connman_dhcp_set_value(dhcp, "Address", address);
133
134         netmask = g_dhcp_client_get_netmask(dhcp_client);
135         if (netmask != NULL)
136                 connman_dhcp_set_value(dhcp, "Netmask", netmask);
137
138         g_free(address);
139         g_free(netmask);
140
141         connman_dhcp_bound(dhcp);
142 }
143
144 static int dhcp_request(struct connman_dhcp *dhcp)
145 {
146         GDHCPClient *dhcp_client;
147         GDHCPClientError error;
148         const char *hostname;
149         int index;
150
151         DBG("dhcp %p", dhcp);
152
153         index = connman_dhcp_get_index(dhcp);
154
155         dhcp_client = g_dhcp_client_new(G_DHCP_IPV4, index, &error);
156         if (error != G_DHCP_CLIENT_ERROR_NONE)
157                 return -EINVAL;
158
159         if (getenv("CONNMAN_DHCP_DEBUG"))
160                 g_dhcp_client_set_debug(dhcp_client, dhcp_debug, "DHCP");
161
162         hostname = connman_utsname_get_hostname();
163         if (hostname != NULL)
164                 g_dhcp_client_set_send(dhcp_client, G_DHCP_HOST_NAME, hostname);
165
166         g_dhcp_client_set_request(dhcp_client, G_DHCP_HOST_NAME);
167         g_dhcp_client_set_request(dhcp_client, G_DHCP_SUBNET);
168         g_dhcp_client_set_request(dhcp_client, G_DHCP_DNS_SERVER);
169         g_dhcp_client_set_request(dhcp_client, G_DHCP_DOMAIN_NAME);
170         g_dhcp_client_set_request(dhcp_client, G_DHCP_NTP_SERVER);
171         g_dhcp_client_set_request(dhcp_client, G_DHCP_ROUTER);
172         g_dhcp_client_set_request(dhcp_client, 252);
173
174         g_dhcp_client_register_event(dhcp_client,
175                         G_DHCP_CLIENT_EVENT_LEASE_AVAILABLE,
176                                                 lease_available_cb, dhcp);
177
178         g_dhcp_client_register_event(dhcp_client,
179                         G_DHCP_CLIENT_EVENT_IPV4LL_AVAILABLE,
180                                                 ipv4ll_available_cb, dhcp);
181
182         g_dhcp_client_register_event(dhcp_client,
183                         G_DHCP_CLIENT_EVENT_LEASE_LOST, lease_lost_cb, dhcp);
184
185         g_dhcp_client_register_event(dhcp_client,
186                         G_DHCP_CLIENT_EVENT_IPV4LL_LOST, ipv4ll_lost_cb, dhcp);
187
188         g_dhcp_client_register_event(dhcp_client,
189                         G_DHCP_CLIENT_EVENT_NO_LEASE, no_lease_cb, dhcp);
190
191         connman_dhcp_set_data(dhcp, dhcp_client);
192
193         g_dhcp_client_ref(dhcp_client);
194
195         return g_dhcp_client_start(dhcp_client);
196 }
197
198 static int dhcp_release(struct connman_dhcp *dhcp)
199 {
200         GDHCPClient *dhcp_client = connman_dhcp_get_data(dhcp);
201
202         DBG("dhcp %p", dhcp);
203
204         g_dhcp_client_stop(dhcp_client);
205         g_dhcp_client_unref(dhcp_client);
206
207         return 0;
208 }
209
210 static struct connman_dhcp_driver dhcp_driver = {
211         .name           = "dhcp",
212         .priority       = CONNMAN_DHCP_PRIORITY_DEFAULT,
213         .request        = dhcp_request,
214         .release        = dhcp_release,
215 };
216
217 static int dhcp_init(void)
218 {
219         return connman_dhcp_driver_register(&dhcp_driver);
220 }
221
222 static void dhcp_exit(void)
223 {
224         connman_dhcp_driver_unregister(&dhcp_driver);
225 }
226
227 CONNMAN_PLUGIN_DEFINE(dhcp, "Generic DHCP plugin", VERSION,
228                         CONNMAN_PLUGIN_PRIORITY_DEFAULT, dhcp_init, dhcp_exit)