diff --git a/Makefile b/Makefile
index 66d0bbb4900c8ef3c32040b39ead18774c1b5512..545074d39e0a3e6c7b9d60bd9a8d83f7c730bb02 100644
--- a/Makefile
+++ b/Makefile
@@ -20,11 +20,12 @@ CFLAGS += -Itest_stub
 LIBETH_CFLAGS += $(DIAG_CFLAGS) -Werror
 objs_lib += econet/econet.o econet/ecnt_prvt.o
 LIBS += -lapi_lib_switchmgr
+else ifeq ($(PLATFORM),IPQ95XX)
+objs_lib += ipq95xx/ipq95xx.o
 else ifeq ($(PLATFORM),TEST)
 CFLAGS += -DIOPSYS_TEST -I/usr/include/libnl3
 LIBETH_CFLAGS += $(DIAG_CFLAGS) -Werror
 objs_lib += test_stub/stub.o
-
 endif
 
 all: libethernet.so
diff --git a/ethernet.c b/ethernet.c
index 451aa92db3edc426f4ff1b73be25f6a7697a7397..8a0b199b3eeee1493a6f53c5e721ddd10e711e58 100644
--- a/ethernet.c
+++ b/ethernet.c
@@ -46,6 +46,8 @@ extern const struct eth_ops test_eth_ops;
 extern const struct eth_ops econet_gen_eth_ops;
 extern const struct eth_ops econet_nas_wan_eth_ops;
 extern const struct eth_ops econet_ae_wan_eth_ops;
+#elif defined(IPQ95XX)
+extern const struct eth_ops ipq95xx_eth_ops;
 #else
 extern const struct eth_ops ethsw_ops;
 #endif
@@ -59,6 +61,8 @@ const struct eth_ops *eth_ops[] = {
 	&econet_gen_eth_ops,
 	&econet_nas_wan_eth_ops,
 	&econet_ae_wan_eth_ops,
+#elif defined(IPQ95XX)
+	&ipq95xx_eth_ops,
 #else
 	&ethsw_ops,   /* FIXME */
 #endif
diff --git a/ipq95xx/ipq95xx.c b/ipq95xx/ipq95xx.c
new file mode 100644
index 0000000000000000000000000000000000000000..af71fd88c7ff841d4daea18f75ee1eb424100f3d
--- /dev/null
+++ b/ipq95xx/ipq95xx.c
@@ -0,0 +1,139 @@
+/*
+ * ipq95xx.c
+ */
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stdint.h>
+#include <errno.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <time.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/sockios.h>
+#include "easy.h"
+#include "if_utils.h"
+#include "../ethernet.h"
+
+#include "ipq95xx.h"
+
+int ipq95xx_eth_set_link_settings(const char *ifname, struct eth_link link)
+{
+	struct {
+		struct ethtool_link_settings req;
+		__u32 link_mode_data[3 * 32 * 127];
+	} ecmd;
+
+	memset(&ecmd, 0, sizeof(struct ethtool_link_settings));
+
+	if (ipq95xx_eth_get_link_settings(ifname, &link))
+		return -1;
+
+	ecmd.req.cmd = ETHTOOL_SLINKSETTINGS;
+
+	ecmd.req.port = link.portid;
+	ecmd.req.speed = link.speed;
+	ecmd.req.autoneg = (link.autoneg == 0 ? false : true);
+	ecmd.req.duplex = (link.fullduplex == 1 ? false : true);
+
+	if (0 != eth_ioctl(ifname, SIOCETHTOOL, &ecmd, sizeof(struct ethtool_link_settings)))
+		return -1;
+	return 0;
+}
+
+int ipq95xx_eth_get_link_settings(const char *ifname, struct eth_link *link)
+{
+	struct {
+		struct ethtool_link_settings req;
+		__u32 link_mode_data[3 * 32 * 127];
+	} ecmd;
+
+	memset(&ecmd, 0, sizeof(struct ethtool_link_settings));
+
+	ecmd.req.cmd = ETHTOOL_GLINKSETTINGS;
+
+	if (0 != eth_ioctl(ifname, SIOCETHTOOL, &ecmd, sizeof(struct ethtool_link_settings)))
+		return -1;
+
+	if (ecmd.req.link_mode_masks_nwords >= 0 || ecmd.req.cmd != ETHTOOL_GLINKSETTINGS)
+		return -1;
+
+	ecmd.req.link_mode_masks_nwords = -ecmd.req.link_mode_masks_nwords;
+
+	if (0 != eth_ioctl(ifname, SIOCETHTOOL, &ecmd, sizeof(struct ethtool_link_settings)))
+		return -1;
+
+	if (ecmd.req.link_mode_masks_nwords <= 0 || ecmd.req.cmd != ETHTOOL_GLINKSETTINGS)
+		return -1;
+
+	link->portid = ecmd.req.port;
+	link->speed = ecmd.req.speed;
+	link->autoneg = ecmd.req.autoneg == 0 ? false : true;
+	link->fullduplex = ecmd.req.duplex == 1 ? false : true;
+
+	return 0;
+}
+
+int ipq95xx_eth_poweron_phy(const char *ifname, struct eth_phy p)
+{
+	libethernet_err("%s(): TODO\n", __func__);
+	return 0;
+}
+
+int ipq95xx_eth_poweroff_phy(const char *ifname, struct eth_phy p)
+{
+	libethernet_err("%s(): TODO\n", __func__);
+	return 0;
+}
+
+int ipq95xx_eth_reset_phy(const char *ifname, int phy_id)
+{
+	return eth_mii_reset_phy(ifname, phy_id);
+}
+
+int ipq95xx_eth_get_stats(const char *ifname, struct eth_stats *s)
+{
+	struct if_stats ifstats;
+
+	memset(&ifstats, 0, sizeof(struct if_stats));
+
+	if (if_getstats(ifname, &ifstats) < 0)
+		return -1;
+
+	s->rx_packets = ifstats.rx_packets;
+	s->tx_packets = ifstats.tx_packets;
+	s->rx_bytes = ifstats.rx_bytes;
+	s->tx_bytes = ifstats.tx_bytes;
+	s->rx_errors = ifstats.rx_errors;
+	s->tx_errors = ifstats.tx_errors;
+	s->rx_discard_packets = ifstats.rx_dropped;
+	s->tx_discard_packets = ifstats.tx_dropped;
+
+	return 0;
+}
+
+int ipq95xx_eth_get_rmon_stats(const char *ifname, struct eth_rmon_stats *rmon)
+{
+	libethernet_err("%s(): TODO\n", __func__);
+        return 0;
+}
+
+const struct eth_ops ipq95xx_eth_ops = {
+        .ifname = "eth",
+        .set_link_settings = ipq95xx_eth_set_link_settings,
+        .get_link_settings = ipq95xx_eth_get_link_settings,
+        .get_stats = ipq95xx_eth_get_stats,
+        .get_rmon_stats = ipq95xx_eth_get_rmon_stats,
+        .poweron_phy = ipq95xx_eth_poweron_phy,
+        .poweroff_phy = ipq95xx_eth_poweroff_phy,
+        .reset_phy = ipq95xx_eth_reset_phy,
+};
diff --git a/ipq95xx/ipq95xx.h b/ipq95xx/ipq95xx.h
new file mode 100644
index 0000000000000000000000000000000000000000..6017ae2e22c8d4825f458f9fcf3ed3662781b59b
--- /dev/null
+++ b/ipq95xx/ipq95xx.h
@@ -0,0 +1,20 @@
+#ifndef IPQ95XX
+#define IPQ95XX
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int ipq95xx_eth_set_link_settings(const char *ifname, struct eth_link link);
+int ipq95xx_eth_get_link_settings(const char *ifname, struct eth_link *link);
+int ipq95xx_eth_poweron_phy(const char *ifname, struct eth_phy p);
+int ipq95xx_eth_poweroff_phy(const char *ifname, struct eth_phy p);
+int ipq95xx_eth_reset_phy(const char *ifname, int phy_id);
+int ipq95xx_eth_get_stats(const char *ifname, struct eth_stats *s);
+int ipq95xx_eth_get_rmon_stats(const char *ifname, struct eth_rmon_stats *rmon);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* IPQ95XX */