+
+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);
+
+ return 0;
+}
+
+static void eth_network_remove(struct connman_network *network)
+{
+ DBG("network %p", network);
+}
+
+#if defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET
+static struct connman_network *g_network = NULL;
+
+void handle_eap_signal(GSupplicantInterface *interface, bool status)
+{
+ DBG("captured EAP signal");
+
+ if (!g_network)
+ return;
+
+ if (g_strcmp0("wired", g_supplicant_interface_get_driver(interface)))
+ return;
+
+ if (!connman_network_check_validity(g_network))
+ return;
+
+ DBG("network is valid");
+
+ g_supplicant_unregister_eap_callback();
+
+ if (!status) {
+ // Should we mark service as non favorite or make autoconnect as false?
+
+ struct ethernet_data *ethernet = g_supplicant_interface_get_data(interface);
+ if (ethernet && ethernet->interface) {
+ g_supplicant_interface_remove(ethernet->interface, NULL, NULL);
+ ethernet->interface = NULL;
+ }
+
+ connman_network_set_error(g_network, CONNMAN_NETWORK_ERROR_ASSOCIATE_FAIL);
+ g_network = NULL;
+ return;
+ }
+
+ connman_network_set_connected(g_network, status);
+ g_network = NULL;
+}
+
+static void interface_create_callback(int result,
+ GSupplicantInterface *interface, void *user_data)
+{
+ struct ethernet_data *ethernet = user_data;
+
+ if (result < 0 || !interface || !ethernet)
+ return;
+
+ DBG("result %d ifname %s, ethernet %p", result,
+ g_supplicant_interface_get_ifname(interface),
+ ethernet);
+
+ ethernet->interface = interface;
+ g_supplicant_interface_set_data(interface, ethernet);
+}
+
+static int eth_network_connect(struct connman_network *network)
+{
+ DBG("network %p", network);
+
+ struct connman_service *service = connman_service_lookup_from_network(network);
+
+ if (service && __connman_service_get_use_eapol(service)) {
+ struct connman_device *device = connman_network_get_device(network);
+ struct ethernet_data *ethernet = connman_device_get_data(device);
+ const char *driver = "wired";
+ int index = connman_network_get_index(network);
+ char *ifname = connman_inet_ifname(index);;
+ char *config_file = NULL;
+
+ g_supplicant_register_eap_callback(handle_eap_signal);
+ g_network = network;
+
+ if (asprintf(&config_file, "/var/lib/connman/%s-eapol.conf", ifname) < 0) {
+ g_free(ifname);
+ return -ENOMEM;
+ }
+
+ DBG("config_file %s", config_file);
+
+ g_supplicant_replace_config_file(ifname, config_file);
+ free(config_file);
+
+ /*
+ * TODO: RemoveInterface if already present because
+ * already created interface will not start EAP handshake.
+ */
+ g_supplicant_interface_create(ifname, driver, NULL,
+ interface_create_callback, ethernet);
+
+ g_free(ifname);
+
+ return 0;
+ }
+
+ connman_network_set_connected(network, true);
+
+ return 0;
+}
+
+static int eth_network_disconnect(struct connman_network *network)
+{
+ DBG("network %p", network);
+
+ struct connman_service *service = connman_service_lookup_from_network(network);
+
+ if (service && __connman_service_get_use_eapol(service)) {
+ struct connman_device *device = connman_network_get_device(network);
+ struct ethernet_data *ethernet = connman_device_get_data(device);
+
+ g_network = NULL;
+ g_supplicant_unregister_eap_callback();
+ if (ethernet && ethernet->interface) {
+ g_supplicant_interface_remove(ethernet->interface, NULL, NULL);
+ ethernet->interface = NULL;
+ }
+ connman_network_set_associating(network, false);
+ connman_network_set_connected(network, false);
+
+ return 0;
+ }
+
+ connman_network_set_connected(network, false);
+
+ return 0;
+}
+
+#else /* defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET */
+
+static int eth_network_connect(struct connman_network *network)
+{
+ DBG("network %p", network);
+
+ connman_network_set_connected(network, true);
+
+ return 0;
+}
+
+static int eth_network_disconnect(struct connman_network *network)
+{
+ DBG("network %p", network);
+
+ connman_network_set_connected(network, false);
+
+ return 0;
+}
+
+#endif /* defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET */
+
+static struct connman_network_driver eth_network_driver = {
+ .name = "cable",
+ .type = CONNMAN_NETWORK_TYPE_ETHERNET,
+ .probe = eth_network_probe,
+ .remove = eth_network_remove,
+ .connect = eth_network_connect,
+ .disconnect = eth_network_disconnect,
+};
+
+static void add_network(struct connman_device *device,
+ struct ethernet_data *ethernet)
+{
+ struct connman_network *network;
+ int index;
+ char *ifname;
+
+ network = connman_network_create("carrier",
+ CONNMAN_NETWORK_TYPE_ETHERNET);
+ if (!network)
+ return;
+
+ 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) {
+ 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.
+ */
+ 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,
+ struct ethernet_data *ethernet)
+{
+ if (!ethernet->network)
+ return;
+
+ connman_device_remove_network(device, ethernet->network);
+ connman_network_unref(ethernet->network);
+
+ ethernet->network = NULL;
+}
+