diff --git a/router/java/src/net/i2p/router/transport/udp/InboundEstablishState2.java b/router/java/src/net/i2p/router/transport/udp/InboundEstablishState2.java
index 746d1e94e10419216e0c5fdee03c965b0ec466a8..0f262918c5addeb2d113efc720f5046e1618ae9e 100644
--- a/router/java/src/net/i2p/router/transport/udp/InboundEstablishState2.java
+++ b/router/java/src/net/i2p/router/transport/udp/InboundEstablishState2.java
@@ -54,7 +54,7 @@ class InboundEstablishState2 extends InboundEstablishState implements SSU2Payloa
     private PeerState2 _pstate;
     
     // testing
-    private static final boolean ENFORCE_TOKEN = false;
+    private static final boolean ENFORCE_TOKEN = true;
     private static final long MAX_SKEW = 2*60*1000L;
 
 
diff --git a/router/java/src/net/i2p/router/transport/udp/OutboundMessageState.java b/router/java/src/net/i2p/router/transport/udp/OutboundMessageState.java
index 8940f6606e7ddce7cea85e89c7e12e45669ea5fc..869af99900e20831e6f3eeb90279d4a1f59933fc 100644
--- a/router/java/src/net/i2p/router/transport/udp/OutboundMessageState.java
+++ b/router/java/src/net/i2p/router/transport/udp/OutboundMessageState.java
@@ -307,6 +307,9 @@ class OutboundMessageState implements CDPQEntry {
         return rv;
     }
 
+    /**
+     * @return true if the fragment has not been ACKed
+     */
     public synchronized boolean needsSending(int fragment) {
         return (_fragmentAcks & mask(fragment)) != 0;
     }
diff --git a/router/java/src/net/i2p/router/transport/udp/PeerState2.java b/router/java/src/net/i2p/router/transport/udp/PeerState2.java
index 31fffcadf968bbcd2dcef71ab4fe3186e6fcddec..3533c98929bc1e1c5432e4e55e509f61f73d8e47 100644
--- a/router/java/src/net/i2p/router/transport/udp/PeerState2.java
+++ b/router/java/src/net/i2p/router/transport/udp/PeerState2.java
@@ -73,6 +73,7 @@ public class PeerState2 extends PeerState implements SSU2Payload.PayloadCallback
     public static final int MAX_MTU = 1500;
     public static final int DEFAULT_MTU = MAX_MTU;
 
+    private static final int BITFIELD_SIZE = 512;
     private static final int MAX_SESS_CONF_RETX = 6;
     private static final int SESS_CONF_RETX_TIME = 1000;
 
@@ -94,8 +95,8 @@ public class PeerState2 extends PeerState implements SSU2Payload.PayloadCallback
         _rcvHeaderEncryptKey1 = transport.getSSU2StaticIntroKey();
         _sendHeaderEncryptKey2 = sendHdrKey2;
         _rcvHeaderEncryptKey2 = rcvHdrKey2;
-        _receivedMessages = new SSU2Bitfield(256, 0);
-        _ackedMessages = new SSU2Bitfield(256, 0);
+        _receivedMessages = new SSU2Bitfield(BITFIELD_SIZE, 0);
+        _ackedMessages = new SSU2Bitfield(BITFIELD_SIZE, 0);
         _sentMessages = new ConcurrentHashMap<Long, List<PacketBuilder.Fragment>>(32);
         if (isInbound) {
             // Send immediate ack of Session Confirmed
@@ -404,12 +405,9 @@ public class PeerState2 extends PeerState implements SSU2Payload.PayloadCallback
 
     public void gotACK(long ackThru, int acks, byte[] ranges) {
         SSU2Bitfield ackbf;
-        if (ranges != null)
-            ackbf = SSU2Bitfield.fromACKBlock(ackThru, acks, ranges, ranges.length / 2);
-        else
-            ackbf = SSU2Bitfield.fromACKBlock(ackThru, acks, null, 0);
+        ackbf = SSU2Bitfield.fromACKBlock(ackThru, acks, ranges, (ranges != null ? ranges.length / 2 : 0));
         if (_log.shouldDebug())
-            _log.debug("Got ACK block: " + ackbf);
+            _log.debug("Got ACK block: " + SSU2Bitfield.toString(ackThru, acks, ranges, (ranges != null ? ranges.length / 2 : 0)));
         // calls bitSet() below
         ackbf.forEachAndNot(_ackedMessages, this);
     }
@@ -517,6 +515,12 @@ public class PeerState2 extends PeerState implements SSU2Payload.PayloadCallback
                 continue;
             }
             int num = f.num;
+            if (!state.needsSending(num)) {
+                // will happen with retransmission as a different packet number
+                if (_log.shouldWarn())
+                    _log.warn("New ACK for fragment " + num + " but already acked? " + state);
+                continue;
+            }
             int ackedSize = state.getUnackedSize();
             boolean complete = state.acked(f.num);
             if (complete) {
@@ -596,17 +600,17 @@ public class PeerState2 extends PeerState implements SSU2Payload.PayloadCallback
          */
         public void timeReached() {
             synchronized(PeerState2.this) {
-                long wanted = _wantACKSendSince;
-                if (wanted <= 0) {
+                if (_wantACKSendSince <= 0) {
                     if (_log.shouldDebug())
                         _log.debug("Already acked:" + PeerState2.this);
                     return;
                 }
-                UDPPacket ack = _transport.getBuilder2().buildACK(PeerState2.this);
-                if (_log.shouldDebug())
-                    _log.debug("Sending acks to " + PeerState2.this);
-                _transport.send(ack);
+                _wantACKSendSince = 0;
             }
+            UDPPacket ack = _transport.getBuilder2().buildACK(PeerState2.this);
+            if (_log.shouldDebug())
+                _log.debug("Sending acks to " + PeerState2.this);
+            _transport.send(ack);
         }
     }
 }