5 * Copyright (C) 2007-2013 Intel Corporation. All rights reserved.
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.
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.
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
29 #include <sys/ioctl.h>
30 #include <sys/types.h>
34 #include <linux/if_vlan.h>
35 #include <linux/sockios.h>
36 #include <linux/ethtool.h>
39 #define IFF_LOWER_UP 0x10000
44 #define CONNMAN_API_SUBJECT_TO_CHANGE
45 #include <connman/technology.h>
46 #include <connman/plugin.h>
47 #include <connman/device.h>
48 #include <connman/inet.h>
49 #include <connman/rtnl.h>
50 #include <connman/log.h>
51 #include <connman/setting.h>
52 #if defined TIZEN_EXT_WIFI_MESH
53 #include <connman/mesh.h>
56 static bool eth_tethering = false;
58 struct ethernet_data {
62 struct connman_network *network;
66 static int get_vlan_vid(const char *ifname)
68 struct vlan_ioctl_args vifr;
72 memset(&vifr, 0, sizeof(vifr));
74 sk = socket(AF_INET, SOCK_STREAM, 0);
78 vifr.cmd = GET_VLAN_VID_CMD;
79 strncpy(vifr.device1, ifname, sizeof(vifr.device1));
81 if(ioctl(sk, SIOCSIFVLAN, &vifr) >= 0)
91 static int get_dsa_port(const char *ifname)
96 struct ethtool_cmd cmd;
97 struct ethtool_drvinfo drvinfocmd;
98 struct vlan_ioctl_args vifr;
100 sk = socket(AF_INET, SOCK_STREAM, 0);
104 memset(&ifr, 0, sizeof(ifr));
105 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
107 /* check if it is a vlan and get physical interface name*/
108 vifr.cmd = GET_VLAN_REALDEV_NAME_CMD;
109 strncpy(vifr.device1, ifname, sizeof(vifr.device1));
111 if(ioctl(sk, SIOCSIFVLAN, &vifr) >= 0)
112 strncpy(ifr.ifr_name, vifr.u.device2, sizeof(ifr.ifr_name));
114 /* get driver info */
115 drvinfocmd.cmd = ETHTOOL_GDRVINFO;
116 ifr.ifr_data = (caddr_t)&drvinfocmd;
118 if (!ioctl(sk, SIOCETHTOOL, &ifr)) {
119 if(!strcmp(drvinfocmd.driver, "dsa")) {
121 cmd.cmd = ETHTOOL_GSET;
122 ifr.ifr_data = (caddr_t)&cmd;
124 if (!ioctl(sk, SIOCETHTOOL, &ifr))
125 dsaport = cmd.phy_address;
133 static int eth_network_probe(struct connman_network *network)
135 DBG("network %p", network);
140 static void eth_network_remove(struct connman_network *network)
142 DBG("network %p", network);
145 static int eth_network_connect(struct connman_network *network)
147 DBG("network %p", network);
149 connman_network_set_connected(network, true);
154 static int eth_network_disconnect(struct connman_network *network)
156 DBG("network %p", network);
158 connman_network_set_connected(network, false);
163 static struct connman_network_driver eth_network_driver = {
165 .type = CONNMAN_NETWORK_TYPE_ETHERNET,
166 .probe = eth_network_probe,
167 .remove = eth_network_remove,
168 .connect = eth_network_connect,
169 .disconnect = eth_network_disconnect,
172 static void add_network(struct connman_device *device,
173 struct ethernet_data *ethernet)
175 struct connman_network *network;
179 network = connman_network_create("carrier",
180 CONNMAN_NETWORK_TYPE_ETHERNET);
184 index = connman_device_get_index(device);
185 connman_network_set_index(network, index);
186 ifname = connman_inet_ifname(index);
190 connman_network_set_name(network, "Wired");
192 if (connman_device_add_network(device, network) < 0) {
193 connman_network_unref(network);
198 if (!eth_tethering) {
199 char group[25] = "cable";
202 vid = get_vlan_vid(ifname);
203 dsaport = get_dsa_port(ifname);
206 * Prevent service from starting the reconnect
207 * procedure as we do not want the DHCP client
208 * to run when tethering.
210 if((vid >= 0) && (dsaport >= 0))
211 snprintf(group, sizeof(group), "p%02x_%03x_cable", dsaport, vid);
213 snprintf(group, sizeof(group), "%03x_cable", vid);
214 else if (dsaport >= 0)
215 snprintf(group, sizeof(group), "p%02x_cable", dsaport);
217 connman_network_set_group(network, group);
220 ethernet->network = network;
224 static void remove_network(struct connman_device *device,
225 struct ethernet_data *ethernet)
227 if (!ethernet->network)
230 connman_device_remove_network(device, ethernet->network);
231 connman_network_unref(ethernet->network);
233 ethernet->network = NULL;
236 static void ethernet_newlink(unsigned flags, unsigned change, void *user_data)
238 struct connman_device *device = user_data;
239 struct ethernet_data *ethernet = connman_device_get_data(device);
241 DBG("index %d flags %d change %d", ethernet->index, flags, change);
243 if ((ethernet->flags & IFF_UP) != (flags & IFF_UP)) {
244 if (flags & IFF_UP) {
246 connman_device_set_powered(device, true);
249 connman_device_set_powered(device, false);
253 if ((ethernet->flags & IFF_LOWER_UP) != (flags & IFF_LOWER_UP)) {
254 if (flags & IFF_LOWER_UP) {
256 add_network(device, ethernet);
259 remove_network(device, ethernet);
260 #if defined TIZEN_EXT_WIFI_MESH
261 /* Remove ethernet from mesh bridge */
262 __connman_mesh_remove_ethernet_from_bridge();
267 ethernet->flags = flags;
270 static int eth_dev_probe(struct connman_device *device)
272 struct ethernet_data *ethernet;
274 DBG("device %p", device);
276 ethernet = g_try_new0(struct ethernet_data, 1);
280 connman_device_set_data(device, ethernet);
282 ethernet->index = connman_device_get_index(device);
285 ethernet->watch = connman_rtnl_add_newlink_watch(ethernet->index,
286 ethernet_newlink, device);
291 static void eth_dev_remove(struct connman_device *device)
293 struct ethernet_data *ethernet = connman_device_get_data(device);
295 DBG("device %p", device);
297 connman_device_set_data(device, NULL);
299 connman_rtnl_remove_watch(ethernet->watch);
301 remove_network(device, ethernet);
306 static int eth_dev_enable(struct connman_device *device)
308 struct ethernet_data *ethernet = connman_device_get_data(device);
310 DBG("device %p", device);
312 return connman_inet_ifup(ethernet->index);
315 static int eth_dev_disable(struct connman_device *device)
317 struct ethernet_data *ethernet = connman_device_get_data(device);
319 DBG("device %p", device);
321 return connman_inet_ifdown(ethernet->index);
324 static struct connman_device_driver eth_dev_driver = {
326 .type = CONNMAN_DEVICE_TYPE_ETHERNET,
327 .probe = eth_dev_probe,
328 .remove = eth_dev_remove,
329 .enable = eth_dev_enable,
330 .disable = eth_dev_disable,
333 static int eth_tech_probe(struct connman_technology *technology)
338 static void eth_tech_remove(struct connman_technology *technology)
343 static GList *eth_interface_list = NULL;
345 static void eth_tech_add_interface(struct connman_technology *technology,
346 int index, const char *name, const char *ident)
348 DBG("index %d name %s ident %s", index, name, ident);
350 if (g_list_find(eth_interface_list, GINT_TO_POINTER((int)index)))
353 eth_interface_list = g_list_prepend(eth_interface_list,
354 (GINT_TO_POINTER((int) index)));
357 static void eth_tech_remove_interface(struct connman_technology *technology,
360 DBG("index %d", index);
362 eth_interface_list = g_list_remove(eth_interface_list,
363 GINT_TO_POINTER((int) index));
366 static void eth_tech_enable_tethering(struct connman_technology *technology,
370 struct ethernet_data *ethernet;
372 for (list = eth_interface_list; list; list = list->next) {
373 int index = GPOINTER_TO_INT(list->data);
374 struct connman_device *device =
375 connman_device_find_by_index(index);
378 ethernet = connman_device_get_data(device);
380 remove_network(device, ethernet);
383 connman_technology_tethering_notify(technology, true);
385 connman_inet_ifup(index);
387 connman_inet_add_to_bridge(index, bridge);
389 eth_tethering = true;
393 static void eth_tech_disable_tethering(struct connman_technology *technology,
398 for (list = eth_interface_list; list; list = list->next) {
399 int index = GPOINTER_TO_INT(list->data);
400 struct connman_device *device =
401 connman_device_find_by_index(index);
403 connman_inet_remove_from_bridge(index, bridge);
405 connman_technology_tethering_notify(technology, false);
408 connman_device_reconnect_service(device);
410 eth_tethering = false;
414 static int eth_tech_set_tethering(struct connman_technology *technology,
415 const char *identifier, const char *passphrase,
416 const char *bridge, bool enabled)
418 if (!connman_technology_is_tethering_allowed(
419 CONNMAN_SERVICE_TYPE_ETHERNET))
422 DBG("bridge %s enabled %d", bridge, enabled);
425 eth_tech_enable_tethering(technology, bridge);
427 eth_tech_disable_tethering(technology, bridge);
432 static struct connman_technology_driver eth_tech_driver = {
434 .type = CONNMAN_SERVICE_TYPE_ETHERNET,
435 .probe = eth_tech_probe,
436 .remove = eth_tech_remove,
437 .add_interface = eth_tech_add_interface,
438 .remove_interface = eth_tech_remove_interface,
439 .set_tethering = eth_tech_set_tethering,
442 #if defined TIZEN_EXT_WIFI_MESH
443 static int eth_mesh_add_to_bridge(const char *bridge)
446 struct ethernet_data *ethernet;
448 DBG("Add ethernet to bridge %s", bridge);
450 for (list = eth_interface_list; list; list = list->next) {
451 int index = GPOINTER_TO_INT(list->data);
452 struct connman_device *device =
453 connman_device_find_by_index(index);
456 ethernet = connman_device_get_data(device);
458 remove_network(device, ethernet);
461 connman_inet_ifup(index);
463 connman_inet_add_to_bridge(index, bridge);
469 static int eth_mesh_remove_from_bridge(const char *bridge)
473 DBG("Remove ethernet from bridge %s", bridge);
475 for (list = eth_interface_list; list; list = list->next) {
476 int index = GPOINTER_TO_INT(list->data);
478 connman_inet_remove_from_bridge(index, bridge);
484 static struct connman_mesh_eth_driver eth_mesh_driver = {
485 .add_to_bridge = eth_mesh_add_to_bridge,
486 .remove_from_bridge = eth_mesh_remove_from_bridge,
490 static int ethernet_init(void)
494 err = connman_technology_driver_register(ð_tech_driver);
498 #if defined TIZEN_EXT_WIFI_MESH
499 err = connman_mesh_eth_driver_register(ð_mesh_driver);
504 err = connman_network_driver_register(ð_network_driver);
508 err = connman_device_driver_register(ð_dev_driver);
510 connman_network_driver_unregister(ð_network_driver);
517 static void ethernet_exit(void)
519 connman_technology_driver_unregister(ð_tech_driver);
521 #if defined TIZEN_EXT_WIFI_MESH
522 connman_mesh_eth_driver_unregister(ð_mesh_driver);
525 connman_network_driver_unregister(ð_network_driver);
527 connman_device_driver_unregister(ð_dev_driver);
530 CONNMAN_PLUGIN_DEFINE(ethernet, "Ethernet interface plugin", VERSION,
531 CONNMAN_PLUGIN_PRIORITY_DEFAULT, ethernet_init, ethernet_exit)