diff --git a/boards/arria/board.h b/boards/arria/board.h
index 87cc6cb041bc8f8e97971bcf733553c1dfaf2174..39b2948f6b5d2c3ecf7d9f84eb9ef0d2d876cc29 100644
--- a/boards/arria/board.h
+++ b/boards/arria/board.h
@@ -6,7 +6,7 @@
 /* Board-specific parameters */
 
 /* WR Core system/CPU clock frequency in Hz */
-#define CPU_CLOCK 62500000ULL
+#define CPU_CLOCK 125000000ULL
 
 /* WR Reference clock period (picoseconds) and frequency (Hz) */
 #define REF_CLOCK_PERIOD_PS 8000
@@ -19,7 +19,7 @@
 #define NET_MAX_SOCKETS 3
 
 /* Socket buffer size, determines the max. RX packet size */
-#define NET_SKBUF_SIZE 256
+#define NET_SKBUF_SIZE 512
 
 /* Number of auxillary clock channels - usually equal to the number of FMCs */
 #define NUM_AUX_CLOCKS 1
diff --git a/lib/arp.c b/lib/arp.c
index 5593ffe3b6a61dcf5a31abc712630240bca1aa19..a8a459e6b7c16a18f5699d3b0013ce7f946a7a6c 100644
--- a/lib/arp.c
+++ b/lib/arp.c
@@ -72,6 +72,8 @@ void arp_poll(void) {
   wr_sockaddr_t addr;
   int len;
   
+  if (needIP) return; /* can't do ARP w/o an address... */
+  
   if ((len = ptpd_netif_recvfrom(arp_socket, &addr, buf, sizeof(buf), 0)) > 0)
     if ((len = process_arp(buf, len)) > 0)
       ptpd_netif_sendto(arp_socket, &addr, buf, len, 0);
diff --git a/lib/bootp.c b/lib/bootp.c
new file mode 100644
index 0000000000000000000000000000000000000000..38d4162107ae4e376c80d96f2faea8f3bbaf8da2
--- /dev/null
+++ b/lib/bootp.c
@@ -0,0 +1,144 @@
+#include <string.h>
+
+#include "ipv4.h"
+
+#define IP_VERSION	0
+#define IP_TOS		(IP_VERSION+1)
+#define IP_LEN		(IP_TOS+1)
+#define IP_ID		(IP_LEN+2)
+#define IP_FLAGS	(IP_ID+2)
+#define IP_TTL		(IP_FLAGS+2)
+#define IP_PROTOCOL	(IP_TTL+1)
+#define IP_CHECKSUM	(IP_PROTOCOL+1)
+#define IP_SOURCE	(IP_CHECKSUM+2)
+#define IP_DEST		(IP_SOURCE+4)
+#define IP_END		(IP_DEST+4)
+
+#define UDP_VIRT_SADDR	(IP_END-12)
+#define UDP_VIRT_DADDR	(UDP_VIRT_SADDR+4)
+#define UDP_VIRT_ZEROS	(UDP_VIRT_DADDR+4)
+#define UDP_VIRT_PROTO	(UDP_VIRT_ZEROS+1)
+#define UDP_VIRT_LENGTH	(UDP_VIRT_PROTO+1)
+
+#define UDP_SPORT	(IP_END)
+#define UDP_DPORT	(UDP_SPORT+2)
+#define UDP_LENGTH	(UDP_DPORT+2)
+#define UDP_CHECKSUM	(UDP_LENGTH+2)
+#define UDP_END		(UDP_CHECKSUM+2)
+
+#define BOOTP_OP	(UDP_END)
+#define BOOTP_HTYPE	(BOOTP_OP+1)
+#define BOOTP_HLEN	(BOOTP_HTYPE+1)
+#define BOOTP_HOPS	(BOOTP_HLEN+1)
+#define BOOTP_XID	(BOOTP_HOPS+1)
+#define BOOTP_SECS	(BOOTP_XID+4)
+#define BOOTP_UNUSED	(BOOTP_SECS+2)
+#define BOOTP_CIADDR	(BOOTP_UNUSED+2)
+#define BOOTP_YIADDR	(BOOTP_CIADDR+4)
+#define BOOTP_SIADDR	(BOOTP_YIADDR+4)
+#define BOOTP_GIADDR	(BOOTP_SIADDR+4)
+#define BOOTP_CHADDR	(BOOTP_GIADDR+4)
+#define BOOTP_SNAME	(BOOTP_CHADDR+16)
+#define BOOTP_FILE	(BOOTP_SNAME+64)
+#define BOOTP_VEND	(BOOTP_FILE+128)
+#define BOOTP_END	(BOOTP_VEND+64)
+
+int send_bootp(uint8_t* buf, int retry) {
+  unsigned short sum;
+  
+  // ----------- BOOTP ------------
+  buf[BOOTP_OP]     = 1; /* bootrequest */
+  buf[BOOTP_HTYPE]  = 1; /* ethernet */
+  buf[BOOTP_HLEN]   = 6; /* MAC length */
+  buf[BOOTP_HOPS]   = 0;
+  
+  /* A unique identifier for the request !!! FIXME */
+  get_mac_addr(buf+BOOTP_XID);
+  buf[BOOTP_XID+0]  ^= buf[BOOTP_XID+4];
+  buf[BOOTP_XID+1]  ^= buf[BOOTP_XID+5];
+  buf[BOOTP_XID+2]  ^= (retry >> 8) & 0xFF;
+  buf[BOOTP_XID+3]  ^=  retry       & 0xFF;
+  
+  buf[BOOTP_SECS]   = (retry >>  8) & 0xFF;
+  buf[BOOTP_SECS+1] =  retry        & 0xFF;
+  memset(buf+BOOTP_UNUSED, 0, 2);
+  
+  memset(buf+BOOTP_CIADDR, 0, 4); /* own IP if known */
+  memset(buf+BOOTP_YIADDR, 0, 4);
+  memset(buf+BOOTP_SIADDR, 0, 4);
+  memset(buf+BOOTP_GIADDR, 0, 4);
+  
+  memset(buf+BOOTP_CHADDR, 0, 16);
+  get_mac_addr(buf+BOOTP_CHADDR); /* own MAC address */
+  
+  memset(buf+BOOTP_SNAME, 0, 64); /* desired BOOTP server */
+  memset(buf+BOOTP_FILE, 0, 128); /* desired BOOTP file */
+  memset(buf+BOOTP_VEND, 0,  64); /* vendor extensions */
+  
+  // ------------ UDP -------------
+  memset(buf+UDP_VIRT_SADDR, 0, 4);
+  memset(buf+UDP_VIRT_DADDR, 0xFF, 4);
+  buf[UDP_VIRT_ZEROS]    = 0;
+  buf[UDP_VIRT_PROTO]    = 0x11; /* UDP */
+  buf[UDP_VIRT_LENGTH]   = (BOOTP_END-IP_END) >> 8;
+  buf[UDP_VIRT_LENGTH+1] = (BOOTP_END-IP_END) & 0xff;
+  
+  buf[UDP_SPORT]      = 0;
+  buf[UDP_SPORT+1]    = 68; /* BOOTP client */
+  buf[UDP_DPORT]      = 0;
+  buf[UDP_DPORT+1]    = 67; /* BOOTP server */
+  buf[UDP_LENGTH]     = (BOOTP_END-IP_END) >> 8;
+  buf[UDP_LENGTH+1]   = (BOOTP_END-IP_END) & 0xff;
+  buf[UDP_CHECKSUM]   = 0;
+  buf[UDP_CHECKSUM+1] = 0;
+  
+  sum = ipv4_checksum((unsigned short*)(buf+UDP_VIRT_SADDR), (BOOTP_END-UDP_VIRT_SADDR)/2);
+  if (sum == 0) sum = 0xFFFF;
+  
+  buf[UDP_CHECKSUM+0] = (sum >> 8);
+  buf[UDP_CHECKSUM+1] = sum & 0xff;
+
+  // ------------ IP --------------
+  buf[IP_VERSION]    = 0x45;
+  buf[IP_TOS]        = 0;
+  buf[IP_LEN+0]      = (BOOTP_END) >> 8;
+  buf[IP_LEN+1]      = (BOOTP_END) & 0xff;
+  buf[IP_ID+0]       = 0;
+  buf[IP_ID+1]       = 0;
+  buf[IP_FLAGS+0]    = 0;
+  buf[IP_FLAGS+1]    = 0;
+  buf[IP_TTL]        = 63;
+  buf[IP_PROTOCOL]   = 17; /* UDP */
+  buf[IP_CHECKSUM+0] = 0;
+  buf[IP_CHECKSUM+1] = 0;
+  memset(buf+IP_SOURCE, 0, 4);
+  memset(buf+IP_DEST, 0xFF, 4);
+  
+  sum = ipv4_checksum((unsigned short*)(buf+IP_VERSION), (IP_END-IP_VERSION)/2);
+  buf[IP_CHECKSUM+0] = sum >> 8;
+  buf[IP_CHECKSUM+1] = sum & 0xff;
+  
+  mprintf("Sending BOOTP request...\n");
+  return BOOTP_END;
+}
+
+int process_bootp(uint8_t* buf, int len) 
+{
+  uint8_t mac[6];
+  get_mac_addr(mac);
+  
+  mprintf("recvd: %d %x %d %d %d\n", len, buf[IP_VERSION], buf[IP_PROTOCOL], buf[UDP_DPORT+1], buf[UDP_SPORT+1]);
+  if (len != BOOTP_END) return 0;
+  
+  if (buf[IP_VERSION] != 0x45) return 0;
+  
+  if (buf[IP_PROTOCOL] != 17 || 
+      buf[UDP_DPORT] != 0 || buf[UDP_DPORT+1] != 68 || 
+      buf[UDP_SPORT] != 0 || buf[UDP_SPORT+1] != 67) return 0;
+  
+  if (memcmp(buf+BOOTP_CHADDR, mac, 6)) return 0;
+  
+  mprintf("Discovered IP address!\n");
+  memcpy(myIP, buf+BOOTP_YIADDR, 4);
+  return 1;
+}
diff --git a/lib/icmp.c b/lib/icmp.c
index d2654703308b09b89de9dd862afe23489b284aee..9091ebd9fe2873a6946ee7b76018db14fe2797cb 100644
--- a/lib/icmp.c
+++ b/lib/icmp.c
@@ -3,8 +3,6 @@
 #include "ipv4.h"
 #include "ptpd_netif.h"
 
-static wr_socket_t* icmp_socket;
-
 #define IP_VERSION	0
 #define IP_TOS		(IP_VERSION+1)
 #define IP_LEN		(IP_TOS+1)
@@ -22,20 +20,7 @@ static wr_socket_t* icmp_socket;
 #define ICMP_CHECKSUM	(ICMP_CODE+1)
 #define ICMP_END	(ICMP_CHECKSUM+2)
 
-void icmp_init(const char* if_name) {
-  wr_sockaddr_t saddr;
-  
-  /* Configure socket filter */
-  memset(&saddr, 0, sizeof(saddr));
-  strcpy(saddr.if_name, if_name);
-  get_mac_addr(&saddr.mac); /* Unicast */
-  saddr.ethertype = htons(0x0800); /* IPv4 */
-  saddr.family = PTPD_SOCK_RAW_ETHERNET;
-  
-  icmp_socket = ptpd_netif_create_socket(PTPD_SOCK_RAW_ETHERNET, 0, &saddr);
-}
-
-static int process_icmp(uint8_t* buf, int len) {
+int process_icmp(uint8_t* buf, int len) {
   int iplen, hisBodyLen;
   uint8_t hisIP[4];
   uint16_t sum;
@@ -89,13 +74,3 @@ static int process_icmp(uint8_t* buf, int len) {
   
   return 24+hisBodyLen;
 }
-
-void icmp_poll(void) {
-  uint8_t buf[ICMP_END+136];
-  wr_sockaddr_t addr;
-  int len;
-  
-  if ((len = ptpd_netif_recvfrom(icmp_socket, &addr, buf, sizeof(buf), 0)) > 0)
-    if ((len = process_icmp(buf, len)) > 0)
-      ptpd_netif_sendto(icmp_socket, &addr, buf, len, 0);
-}
diff --git a/lib/ipv4.c b/lib/ipv4.c
index 36818665462e91020160996b96fb3d2baffaa72b..3565853f6cf0f22b7c5a6b4cfb22a722299e5d3c 100644
--- a/lib/ipv4.c
+++ b/lib/ipv4.c
@@ -2,8 +2,11 @@
 
 #include "endpoint.h"
 #include "ipv4.h"
+#include "ptpd_netif.h"
 
 uint8_t myIP[4];
+int needIP = 1;
+static wr_socket_t* ipv4_socket;
 
 unsigned int ipv4_checksum(unsigned short* buf, int shorts) {
   int i;
@@ -19,19 +22,45 @@ unsigned int ipv4_checksum(unsigned short* buf, int shorts) {
   return (~sum & 0xffff);
 }
 
-void ipv4_init(const char* if_name, uint32_t ip) {
-  uint32_t ip_bigendian;
+void ipv4_init(const char* if_name) {
+  wr_sockaddr_t saddr;
   
-  ip_bigendian = htonl(ip);
-  memcpy(myIP, &ip_bigendian, 4);
+  /* Configure socket filter */
+  memset(&saddr, 0, sizeof(saddr));
+  strcpy(saddr.if_name, if_name);
+  get_mac_addr(&saddr.mac[0]); /* Unicast */
+  saddr.ethertype = htons(0x0800); /* IPv4 */
+  saddr.family = PTPD_SOCK_RAW_ETHERNET;
   
-  arp_init(if_name);
-  icmp_init(if_name);
-  
-  // TRACE_DEV("My IP: %d.%d.%d.%d\n", myIP[0], myIP[1], myIP[2], myIP[3]);
+  ipv4_socket = ptpd_netif_create_socket(PTPD_SOCK_RAW_ETHERNET, 0, &saddr);
 }
 
 void ipv4_poll(void) {
-  arp_poll();
-  icmp_poll();
+  static int retry = 0;
+  static int timer = 0;
+  
+  uint8_t buf[400];
+  wr_sockaddr_t addr;
+  int len;
+  
+  if ((len = ptpd_netif_recvfrom(ipv4_socket, &addr, buf, sizeof(buf), 0)) > 0) {
+    if (needIP && process_bootp(buf, len-14)) {
+      retry = 0;
+      needIP = 0;
+      timer = 0;
+    }
+    
+    if (!needIP && (len = process_icmp(buf, len-14)) > 0)
+      ptpd_netif_sendto(ipv4_socket, &addr, buf, len, 0);
+  }
+  
+  if (needIP && timer == 0) {
+    len = send_bootp(buf, ++retry);
+    
+    memset(addr.mac, 0xFF, 6);
+    addr.ethertype = htons(0x0800); /* IPv4 */
+    ptpd_netif_sendto(ipv4_socket, &addr, buf, len, 0);
+  }
+  
+  if (needIP && ++timer == 100000) timer = 0;
 }
diff --git a/lib/ipv4.h b/lib/ipv4.h
index 8b7c92ab025a273afaf36124c3f8d04510c1a296..0c2e621ad6da571f1812e8f5974d10fbe47658a5 100644
--- a/lib/ipv4.h
+++ b/lib/ipv4.h
@@ -1,17 +1,21 @@
 #ifndef IPV4_H
 #define IPV4_H
 
-void ipv4_init(const char* if_name, uint32_t ip);
+void ipv4_init(const char* if_name);
 void ipv4_poll(void);
 
 /* Internal to IP stack: */
 unsigned int ipv4_checksum(unsigned short* buf, int shorts);
+
 void arp_init(const char* if_name);
-void icmp_init(const char* if_name);
 void arp_poll(void);
-void icmp_poll(void);
 
 extern uint8_t myMAC[6];
 extern uint8_t myIP[4];
+extern int needIP;
+
+int process_icmp(uint8_t* buf, int len);
+int process_bootp(uint8_t* buf, int len); /* non-zero if IP was set */
+int send_bootp(uint8_t* buf, int retry);
 
 #endif
diff --git a/lib/lib.mk b/lib/lib.mk
index 53b47b39aa1e72cfed552a7fa96963a8ad20d705..eca0978b84b3321b95a538dfb43e1cb2c73d8250 100644
--- a/lib/lib.mk
+++ b/lib/lib.mk
@@ -3,6 +3,6 @@ OBJS_LIB= 	lib/mprintf.o \
 						
 ifneq ($(WITH_ETHERBONE), 0)
 
-OBJS_LIB += lib/arp.o lib/icmp.o lib/ipv4.o
+OBJS_LIB += lib/arp.o lib/icmp.o lib/ipv4.o lib/bootp.o
 
 endif
\ No newline at end of file
diff --git a/shell/cmd_ip.c b/shell/cmd_ip.c
index 3d2f86ace6492732fbe7c48fe36a6c8ef1730f3b..f577fad41bbfcea8728f4e328acf314ae835910e 100644
--- a/shell/cmd_ip.c
+++ b/shell/cmd_ip.c
@@ -27,10 +27,15 @@ int cmd_ip(const char *args[])
   } else if (!strcasecmp(args[0], "set") && args[1]) {
     decode_ip(args[1], ip);
     memcpy(myIP, ip, 4);
+    needIP = !ip[0] && !ip[1] && !ip[2] && !ip[3];
   } else {
     return -EINVAL;
   }
   
-  mprintf("IP-address: %d.%d.%d.%d\n", 
-    ip[0], ip[1], ip[2], ip[3]);
+  if (needIP) {
+    mprintf("IP-address: in training\n");
+  } else {
+    mprintf("IP-address: %d.%d.%d.%d\n", 
+      ip[0], ip[1], ip[2], ip[3]);
+  }
 }
diff --git a/shell/cmd_mac.c b/shell/cmd_mac.c
index c87cf1054273246c9e493eea67bf2ff79d8dc408..e5c8bd63c901dc5c75b5004a58ad1bc141ebea9a 100644
--- a/shell/cmd_mac.c
+++ b/shell/cmd_mac.c
@@ -31,6 +31,7 @@ int cmd_mac(const char *args[])
   } else if (!strcasecmp(args[0], "set") && args[1]) {
     decode_mac(args[1], mac);
     set_mac_addr(mac);
+    pfilter_init_default();
   } else if (!strcasecmp(args[0], "setp") && args[1]) {
     decode_mac(args[1], mac);
     set_persistent_mac(mac);
diff --git a/wrc_main.c b/wrc_main.c
index 3662bcacb5342875c3d57e75a81457f6fd132df2..9b322d4bd923a771ca40e073a7994b91fdc6ccc4 100644
--- a/wrc_main.c
+++ b/wrc_main.c
@@ -14,6 +14,7 @@
 //#include "eeprom.h"
 #include "softpll_ng.h"
 #include "persistent_mac.h"
+#include "lib/ipv4.h"
 
 #include "wrc_ptp.h"
 
@@ -59,9 +60,8 @@ void wrc_initialize()
   pps_gen_init();
   wrc_ptp_init();
   
-  /* Derive the IP from the MAC address (10.x.y.z) */
-  /* This will be done with BOOTP in the near future */
-  ipv4_init("wru1", 0x0A000000 | mac_addr[3] << 16 | mac_addr[4] << 8 | mac_addr[5]);
+  ipv4_init("wru1");
+  arp_init("wru1");
 }
 
 #define LINK_WENT_UP 1
@@ -136,33 +136,34 @@ int main(void)
   wrc_gui_mode = 0;
 
   wrc_initialize();
-
-	shell_init();
-
-	wrc_ptp_set_mode(WRC_MODE_SLAVE);
-	wrc_ptp_start();
-
-	for(;;)
-	{
-	
+  shell_init();
+  
+  wrc_ptp_set_mode(WRC_MODE_SLAVE);
+  wrc_ptp_start();
+  
+  for (;;)
+  {
     int l_status = wrc_check_link();
 
     switch (l_status)
     {
+      case LINK_WENT_UP:
+        needIP = 1;
+        break;
+        
       case LINK_UP:
         update_rx_queues();
+        ipv4_poll();
+        arp_poll();
         break;
 
       case LINK_WENT_DOWN:
         spll_init(SPLL_MODE_FREE_RUNNING_MASTER, 0, 1);
-
         break;
-    }        
+    }
 
-		ui_update();
-		wrc_ptp_update();
+    ui_update();
+    wrc_ptp_update();
     spll_update_aux_clocks();
-    ipv4_poll();
   }
 }
-