diff --git a/api/net/sf/briar/api/plugins/SegmentSink.java b/api/net/sf/briar/api/plugins/SegmentSink.java
index 55caa493403d95c52e3f7d4599328ca095c44c8a..83eaa2f6ae62eca33535d184112ccbb8d6cdb8b5 100644
--- a/api/net/sf/briar/api/plugins/SegmentSink.java
+++ b/api/net/sf/briar/api/plugins/SegmentSink.java
@@ -8,4 +8,9 @@ public interface SegmentSink {
 
 	/** Writes the given segment. */
 	void writeSegment(Segment s) throws IOException;
+
+	/**
+	 * Returns the maximum length in bytes of the segments this sink accepts.
+	 */
+	int getMaxSegmentLength();
 }
diff --git a/api/net/sf/briar/api/plugins/SegmentSource.java b/api/net/sf/briar/api/plugins/SegmentSource.java
index 403659a0b1fc831f865db2c4418a7676a7e1ab63..135d03f548a624962ff5ea3c2d674e4d4868d95a 100644
--- a/api/net/sf/briar/api/plugins/SegmentSource.java
+++ b/api/net/sf/briar/api/plugins/SegmentSource.java
@@ -11,4 +11,9 @@ public interface SegmentSource {
 	 * segment was read, or false if no more segments can be read.
 	 */
 	boolean readSegment(Segment s) throws IOException;
+
+	/**
+	 * Returns the maximum length in bytes of the segments this source returns.
+	 */
+	int getMaxSegmentLength();
 }
diff --git a/components/net/sf/briar/transport/ConnectionReaderImpl.java b/components/net/sf/briar/transport/ConnectionReaderImpl.java
index 581c026ce5875f396811515a0c4a25aa4b3286c1..1859eda8dca6aec5f2987257af8b3544310fb6d5 100644
--- a/components/net/sf/briar/transport/ConnectionReaderImpl.java
+++ b/components/net/sf/briar/transport/ConnectionReaderImpl.java
@@ -19,7 +19,7 @@ class ConnectionReaderImpl extends InputStream implements ConnectionReader {
 	ConnectionReaderImpl(IncomingReliabilityLayer in, boolean tolerateErrors) {
 		this.in = in;
 		this.tolerateErrors = tolerateErrors;
-		frame = new Frame();
+		frame = new Frame(in.getMaxFrameLength());
 	}
 
 	public InputStream getInputStream() {
diff --git a/components/net/sf/briar/transport/ConnectionWriterImpl.java b/components/net/sf/briar/transport/ConnectionWriterImpl.java
index d1fcbd7a0d74a3fdd6843c1421837ab03a276dfb..e39de66619f253f1de7aa2c9fa99cf0abaa67998 100644
--- a/components/net/sf/briar/transport/ConnectionWriterImpl.java
+++ b/components/net/sf/briar/transport/ConnectionWriterImpl.java
@@ -2,7 +2,6 @@ package net.sf.briar.transport;
 
 import static net.sf.briar.api.transport.TransportConstants.FRAME_HEADER_LENGTH;
 import static net.sf.briar.api.transport.TransportConstants.MAC_LENGTH;
-import static net.sf.briar.api.transport.TransportConstants.MAX_FRAME_LENGTH;
 import static net.sf.briar.util.ByteUtils.MAX_32_BIT_UNSIGNED;
 
 import java.io.IOException;
@@ -19,6 +18,7 @@ import net.sf.briar.api.transport.ConnectionWriter;
 class ConnectionWriterImpl extends OutputStream implements ConnectionWriter {
 
 	private final OutgoingReliabilityLayer out;
+	private final int maxFrameLength;
 	private final Frame frame;
 
 	private int offset = FRAME_HEADER_LENGTH;
@@ -26,7 +26,8 @@ class ConnectionWriterImpl extends OutputStream implements ConnectionWriter {
 
 	ConnectionWriterImpl(OutgoingReliabilityLayer out) {
 		this.out = out;
-		frame = new Frame();
+		maxFrameLength = out.getMaxFrameLength();
+		frame = new Frame(maxFrameLength);
 	}
 
 	public OutputStream getOutputStream() {
@@ -39,7 +40,7 @@ class ConnectionWriterImpl extends OutputStream implements ConnectionWriter {
 		if(offset > FRAME_HEADER_LENGTH)
 			capacity -= offset + MAC_LENGTH;
 		// Subtract the overhead from the remaining capacity
-		long frames = (long) Math.ceil((double) capacity / MAX_FRAME_LENGTH);
+		long frames = (long) Math.ceil((double) capacity / maxFrameLength);
 		int overheadPerFrame = FRAME_HEADER_LENGTH + MAC_LENGTH;
 		return Math.max(0L, capacity - frames * overheadPerFrame);
 	}
@@ -53,7 +54,7 @@ class ConnectionWriterImpl extends OutputStream implements ConnectionWriter {
 	@Override
 	public void write(int b) throws IOException {
 		frame.getBuffer()[offset++] = (byte) b;
-		if(offset + MAC_LENGTH == MAX_FRAME_LENGTH) writeFrame();
+		if(offset + MAC_LENGTH == maxFrameLength) writeFrame();
 	}
 
 	@Override
@@ -64,14 +65,14 @@ class ConnectionWriterImpl extends OutputStream implements ConnectionWriter {
 	@Override
 	public void write(byte[] b, int off, int len) throws IOException {
 		byte[] buf = frame.getBuffer();
-		int available = MAX_FRAME_LENGTH - offset - MAC_LENGTH;
+		int available = maxFrameLength - offset - MAC_LENGTH;
 		while(available <= len) {
 			System.arraycopy(b, off, buf, offset, available);
 			offset += available;
 			writeFrame();
 			off += available;
 			len -= available;
-			available = MAX_FRAME_LENGTH - offset - MAC_LENGTH;
+			available = maxFrameLength - offset - MAC_LENGTH;
 		}
 		System.arraycopy(b, off, buf, offset, len);
 		offset += len;
diff --git a/components/net/sf/briar/transport/Frame.java b/components/net/sf/briar/transport/Frame.java
index 64c8eeda9a94cf71b7752bde3c0498f3395742de..921e5ff23e6d1d553b06f09c4bdd67208a2d827b 100644
--- a/components/net/sf/briar/transport/Frame.java
+++ b/components/net/sf/briar/transport/Frame.java
@@ -1,6 +1,9 @@
 package net.sf.briar.transport;
 
+import static net.sf.briar.api.transport.TransportConstants.FRAME_HEADER_LENGTH;
+import static net.sf.briar.api.transport.TransportConstants.MAC_LENGTH;
 import static net.sf.briar.api.transport.TransportConstants.MAX_FRAME_LENGTH;
+import static net.sf.briar.api.transport.TransportConstants.MAX_SEGMENT_LENGTH;
 
 class Frame {
 
@@ -13,6 +16,9 @@ class Frame {
 	}
 
 	Frame(int length) {
+		if(length < FRAME_HEADER_LENGTH + MAC_LENGTH)
+			throw new IllegalArgumentException();
+		if(length > MAX_SEGMENT_LENGTH) throw new IllegalArgumentException();
 		buf = new byte[length];
 	}
 
diff --git a/components/net/sf/briar/transport/IncomingAuthenticationLayer.java b/components/net/sf/briar/transport/IncomingAuthenticationLayer.java
index 22dd0df36510f5961c3cbc5012b66c5d204eabb1..33a6f20aa3e9590bc47c6390cb6d202aed00683b 100644
--- a/components/net/sf/briar/transport/IncomingAuthenticationLayer.java
+++ b/components/net/sf/briar/transport/IncomingAuthenticationLayer.java
@@ -15,4 +15,7 @@ interface IncomingAuthenticationLayer {
 	 */
 	boolean readFrame(Frame f, FrameWindow window) throws IOException,
 	InvalidDataException;
+
+	/** Returns the maximum length in bytes of the frames this layer returns. */
+	int getMaxFrameLength();
 }
diff --git a/components/net/sf/briar/transport/IncomingAuthenticationLayerImpl.java b/components/net/sf/briar/transport/IncomingAuthenticationLayerImpl.java
index c2332c74583aa9c2405e7735618464aeeffe9c33..5489a8ba9c50165a9f57e338a05a17fc8423389c 100644
--- a/components/net/sf/briar/transport/IncomingAuthenticationLayerImpl.java
+++ b/components/net/sf/briar/transport/IncomingAuthenticationLayerImpl.java
@@ -2,7 +2,6 @@ package net.sf.briar.transport;
 
 import static net.sf.briar.api.transport.TransportConstants.FRAME_HEADER_LENGTH;
 import static net.sf.briar.api.transport.TransportConstants.MAC_LENGTH;
-import static net.sf.briar.api.transport.TransportConstants.MAX_FRAME_LENGTH;
 
 import java.io.IOException;
 import java.security.InvalidKeyException;
@@ -14,13 +13,13 @@ import net.sf.briar.api.crypto.ErasableKey;
 class IncomingAuthenticationLayerImpl implements IncomingAuthenticationLayer {
 
 	private final IncomingErrorCorrectionLayer in;
+	private final int maxFrameLength;
 	private final Mac mac;
 
 	IncomingAuthenticationLayerImpl(IncomingErrorCorrectionLayer in, Mac mac,
 			ErasableKey macKey) {
 		this.in = in;
 		this.mac = mac;
-		// Initialise the MAC
 		try {
 			mac.init(macKey);
 		} catch(InvalidKeyException e) {
@@ -29,6 +28,7 @@ class IncomingAuthenticationLayerImpl implements IncomingAuthenticationLayer {
 		macKey.erase();
 		if(mac.getMacLength() != MAC_LENGTH)
 			throw new IllegalArgumentException();
+		maxFrameLength = in.getMaxFrameLength();
 	}
 
 	public boolean readFrame(Frame f, FrameWindow window) throws IOException,
@@ -39,7 +39,7 @@ class IncomingAuthenticationLayerImpl implements IncomingAuthenticationLayer {
 		int length = f.getLength();
 		if(length < FRAME_HEADER_LENGTH + MAC_LENGTH)
 			throw new InvalidDataException();
-		if(length > MAX_FRAME_LENGTH) throw new InvalidDataException();
+		if(length > maxFrameLength) throw new InvalidDataException();
 		// Check that the payload and padding lengths are correct
 		byte[] buf = f.getBuffer();
 		int payload = HeaderEncoder.getPayloadLength(buf);
@@ -61,4 +61,8 @@ class IncomingAuthenticationLayerImpl implements IncomingAuthenticationLayer {
 		}
 		return true;
 	}
+
+	public int getMaxFrameLength() {
+		return maxFrameLength;
+	}
 }
diff --git a/components/net/sf/briar/transport/IncomingEncryptionLayer.java b/components/net/sf/briar/transport/IncomingEncryptionLayer.java
index 3521ce46e6b71dd8a8b00fe9eb4ed1be8da59a0d..08e903a28b6ed1810eb952c8041f80e1fe5c1f85 100644
--- a/components/net/sf/briar/transport/IncomingEncryptionLayer.java
+++ b/components/net/sf/briar/transport/IncomingEncryptionLayer.java
@@ -15,4 +15,9 @@ interface IncomingEncryptionLayer {
 	 * may choose whether to retry the read or close the connection.
 	 */
 	boolean readSegment(Segment s) throws IOException, InvalidDataException;
+
+	/**
+	 * Returns the maximum length in bytes of the segments this layer returns.
+	 */
+	int getMaxSegmentLength();
 }
diff --git a/components/net/sf/briar/transport/IncomingEncryptionLayerImpl.java b/components/net/sf/briar/transport/IncomingEncryptionLayerImpl.java
index 2f1bfb44e92a5842c69bd5d721d31385a32da184..b9c702b278de0cd5fc86ca60c458566f9fa9f1d8 100644
--- a/components/net/sf/briar/transport/IncomingEncryptionLayerImpl.java
+++ b/components/net/sf/briar/transport/IncomingEncryptionLayerImpl.java
@@ -23,9 +23,9 @@ class IncomingEncryptionLayerImpl implements IncomingEncryptionLayer {
 	private final InputStream in;
 	private final Cipher tagCipher, segCipher;
 	private final ErasableKey tagKey, segKey;
+	private final boolean tagEverySegment;
 	private final int blockSize;
 	private final byte[] iv, ciphertext;
-	private final boolean tagEverySegment;
 
 	private byte[] bufferedTag;
 	private boolean firstSegment = true;
@@ -128,4 +128,8 @@ class IncomingEncryptionLayerImpl implements IncomingEncryptionLayer {
 			throw e;
 		}
 	}
+
+	public int getMaxSegmentLength() {
+		return MAX_SEGMENT_LENGTH - TAG_LENGTH;
+	}
 }
\ No newline at end of file
diff --git a/components/net/sf/briar/transport/IncomingErrorCorrectionLayer.java b/components/net/sf/briar/transport/IncomingErrorCorrectionLayer.java
index e49e0cbb9fe5ca344c29459695ec31f8e66cd521..f909dcd606b0a46957643456e4da05a52e39138e 100644
--- a/components/net/sf/briar/transport/IncomingErrorCorrectionLayer.java
+++ b/components/net/sf/briar/transport/IncomingErrorCorrectionLayer.java
@@ -15,4 +15,7 @@ interface IncomingErrorCorrectionLayer {
 	 */
 	boolean readFrame(Frame f, FrameWindow window) throws IOException,
 	InvalidDataException;
+
+	/** Returns the maximum length in bytes of the frames this layer returns. */
+	int getMaxFrameLength();
 }
diff --git a/components/net/sf/briar/transport/IncomingErrorCorrectionLayerImpl.java b/components/net/sf/briar/transport/IncomingErrorCorrectionLayerImpl.java
index e20ac44d79a0f3a9211a848cfaaca947d2d2ffcc..ff1d2f89524966fdff4012288997b372b992a454 100644
--- a/components/net/sf/briar/transport/IncomingErrorCorrectionLayerImpl.java
+++ b/components/net/sf/briar/transport/IncomingErrorCorrectionLayerImpl.java
@@ -1,5 +1,7 @@
 package net.sf.briar.transport;
 
+import static net.sf.briar.api.transport.TransportConstants.MAX_FRAME_LENGTH;
+
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -14,7 +16,7 @@ class IncomingErrorCorrectionLayerImpl implements IncomingErrorCorrectionLayer {
 
 	private final IncomingEncryptionLayer in;
 	private final ErasureDecoder decoder;
-	private final int n, k;
+	private final int n, k, maxSegmentLength, maxFrameLength;
 	private final Map<Long, Integer> discardCounts;
 	private final Map<Long, Segment[]> segmentSets;
 	private final ArrayList<Segment> freeSegments;
@@ -25,6 +27,8 @@ class IncomingErrorCorrectionLayerImpl implements IncomingErrorCorrectionLayer {
 		this.decoder = decoder;
 		this.n = n;
 		this.k = k;
+		maxSegmentLength = in.getMaxSegmentLength();
+		maxFrameLength = Math.min(MAX_FRAME_LENGTH, maxSegmentLength * k);
 		discardCounts = new HashMap<Long, Integer>();
 		segmentSets = new HashMap<Long, Segment[]>();
 		freeSegments = new ArrayList<Segment>();
@@ -47,7 +51,7 @@ class IncomingErrorCorrectionLayerImpl implements IncomingErrorCorrectionLayer {
 		// Grab a free segment, or allocate one if necessary
 		Segment s;
 		int free = freeSegments.size();
-		if(free == 0) s = new SegmentImpl();
+		if(free == 0) s = new SegmentImpl(maxSegmentLength);
 		else s = freeSegments.remove(free - 1);
 		// Read segments until a frame can be decoded
 		while(true) {
@@ -74,6 +78,10 @@ class IncomingErrorCorrectionLayerImpl implements IncomingErrorCorrectionLayer {
 		}
 	}
 
+	public int getMaxFrameLength() {
+		return maxFrameLength;
+	}
+
 	private void countDiscard(long frameNumber) throws FormatException {
 		Integer count = discardCounts.get(frameNumber);
 		if(count == null) discardCounts.put(frameNumber, 1);
diff --git a/components/net/sf/briar/transport/IncomingReliabilityLayer.java b/components/net/sf/briar/transport/IncomingReliabilityLayer.java
index 417a2525f199a747278252ddcd0f32ebb8a7b299..162a228c2dc99dd79f6cb3a5d0932a19ae213ab8 100644
--- a/components/net/sf/briar/transport/IncomingReliabilityLayer.java
+++ b/components/net/sf/briar/transport/IncomingReliabilityLayer.java
@@ -13,4 +13,7 @@ interface IncomingReliabilityLayer {
 	 * may choose whether to retry the read or close the connection.
 	 */
 	boolean readFrame(Frame f) throws IOException, InvalidDataException;
+
+	/** Returns the maximum length in bytes of the frames this layer returns. */
+	int getMaxFrameLength();
 }
diff --git a/components/net/sf/briar/transport/IncomingSegmentedEncryptionLayer.java b/components/net/sf/briar/transport/IncomingSegmentedEncryptionLayer.java
index f2a2ad40a3ddda8e77b7c258355f6dce51d498b9..50dacb4485d2c24d847c967fda8666e0140d066d 100644
--- a/components/net/sf/briar/transport/IncomingSegmentedEncryptionLayer.java
+++ b/components/net/sf/briar/transport/IncomingSegmentedEncryptionLayer.java
@@ -20,10 +20,10 @@ class IncomingSegmentedEncryptionLayer implements IncomingEncryptionLayer {
 	private final SegmentSource in;
 	private final Cipher tagCipher, segCipher;
 	private final ErasableKey tagKey, segKey;
-	private final int blockSize;
-	private final byte[] iv;
 	private final boolean tagEverySegment;
+	private final int blockSize, maxSegmentLength;
 	private final Segment segment;
+	private final byte[] iv;
 
 	private Segment bufferedSegment;
 	private boolean firstSegment = true;
@@ -42,8 +42,13 @@ class IncomingSegmentedEncryptionLayer implements IncomingEncryptionLayer {
 		blockSize = segCipher.getBlockSize();
 		if(blockSize < FRAME_HEADER_LENGTH)
 			throw new IllegalArgumentException();
+		int length = in.getMaxSegmentLength();
+		if(length < TAG_LENGTH + FRAME_HEADER_LENGTH + 1 + MAC_LENGTH)
+			throw new IllegalArgumentException();
+		if(length > MAX_SEGMENT_LENGTH) throw new IllegalArgumentException();
+		maxSegmentLength = length - TAG_LENGTH;
+		segment = new SegmentImpl(length);
 		iv = IvEncoder.encodeIv(0L, blockSize);
-		segment = new SegmentImpl();
 	}
 
 	public boolean readSegment(Segment s) throws IOException,
@@ -62,9 +67,10 @@ class IncomingSegmentedEncryptionLayer implements IncomingEncryptionLayer {
 			}
 			int offset = expectTag ? TAG_LENGTH : 0;
 			int length = segment.getLength();
-			if(length > MAX_SEGMENT_LENGTH) throw new InvalidDataException();
 			if(length < offset + FRAME_HEADER_LENGTH + MAC_LENGTH)
 				throw new InvalidDataException();
+			if(length > offset + maxSegmentLength)
+				throw new InvalidDataException();
 			byte[] ciphertext = segment.getBuffer();
 			// If a tag is expected then decrypt and validate it
 			if(expectTag) {
@@ -92,4 +98,8 @@ class IncomingSegmentedEncryptionLayer implements IncomingEncryptionLayer {
 			throw e;
 		}
 	}
+
+	public int getMaxSegmentLength() {
+		return maxSegmentLength;
+	}
 }
diff --git a/components/net/sf/briar/transport/NullIncomingErrorCorrectionLayer.java b/components/net/sf/briar/transport/NullIncomingErrorCorrectionLayer.java
index 54e1f04aec8821e127bc7ae4486da58cc6bed18b..1e5077d3c139d7377bd93ec8e7d620b699064f0d 100644
--- a/components/net/sf/briar/transport/NullIncomingErrorCorrectionLayer.java
+++ b/components/net/sf/briar/transport/NullIncomingErrorCorrectionLayer.java
@@ -7,11 +7,13 @@ import net.sf.briar.api.transport.Segment;
 class NullIncomingErrorCorrectionLayer implements IncomingErrorCorrectionLayer {
 
 	private final IncomingEncryptionLayer in;
+	private final int maxFrameLength;
 	private final Segment segment;
 
 	NullIncomingErrorCorrectionLayer(IncomingEncryptionLayer in) {
 		this.in = in;
-		segment = new SegmentImpl();
+		maxFrameLength = in.getMaxSegmentLength();
+		segment = new SegmentImpl(maxFrameLength);
 	}
 
 	public boolean readFrame(Frame f, FrameWindow window) throws IOException,
@@ -28,4 +30,8 @@ class NullIncomingErrorCorrectionLayer implements IncomingErrorCorrectionLayer {
 		f.setLength(length);
 		return true;
 	}
+
+	public int getMaxFrameLength() {
+		return maxFrameLength;
+	}
 }
diff --git a/components/net/sf/briar/transport/NullIncomingReliabilityLayer.java b/components/net/sf/briar/transport/NullIncomingReliabilityLayer.java
index 25ddb59d24846c50ac99adc6c5d7b93b07c5dfcc..ecd871d22f27eef6474936eafe5be01a9874f917 100644
--- a/components/net/sf/briar/transport/NullIncomingReliabilityLayer.java
+++ b/components/net/sf/briar/transport/NullIncomingReliabilityLayer.java
@@ -5,10 +5,12 @@ import java.io.IOException;
 class NullIncomingReliabilityLayer implements IncomingReliabilityLayer {
 
 	private final IncomingAuthenticationLayer in;
+	private final int maxFrameLength;
 	private final FrameWindow window;
 
 	NullIncomingReliabilityLayer(IncomingAuthenticationLayer in) {
 		this.in = in;
+		maxFrameLength = in.getMaxFrameLength();
 		window = new NullFrameWindow();
 	}
 
@@ -18,4 +20,8 @@ class NullIncomingReliabilityLayer implements IncomingReliabilityLayer {
 		if(!window.remove(frameNumber)) throw new IllegalStateException();
 		return true;
 	}
+
+	public int getMaxFrameLength() {
+		return maxFrameLength;
+	}
 }
diff --git a/components/net/sf/briar/transport/NullOutgoingErrorCorrectionLayer.java b/components/net/sf/briar/transport/NullOutgoingErrorCorrectionLayer.java
index c0719e2ead3745148f84945dd45d136be67fa332..6847697f9a59e0231dbd495a0652b8ed335d57d3 100644
--- a/components/net/sf/briar/transport/NullOutgoingErrorCorrectionLayer.java
+++ b/components/net/sf/briar/transport/NullOutgoingErrorCorrectionLayer.java
@@ -9,13 +9,15 @@ import net.sf.briar.api.transport.Segment;
 class NullOutgoingErrorCorrectionLayer implements OutgoingErrorCorrectionLayer {
 
 	private final OutgoingEncryptionLayer out;
+	private final int maxSegmentLength;
 	private final Segment segment;
 
 	private long segmentNumber = 0L;
 
 	public NullOutgoingErrorCorrectionLayer(OutgoingEncryptionLayer out) {
 		this.out = out;
-		segment = new SegmentImpl();
+		maxSegmentLength = out.getMaxSegmentLength();
+		segment = new SegmentImpl(maxSegmentLength);
 	}
 
 	public void writeFrame(Frame f) throws IOException {
@@ -36,4 +38,8 @@ class NullOutgoingErrorCorrectionLayer implements OutgoingErrorCorrectionLayer {
 	public long getRemainingCapacity() {
 		return out.getRemainingCapacity();
 	}
+
+	public int getMaxFrameLength() {
+		return maxSegmentLength;
+	}
 }
diff --git a/components/net/sf/briar/transport/NullOutgoingReliabilityLayer.java b/components/net/sf/briar/transport/NullOutgoingReliabilityLayer.java
index a00a2e9c4e0c1bd14ef356dee2a3ce41673440a5..650f245e54c0e9b84ae8119d62ce8329138a598d 100644
--- a/components/net/sf/briar/transport/NullOutgoingReliabilityLayer.java
+++ b/components/net/sf/briar/transport/NullOutgoingReliabilityLayer.java
@@ -5,9 +5,11 @@ import java.io.IOException;
 class NullOutgoingReliabilityLayer implements OutgoingReliabilityLayer {
 
 	private final OutgoingAuthenticationLayer out;
+	private final int maxFrameLength;
 
 	NullOutgoingReliabilityLayer(OutgoingAuthenticationLayer out) {
 		this.out = out;
+		maxFrameLength = out.getMaxFrameLength();
 	}
 
 	public void writeFrame(Frame f) throws IOException {
@@ -21,4 +23,8 @@ class NullOutgoingReliabilityLayer implements OutgoingReliabilityLayer {
 	public long getRemainingCapacity() {
 		return out.getRemainingCapacity();
 	}
+
+	public int getMaxFrameLength() {
+		return maxFrameLength;
+	}
 }
diff --git a/components/net/sf/briar/transport/OutgoingAuthenticationLayer.java b/components/net/sf/briar/transport/OutgoingAuthenticationLayer.java
index e1b9b72b6d7ed61857b0c80cfe1714c2fdb6c0d1..21e41a9243aed1bbc5cd58444c61b2d634d83664 100644
--- a/components/net/sf/briar/transport/OutgoingAuthenticationLayer.java
+++ b/components/net/sf/briar/transport/OutgoingAuthenticationLayer.java
@@ -12,4 +12,7 @@ interface OutgoingAuthenticationLayer {
 
 	/** Returns the maximum number of bytes that can be written. */
 	long getRemainingCapacity();
+
+	/** Returns the maximum length in bytes of the frames this layer accepts. */
+	int getMaxFrameLength();
 }
diff --git a/components/net/sf/briar/transport/OutgoingAuthenticationLayerImpl.java b/components/net/sf/briar/transport/OutgoingAuthenticationLayerImpl.java
index c8cee560b454b3e083cfd4e933061c15de204bfa..535ec4834a2a0af64d12da6616527b657f8d5ea7 100644
--- a/components/net/sf/briar/transport/OutgoingAuthenticationLayerImpl.java
+++ b/components/net/sf/briar/transport/OutgoingAuthenticationLayerImpl.java
@@ -14,12 +14,12 @@ class OutgoingAuthenticationLayerImpl implements OutgoingAuthenticationLayer {
 
 	private final OutgoingErrorCorrectionLayer out;
 	private final Mac mac;
+	private final int maxFrameLength;
 
 	OutgoingAuthenticationLayerImpl(OutgoingErrorCorrectionLayer out, Mac mac,
 			ErasableKey macKey) {
 		this.out = out;
 		this.mac = mac;
-		// Initialise the MAC
 		try {
 			mac.init(macKey);
 		} catch(InvalidKeyException badKey) {
@@ -28,6 +28,7 @@ class OutgoingAuthenticationLayerImpl implements OutgoingAuthenticationLayer {
 		macKey.erase();
 		if(mac.getMacLength() != MAC_LENGTH)
 			throw new IllegalArgumentException();
+		maxFrameLength = out.getMaxFrameLength();
 	}
 
 	public void writeFrame(Frame f) throws IOException {
@@ -49,4 +50,8 @@ class OutgoingAuthenticationLayerImpl implements OutgoingAuthenticationLayer {
 	public long getRemainingCapacity() {
 		return out.getRemainingCapacity();
 	}
+
+	public int getMaxFrameLength() {
+		return maxFrameLength;
+	}
 }
diff --git a/components/net/sf/briar/transport/OutgoingEncryptionLayer.java b/components/net/sf/briar/transport/OutgoingEncryptionLayer.java
index e3b11cfe2ee0c25e3b6ff7d4786a56583e7e1eb2..e0e4b44023ae29e67cc6d3776dcb6a2397f0a5e6 100644
--- a/components/net/sf/briar/transport/OutgoingEncryptionLayer.java
+++ b/components/net/sf/briar/transport/OutgoingEncryptionLayer.java
@@ -14,4 +14,9 @@ interface OutgoingEncryptionLayer {
 
 	/** Returns the maximum number of bytes that can be written. */
 	long getRemainingCapacity();
+
+	/**
+	 * Returns the maximum length in bytes of the segments this layer accepts.
+	 */
+	int getMaxSegmentLength();
 }
diff --git a/components/net/sf/briar/transport/OutgoingEncryptionLayerImpl.java b/components/net/sf/briar/transport/OutgoingEncryptionLayerImpl.java
index 4169eef5afb7232f703cbf1a159fb33cfa7477fd..6e9696b2060aef6f545b2bee480e61a29a9eef4f 100644
--- a/components/net/sf/briar/transport/OutgoingEncryptionLayerImpl.java
+++ b/components/net/sf/briar/transport/OutgoingEncryptionLayerImpl.java
@@ -73,4 +73,8 @@ class OutgoingEncryptionLayerImpl implements OutgoingEncryptionLayer {
 	public long getRemainingCapacity() {
 		return capacity;
 	}
+
+	public int getMaxSegmentLength() {
+		return MAX_SEGMENT_LENGTH - TAG_LENGTH;
+	}
 }
\ No newline at end of file
diff --git a/components/net/sf/briar/transport/OutgoingErrorCorrectionLayer.java b/components/net/sf/briar/transport/OutgoingErrorCorrectionLayer.java
index 206a594df3e0e9704e85e3e24b586ec38a8843c2..9dfd9eac37647014bb66dc871a41eedd18f5dffb 100644
--- a/components/net/sf/briar/transport/OutgoingErrorCorrectionLayer.java
+++ b/components/net/sf/briar/transport/OutgoingErrorCorrectionLayer.java
@@ -12,4 +12,7 @@ interface OutgoingErrorCorrectionLayer {
 
 	/** Returns the maximum number of bytes that can be written. */
 	long getRemainingCapacity();
+
+	/** Returns the maximum length in bytes of the frames this layer accepts. */
+	int getMaxFrameLength();
 }
diff --git a/components/net/sf/briar/transport/OutgoingErrorCorrectionLayerImpl.java b/components/net/sf/briar/transport/OutgoingErrorCorrectionLayerImpl.java
index 24168939b68b6cd511108e00aa8103a81561bb85..e7662d002e123b8b9cecefacdf5c43e754f12c11 100644
--- a/components/net/sf/briar/transport/OutgoingErrorCorrectionLayerImpl.java
+++ b/components/net/sf/briar/transport/OutgoingErrorCorrectionLayerImpl.java
@@ -1,5 +1,7 @@
 package net.sf.briar.transport;
 
+import static net.sf.briar.api.transport.TransportConstants.MAX_FRAME_LENGTH;
+
 import java.io.IOException;
 
 import net.sf.briar.api.transport.Segment;
@@ -8,13 +10,15 @@ class OutgoingErrorCorrectionLayerImpl implements OutgoingErrorCorrectionLayer {
 
 	private final OutgoingEncryptionLayer out;
 	private final ErasureEncoder encoder;
-	private final int n;
+	private final int n, maxFrameLength;
 
 	OutgoingErrorCorrectionLayerImpl(OutgoingEncryptionLayer out,
-			ErasureEncoder encoder, int n) {
+			ErasureEncoder encoder, int n, int k) {
 		this.out = out;
 		this.encoder = encoder;
 		this.n = n;
+		maxFrameLength = Math.min(MAX_FRAME_LENGTH,
+				out.getMaxSegmentLength() * k);
 	}
 
 	public void writeFrame(Frame f) throws IOException {
@@ -28,4 +32,8 @@ class OutgoingErrorCorrectionLayerImpl implements OutgoingErrorCorrectionLayer {
 	public long getRemainingCapacity() {
 		return out.getRemainingCapacity() / n;
 	}
+
+	public int getMaxFrameLength() {
+		return maxFrameLength;
+	}
 }
diff --git a/components/net/sf/briar/transport/OutgoingReliabilityLayer.java b/components/net/sf/briar/transport/OutgoingReliabilityLayer.java
index 49aacb499a883964f7d52a3b5057035fe89cd79f..ef6797d9a893fdfb6576bc53491130928593eb4f 100644
--- a/components/net/sf/briar/transport/OutgoingReliabilityLayer.java
+++ b/components/net/sf/briar/transport/OutgoingReliabilityLayer.java
@@ -12,4 +12,7 @@ interface OutgoingReliabilityLayer {
 
 	/** Returns the maximum number of bytes that can be written. */
 	long getRemainingCapacity();
+
+	/** Returns the maximum length in bytes of the frames this layer accepts. */
+	int getMaxFrameLength();
 }
diff --git a/components/net/sf/briar/transport/OutgoingSegmentedEncryptionLayer.java b/components/net/sf/briar/transport/OutgoingSegmentedEncryptionLayer.java
index 1214dec4a8c49a2913c03ff824f60cf2bace0123..eb188ff608d8546c6ace6710dda8c8d45ef59e2a 100644
--- a/components/net/sf/briar/transport/OutgoingSegmentedEncryptionLayer.java
+++ b/components/net/sf/briar/transport/OutgoingSegmentedEncryptionLayer.java
@@ -1,5 +1,8 @@
 package net.sf.briar.transport;
 
+import static net.sf.briar.api.transport.TransportConstants.FRAME_HEADER_LENGTH;
+import static net.sf.briar.api.transport.TransportConstants.MAC_LENGTH;
+import static net.sf.briar.api.transport.TransportConstants.MAX_SEGMENT_LENGTH;
 import static net.sf.briar.api.transport.TransportConstants.TAG_LENGTH;
 
 import java.io.IOException;
@@ -18,8 +21,9 @@ class OutgoingSegmentedEncryptionLayer implements OutgoingEncryptionLayer {
 	private final Cipher tagCipher, segCipher;
 	private final ErasableKey tagKey, segKey;
 	private final boolean tagEverySegment;
-	private final byte[] iv;
+	private final int maxSegmentLength;
 	private final Segment segment;
+	private final byte[] iv;
 
 	private long capacity;
 
@@ -33,8 +37,13 @@ class OutgoingSegmentedEncryptionLayer implements OutgoingEncryptionLayer {
 		this.tagKey = tagKey;
 		this.segKey = segKey;
 		this.tagEverySegment = tagEverySegment;
+		int length = out.getMaxSegmentLength();
+		if(length < TAG_LENGTH + FRAME_HEADER_LENGTH + 1 + MAC_LENGTH)
+			throw new RuntimeException();
+		if(length > MAX_SEGMENT_LENGTH) throw new RuntimeException();
+		maxSegmentLength = length - MAC_LENGTH;
+		segment = new SegmentImpl(length);
 		iv = IvEncoder.encodeIv(0L, segCipher.getBlockSize());
-		segment = new SegmentImpl();
 	}
 
 	public void writeSegment(Segment s) throws IOException {
@@ -72,4 +81,8 @@ class OutgoingSegmentedEncryptionLayer implements OutgoingEncryptionLayer {
 	public long getRemainingCapacity() {
 		return capacity;
 	}
+
+	public int getMaxSegmentLength() {
+		return maxSegmentLength;
+	}
 }
\ No newline at end of file
diff --git a/components/net/sf/briar/transport/SegmentImpl.java b/components/net/sf/briar/transport/SegmentImpl.java
index 991585457303b9c9c32644420c4cfcad5164827c..3c4552cf6159a48b30ad42fdc12251a504427c0e 100644
--- a/components/net/sf/briar/transport/SegmentImpl.java
+++ b/components/net/sf/briar/transport/SegmentImpl.java
@@ -1,5 +1,7 @@
 package net.sf.briar.transport;
 
+import static net.sf.briar.api.transport.TransportConstants.FRAME_HEADER_LENGTH;
+import static net.sf.briar.api.transport.TransportConstants.MAC_LENGTH;
 import static net.sf.briar.api.transport.TransportConstants.MAX_SEGMENT_LENGTH;
 import static net.sf.briar.util.ByteUtils.MAX_32_BIT_UNSIGNED;
 import net.sf.briar.api.transport.Segment;
@@ -16,6 +18,9 @@ class SegmentImpl implements Segment {
 	}
 
 	SegmentImpl(int length) {
+		if(length < FRAME_HEADER_LENGTH + MAC_LENGTH)
+			throw new IllegalArgumentException();
+		if(length > MAX_SEGMENT_LENGTH) throw new IllegalArgumentException();
 		buf = new byte[length];
 	}
 
diff --git a/test/net/sf/briar/transport/IncomingErrorCorrectionLayerImplTest.java b/test/net/sf/briar/transport/IncomingErrorCorrectionLayerImplTest.java
index 9072b728b0a4e14e20546bc5a8ca4809137a06f3..f6f507bb55aad999f154cbce0374c6142464a9a2 100644
--- a/test/net/sf/briar/transport/IncomingErrorCorrectionLayerImplTest.java
+++ b/test/net/sf/briar/transport/IncomingErrorCorrectionLayerImplTest.java
@@ -160,5 +160,9 @@ public class IncomingErrorCorrectionLayerImplTest extends BriarTestCase {
 			s.setLength(length);
 			return true;
 		}
+
+		public int getMaxSegmentLength() {
+			return length;
+		}
 	}
 }
diff --git a/test/net/sf/briar/transport/IncomingSegmentedEncryptionLayerTest.java b/test/net/sf/briar/transport/IncomingSegmentedEncryptionLayerTest.java
index 7359cf515e7f48cf0bff18a2370140ca9879ddb4..13243605ed0a2ca9c1aa202f49b740f682a9cb80 100644
--- a/test/net/sf/briar/transport/IncomingSegmentedEncryptionLayerTest.java
+++ b/test/net/sf/briar/transport/IncomingSegmentedEncryptionLayerTest.java
@@ -2,6 +2,7 @@ package net.sf.briar.transport;
 
 import static net.sf.briar.api.transport.TransportConstants.FRAME_HEADER_LENGTH;
 import static net.sf.briar.api.transport.TransportConstants.MAC_LENGTH;
+import static net.sf.briar.api.transport.TransportConstants.MAX_SEGMENT_LENGTH;
 import static net.sf.briar.api.transport.TransportConstants.TAG_LENGTH;
 
 import java.io.IOException;
@@ -149,5 +150,9 @@ public class IncomingSegmentedEncryptionLayerTest extends BriarTestCase {
 			s.setLength(segment.length);
 			return true;
 		}
+
+		public int getMaxSegmentLength() {
+			return MAX_SEGMENT_LENGTH;
+		}
 	}
 }
diff --git a/test/net/sf/briar/transport/NullIncomingEncryptionLayer.java b/test/net/sf/briar/transport/NullIncomingEncryptionLayer.java
index def5509b8381ce1017533f5ecea85fdd6d527306..dd244eeaffc0a43b89cfdcac11d0ab8fa294b5e6 100644
--- a/test/net/sf/briar/transport/NullIncomingEncryptionLayer.java
+++ b/test/net/sf/briar/transport/NullIncomingEncryptionLayer.java
@@ -3,6 +3,8 @@ package net.sf.briar.transport;
 import static net.sf.briar.api.transport.TransportConstants.FRAME_HEADER_LENGTH;
 import static net.sf.briar.api.transport.TransportConstants.MAC_LENGTH;
 import static net.sf.briar.api.transport.TransportConstants.MAX_FRAME_LENGTH;
+import static net.sf.briar.api.transport.TransportConstants.MAX_SEGMENT_LENGTH;
+import static net.sf.briar.api.transport.TransportConstants.TAG_LENGTH;
 
 import java.io.EOFException;
 import java.io.IOException;
@@ -49,4 +51,8 @@ class NullIncomingEncryptionLayer implements IncomingEncryptionLayer {
 		s.setSegmentNumber(segmentNumber++);
 		return true;
 	}
+
+	public int getMaxSegmentLength() {
+		return MAX_SEGMENT_LENGTH - TAG_LENGTH;
+	}
 }
diff --git a/test/net/sf/briar/transport/NullOutgoingEncryptionLayer.java b/test/net/sf/briar/transport/NullOutgoingEncryptionLayer.java
index 574b404c1b67067b942efd72f54e3c2478f8fc26..88921aff0321f7ca4ac996c0fc56972be0beb21e 100644
--- a/test/net/sf/briar/transport/NullOutgoingEncryptionLayer.java
+++ b/test/net/sf/briar/transport/NullOutgoingEncryptionLayer.java
@@ -1,5 +1,8 @@
 package net.sf.briar.transport;
 
+import static net.sf.briar.api.transport.TransportConstants.MAX_SEGMENT_LENGTH;
+import static net.sf.briar.api.transport.TransportConstants.TAG_LENGTH;
+
 import java.io.IOException;
 import java.io.OutputStream;
 
@@ -34,4 +37,8 @@ class NullOutgoingEncryptionLayer implements OutgoingEncryptionLayer {
 	public long getRemainingCapacity() {
 		return capacity;
 	}
+
+	public int getMaxSegmentLength() {
+		return MAX_SEGMENT_LENGTH - TAG_LENGTH;
+	}
 }
diff --git a/test/net/sf/briar/transport/OutgoingSegmentedEncryptionLayerTest.java b/test/net/sf/briar/transport/OutgoingSegmentedEncryptionLayerTest.java
index 398ca9cc5c433f5a6369f12ce4ccd5cee516f0a7..00d467e92c99d43ffc0861a21f5f14a23d6a9161 100644
--- a/test/net/sf/briar/transport/OutgoingSegmentedEncryptionLayerTest.java
+++ b/test/net/sf/briar/transport/OutgoingSegmentedEncryptionLayerTest.java
@@ -1,5 +1,6 @@
 package net.sf.briar.transport;
 
+import static net.sf.briar.api.transport.TransportConstants.MAX_SEGMENT_LENGTH;
 import static net.sf.briar.api.transport.TransportConstants.TAG_LENGTH;
 import static org.junit.Assert.assertArrayEquals;
 
@@ -136,5 +137,9 @@ public class OutgoingSegmentedEncryptionLayerTest extends BriarTestCase {
 		public void writeSegment(Segment s) throws IOException {
 			write(s.getBuffer(), 0, s.getLength());
 		}
+
+		public int getMaxSegmentLength() {
+			return MAX_SEGMENT_LENGTH;
+		}
 	}
 }
diff --git a/test/net/sf/briar/transport/XorErasureCodeTest.java b/test/net/sf/briar/transport/XorErasureCodeTest.java
index b361cc2d83371fbaceb9fc4d39a83a0c14dca175..f8a0b017fe67902c6650637407bac81e08c7f136 100644
--- a/test/net/sf/briar/transport/XorErasureCodeTest.java
+++ b/test/net/sf/briar/transport/XorErasureCodeTest.java
@@ -2,13 +2,13 @@ package net.sf.briar.transport;
 
 import static net.sf.briar.api.transport.TransportConstants.FRAME_HEADER_LENGTH;
 import static net.sf.briar.api.transport.TransportConstants.MAC_LENGTH;
+import static org.junit.Assert.assertArrayEquals;
 
 import java.util.Random;
 
 import net.sf.briar.BriarTestCase;
 import net.sf.briar.api.transport.Segment;
 
-import static org.junit.Assert.assertArrayEquals;
 import org.junit.Test;
 
 public class XorErasureCodeTest extends BriarTestCase {
diff --git a/test/net/sf/briar/transport/XorErasureDecoderTest.java b/test/net/sf/briar/transport/XorErasureDecoderTest.java
index 944610fcbeae3700f9ef429410095d0a8efa4480..43b66551b63ad0987778b260e1a53a256bce631b 100644
--- a/test/net/sf/briar/transport/XorErasureDecoderTest.java
+++ b/test/net/sf/briar/transport/XorErasureDecoderTest.java
@@ -3,11 +3,11 @@ package net.sf.briar.transport;
 import static net.sf.briar.api.transport.TransportConstants.FRAME_HEADER_LENGTH;
 import static net.sf.briar.api.transport.TransportConstants.MAC_LENGTH;
 import static net.sf.briar.api.transport.TransportConstants.MAX_FRAME_LENGTH;
+import static org.junit.Assert.assertArrayEquals;
 import net.sf.briar.BriarTestCase;
 import net.sf.briar.api.FormatException;
 import net.sf.briar.api.transport.Segment;
 
-import static org.junit.Assert.assertArrayEquals;
 import org.junit.Test;
 
 public class XorErasureDecoderTest extends BriarTestCase {
diff --git a/test/net/sf/briar/transport/XorErasureEncoderTest.java b/test/net/sf/briar/transport/XorErasureEncoderTest.java
index e1ca00b3aecf356a9d4d1cee576ab13b232a8d04..af67c0b644d28c8536b95eac1054f900532cdcdd 100644
--- a/test/net/sf/briar/transport/XorErasureEncoderTest.java
+++ b/test/net/sf/briar/transport/XorErasureEncoderTest.java
@@ -10,30 +10,29 @@ public class XorErasureEncoderTest extends BriarTestCase {
 
 	@Test
 	public void testEncoding() {
-		// Create a 100-byte frame
+		// Create a frame
 		Frame f = new Frame();
-		f.setLength(100);
+		f.setLength(200);
 		byte[] b = f.getBuffer();
-		for(int i = 0; i < 100; i++) b[i] = (byte) i;
+		for(int i = 0; i < 200; i++) b[i] = (byte) i;
 		// Encode the frame
 		XorErasureEncoder e = new XorErasureEncoder(4);
 		Segment[] set = e.encodeFrame(f);
-		// There should be four pieces of 34 bytes each
+		// There should be four pieces of 67 bytes each
 		assertEquals(4, set.length);
-		for(int i = 0; i < 4; i++) assertEquals(34, set[i].getLength());
-		// The first three pieces should contain the data, plus two zero bytes
+		for(int i = 0; i < 4; i++) assertEquals(67, set[i].getLength());
+		// The first three pieces should contain the data plus on padding byte
 		byte[] b1 = set[0].getBuffer();
-		for(int i = 0; i < 34; i++) assertEquals(i, b1[i]);
+		for(int i = 0; i < 67; i++) assertEquals((byte) i, b1[i]);
 		byte[] b2 = set[1].getBuffer();
-		for(int i = 0; i < 34; i++) assertEquals(i + 34, b2[i]);
+		for(int i = 0; i < 67; i++) assertEquals((byte) (i + 67), b2[i]);
 		byte[] b3 = set[2].getBuffer();
-		for(int i = 0; i < 32; i++) assertEquals(i + 68, b3[i]);
-		assertEquals(0, b3[32]);
-		assertEquals(0, b3[33]);
+		for(int i = 0; i < 66; i++) assertEquals((byte) (i + 134), b3[i]);
+		assertEquals(0, b3[66]);
 		// The fourth piece should be the XOR of the other three
 		byte[] b4 = set[3].getBuffer();
-		byte[] expected = new byte[34];
-		for(int i = 0; i < 34; i++) {
+		byte[] expected = new byte[67];
+		for(int i = 0; i < 67; i++) {
 			expected[i] = (byte) (b1[i] ^ b2[i] ^ b3[i]);
 		}
 		assertArrayEquals(expected, b4);