diff --git a/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImpl.java b/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImpl.java
index d3b3ee0e7e55b49981f79a2b6e42a6ce26be97ee..884618191e562425f599c8434cff9fedfa35c5a5 100755
--- a/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImpl.java
+++ b/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImpl.java
@@ -132,33 +132,34 @@ IFlowReconcileListener, IInfoProvider {
      */
     public static final String MODULE_NAME = "devicemanager";
     public static final String WARN = "warn";
-    public static IDebugCounter cntIncoming;
-    public static IDebugCounter cntReconcileRequest;
-    public static IDebugCounter cntReconcileNoSource;
-    public static IDebugCounter cntReconcileNoDest;
-    public static IDebugCounter cntBroadcastSource;
-    public static IDebugCounter cntNoSource;
-    public static IDebugCounter cntNoDest;
-    public static IDebugCounter cntDhcpClientNameSnooped;
-    public static IDebugCounter cntDeviceOnInternalPortNotLearned;
-    public static IDebugCounter cntPacketNotAllowed;
-    public static IDebugCounter cntNewDevice;
-    public static IDebugCounter cntPacketOnInternalPortForKnownDevice;
-    public static IDebugCounter cntNewEntity;
-    public static IDebugCounter cntDeviceChanged;
-    public static IDebugCounter cntDeviceMoved;
-    public static IDebugCounter cntCleanupEntitiesRuns;
-    public static IDebugCounter cntEntityRemovedTimeout;
-    public static IDebugCounter cntDeviceDeleted;
-    public static IDebugCounter cntDeviceReclassifyDelete;
-    public static IDebugCounter cntDeviceStrored;
-    public static IDebugCounter cntDeviceStoreThrottled;
-    public static IDebugCounter cntDeviceRemovedFromStore;
-    public static IDebugCounter cntSyncException;
-    public static IDebugCounter cntDevicesFromStore;
-    public static IDebugCounter cntConsolidateStoreRuns;
-    public static IDebugCounter cntConsolidateStoreDevicesRemoved;
-    public static IDebugCounter cntTransitionToMaster;
+    public IDebugCounter cntIncoming;
+    public IDebugCounter cntReconcileRequest;
+    public IDebugCounter cntReconcileNoSource;
+    public IDebugCounter cntReconcileNoDest;
+    public IDebugCounter cntInvalidSource;
+    public IDebugCounter cntInvalidDest;
+    public IDebugCounter cntNoSource;
+    public IDebugCounter cntNoDest;
+    public IDebugCounter cntDhcpClientNameSnooped;
+    public IDebugCounter cntDeviceOnInternalPortNotLearned;
+    public IDebugCounter cntPacketNotAllowed;
+    public IDebugCounter cntNewDevice;
+    public IDebugCounter cntPacketOnInternalPortForKnownDevice;
+    public IDebugCounter cntNewEntity;
+    public IDebugCounter cntDeviceChanged;
+    public IDebugCounter cntDeviceMoved;
+    public IDebugCounter cntCleanupEntitiesRuns;
+    public IDebugCounter cntEntityRemovedTimeout;
+    public IDebugCounter cntDeviceDeleted;
+    public IDebugCounter cntDeviceReclassifyDelete;
+    public IDebugCounter cntDeviceStrored;
+    public IDebugCounter cntDeviceStoreThrottled;
+    public IDebugCounter cntDeviceRemovedFromStore;
+    public IDebugCounter cntSyncException;
+    public IDebugCounter cntDevicesFromStore;
+    public IDebugCounter cntConsolidateStoreRuns;
+    public IDebugCounter cntConsolidateStoreDevicesRemoved;
+    public IDebugCounter cntTransitionToMaster;
 
     private boolean isMaster = false;
 
@@ -924,10 +925,10 @@ IFlowReconcileListener, IInfoProvider {
                 "Number of flow reconcile events that failed because no " +
                 "destination device could be identified",
                 CounterType.ALWAYS_COUNT, WARN); // is this really a warning
-            cntBroadcastSource = debugCounters.registerCounter(MODULE_NAME,
-                "broadcast-source",
+            cntInvalidSource = debugCounters.registerCounter(MODULE_NAME,
+                "invalid-source",
                 "Number of packetIns that were discarded because the source " +
-                "MAC was broadcast or multicast",
+                "MAC was invalid (broadcast, multicast, or zero)",
                 CounterType.ALWAYS_COUNT, WARN);
             cntNoSource = debugCounters.registerCounter(MODULE_NAME, "no-source-device",
                  "Number of packetIns that were discarded because the " +
@@ -935,6 +936,11 @@ IFlowReconcileListener, IInfoProvider {
                  "packet is not allowed, appears on an illegal port, does not " +
                  "have a valid address space, etc.",
                  CounterType.ALWAYS_COUNT, WARN);
+            cntInvalidDest = debugCounters.registerCounter(MODULE_NAME,
+                "invalid-dest",
+                "Number of packetIns that were discarded because the dest " +
+                "MAC was invalid (zero)",
+                CounterType.ALWAYS_COUNT, WARN);
             cntNoDest = debugCounters.registerCounter(MODULE_NAME, "no-dest-device",
                  "Number of packetIns that did not have an associated " +
                  "destination device. E.g., because the destination MAC is " +
@@ -1093,7 +1099,7 @@ IFlowReconcileListener, IInfoProvider {
         Entity srcEntity =
                 getSourceEntityFromPacket(eth, sw.getId(), pi.getInPort());
         if (srcEntity == null) {
-            cntBroadcastSource.updateCounterNoFlush();
+            cntInvalidSource.updateCounterNoFlush();
             return Command.STOP;
         }
 
@@ -1117,6 +1123,10 @@ IFlowReconcileListener, IInfoProvider {
 
         // Find the device matching the destination from the entity
         // classes of the source.
+        if (eth.getDestinationMAC().toLong() == 0) {
+            cntInvalidDest.updateCounterNoFlush();
+            return Command.STOP;
+        }
         Entity dstEntity = getDestEntityFromPacket(eth);
         Device dstDevice = null;
         if (dstEntity != null) {
@@ -1188,8 +1198,9 @@ IFlowReconcileListener, IInfoProvider {
     }
 
     /**
-     * Get sender IP address from packet if the packet is either an ARP
-     * packet.
+     * Get sender IP address from packet if the packet is an ARP
+     * packet and if the source MAC address matches the ARP packets
+     * sender MAC address.
      * @param eth
      * @param dlAddr
      * @return
@@ -1221,6 +1232,9 @@ IFlowReconcileListener, IInfoProvider {
         // Ignore broadcast/multicast source
         if ((dlAddrArr[0] & 0x1) != 0)
             return null;
+        // Ignore 0 source mac
+        if (dlAddr == 0)
+            return null;
 
         short vlan = eth.getVlanID();
         int nwSrc = getSrcNwAddr(eth, dlAddr);
@@ -1255,6 +1269,9 @@ IFlowReconcileListener, IInfoProvider {
         // Ignore broadcast/multicast source
         if ((senderHardwareAddr[0] & 0x1) != 0)
             return;
+        // Ignore zero sender mac
+        if (senderAddr == 0)
+            return;
 
         short vlan = eth.getVlanID();
         int nwSrc = IPv4.toIPv4Address(arp.getSenderProtocolAddress());
@@ -1283,6 +1300,9 @@ IFlowReconcileListener, IInfoProvider {
         // Ignore broadcast/multicast destination
         if ((dlAddrArr[0] & 0x1) != 0)
             return null;
+        // Ignore zero dest mac
+        if (dlAddr == 0)
+            return null;
 
         if (eth.getPayload() instanceof IPv4) {
             IPv4 ipv4 = (IPv4) eth.getPayload();
diff --git a/src/test/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImplTest.java b/src/test/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImplTest.java
index e9443b810c2ab8bd94ee97a9f2e01a0c2a83ceff..36a844d1c251f0d10b963460a432303ec077a0da 100644
--- a/src/test/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImplTest.java
+++ b/src/test/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImplTest.java
@@ -49,7 +49,9 @@ import java.util.Map.Entry;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 
+import net.floodlightcontroller.core.FloodlightContext;
 import net.floodlightcontroller.core.IFloodlightProviderService;
+import net.floodlightcontroller.core.IListener.Command;
 import net.floodlightcontroller.core.IOFSwitch;
 import net.floodlightcontroller.core.IFloodlightProviderService.Role;
 import net.floodlightcontroller.core.ImmutablePort;
@@ -72,9 +74,11 @@ import net.floodlightcontroller.devicemanager.test.MockFlexEntityClassifier;
 import net.floodlightcontroller.flowcache.FlowReconcileManager;
 import net.floodlightcontroller.flowcache.IFlowReconcileService;
 import net.floodlightcontroller.packet.ARP;
+import net.floodlightcontroller.packet.Data;
 import net.floodlightcontroller.packet.Ethernet;
 import net.floodlightcontroller.packet.IPacket;
 import net.floodlightcontroller.packet.IPv4;
+import net.floodlightcontroller.packet.UDP;
 import net.floodlightcontroller.restserver.IRestApiService;
 import net.floodlightcontroller.restserver.RestApiServer;
 import net.floodlightcontroller.storage.IStorageSourceService;
@@ -104,11 +108,12 @@ public class DeviceManagerImplTest extends FloodlightTestCase {
     protected static Logger logger =
             LoggerFactory.getLogger(DeviceManagerImplTest.class);
 
-    protected OFPacketIn packetIn_1, packetIn_2, packetIn_3;
-    protected IPacket testARPReplyPacket_1, testARPReplyPacket_2,
-    testARPReplyPacket_3;
-    protected IPacket testARPReqPacket_1, testARPReqPacket_2;
+    protected OFPacketIn testARPReplyPacketIn_1, testARPReplyPacketIn_2;
+    protected OFPacketIn testUDPPacketIn;
+    protected IPacket testARPReplyPacket_1, testARPReplyPacket_2;
+    protected Ethernet testUDPPacket;
     protected byte[] testARPReplyPacket_1_Srld, testARPReplyPacket_2_Srld;
+    protected byte[] testUDPPacketSrld;
     private MockSyncService syncService;
     private IStoreClient<String, DeviceSyncRepresentation> storeClient;
 
@@ -236,7 +241,8 @@ public class DeviceManagerImplTest extends FloodlightTestCase {
                     .setTargetProtocolAddress(IPv4.toIPv4AddressBytes("192.168.1.2")));
         this.testARPReplyPacket_1_Srld = testARPReplyPacket_1.serialize();
 
-        // Another test packet with a different source IP
+        // Another test packet with the same ARP payload as packet 1 but with
+        // a different source MAC. (i.e., sender MAC and source MAC differ)
         this.testARPReplyPacket_2 = new Ethernet()
         .setSourceMACAddress("00:99:88:77:66:55")
         .setDestinationMACAddress("00:11:22:33:44:55")
@@ -255,8 +261,25 @@ public class DeviceManagerImplTest extends FloodlightTestCase {
                     .setTargetProtocolAddress(IPv4.toIPv4AddressBytes("192.168.1.2")));
         this.testARPReplyPacket_2_Srld = testARPReplyPacket_2.serialize();
 
+        // This packet reverses the MACs and IP from testARPReplyPacket_1
+        this.testUDPPacket = (Ethernet) new Ethernet()
+        .setSourceMACAddress("00:11:22:33:44:55")
+        .setDestinationMACAddress("00:44:33:22:11:01")
+        .setEtherType(Ethernet.TYPE_IPv4)
+        .setVlanID((short)5)
+        .setPayload(
+                    new IPv4()
+                    .setTtl((byte) 128)
+                    .setSourceAddress("192.168.1.2")
+                    .setDestinationAddress("192.168.1.1")
+                    .setPayload(new UDP()
+                    .setSourcePort((short) 5000)
+                    .setDestinationPort((short) 5001)
+                    .setPayload(new Data(new byte[] {0x01}))));
+        updateUDPPacketIn();
+
         // Build the PacketIn
-        this.packetIn_1 = ((OFPacketIn) mockFloodlightProvider.
+        this.testARPReplyPacketIn_1 = ((OFPacketIn) mockFloodlightProvider.
                 getOFMessageFactory().getMessage(OFType.PACKET_IN))
                 .setBufferId(-1)
                 .setInPort((short) 1)
@@ -265,18 +288,32 @@ public class DeviceManagerImplTest extends FloodlightTestCase {
                 .setTotalLength((short) this.testARPReplyPacket_1_Srld.length);
 
         // Build the PacketIn
-        this.packetIn_2 = ((OFPacketIn) mockFloodlightProvider.
+        this.testARPReplyPacketIn_2 = ((OFPacketIn) mockFloodlightProvider.
                 getOFMessageFactory().getMessage(OFType.PACKET_IN))
                 .setBufferId(-1)
                 .setInPort((short) 1)
                 .setPacketData(this.testARPReplyPacket_2_Srld)
                 .setReason(OFPacketInReason.NO_MATCH)
                 .setTotalLength((short) this.testARPReplyPacket_2_Srld.length);
-    }
-
 
 
+    }
 
+    /**
+     * Updates testUDPPacketIn and testUDPPacketSrld from testUDPPacket
+     * To be called after testUDPPacket has been mangled.
+     */
+    private void updateUDPPacketIn() {
+        this.testUDPPacketSrld = this.testUDPPacket.serialize();
+        // Build the PacketIn
+        this.testUDPPacketIn = ((OFPacketIn) mockFloodlightProvider.
+                getOFMessageFactory().getMessage(OFType.PACKET_IN))
+                .setBufferId(-1)
+                .setInPort((short) 3)
+                .setPacketData(this.testUDPPacketSrld)
+                .setReason(OFPacketInReason.NO_MATCH)
+                .setTotalLength((short) this.testUDPPacketSrld.length);
+    }
 
     @Test
     public void testLastSeen() throws Exception {
@@ -298,6 +335,7 @@ public class DeviceManagerImplTest extends FloodlightTestCase {
         assertEquals(c.getTime(), d.getLastSeen());
     }
 
+
     @Test
     public void testEntityLearning() throws Exception {
         IDeviceListener mockListener =
@@ -996,114 +1034,172 @@ public class DeviceManagerImplTest extends FloodlightTestCase {
         assertArrayEquals(new SwitchPort[] { new SwitchPort(1L, OFPort.OFPP_LOCAL.getValue()) }, aps);
     }
 
-    @Test
-    public void testPacketInBasic(byte[] deviceMac, OFPacketIn packetIn) {
-        // Mock up our expected behavior
-        ITopologyService mockTopology = createMock(ITopologyService.class);
-        deviceManager.topology = mockTopology;
-        expect(mockTopology.isAttachmentPointPort(EasyMock.anyLong(),
-                EasyMock.anyShort())).
-                andReturn(true).anyTimes();
+    private static void
+            mockTopologyForPacketInTests(ITopologyService mockTopology) {
+        expect(mockTopology.isAttachmentPointPort(anyLong(),
+                anyShort())).
+                andReturn(true).
+                anyTimes();
         expect(mockTopology.isConsistent(EasyMock.anyLong(),
                 EasyMock.anyShort(),
                 EasyMock.anyLong(),
                 EasyMock.anyShort())).andReturn(false).
                 anyTimes();
-        expect(mockTopology.getL2DomainId(EasyMock.anyLong())).andReturn(1L).anyTimes();
-        replay(mockTopology);
+        expect(mockTopology.isBroadcastDomainPort(EasyMock.anyLong(),
+                EasyMock.anyShort()))
+                .andReturn(false)
+                .anyTimes();
+        expect(mockTopology.getL2DomainId(anyLong())).andReturn(1L).anyTimes();
+        expect(mockTopology.isInSameBroadcastDomain(anyLong(),
+                                                    anyShort(),
+                                                    anyLong(),
+                                                    anyShort()))
+                .andReturn(false).anyTimes();
 
-        Date currentDate = new Date();
+    }
+
+    private Command dispatchPacketIn(long swId, OFPacketIn pi,
+                                     FloodlightContext cntx) {
+        IOFSwitch sw = mockFloodlightProvider.getSwitch(swId);
+        Ethernet eth = new Ethernet();
+        eth.deserialize(pi.getPacketData(), 0, pi.getPacketData().length);
+        IFloodlightProviderService.bcStore.put(cntx,
+                IFloodlightProviderService.CONTEXT_PI_PAYLOAD,
+                eth);
+        return deviceManager.receive(sw, pi, cntx);
+    }
+
+    /**
+     * Verify that the given device exactly matches the given fields. E.g.,
+     * if ip is not null we expect the device to have exactly one IP address.
+     * swId and port are the attachment point port.
+     * Vlan and ip are optional all other fields must be specified.
+     * @return
+     */
+    private static void verifyDevice(IDevice d, long mac, Short vlan, Integer ip,
+                                long swId, int port) {
+        assertNotNull(d);
+        assertEquals(mac, d.getMACAddress());
+        if (vlan == null)
+            assertArrayEquals(new Short[0], d.getVlanId());
+        else
+            assertArrayEquals(new Short[] { vlan }, d.getVlanId());
+
+        if (ip == null)
+            assertArrayEquals(new Integer[0], d.getIPv4Addresses());
+        else
+            assertArrayEquals(new Integer[] { ip }, d.getIPv4Addresses());
+
+        SwitchPort expectedAp = new SwitchPort(swId, port);
+        assertArrayEquals(new SwitchPort[] { expectedAp },
+                          d.getAttachmentPoints());
+    }
 
-        // build our expected Device
+
+    @Test
+    public void testPacketInBasic() throws Exception {
+        byte[] deviceMac =
+                ((Ethernet)this.testARPReplyPacket_1).getSourceMACAddress();
+        OFPacketIn packetIn = testARPReplyPacketIn_1;
         Integer ipaddr = IPv4.toIPv4Address("192.168.1.1");
-        Device device =
-                new Device(deviceManager,
-                        new Long(deviceManager.deviceKeyCounter),
-                        new Entity(Ethernet.toLong(deviceMac),
-                                (short)5,
-                                ipaddr,
-                                1L,
-                                1,
-                                currentDate),
-                                DefaultEntityClassifier.entityClass);
-
-        // Get the listener and trigger the packet in
-        IOFSwitch switch1 = mockFloodlightProvider.getSwitch(1L);
-        mockFloodlightProvider.dispatchMessage(switch1, packetIn);
 
-        // Verify the replay matched our expectations
-        // verify(mockTopology);
+        // Mock up our expected behavior
+        ITopologyService mockTopology = createMock(ITopologyService.class);
+        deviceManager.topology = mockTopology;
+        mockTopologyForPacketInTests(mockTopology);
+        replay(mockTopology);
 
+        FloodlightContext cntx = new FloodlightContext();
+        Command cmd = dispatchPacketIn(1L, packetIn, cntx);
+        verify(mockTopology);
+        assertEquals(Command.CONTINUE, cmd);
         // Verify the device
         Device rdevice = (Device)
                 deviceManager.findDevice(Ethernet.toLong(deviceMac),
                         (short)5, null, null, null);
-
-        assertEquals(device, rdevice);
-        assertEquals(new Short((short)5), rdevice.getVlanId()[0]);
+        verifyDevice(rdevice, Ethernet.toLong(deviceMac),
+                     (short)5, ipaddr, 1L, 1);
+        IDevice cntxSrcDev = IDeviceService.fcStore.get(cntx,
+                IDeviceService.CONTEXT_SRC_DEVICE);
+        assertEquals(rdevice, cntxSrcDev);
+        IDevice cntxDstDev = IDeviceService.fcStore.get(cntx,
+                IDeviceService.CONTEXT_DST_DEVICE);
+        assertNull(cntxDstDev);
 
         Device result = null;
         Iterator<? extends IDevice> dstiter =
-                deviceManager.queryClassDevices(device.getEntityClass(),
-                        null, null, ipaddr,
+                deviceManager.queryDevices(null, null, ipaddr,
                         null, null);
         if (dstiter.hasNext()) {
             result = (Device)dstiter.next();
         }
+        assertFalse("There shouldn't be more than 1 device", dstiter.hasNext());
+        assertEquals(rdevice, result);
 
-        assertEquals(device, result);
-
-        device =
-                new Device(device,
-                        new Entity(Ethernet.toLong(deviceMac),
-                                (short)5,
-                                ipaddr,
-                                5L,
-                                2,
-                                currentDate),
-                                -1);
 
+        //-----------------
+        // Test packetIn again with a different source port. Should be
+        // the same device
         reset(mockTopology);
-        expect(mockTopology.isAttachmentPointPort(anyLong(),
-                anyShort())).
-                andReturn(true).
-                anyTimes();
-        expect(mockTopology.isConsistent(EasyMock.anyLong(),
-                EasyMock.anyShort(),
-                EasyMock.anyLong(),
-                EasyMock.anyShort())).andReturn(false).
-                anyTimes();
-        expect(mockTopology.isBroadcastDomainPort(EasyMock.anyLong(),
-                EasyMock.anyShort()))
-                .andReturn(false)
-                .anyTimes();
-        expect(mockTopology.getL2DomainId(1L)).andReturn(1L).anyTimes();
-        expect(mockTopology.getL2DomainId(5L)).andReturn(1L).anyTimes();
-        expect(mockTopology.isInSameBroadcastDomain(1L, (short)1, 5L, (short)2)).
-        andReturn(false).anyTimes();
-
-        // Start recording the replay on the mocks
+        mockTopologyForPacketInTests(mockTopology);
         replay(mockTopology);
-        // Get the listener and trigger the packet in
-        IOFSwitch switch5 = mockFloodlightProvider.getSwitch(5L);
-        mockFloodlightProvider.
-        dispatchMessage(switch5, this.packetIn_1.setInPort((short)2));
 
-        // Verify the replay matched our expectations
+        // trigger the packet in
+        cntx = new FloodlightContext();
+        packetIn.setInPort((short)2);
+        cmd = dispatchPacketIn(5L, packetIn, cntx);
         verify(mockTopology);
+        // Verify the replay matched our expectations
+        assertEquals(Command.CONTINUE, cmd);
 
         // Verify the device
         rdevice = (Device)
                 deviceManager.findDevice(Ethernet.toLong(deviceMac),
                         (short)5, null, null, null);
-        assertEquals(device, rdevice);
-    }
+        verifyDevice(rdevice, Ethernet.toLong(deviceMac),
+                     (short)5, ipaddr, 5L, 2);
+        cntxSrcDev = IDeviceService.fcStore.get(cntx,
+                IDeviceService.CONTEXT_SRC_DEVICE);
+        assertEquals(rdevice, cntxSrcDev);
+        cntxDstDev = IDeviceService.fcStore.get(cntx,
+                IDeviceService.CONTEXT_DST_DEVICE);
+        assertNull(cntxDstDev);
+        // There can be only one device
+        assertEquals(1, deviceManager.getAllDevices().size());
 
-    @Test
-    public void testPacketIn() throws Exception {
-        byte[] deviceMac1 =
-                ((Ethernet)this.testARPReplyPacket_1).getSourceMACAddress();
-        testPacketInBasic(deviceMac1, packetIn_1);
+        //----------------------------
+        // Test packetIn with a different packet going the reverse direction.
+        // We should now get source and dest device in the context
+        //==> The destination device in this step has been learned just before
+        long srcMac = Ethernet.toLong(testUDPPacket.getSourceMACAddress());
+        long dstMac = Ethernet.toLong(deviceMac);
+        reset(mockTopology);
+        mockTopologyForPacketInTests(mockTopology);
+        replay(mockTopology);
+        // trigger the packet in
+        cntx = new FloodlightContext();
+        cmd = dispatchPacketIn(1L, testUDPPacketIn, cntx);
+        verify(mockTopology);
+
+        assertEquals(Command.CONTINUE, cmd);
+        IDevice srcDev =
+                deviceManager.findDevice(srcMac, (short)5, null, null, null);
+        verifyDevice(srcDev, srcMac, (short)5, null,
+                     1L, testUDPPacketIn.getInPort());
+
+        IDevice dstDev =
+                deviceManager.findDevice(dstMac, (short)5, null, null, null);
+        verifyDevice(dstDev, dstMac, (short)5, ipaddr, 5L, 2);
+
+        cntxSrcDev = IDeviceService.fcStore.get(cntx,
+                IDeviceService.CONTEXT_SRC_DEVICE);
+        assertEquals(srcDev, cntxSrcDev);
+
+        cntxDstDev = IDeviceService.fcStore.get(cntx,
+                IDeviceService.CONTEXT_DST_DEVICE);
+        assertEquals(dstDev, cntxDstDev);
+
+        assertEquals(2, deviceManager.getAllDevices().size());
     }
 
     /**
@@ -1112,16 +1208,188 @@ public class DeviceManagerImplTest extends FloodlightTestCase {
      * in an ARP response whenever the senderHardwareAddress is different
      * from the source MAC address of the Ethernet frame.
      *
-     * This test is the same as testPacketIn method, except for the
-     * packet-in that's used.
      * @throws Exception
      */
     @Test
     public void testDeviceLearningFromArpResponseData() throws Exception {
         ARP arp = (ARP)((Ethernet)this.testARPReplyPacket_2).getPayload();
-        byte[] deviceMac2 = arp.getSenderHardwareAddress();
+        long senderMac = Ethernet.toLong(arp.getSenderHardwareAddress());
+        long sourceMac =
+                Ethernet.toLong(((Ethernet)this.testARPReplyPacket_2)
+                                .getSourceMACAddress());
+        Integer ipaddr = IPv4.toIPv4Address("192.168.1.1");
+        OFPacketIn packetIn = testARPReplyPacketIn_2;
+
+        // Mock up our expected behavior
+        ITopologyService mockTopology = createMock(ITopologyService.class);
+        deviceManager.topology = mockTopology;
+        mockTopologyForPacketInTests(mockTopology);
+        replay(mockTopology);
+
+
+        FloodlightContext cntx = new FloodlightContext();
+        Command cmd = dispatchPacketIn(1L, packetIn, cntx);
+        verify(mockTopology);
+        assertEquals(Command.CONTINUE, cmd);
+        // Verify the device for the sender HW address
+        Device senderDev = (Device)
+                deviceManager.findDevice(senderMac, (short)5, null, null, null);
+        verifyDevice(senderDev, senderMac, (short)5, ipaddr, 1L, 1);
 
-        testPacketInBasic(deviceMac2, packetIn_2);
+        Device result = null;
+        Iterator<? extends IDevice> dstiter =
+                deviceManager.queryDevices(null, null, ipaddr,
+                        null, null);
+        if (dstiter.hasNext()) {
+            result = (Device)dstiter.next();
+        }
+        assertFalse("There shouldn't be more than 1 device", dstiter.hasNext());
+        assertEquals(senderDev, result);
+
+
+
+        // Verify the device for the source MAC
+        Device srcDev = (Device)
+                deviceManager.findDevice(sourceMac, (short)5, null, null, null);
+        // must NOT learn IP on this device
+        verifyDevice(srcDev, sourceMac, (short)5, null, 1L, 1);
+        assertFalse("Device must differ", srcDev.equals(senderDev));
+        // Context is annotated with this device, not the device associated
+        // with ARP sender address
+        IDevice cntxSrcDev = IDeviceService.fcStore.get(cntx,
+                IDeviceService.CONTEXT_SRC_DEVICE);
+        assertEquals(srcDev, cntxSrcDev);
+
+        assertEquals(2, deviceManager.getAllDevices().size());
+    }
+
+
+    @Test
+    public void testPacketInInvalidSrcMac() throws Exception {
+        // Mock up our expected behavior
+        ITopologyService mockTopology = createMock(ITopologyService.class);
+        deviceManager.topology = mockTopology;
+        mockTopologyForPacketInTests(mockTopology);
+        replay(mockTopology);
+        FloodlightContext cntx = new FloodlightContext();
+
+        testUDPPacket.setSourceMACAddress(Ethernet.toByteArray(0L));
+        updateUDPPacketIn();
+        Command cmd = dispatchPacketIn(1L, testUDPPacketIn, cntx);
+        assertEquals(Command.STOP, cmd);
+        IDevice cntxSrcDev = IDeviceService.fcStore.get(cntx,
+                IDeviceService.CONTEXT_SRC_DEVICE);
+        assertNull(cntxSrcDev);
+        IDevice cntxDstDev = IDeviceService.fcStore.get(cntx,
+                IDeviceService.CONTEXT_DST_DEVICE);
+        assertNull(cntxDstDev);
+
+        testUDPPacket.setSourceMACAddress(Ethernet.toByteArray(-1L));
+        updateUDPPacketIn();
+        cmd = dispatchPacketIn(1L, testUDPPacketIn, cntx);
+        assertEquals(Command.STOP, cmd);
+        cntxSrcDev = IDeviceService.fcStore.get(cntx,
+                IDeviceService.CONTEXT_SRC_DEVICE);
+        assertNull(cntxSrcDev);
+        cntxDstDev = IDeviceService.fcStore.get(cntx,
+                IDeviceService.CONTEXT_DST_DEVICE);
+        assertNull(cntxDstDev);
+
+        // MAC with only the multicast bit set
+        testUDPPacket.setSourceMACAddress(new byte[] { 1, 0, 0, 0, 0, 0 });
+        updateUDPPacketIn();
+        cmd = dispatchPacketIn(1L, testUDPPacketIn, cntx);
+        assertEquals(Command.STOP, cmd);
+        cntxSrcDev = IDeviceService.fcStore.get(cntx,
+                IDeviceService.CONTEXT_SRC_DEVICE);
+        assertNull(cntxSrcDev);
+        cntxDstDev = IDeviceService.fcStore.get(cntx,
+                IDeviceService.CONTEXT_DST_DEVICE);
+        assertNull(cntxDstDev);
+
+        // Now use a real MAC. We should get a src device
+        testUDPPacket.setSourceMACAddress(Ethernet.toByteArray(1L));
+        updateUDPPacketIn();
+        cmd = dispatchPacketIn(1L, testUDPPacketIn, cntx);
+        assertEquals(Command.CONTINUE, cmd);
+        cntxSrcDev = IDeviceService.fcStore.get(cntx,
+                IDeviceService.CONTEXT_SRC_DEVICE);
+        verifyDevice(cntxSrcDev, 1L, (short)5, null,
+                     1L, testUDPPacketIn.getInPort());
+
+        cntxDstDev = IDeviceService.fcStore.get(cntx,
+                IDeviceService.CONTEXT_DST_DEVICE);
+        assertNull(cntxDstDev);
+        verify(mockTopology);
+    }
+
+
+    @Test
+    public void testPacketInInvalidDstMac() throws Exception {
+        // Mock up our expected behavior
+        ITopologyService mockTopology = createMock(ITopologyService.class);
+        deviceManager.topology = mockTopology;
+        mockTopologyForPacketInTests(mockTopology);
+        replay(mockTopology);
+        FloodlightContext cntx = new FloodlightContext();
+
+        long srcMac = Ethernet.toLong(testUDPPacket.getSourceMACAddress());
+        long dstMac = Ethernet.toLong(testUDPPacket.getDestinationMACAddress());
+
+        // Prime device manager with the source device
+        Command cmd = dispatchPacketIn(1L, testUDPPacketIn, cntx);
+        assertEquals(Command.CONTINUE, cmd);
+        IDevice cntxSrcDev = IDeviceService.fcStore.get(cntx,
+                IDeviceService.CONTEXT_SRC_DEVICE);
+        verifyDevice(cntxSrcDev, srcMac, (short)5, null,
+                     1L, testUDPPacketIn.getInPort());
+        IDevice cntxDstDev = IDeviceService.fcStore.get(cntx,
+                IDeviceService.CONTEXT_DST_DEVICE);
+        assertNull(cntxDstDev);
+        IDevice expectedSrcDev = cntxSrcDev;
+
+        // Create a device for the destination. We can use testARPPacketIn_1
+        // for that.
+        cntx = new FloodlightContext();
+        // Prime device manager with the source device
+        cmd = dispatchPacketIn(1L, testARPReplyPacketIn_1, cntx);
+        assertEquals(Command.CONTINUE, cmd);
+        cntxSrcDev = IDeviceService.fcStore.get(cntx,
+                IDeviceService.CONTEXT_SRC_DEVICE);
+        // yes: we check that cntxSrcDev matched dstMAC because we are
+        // just adding the dest device
+        int ip = IPv4.toIPv4Address("192.168.1.1");
+        verifyDevice(cntxSrcDev, dstMac, (short)5, ip,
+                     1L, testARPReplyPacketIn_1.getInPort());
+        // yes: we set the expected dst device to the current srcDev
+        IDevice expectedDstDev = cntxSrcDev;
+
+        //-------------------------------
+        // Let the real tests begin
+
+        cntx = new FloodlightContext();
+        testUDPPacket.setDestinationMACAddress(Ethernet.toByteArray(0L));
+        updateUDPPacketIn();
+        cmd = dispatchPacketIn(1L, testUDPPacketIn, cntx);
+        assertEquals(Command.STOP, cmd);
+        cntxDstDev = IDeviceService.fcStore.get(cntx,
+                IDeviceService.CONTEXT_DST_DEVICE);
+        assertNull(cntxDstDev);
+
+        // use a real dest mac
+        cntx = new FloodlightContext();
+        testUDPPacket.setDestinationMACAddress(Ethernet.toByteArray(dstMac));
+        updateUDPPacketIn();
+        cmd = dispatchPacketIn(1L, testUDPPacketIn, cntx);
+        assertEquals(Command.CONTINUE, cmd);
+        cntxSrcDev = IDeviceService.fcStore.get(cntx,
+                IDeviceService.CONTEXT_SRC_DEVICE);
+        assertEquals(expectedSrcDev, cntxSrcDev);
+        cntxDstDev = IDeviceService.fcStore.get(cntx,
+                IDeviceService.CONTEXT_DST_DEVICE);
+        assertEquals(expectedDstDev, cntxDstDev);
+
+        verify(mockTopology);
     }
 
     /**