#include <palacios/vmm_string.h>
 #include <palacios/vmm_hashtable.h>
 #include <palacios/vmm_config.h>
+#include <palacios/vmm_ethernet.h>
 
 
 struct v3_vm_info;
 
     /* This is ugly... */
     void * frontend_data; 
+    char fnt_mac[ETH_ALEN];
 };
 
 struct v3_dev_console_ops {
 
--- /dev/null
+/* 
+ * This file is part of the Palacios Virtual Machine Monitor developed
+ * by the V3VEE Project with funding from the United States National 
+ * Science Foundation and the Department of Energy.  
+ *
+ * The V3VEE Project is a joint project between Northwestern University
+ * and the University of New Mexico.  You can find out more at 
+ * http://www.v3vee.org
+ *
+ * Copyright (c) 2011, Lei Xia <lxia@northwestern.edu> 
+ * Copyright (c) 2011, The V3VEE Project <http://www.v3vee.org> 
+ * All rights reserved.
+ *
+ * Author: Lei Xia <lxia@northwestern.edu>
+ *
+ * This is free software.  You are permitted to use,
+ * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
+ */
+
+#ifndef __ETHERNET_H__
+#define __ETHERNET_H__
+
+#define ETHERNET_HEADER_LEN 14
+#define ETHERNET_MTU   1500
+#define ETHERNET_PACKET_LEN (ETHERNET_HEADER_LEN + ETHERNET_MTU)
+#define ETH_ALEN 6
+
+
+#ifdef __V3VEE__
+
+#include <palacios/vmm.h>
+
+static inline int is_multicast_ethaddr(const uint8_t * addr)
+{
+    V3_ASSERT(ETH_ALEN == 6);
+       
+    return (0x01 & addr[0]);
+}
+
+static inline int is_broadcast_ethaddr(const uint8_t * addr)
+{
+    V3_ASSERT(ETH_ALEN == 6);
+       
+    return (addr[0] & addr[1] & addr[2] & addr[3] & addr[4] & addr[5]) == 0xff;
+}
+
+
+static inline int compare_ethaddr(const uint8_t * addr1, const uint8_t * addr2)
+{
+    const uint16_t *a = (const uint16_t *) addr1;
+    const uint16_t *b = (const uint16_t *) addr2;
+
+    V3_ASSERT(ETH_ALEN == 6);
+    return ((a[0] ^ b[0]) | (a[1] ^ b[1]) | (a[2] ^ b[2])) != 0;
+}
+
+
+static inline int compare_ether_hdr(const uint8_t * hdr1, const uint8_t * hdr2)
+{
+    uint32_t *a32 = (uint32_t *)(hdr1 + 2);
+    uint32_t *b32 = (uint32_t *)(hdr2 + 2);
+
+    V3_ASSERT(ETHERNET_HEADER_LEN == 14);
+
+    return (*(uint16_t *)hdr1 ^ *(uint16_t *)hdr2) | (a32[0] ^ b32[0]) |
+             (a32[1] ^ b32[1]) | (a32[2] ^ b32[2]);
+}
+
+#endif
+
+#endif
+
+
 
 #define __VMM_PACKET_H__
 
 #include <palacios/vmm.h>
+#include <palacios/vmm_ethernet.h>
 
 #ifdef __V3VEE__
 
 int V3_send_raw(const char * pkt, uint32_t len);
-int V3_register_mac(const char mac[6], struct v3_vm_info * vm);
+int V3_packet_register_mac(const char * mac, struct v3_vm_info * vm);
 
 #endif
 
 
  * All rights reserved.
  *
  * Author: Lei Xia <lxia@northwestern.edu>
- *        Yuan Tang <ytang@northwestern.edu>
+ *               Yuan Tang <ytang@northwestern.edu>
  *
  * This is free software.  You are permitted to use,
  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
 #define __VNET_H__
 
 #include <palacios/vmm.h>
+#include <palacios/vmm_ethernet.h>
 
 #define MAC_ANY 0
 #define MAC_NOT 1
 #define LINK_ANY 2
 
 #define VNET_HASH_SIZE 17
-#define ETHERNET_HEADER_LEN 14
-#define ETHERNET_MTU   1500
-#define ETHERNET_PACKET_LEN (ETHERNET_HEADER_LEN + ETHERNET_MTU)
-
 #define VMM_DRIVERN 1
 #define GUEST_DRIVERN 0
 
 
 #include <palacios/vmm_lock.h>
 #include <palacios/vmm_util.h>
 #include <devices/pci.h>
+#include <palacios/vmm_ethernet.h>
 
 
 #ifndef CONFIG_DEBUG_VIRTIO_NET
 #define VIRTIO_NET_S_LINK_UP   1       /* Link is up */
 #define VIRTIO_NET_MAX_BUFSIZE (sizeof(struct virtio_net_hdr) + (64 << 10))
 
+
 struct virtio_net_hdr {
        uint8_t flags;
 
 #define TX_QUEUE_SIZE 64
 #define RX_QUEUE_SIZE 1024
 #define CTRL_QUEUE_SIZE 64
-#define ETH_ALEN 6
 
 #define VIRTIO_NET_F_MRG_RXBUF 15      /* Host can merge receive buffers. */
 #define VIRTIO_NET_F_MAC       5       /* Host has given MAC address. */
 #define VIRTIO_NET_F_GSO       6       /* Host handles pkts w/ any GSO type */
 #define VIRTIO_NET_F_HOST_TSO4 11      /* Host can handle TSOv4 in. */
 
+/* this is not how virtio supposed to be,
+ * we may need a separately implemented virtio_pci
+ * In order to make guest to get virtio MAC from host
+ * I added it here  -- Lei
+ */
+ #define VIRTIO_NET_CONFIG 20  
+
+
 struct virtio_net_config
 {
     uint8_t mac[ETH_ALEN];     /* VIRTIO_NET_F_MAC */
     struct vm_device * pci_bus;
     struct list_head dev_list;
     struct v3_vm_info *vm;
+
+    char mac[ETH_ALEN];
 };
 
 struct virtio_net_state {
 
     virtio->virtio_cfg.pci_isr = 0;
        
-    virtio->virtio_cfg.host_features = 0; // (1 << VIRTIO_NET_F_MAC);
+    virtio->virtio_cfg.host_features = 0 | (1 << VIRTIO_NET_F_MAC);
 
     if ((v3_lock_init(&(virtio->rx_lock)) == -1) ||
        (v3_lock_init(&(virtio->tx_lock)) == -1)){
     int port_idx = port % virtio->io_range_size;
     uint16_t queue_idx = virtio->virtio_cfg.vring_queue_selector;
 
-    PrintDebug("Virtio NIC %p: Read  for port %d (index =%d), length=%d\n", private_data,
+    PrintDebug("Virtio NIC %p: Read  for port 0x%x (index =%d), length=%d\n", private_data,
               port, port_idx, length);
        
     switch (port_idx) {
            v3_pci_lower_irq(virtio->virtio_dev->pci_bus, 0, virtio->pci_dev);
            break;
 
+       case VIRTIO_NET_CONFIG ... VIRTIO_NET_CONFIG + ETH_ALEN:
+           *(uint8_t *)dst = virtio->net_cfg.mac[port_idx-VIRTIO_NET_CONFIG];
+           break;
+
        default:
            PrintError("Virtio NIC: Read of Unhandled Virtio Read:%d\n", port_idx);
            return -1;
     net_state->pci_dev = pci_dev;
     net_state->virtio_dev = virtio;
 
-    uchar_t mac[6] = {0x11,0x11,0x11,0x11,0x11,0x11};
-    memcpy(net_state->net_cfg.mac, mac, 6);
-                                                                                                          
-    memcpy(pci_dev->config_data, net_state->net_cfg.mac, ETH_ALEN);
-    
+    memcpy(net_state->net_cfg.mac, virtio->mac, 6);                           
+       
     virtio_init_state(net_state);
 
-
     /* Add backend to list of devices */
     list_add(&(net_state->dev_link), &(virtio->dev_list));
 
     ops->start_tx = virtio_start_tx;
     ops->stop_tx = virtio_stop_tx;
     ops->frontend_data = net_state;
+    memcpy(ops->fnt_mac, virtio->mac, ETH_ALEN);
 
     return 0;
 }
 
+
+static int str2mac(char * macstr, char * mac){
+    char hex[2], *s = macstr;
+    int i = 0;
+
+    while(s){
+       memcpy(hex, s, 2);
+       mac[i++] = (char)atox(hex);     
+       if (i == ETH_ALEN) return 0;
+       s=strchr(s, ':');
+       if(s) s++;
+    }
+
+    return -1;
+}
+
+static inline void random_ethaddr(uchar_t * addr)
+{
+    uint64_t val;
+
+    /* using current rdtsc as random number */
+    rdtscll(val);
+    *(uint64_t *)addr = val;
+       
+    addr [0] &= 0xfe;  /* clear multicast bit */
+    addr [0] |= 0x02;  /* set local assignment bit (IEEE802) */
+}
+
+
 static int virtio_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
     struct vm_device * pci_bus = v3_find_dev(vm, v3_cfg_val(cfg, "bus"));
     struct virtio_dev_state * virtio_state = NULL;
     char * dev_id = v3_cfg_val(cfg, "ID");
-
-    PrintDebug("Virtio NIC: Initializing VIRTIO Network device: %s\n", dev_id);
+    char * macstr = v3_cfg_val(cfg, "mac");
 
     if (pci_bus == NULL) {
        PrintError("Virtio NIC: VirtIO devices require a PCI Bus");
     virtio_state->pci_bus = pci_bus;
     virtio_state->vm = vm;
 
+    if (macstr != NULL && !str2mac(macstr, virtio_state->mac)) {
+       PrintDebug("Virtio NIC: Mac specified %s\n", macstr);
+    }else {
+       PrintDebug("Virtio NIC: MAC not specified\n");
+       random_ethaddr(virtio_state->mac);
+    }
+
     struct vm_device * dev = v3_add_device(vm, dev_id, &dev_ops, virtio_state);
 
     if (dev == NULL) {
 
     PrintDebug("NIC-Bridge: Connect %s to frontend %s\n", 
              dev_id, v3_cfg_val(frontend_cfg, "tag"));
 
+
+    V3_packet_register_mac(bridge->net_ops.fnt_mac, vm);
     v3_hook_host_event(vm, HOST_PACKET_EVT, V3_HOST_EVENT_HANDLER(packet_input), bridge);
 
     return 0;
 
 #include <palacios/vm_guest_mem.h>
 #include <devices/pci.h>
 #include <palacios/vmm_sprintf.h>
+#include <palacios/vmm_ethernet.h>
 
 #ifndef CONFIG_DEBUG_VNET_NIC
 #undef PrintDebug
 
 
 struct vnet_nic_state {
-    char mac[6];
     struct v3_vm_info * vm;
     struct v3_dev_net_ops net_ops;
     int vnet_dev_id;
 }
 
 
-/* tell the frontend to start sending pkt to VNET*/
+/* notify the frontend to start sending pkt to VNET*/
 static void start_tx(void * private_data){
     struct vnet_nic_state *vnetnic = (struct vnet_nic_state *)private_data;
 
     vnetnic->net_ops.start_tx(vnetnic->net_ops.frontend_data);
 }
 
-/* tell the frontend device to stop sending pkt to VNET*/
+/* notify the frontend device to stop sending pkt to VNET*/
 static void stop_tx(void * private_data){
     struct vnet_nic_state *vnetnic = (struct vnet_nic_state *)private_data;
 
     .stop_tx = stop_tx,
 };
 
-static int str2mac(char * macstr, char mac[6]){
-    char hex[2], *s = macstr;
-    int i = 0;
-
-    while(s){
-       memcpy(hex, s, 2);
-       mac[i++] = (char)atox(hex);
-       if (i == 6) return 0;
-       s=strchr(s, ':');
-       if(s) s++;
-    }
-
-    return -1;
-}
 
 static int vnet_nic_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
     struct vnet_nic_state * vnetnic = NULL;
     char * dev_id = v3_cfg_val(cfg, "ID");
-    char * macstr = NULL;
-    char mac[6];
     int vnet_dev_id;
 
     v3_cfg_tree_t * frontend_cfg = v3_cfg_subtree(cfg, "frontend");
-    macstr = v3_cfg_val(frontend_cfg, "mac");
-
-    if (macstr != NULL) {
-       PrintDebug("Vnet-nic: Mac specified %s\n", macstr);
-       str2mac(macstr, mac);
-    }
 
     vnetnic = (struct vnet_nic_state *)V3_Malloc(sizeof(struct vnet_nic_state));
     memset(vnetnic, 0, sizeof(struct vnet_nic_state));
     vnetnic->net_ops.send = vnet_nic_send;
     vnetnic->net_ops.start_rx = start_rx;
     vnetnic->net_ops.stop_rx = stop_rx;
-    memcpy(vnetnic->mac, mac, 6);
     vnetnic->vm = vm;
        
     if (v3_dev_connect_net(vm, v3_cfg_val(frontend_cfg, "tag"), 
     PrintDebug("Vnet-nic: Connect %s to frontend %s\n", 
              dev_id, v3_cfg_val(frontend_cfg, "tag"));
 
-    if ((vnet_dev_id = v3_vnet_add_dev(vm, vnetnic->mac, &vnet_dev_ops, (void *)vnetnic)) == -1) {
-       PrintError("Vnet-nic device %s (mac: %s) fails to registered to VNET\n", dev_id, macstr);
+    if ((vnet_dev_id = v3_vnet_add_dev(vm, vnetnic->net_ops.fnt_mac, &vnet_dev_ops, (void *)vnetnic)) == -1) {
+       PrintError("Vnet-nic device %s fails to registered to VNET\n", dev_id);
        v3_remove_device(dev);
        return 0;
     }
     vnetnic->vnet_dev_id = vnet_dev_id;
 
-    PrintDebug("Vnet-nic device %s (mac: %s, %ld) registered to VNET\n", 
-               dev_id, macstr, *((ulong_t *)vnetnic->mac));
-
-
-//for temporary hack for vnet bridge test
-#if 0
-    {
-       uchar_t zeromac[6] = {0,0,0,0,0,0};
-               
-       if(!strcmp(dev_id, "vnet_nic")){
-           struct v3_vnet_route route;
-               
-           route.dst_id = vnet_dev_id;
-           route.dst_type = LINK_INTERFACE;
-           route.src_id = 0;
-           route.src_type = LINK_EDGE;
-           memcpy(route.dst_mac, zeromac, 6);
-           route.dst_mac_qual = MAC_ANY;
-           memcpy(route.src_mac, zeromac, 6);
-           route.src_mac_qual = MAC_ANY;  
-           v3_vnet_add_route(route);
-
-
-           route.dst_id = 0;
-           route.dst_type = LINK_EDGE;
-           route.src_id = vnet_dev_id;
-           route.src_type = LINK_INTERFACE;
-           memcpy(route.dst_mac, zeromac, 6);
-           route.dst_mac_qual = MAC_ANY;
-           memcpy(route.src_mac, zeromac, 6);
-           route.src_mac_qual = MAC_ANY;
-
-           v3_vnet_add_route(route);
-       }
-    }
-#endif
-
-//for temporary hack for Linux bridge (w/o encapuslation) test
-#if 0
-    {
-       static int vnet_nic_guestid = -1;
-       static int vnet_nic_dom0 = -1;
-       uchar_t zeromac[6] = {0,0,0,0,0,0};
-               
-       if(!strcmp(dev_id, "vnet_nic")){ //domu
-           vnet_nic_guestid = vnet_dev_id;
-       }
-       if (!strcmp(dev_id, "vnet_nic_dom0")){
-           vnet_nic_dom0 = vnet_dev_id;
-       }
-
-       if(vnet_nic_guestid != -1 && vnet_nic_dom0 !=-1){
-           struct v3_vnet_route route;
-               
-           route.src_id = vnet_nic_guestid;
-           route.src_type = LINK_INTERFACE;
-           route.dst_id = vnet_nic_dom0;
-           route.dst_type = LINK_INTERFACE;
-           memcpy(route.dst_mac, zeromac, 6);
-           route.dst_mac_qual = MAC_ANY;
-           memcpy(route.src_mac, zeromac, 6);
-           route.src_mac_qual = MAC_ANY;  
-           v3_vnet_add_route(route);
-
-
-           route.src_id = vnet_nic_dom0;
-           route.src_type = LINK_INTERFACE;
-           route.dst_id = vnet_nic_guestid;
-           route.dst_type = LINK_INTERFACE;
-           memcpy(route.dst_mac, zeromac, 6);
-           route.dst_mac_qual = MAC_ANY;
-           memcpy(route.src_mac, zeromac, 6);
-           route.src_mac_qual = MAC_ANY;
-
-           v3_vnet_add_route(route);
-       }
-    }
-#endif
+    PrintDebug("Vnet-nic device %s registered to VNET\n", dev_id);
 
     return 0;
 }
 
 }
 
 
-int V3_register_mac(const char mac[6], struct v3_vm_info * vm){
+int V3_register_mac(const char * mac, struct v3_vm_info * vm){
 
     return packet_hooks->register_mac(mac, vm);
 }