#include <errno.h>
#include <net/if.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdio.h>
+
+#include <linux/if_vlan.h>
+#include <linux/sockios.h>
+#include <linux/ethtool.h>
#ifndef IFF_LOWER_UP
#define IFF_LOWER_UP 0x10000
#include <connman/rtnl.h>
#include <connman/log.h>
#include <connman/setting.h>
+#if defined TIZEN_EXT_WIFI_MESH
+#include <connman/mesh.h>
+#endif
static bool eth_tethering = false;
struct connman_network *network;
};
+
+static int get_vlan_vid(const char *ifname)
+{
+ struct vlan_ioctl_args vifr;
+ int vid;
+ int sk;
+
+ memset(&vifr, 0, sizeof(vifr));
+
+ sk = socket(AF_INET, SOCK_STREAM, 0);
+ if (sk < 0)
+ return -errno;
+
+ vifr.cmd = GET_VLAN_VID_CMD;
+ strncpy(vifr.device1, ifname, sizeof(vifr.device1));
+
+ if(ioctl(sk, SIOCSIFVLAN, &vifr) >= 0)
+ vid = vifr.u.VID;
+ else
+ vid = -errno;
+
+ close(sk);
+
+ return vid;
+}
+
+static int get_dsa_port(const char *ifname)
+{
+ int sk;
+ int dsaport = -1;
+ struct ifreq ifr;
+ struct ethtool_cmd cmd;
+ struct ethtool_drvinfo drvinfocmd;
+ struct vlan_ioctl_args vifr;
+
+ sk = socket(AF_INET, SOCK_STREAM, 0);
+ if (sk < 0)
+ return -errno;
+
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+
+ /* check if it is a vlan and get physical interface name*/
+ vifr.cmd = GET_VLAN_REALDEV_NAME_CMD;
+ strncpy(vifr.device1, ifname, sizeof(vifr.device1));
+
+ if(ioctl(sk, SIOCSIFVLAN, &vifr) >= 0)
+ strncpy(ifr.ifr_name, vifr.u.device2, sizeof(ifr.ifr_name));
+
+ /* get driver info */
+ drvinfocmd.cmd = ETHTOOL_GDRVINFO;
+ ifr.ifr_data = (caddr_t)&drvinfocmd;
+
+ if (!ioctl(sk, SIOCETHTOOL, &ifr)) {
+ if(!strcmp(drvinfocmd.driver, "dsa")) {
+ /* get dsa port*/
+ cmd.cmd = ETHTOOL_GSET;
+ ifr.ifr_data = (caddr_t)&cmd;
+
+ if (!ioctl(sk, SIOCETHTOOL, &ifr))
+ dsaport = cmd.phy_address;
+ }
+ }
+ close(sk);
+
+ return dsaport;
+}
+
static int eth_network_probe(struct connman_network *network)
{
DBG("network %p", network);
{
struct connman_network *network;
int index;
+ char *ifname;
network = connman_network_create("carrier",
CONNMAN_NETWORK_TYPE_ETHERNET);
index = connman_device_get_index(device);
connman_network_set_index(network, index);
+ ifname = connman_inet_ifname(index);
+ if (!ifname)
+ return;
connman_network_set_name(network, "Wired");
if (connman_device_add_network(device, network) < 0) {
connman_network_unref(network);
+ g_free(ifname);
return;
}
- if (!eth_tethering)
+ if (!eth_tethering) {
+ char group[25] = "cable";
+ int vid, dsaport;
+
+ vid = get_vlan_vid(ifname);
+ dsaport = get_dsa_port(ifname);
+
/*
* Prevent service from starting the reconnect
* procedure as we do not want the DHCP client
* to run when tethering.
*/
- connman_network_set_group(network, "cable");
+ if((vid >= 0) && (dsaport >= 0))
+ snprintf(group, sizeof(group), "p%02x_%03x_cable", dsaport, vid);
+ else if (vid >= 0)
+ snprintf(group, sizeof(group), "%03x_cable", vid);
+ else if (dsaport >= 0)
+ snprintf(group, sizeof(group), "p%02x_cable", dsaport);
+
+ connman_network_set_group(network, group);
+ }
ethernet->network = network;
+ g_free(ifname);
}
static void remove_network(struct connman_device *device,
} else {
DBG("carrier off");
remove_network(device, ethernet);
+#if defined TIZEN_EXT_WIFI_MESH
+ /* Remove ethernet from mesh bridge */
+ __connman_mesh_remove_ethernet_from_bridge();
+#endif
}
}
.set_tethering = eth_tech_set_tethering,
};
+#if defined TIZEN_EXT_WIFI_MESH
+static int eth_mesh_add_to_bridge(const char *bridge)
+{
+ GList *list;
+ struct ethernet_data *ethernet;
+
+ DBG("Add ethernet to bridge %s", bridge);
+
+ for (list = eth_interface_list; list; list = list->next) {
+ int index = GPOINTER_TO_INT(list->data);
+ struct connman_device *device =
+ connman_device_find_by_index(index);
+
+ if (device) {
+ ethernet = connman_device_get_data(device);
+ if (ethernet)
+ remove_network(device, ethernet);
+ }
+
+ connman_inet_ifup(index);
+
+ connman_inet_add_to_bridge(index, bridge);
+ }
+
+ return 0;
+}
+
+static int eth_mesh_remove_from_bridge(const char *bridge)
+{
+ GList *list;
+
+ DBG("Remove ethernet from bridge %s", bridge);
+
+ for (list = eth_interface_list; list; list = list->next) {
+ int index = GPOINTER_TO_INT(list->data);
+
+ connman_inet_remove_from_bridge(index, bridge);
+ }
+
+ return 0;
+}
+
+static struct connman_mesh_eth_driver eth_mesh_driver = {
+ .add_to_bridge = eth_mesh_add_to_bridge,
+ .remove_from_bridge = eth_mesh_remove_from_bridge,
+};
+#endif
+
static int ethernet_init(void)
{
int err;
if (err < 0)
return err;
+#if defined TIZEN_EXT_WIFI_MESH
+ err = connman_mesh_eth_driver_register(ð_mesh_driver);
+ if (err < 0)
+ return err;
+#endif
+
err = connman_network_driver_register(ð_network_driver);
if (err < 0)
return err;
{
connman_technology_driver_unregister(ð_tech_driver);
+#if defined TIZEN_EXT_WIFI_MESH
+ connman_mesh_eth_driver_unregister(ð_mesh_driver);
+#endif
+
connman_network_driver_unregister(ð_network_driver);
connman_device_driver_unregister(ð_dev_driver);