Index: uspace/drv/nic/rtl8169/defs.h
===================================================================
--- uspace/drv/nic/rtl8169/defs.h	(revision 91e057c6b2bdaac372a47885481f6c956b863278)
+++ uspace/drv/nic/rtl8169/defs.h	(revision 727e639a29bca72f88f06f7456100ac6b162ffc9)
@@ -110,4 +110,10 @@
 };
 
+enum rtl8169_mii_registers {
+	MII_BMCR = 0x00,
+	MII_BMSR = 0x01,
+	MII_ANAR = 0x04,
+};
+
 /** Command register bits */
 enum rtl8169_cr {
@@ -266,4 +272,22 @@
 };
 
+enum rtl8169_phyar {
+	PHYAR_RW_SHIFT = 31, /**< Read (0) or write (1) command */
+	PHYAR_RW_READ = (0 << PHYAR_RW_SHIFT),
+	PHYAR_RW_WRITE = (1 << PHYAR_RW_SHIFT),
+	PHYAR_ADDR_SHIFT = 15,
+	PHYAR_ADDR_MASK = 0x1f,
+	PHYAR_DATA_MASK = 0xffff
+};
+
+enum rtl8169_bmcr {
+	BMCR_RESET = (1 << 15), /**< Software reset */
+	BMCR_SPD_100 = (1 << 13), /**< 100 MBit mode set */
+	BMCR_AN_ENABLE = (1 << 12), /**< Autonegotion enable */
+	BMCR_AN_RESTART = (1 << 9), /**< Restart autonegotion */
+	BMCR_DUPLEX = (1 << 8), /**< Duplex mode: 1=full duplex */
+	BMCR_SPD_1000 = (1 << 6), /**< 1000 Mbit mode set */
+};
+
 enum rtl8169_descr_control {
 	CONTROL_OWN = (1 << 31), /**< Descriptor ownership */
Index: uspace/drv/nic/rtl8169/driver.c
===================================================================
--- uspace/drv/nic/rtl8169/driver.c	(revision 91e057c6b2bdaac372a47885481f6c956b863278)
+++ uspace/drv/nic/rtl8169/driver.c	(revision 727e639a29bca72f88f06f7456100ac6b162ffc9)
@@ -92,4 +92,6 @@
 static int rtl8169_broadcast_set(nic_t *nic_data, nic_broadcast_mode_t mode);
 
+static uint16_t rtl8169_mii_read(rtl8169_t *rtl8169, uint8_t addr);
+static void rtl8169_mii_write(rtl8169_t *rtl8169, uint8_t addr, uint16_t value);
 static void rtl8169_rx_ring_refill(rtl8169_t *rtl8169, unsigned int first,
     unsigned int last);
@@ -494,4 +496,20 @@
     nic_channel_mode_t *duplex, nic_role_t *role)
 {
+	rtl8169_t *rtl8169 = nic_get_specific(nic_get_from_ddf_fun(fun));
+	uint8_t phystatus = pio_read_8(rtl8169->regs + PHYSTATUS);
+
+	*duplex = phystatus & PHYSTATUS_FDX
+	    ? NIC_CM_FULL_DUPLEX : NIC_CM_HALF_DUPLEX;
+
+	if (phystatus & PHYSTATUS_10M)
+		*speed = 10;
+
+	if (phystatus & PHYSTATUS_100M)
+		*speed = 100;
+
+	if (phystatus & PHYSTATUS_1000M)
+		*speed = 1000;
+
+	*role = NIC_ROLE_UNKNOWN;
 	return EOK;
 }
@@ -500,4 +518,26 @@
     nic_channel_mode_t duplex, nic_role_t role)
 {
+	rtl8169_t *rtl8169 = nic_get_specific(nic_get_from_ddf_fun(fun));
+	uint16_t bmcr;
+
+	if (speed != 10 && speed != 100 && speed != 1000)
+		return EINVAL;
+
+ 	if (duplex != NIC_CM_HALF_DUPLEX && duplex != NIC_CM_FULL_DUPLEX)
+		return EINVAL;
+
+	bmcr = rtl8169_mii_read(rtl8169, MII_BMCR);
+	bmcr &= ~(BMCR_DUPLEX | BMCR_SPD_100 | BMCR_SPD_1000);
+	
+	if (duplex == NIC_CM_FULL_DUPLEX)
+		bmcr |= BMCR_DUPLEX;
+
+	if (speed == 100)
+		bmcr |= BMCR_SPD_100;
+
+	if (speed == 1000)
+		bmcr |= BMCR_SPD_1000;
+
+	rtl8169_mii_write(rtl8169, MII_BMCR, bmcr);
 	return EOK;
 }
@@ -517,4 +557,23 @@
 static int rtl8169_autoneg_enable(ddf_fun_t *fun, uint32_t advertisement)
 {
+	rtl8169_t *rtl8169 = nic_get_specific(nic_get_from_ddf_fun(fun));
+	uint16_t bmcr = rtl8169_mii_read(rtl8169, MII_BMCR);
+	uint16_t anar = ANAR_SELECTOR;
+
+	if (advertisement & ETH_AUTONEG_10BASE_T_FULL)
+		anar |= ANAR_10_FD;
+	if (advertisement & ETH_AUTONEG_10BASE_T_HALF)
+		anar |= ANAR_10_HD;
+	if (advertisement & ETH_AUTONEG_100BASE_TX_FULL)
+		anar |= ANAR_100TX_FD;
+	if (advertisement & ETH_AUTONEG_100BASE_TX_HALF)
+		anar |= ANAR_100TX_HD;
+	if (advertisement & ETH_AUTONEG_PAUSE_SYMETRIC)
+		anar |= ANAR_PAUSE;
+
+	bmcr |= BMCR_AN_ENABLE;
+	rtl8169_mii_write(rtl8169, MII_BMCR, bmcr);
+	rtl8169_mii_write(rtl8169, MII_ANAR, anar);
+
 	return EOK;
 }
@@ -522,4 +581,10 @@
 static int rtl8169_autoneg_disable(ddf_fun_t *fun)
 {
+	rtl8169_t *rtl8169 = nic_get_specific(nic_get_from_ddf_fun(fun));
+	uint16_t bmcr = rtl8169_mii_read(rtl8169, MII_BMCR);
+
+	bmcr &= ~BMCR_AN_ENABLE;
+	rtl8169_mii_write(rtl8169, MII_BMCR, bmcr);
+
 	return EOK;
 }
@@ -910,4 +975,39 @@
 }
 
+static uint16_t rtl8169_mii_read(rtl8169_t *rtl8169, uint8_t addr)
+{
+	uint32_t phyar;
+
+	phyar = PHYAR_RW_READ
+	    | ((addr & PHYAR_ADDR_MASK) << PHYAR_ADDR_SHIFT);
+
+	pio_write_32(rtl8169->regs + PHYAR, phyar);
+
+	do {
+		phyar = pio_read_32(rtl8169->regs + PHYAR);
+		usleep(20);
+	} while ((phyar & PHYAR_RW_WRITE) == 0);
+
+	return phyar & PHYAR_DATA_MASK;
+}
+
+static void rtl8169_mii_write(rtl8169_t *rtl8169, uint8_t addr, uint16_t value)
+{
+	uint32_t phyar;
+
+	phyar = PHYAR_RW_WRITE
+	    | ((addr & PHYAR_ADDR_MASK) << PHYAR_ADDR_SHIFT)
+	    | (value & PHYAR_DATA_MASK);
+
+	pio_write_32(rtl8169->regs + PHYAR, phyar);
+
+	do {
+		phyar = pio_read_32(rtl8169->regs + PHYAR);
+		usleep(20);
+	} while ((phyar & PHYAR_RW_WRITE) != 0);
+
+	usleep(20);
+}
+
 /** Main function of RTL8169 driver
 *
