netconf chunked framing v2

Change-Id: I93fad5c44315960ca6aebe5b0944947ac8bf6a51
diff --git a/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/impl/NetconfSessionImpl.java b/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/impl/NetconfSessionImpl.java
index bbfb2a0..99ad5f2 100644
--- a/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/impl/NetconfSessionImpl.java
+++ b/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/impl/NetconfSessionImpl.java
@@ -24,6 +24,7 @@
 import com.google.common.base.MoreObjects;
 import com.google.common.base.Objects;
 import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
 import org.onosproject.netconf.NetconfSessionFactory;
 import org.onosproject.netconf.DatastoreId;
 import org.onosproject.netconf.FilteringNetconfDeviceOutputEventListener;
@@ -37,6 +38,7 @@
 import org.slf4j.LoggerFactory;
 
 import java.io.IOException;
+import java.io.UnsupportedEncodingException;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -103,6 +105,12 @@
 
     private static final String SESSION_ID_REGEX = "<session-id>\\s*(.*?)\\s*</session-id>";
     private static final Pattern SESSION_ID_REGEX_PATTERN = Pattern.compile(SESSION_ID_REGEX);
+    private static final String HASH = "#";
+    private static final String LF = "\n";
+    private static final String LESS_THAN = "<";
+    private static final String MSGLEN_REGEX_PATTERN = "\n#\\d+\n";
+    private static final String NETCONF_10_CAPABILITY = "urn:ietf:params:netconf:base:1.0";
+    protected static final String NETCONF_11_CAPABILITY = "urn:ietf:params:netconf:base:1.1";
 
     private String sessionID;
     private final AtomicInteger messageIdInteger = new AtomicInteger(1);
@@ -111,7 +119,7 @@
     private Session sshSession;
     private boolean connectionActive;
     private Iterable<String> onosCapabilities =
-            Collections.singletonList("urn:ietf:params:netconf:base:1.0");
+            ImmutableList.of(NETCONF_10_CAPABILITY, NETCONF_11_CAPABILITY);
 
     /* NOTE: the "serverHelloResponseOld" is deprecated in 1.10.0 and should eventually be removed */
     @Deprecated
@@ -139,6 +147,18 @@
         startConnection();
     }
 
+    public NetconfSessionImpl(NetconfDeviceInfo deviceInfo, List<String> capabilities) throws NetconfException {
+        this.deviceInfo = deviceInfo;
+        this.netconfConnection = null;
+        this.sshSession = null;
+        connectionActive = false;
+        replies = new ConcurrentHashMap<>();
+        errorReplies = new ArrayList<>();
+        setOnosCapabilities(capabilities);
+        startConnection();
+
+    }
+
     private void startConnection() throws NetconfException {
         if (!connectionActive) {
             netconfConnection = new Connection(deviceInfo.ip().toString(), deviceInfo.port());
@@ -153,34 +173,34 @@
             try {
                 if (deviceInfo.getKeyFile() != null && deviceInfo.getKeyFile().canRead()) {
                     log.debug("Authenticating with key file to device {} with username {}",
-                              deviceInfo.getDeviceId(), deviceInfo.name());
+                            deviceInfo.getDeviceId(), deviceInfo.name());
                     isAuthenticated = netconfConnection.authenticateWithPublicKey(
                             deviceInfo.name(), deviceInfo.getKeyFile(),
                             deviceInfo.password().equals("") ? null : deviceInfo.password());
                 } else if (deviceInfo.getKey() != null) {
                     log.debug("Authenticating with key to device {} with username {}",
-                              deviceInfo.getDeviceId(), deviceInfo.name());
+                            deviceInfo.getDeviceId(), deviceInfo.name());
                     isAuthenticated = netconfConnection.authenticateWithPublicKey(
                             deviceInfo.name(), deviceInfo.getKey(),
                             deviceInfo.password().equals("") ? null : deviceInfo.password());
                 } else {
                     log.debug("Authenticating to device {} with username {} with password",
-                              deviceInfo.getDeviceId(), deviceInfo.name());
+                            deviceInfo.getDeviceId(), deviceInfo.name());
                     isAuthenticated = netconfConnection.authenticateWithPassword(
                             deviceInfo.name(), deviceInfo.password());
                 }
             } catch (IOException e) {
                 log.error("Authentication connection to device {} failed",
-                          deviceInfo.getDeviceId(), e);
+                        deviceInfo.getDeviceId(), e);
                 throw new NetconfException("Authentication connection to device " +
-                                                   deviceInfo.getDeviceId() + " failed", e);
+                        deviceInfo.getDeviceId() + " failed", e);
             }
 
             connectionActive = true;
             Preconditions.checkArgument(isAuthenticated,
-                                        "Authentication to device %s with username " +
-                                                "%s failed",
-                                        deviceInfo.getDeviceId(), deviceInfo.name());
+                    "Authentication to device %s with username " +
+                            "%s failed",
+                    deviceInfo.getDeviceId(), deviceInfo.name());
             startSshSession();
         }
     }
@@ -190,15 +210,15 @@
             sshSession = netconfConnection.openSession();
             sshSession.startSubSystem("netconf");
             streamHandler = new NetconfStreamThread(sshSession.getStdout(), sshSession.getStdin(),
-                                                    sshSession.getStderr(), deviceInfo,
-                                                    new NetconfSessionDelegateImpl(),
-                                                    replies);
+                    sshSession.getStderr(), deviceInfo,
+                    new NetconfSessionDelegateImpl(),
+                    replies);
             this.addDeviceOutputListener(new FilteringNetconfDeviceOutputEventListener(deviceInfo));
             sendHello();
         } catch (IOException e) {
             log.error("Failed to create ch.ethz.ssh2.Session session {} ", e.getMessage());
             throw new NetconfException("Failed to create ch.ethz.ssh2.Session session with device" +
-                                               deviceInfo, e);
+                    deviceInfo, e);
         }
     }
 
@@ -211,18 +231,18 @@
             openNewSession = true;
 
         } else if (subscriptionConnected &&
-                   notificationFilterSchema != null &&
-                   !Objects.equal(filterSchema, notificationFilterSchema)) {
+                notificationFilterSchema != null &&
+                !Objects.equal(filterSchema, notificationFilterSchema)) {
             // interleave supported and existing filter is NOT "no filtering"
             // and was requested with different filtering schema
             log.info("Cannot use existing session for subscription {} ({})",
-                     deviceInfo, filterSchema);
+                    deviceInfo, filterSchema);
             openNewSession = true;
         }
 
         if (openNewSession) {
             log.info("Creating notification session to {} with filter {}",
-                     deviceInfo, filterSchema);
+                    deviceInfo, filterSchema);
             NetconfSession child = new NotificationSession(deviceInfo);
 
             child.addDeviceOutputListener(new NotificationForwarder());
@@ -236,7 +256,7 @@
         String reply = sendRequest(createSubscriptionString(filterSchema));
         if (!checkReply(reply)) {
             throw new NetconfException("Subscription not successful with device "
-                                               + deviceInfo + " with reply " + reply);
+                    + deviceInfo + " with reply " + reply);
         }
         subscriptionConnected = true;
     }
@@ -300,7 +320,7 @@
             sessionID = sessionIDMatcher.group(1);
         } else {
             throw new NetconfException("Missing SessionID in server hello " +
-                                               "reponse.");
+                    "reponse.");
         }
 
     }
@@ -347,11 +367,41 @@
         }
     }
 
+    /**
+     * Validate and format message according to chunked framing mechanism.
+     *
+     * @param request to format
+     * @return formated message
+     */
+    private static String validateChunkedMessage(String request) {
+        if (request.endsWith(ENDPATTERN)) {
+            request = request.substring(0, request.length() - ENDPATTERN.length());
+        }
+        if (!request.startsWith(LF + HASH)) {
+            request = LF + HASH + request.length() + LF + request + LF + HASH + HASH + LF;
+        }
+        return request;
+    }
+
+    /**
+     * Validate and format netconf message.
+     *
+     * @param request to format
+     * @return formated message
+     */
+    private String validateNetconfMessage(String request) {
+        if (deviceCapabilities.contains(NETCONF_11_CAPABILITY)) {
+            request = validateChunkedMessage(request);
+        } else {
+            if (!request.contains(ENDPATTERN)) {
+                request = request + NEW_LINE + ENDPATTERN;
+            }
+        }
+        return  request;
+    }
+
     @Override
     public String requestSync(String request) throws NetconfException {
-        if (!request.contains(ENDPATTERN)) {
-            request = request + NEW_LINE + ENDPATTERN;
-        }
         String reply = sendRequest(request);
         checkReply(reply);
         return reply;
@@ -368,6 +418,7 @@
     }
 
     private String sendRequest(String request) throws NetconfException {
+        request = validateNetconfMessage(request);
         return sendRequest(request, false);
     }
 
@@ -377,8 +428,8 @@
         if (!isHello) {
             messageId = messageIdInteger.getAndIncrement();
         }
-        request = formatRequestMessageId(request, messageId);
         request = formatXmlHeader(request);
+        request = formatRequestMessageId(request, messageId);
         CompletableFuture<String> futureReply = request(request, messageId);
         int replyTimeout = NetconfControllerImpl.netconfReplyTimeout;
         String rp;
@@ -415,19 +466,42 @@
         if (request.contains(MESSAGE_ID_STRING)) {
             //FIXME if application provides his own counting of messages this fails that count
             request = request.replaceFirst(MESSAGE_ID_STRING + EQUAL + NUMBER_BETWEEN_QUOTES_MATCHER,
-                                           MESSAGE_ID_STRING + EQUAL + "\"" + messageId + "\"");
+                    MESSAGE_ID_STRING + EQUAL + "\"" + messageId + "\"");
         } else if (!request.contains(MESSAGE_ID_STRING) && !request.contains(HELLO)) {
             //FIXME find out a better way to enforce the presence of message-id
             request = request.replaceFirst(END_OF_RPC_OPEN_TAG, "\" " + MESSAGE_ID_STRING + EQUAL + "\""
                     + messageId + "\"" + ">");
         }
+        request = updateRequestLength(request);
+        return request;
+    }
+
+    private String updateRequestLength(String request) {
+        if (request.contains(LF + HASH + HASH + LF)) {
+            int oldLen = Integer.parseInt(request.split(HASH)[1].split(LF)[0]);
+            String rpcWithEnding = request.substring(request.indexOf(LESS_THAN));
+            String firstBlock = request.split(MSGLEN_REGEX_PATTERN)[1].split(LF + HASH + HASH + LF)[0];
+            int newLen = 0;
+            try {
+                newLen = firstBlock.getBytes("UTF-8").length;
+            } catch (UnsupportedEncodingException e) {
+                e.printStackTrace();
+            }
+            if (oldLen != newLen) {
+                return LF + HASH + newLen + LF + rpcWithEnding;
+            }
+        }
         return request;
     }
 
     private String formatXmlHeader(String request) {
         if (!request.contains(XML_HEADER)) {
             //FIXME if application provieds his own XML header of different type there is a clash
-            request = XML_HEADER + "\n" + request;
+            if (request.startsWith(LF + HASH)) {
+                request = request.split("<")[0] + XML_HEADER + request.substring(request.split("<")[0].length());
+            } else {
+                request = XML_HEADER + "\n" + request;
+            }
         }
         return request;
     }
@@ -517,7 +591,9 @@
 
     @Override
     public boolean editConfig(String newConfiguration) throws NetconfException {
-        newConfiguration = newConfiguration + ENDPATTERN;
+        if (!newConfiguration.endsWith(ENDPATTERN)) {
+            newConfiguration = newConfiguration + ENDPATTERN;
+        }
         return checkReply(sendRequest(newConfiguration));
     }
 
@@ -565,14 +641,14 @@
                               String newConfiguration)
             throws NetconfException {
         return bareCopyConfig(netconfTargetConfig.asXml(),
-                              normalizeCopyConfigParam(newConfiguration));
+                normalizeCopyConfigParam(newConfiguration));
     }
 
     @Override
     public boolean copyConfig(String netconfTargetConfig,
                               String newConfiguration) throws NetconfException {
         return bareCopyConfig(normalizeCopyConfigParam(netconfTargetConfig),
-                              normalizeCopyConfigParam(newConfiguration));
+                normalizeCopyConfigParam(newConfiguration));
     }
 
     /**
@@ -620,7 +696,7 @@
     public boolean deleteConfig(DatastoreId netconfTargetConfig) throws NetconfException {
         if (netconfTargetConfig.equals(DatastoreId.RUNNING)) {
             log.warn("Target configuration for delete operation can't be \"running\"",
-                     netconfTargetConfig);
+                    netconfTargetConfig);
             return false;
         }
         StringBuilder rpc = new StringBuilder(XML_HEADER);
@@ -804,11 +880,11 @@
         public void notify(NetconfDeviceOutputEvent event) {
             Optional<Integer> messageId = event.getMessageID();
             log.debug("messageID {}, waiting replies messageIDs {}", messageId,
-                      replies.keySet());
+                    replies.keySet());
             if (!messageId.isPresent()) {
                 errorReplies.add(event.getMessagePayload());
                 log.error("Device {} sent error reply {}",
-                          event.getDeviceInfo(), event.getMessagePayload());
+                        event.getDeviceInfo(), event.getMessagePayload());
                 return;
             }
             CompletableFuture<String> completedReply =
@@ -826,4 +902,4 @@
             return new NetconfSessionImpl(netconfDeviceInfo);
         }
     }
-}
+}
\ No newline at end of file
diff --git a/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/impl/NetconfSessionMinaImpl.java b/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/impl/NetconfSessionMinaImpl.java
index 7ce42b4..0e2e3ea 100644
--- a/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/impl/NetconfSessionMinaImpl.java
+++ b/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/impl/NetconfSessionMinaImpl.java
@@ -19,6 +19,7 @@
 import com.google.common.annotations.Beta;
 import com.google.common.base.MoreObjects;
 import com.google.common.base.Objects;
+import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
 import org.apache.sshd.client.SshClient;
 import org.apache.sshd.client.channel.ClientChannel;
@@ -38,6 +39,7 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import java.io.IOException;
+import java.io.UnsupportedEncodingException;
 import java.nio.ByteBuffer;
 import java.nio.CharBuffer;
 import java.nio.charset.StandardCharsets;
@@ -47,14 +49,14 @@
 import java.security.PublicKey;
 import java.security.spec.InvalidKeySpecException;
 import java.security.spec.X509EncodedKeySpec;
-import java.util.ArrayList;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.List;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Map;
 import java.util.Optional;
-import java.util.Set;
+import java.util.ArrayList;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.CopyOnWriteArrayList;
@@ -114,12 +116,17 @@
     private static final Pattern SESSION_ID_REGEX_PATTERN = Pattern.compile(SESSION_ID_REGEX);
     private static final String RSA = "RSA";
     private static final String DSA = "DSA";
+    private static final String HASH = "#";
+    private static final String LF = "\n";
+    private static final String MSGLEN_REGEX_PATTERN = "\n#\\d+\n";
+    private static final String NETCONF_10_CAPABILITY = "urn:ietf:params:netconf:base:1.0";
+    private static final String NETCONF_11_CAPABILITY = "urn:ietf:params:netconf:base:1.1";
 
     private String sessionID;
     private final AtomicInteger messageIdInteger = new AtomicInteger(1);
     protected final NetconfDeviceInfo deviceInfo;
     private Iterable<String> onosCapabilities =
-            Collections.singletonList("urn:ietf:params:netconf:base:1.0");
+            ImmutableList.of(NETCONF_10_CAPABILITY, NETCONF_11_CAPABILITY);
 
     /* NOTE: the "serverHelloResponseOld" is deprecated in 1.10.0 and should eventually be removed */
     @Deprecated
@@ -149,6 +156,14 @@
         startConnection();
     }
 
+    public NetconfSessionMinaImpl(NetconfDeviceInfo deviceInfo, List<String> capabilities) throws NetconfException {
+        this.deviceInfo = deviceInfo;
+        replies = new ConcurrentHashMap<>();
+        errorReplies = new ArrayList<>();
+        setOnosCapabilities(capabilities);
+        startConnection();
+    }
+
     private void startConnection() throws NetconfException {
         try {
             startClient();
@@ -172,8 +187,8 @@
     private void startSession() throws IOException {
         final ConnectFuture connectFuture;
         connectFuture = client.connect(deviceInfo.name(),
-                                       deviceInfo.ip().toString(),
-                                       deviceInfo.port())
+                deviceInfo.ip().toString(),
+                deviceInfo.port())
                 .verify(NetconfControllerImpl.netconfConnectTimeout, TimeUnit.SECONDS);
         session = connectFuture.getSession();
         //Using the device ssh key if possible
@@ -189,8 +204,8 @@
                     key = getPublicKey(byteKey, DSA);
                 } catch (NoSuchAlgorithmException | InvalidKeySpecException e1) {
                     throw new NetconfException("Failed to authenticate session with device " +
-                                                       deviceInfo + "check key to be the " +
-                                                       "proper DSA or RSA key", e1);
+                            deviceInfo + "check key to be the " +
+                            "proper DSA or RSA key", e1);
                 }
             }
             //privateKye can set tu null because is not used by the method.
@@ -201,13 +216,13 @@
         session.auth().verify(NetconfControllerImpl.netconfConnectTimeout, TimeUnit.SECONDS);
         Set<ClientSession.ClientSessionEvent> event = session.waitFor(
                 ImmutableSet.of(ClientSession.ClientSessionEvent.WAIT_AUTH,
-                                ClientSession.ClientSessionEvent.CLOSED,
-                                ClientSession.ClientSessionEvent.AUTHED), 0);
+                        ClientSession.ClientSessionEvent.CLOSED,
+                        ClientSession.ClientSessionEvent.AUTHED), 0);
 
         if (!event.contains(ClientSession.ClientSessionEvent.AUTHED)) {
             log.debug("Session closed {} {}", event, session.isClosed());
             throw new NetconfException("Failed to authenticate session with device " +
-                                               deviceInfo + "check the user/pwd or key");
+                    deviceInfo + "check the user/pwd or key");
         }
         openChannel();
     }
@@ -227,11 +242,11 @@
         if (channelFuture.await(NetconfControllerImpl.netconfConnectTimeout, TimeUnit.SECONDS)) {
             if (channelFuture.isOpened()) {
                 streamHandler = new NetconfStreamThread(channel.getInvertedOut(), channel.getInvertedIn(),
-                                                        channel.getInvertedErr(), deviceInfo,
-                                                        new NetconfSessionDelegateImpl(), replies);
+                        channel.getInvertedErr(), deviceInfo,
+                        new NetconfSessionDelegateImpl(), replies);
             } else {
                 throw new NetconfException("Failed to open channel with device " +
-                                                   deviceInfo);
+                        deviceInfo);
             }
             sendHello();
         }
@@ -251,13 +266,13 @@
             // interleave supported and existing filter is NOT "no filtering"
             // and was requested with different filtering schema
             log.info("Cannot use existing session for subscription {} ({})",
-                     deviceInfo, filterSchema);
+                    deviceInfo, filterSchema);
             openNewSession = true;
         }
 
         if (openNewSession) {
             log.info("Creating notification session to {} with filter {}",
-                     deviceInfo, filterSchema);
+                    deviceInfo, filterSchema);
             NetconfSession child = new NotificationSession(deviceInfo);
 
             child.addDeviceOutputListener(new NotificationForwarder());
@@ -271,7 +286,7 @@
         String reply = sendRequest(createSubscriptionString(filterSchema));
         if (!checkReply(reply)) {
             throw new NetconfException("Subscription not successful with device "
-                                               + deviceInfo + " with reply " + reply);
+                    + deviceInfo + " with reply " + reply);
         }
         subscriptionConnected = true;
     }
@@ -335,7 +350,7 @@
             sessionID = sessionIDMatcher.group(1);
         } else {
             throw new NetconfException("Missing SessionID in server hello " +
-                                               "reponse.");
+                    "reponse.");
         }
 
     }
@@ -391,14 +406,50 @@
 
     @Override
     public String requestSync(String request) throws NetconfException {
-        if (!request.contains(ENDPATTERN)) {
-            request = request + NEW_LINE + ENDPATTERN;
-        }
         String reply = sendRequest(request);
         checkReply(reply);
         return reply;
     }
 
+
+    /**
+     * Validate and format netconf message.
+     *
+     * @param message to format
+     * @return formated message
+     */
+    private String formatNetconfMessage(String message) {
+        if (deviceCapabilities.contains(NETCONF_11_CAPABILITY)) {
+            message = formatChunkedMessage(message);
+        } else {
+            if (!message.contains(ENDPATTERN)) {
+                message = message + NEW_LINE + ENDPATTERN;
+            }
+        }
+        return  message;
+    }
+
+    /**
+     * Validate and format message according to chunked framing mechanism.
+     *
+     * @param message to format
+     * @return formated message
+     */
+    private String formatChunkedMessage(String message) {
+        if (message.endsWith(ENDPATTERN)) {
+            message = message.substring(0, message.length() - ENDPATTERN.length());
+        }
+        if (!message.startsWith(LF + HASH)) {
+            try {
+                message = LF + HASH + message.getBytes("UTF-8").length + LF + message + LF + HASH + HASH + LF;
+            } catch (UnsupportedEncodingException e) {
+                e.printStackTrace();
+            }
+        }
+        return message;
+    }
+
+
     @Override
     @Deprecated
     public CompletableFuture<String> request(String request) {
@@ -410,6 +461,7 @@
     }
 
     private String sendRequest(String request) throws NetconfException {
+        request = formatNetconfMessage(request);
         return sendRequest(request, false);
     }
 
@@ -419,8 +471,8 @@
         if (!isHello) {
             messageId = messageIdInteger.getAndIncrement();
         }
-        request = formatRequestMessageId(request, messageId);
         request = formatXmlHeader(request);
+        request = formatRequestMessageId(request, messageId);
         CompletableFuture<String> futureReply = request(request, messageId);
         int replyTimeout = NetconfControllerImpl.netconfReplyTimeout;
         String rp;
@@ -460,19 +512,42 @@
         if (request.contains(MESSAGE_ID_STRING)) {
             //FIXME if application provides his own counting of messages this fails that count
             request = request.replaceFirst(MESSAGE_ID_STRING + EQUAL + NUMBER_BETWEEN_QUOTES_MATCHER,
-                                           MESSAGE_ID_STRING + EQUAL + "\"" + messageId + "\"");
+                    MESSAGE_ID_STRING + EQUAL + "\"" + messageId + "\"");
         } else if (!request.contains(MESSAGE_ID_STRING) && !request.contains(HELLO)) {
             //FIXME find out a better way to enforce the presence of message-id
             request = request.replaceFirst(END_OF_RPC_OPEN_TAG, "\" " + MESSAGE_ID_STRING + EQUAL + "\""
                     + messageId + "\"" + ">");
         }
+        request = updateRequestLenght(request);
+        return request;
+    }
+
+    private String updateRequestLenght(String request) {
+        if (request.contains(LF + HASH + HASH + LF)) {
+            int oldLen = Integer.parseInt(request.split(HASH)[1].split(LF)[0]);
+            String rpcWithEnding = request.substring(request.indexOf('<'));
+            String firstBlock = request.split(MSGLEN_REGEX_PATTERN)[1].split(LF + HASH + HASH + LF)[0];
+            int newLen = 0;
+            try {
+                newLen = firstBlock.getBytes("UTF-8").length;
+            } catch (UnsupportedEncodingException e) {
+                e.printStackTrace();
+            }
+            if (oldLen != newLen) {
+                return LF + HASH + newLen + LF + rpcWithEnding;
+            }
+        }
         return request;
     }
 
     private String formatXmlHeader(String request) {
         if (!request.contains(XML_HEADER)) {
             //FIXME if application provieds his own XML header of different type there is a clash
-            request = XML_HEADER + "\n" + request;
+            if (request.startsWith(LF + HASH)) {
+                request = request.split("<")[0] + XML_HEADER + request.substring(request.split("<")[0].length());
+            } else {
+                request = XML_HEADER + "\n" + request;
+            }
         }
         return request;
     }
@@ -562,7 +637,9 @@
 
     @Override
     public boolean editConfig(String newConfiguration) throws NetconfException {
-        newConfiguration = newConfiguration + ENDPATTERN;
+        if (!newConfiguration.endsWith(ENDPATTERN)) {
+            newConfiguration = newConfiguration + ENDPATTERN;
+        }
         return checkReply(sendRequest(newConfiguration));
     }
 
@@ -613,14 +690,14 @@
                               String newConfiguration)
             throws NetconfException {
         return bareCopyConfig(netconfTargetConfig.asXml(),
-                              normalizeCopyConfigParam(newConfiguration));
+                normalizeCopyConfigParam(newConfiguration));
     }
 
     @Override
     public boolean copyConfig(String netconfTargetConfig,
                               String newConfiguration) throws NetconfException {
         return bareCopyConfig(normalizeCopyConfigParam(netconfTargetConfig),
-                              normalizeCopyConfigParam(newConfiguration));
+                normalizeCopyConfigParam(newConfiguration));
     }
 
     /**
@@ -668,7 +745,7 @@
     public boolean deleteConfig(DatastoreId netconfTargetConfig) throws NetconfException {
         if (netconfTargetConfig.equals(DatastoreId.RUNNING)) {
             log.warn("Target configuration for delete operation can't be \"running\"",
-                     netconfTargetConfig);
+                    netconfTargetConfig);
             return false;
         }
         StringBuilder rpc = new StringBuilder(XML_HEADER);
@@ -852,11 +929,11 @@
         public void notify(NetconfDeviceOutputEvent event) {
             Optional<Integer> messageId = event.getMessageID();
             log.debug("messageID {}, waiting replies messageIDs {}", messageId,
-                      replies.keySet());
+                    replies.keySet());
             if (!messageId.isPresent()) {
                 errorReplies.add(event.getMessagePayload());
                 log.error("Device {} sent error reply {}",
-                          event.getDeviceInfo(), event.getMessagePayload());
+                        event.getDeviceInfo(), event.getMessagePayload());
                 return;
             }
             CompletableFuture<String> completedReply =
@@ -874,4 +951,4 @@
             return new NetconfSessionMinaImpl(netconfDeviceInfo);
         }
     }
-}
+}
\ No newline at end of file
diff --git a/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/impl/NetconfStreamThread.java b/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/impl/NetconfStreamThread.java
index 9ec0e35..a11af4e 100644
--- a/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/impl/NetconfStreamThread.java
+++ b/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/impl/NetconfStreamThread.java
@@ -24,17 +24,21 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+
 import java.io.BufferedReader;
-import java.io.IOException;
 import java.io.InputStream;
-import java.io.InputStreamReader;
 import java.io.OutputStream;
 import java.io.OutputStreamWriter;
 import java.nio.charset.StandardCharsets;
+import java.io.InputStreamReader;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
 import java.util.List;
 import java.util.Map;
+import java.util.ArrayList;
 import java.util.Optional;
 import java.util.concurrent.CompletableFuture;
+import java.util.regex.MatchResult;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -54,6 +58,18 @@
     private static final String NOTIFICATION_LABEL = "<notification";
     private static final String MESSAGE_ID = "message-id=";
     private static final Pattern MSGID_PATTERN = Pattern.compile(MESSAGE_ID + "\"(\\d+)\"");
+    private static final String MSGLEN_REGEX_PATTERN = "\n#\\d+\n";
+    // pattern to verify whole Chunked-Message format
+    private static final Pattern CHUNKED_FRAMING_PATTERN =
+            Pattern.compile("(\\n#([1-9][0-9]*)\\n(.+))+\\n##\\n", Pattern.DOTALL);
+    private static final String MSGLEN_PART_REGEX_PATTERN = "\\d+\n";
+    private static final String CHUNKED_END_REGEX_PATTERN = "\n##\n";
+    // pattern to parse each chunk-size in ChunkedMessage chunk
+    private static final Pattern CHUNKED_SIZE_PATTERN = Pattern.compile("\\n#([1-9][0-9]*)\\n");
+    private static final String HASH = "#";
+    private static final char HASH_CHAR = '#';
+    private static final String LF = "\n";
+    private static final char LF_CHAR = '\n';
 
     private OutputStreamWriter outputStream;
     private final InputStream err;
@@ -113,6 +129,8 @@
             NetconfMessageState evaluateChar(char c) {
                 if (c == ']') {
                     return FIRST_BRACKET;
+                } else if (c == '\n') {
+                    return FIRST_LF;
                 } else {
                     return this;
                 }
@@ -168,6 +186,46 @@
                 }
             }
         },
+        FIRST_LF {
+            @Override
+            NetconfMessageState evaluateChar(char c) {
+                if (c == '#') {
+                    return FIRST_HASH;
+                } else if (c == ']') {
+                    return FIRST_BRACKET;
+                } else if (c == '\n') {
+                    return this;
+                } else {
+                    return NO_MATCHING_PATTERN;
+                }
+            }
+        },
+        FIRST_HASH {
+            @Override
+            NetconfMessageState evaluateChar(char c) {
+                if (c == '#') {
+                    return SECOND_HASH;
+                } else {
+                    return NO_MATCHING_PATTERN;
+                }
+            }
+        },
+        SECOND_HASH {
+            @Override
+            NetconfMessageState evaluateChar(char c) {
+                if (c == '\n') {
+                    return END_CHUNKED_PATTERN;
+                } else {
+                    return NO_MATCHING_PATTERN;
+                }
+            }
+        },
+        END_CHUNKED_PATTERN {
+            @Override
+            NetconfMessageState evaluateChar(char c) {
+                return NO_MATCHING_PATTERN;
+            }
+        },
         END_PATTERN {
             @Override
             NetconfMessageState evaluateChar(char c) {
@@ -180,77 +238,141 @@
 
     @Override
     public void run() {
-        BufferedReader bufferReader = new BufferedReader(new InputStreamReader(in));
+        BufferedReader bufferReader = null;
+        while (bufferReader == null) {
             try {
-                boolean socketClosed = false;
-                StringBuilder deviceReplyBuilder = new StringBuilder();
-                while (!socketClosed) {
-                    int cInt = bufferReader.read();
-                    if (cInt == -1) {
-                        log.debug("Netconf device {}  sent error char in session," +
-                                          " will need to be reopend", netconfDeviceInfo);
-                        NetconfDeviceOutputEvent event = new NetconfDeviceOutputEvent(
-                                NetconfDeviceOutputEvent.Type.SESSION_CLOSED,
-                                null, null, Optional.of(-1), netconfDeviceInfo);
-                        netconfDeviceEventListeners.forEach(
-                                listener -> listener.event(event));
+                bufferReader = new BufferedReader(new InputStreamReader(in, "UTF-8"));
+            } catch (UnsupportedEncodingException e) {
+                e.printStackTrace();
+            }
+        }
+
+        try {
+            boolean socketClosed = false;
+            StringBuilder deviceReplyBuilder = new StringBuilder();
+            while (!socketClosed) {
+                int cInt = bufferReader.read();
+                if (cInt == -1) {
+                    log.debug("Netconf device {}  sent error char in session," +
+                            " will need to be reopend", netconfDeviceInfo);
+                    NetconfDeviceOutputEvent event = new NetconfDeviceOutputEvent(
+                            NetconfDeviceOutputEvent.Type.SESSION_CLOSED,
+                            null, null, Optional.of(-1), netconfDeviceInfo);
+                    netconfDeviceEventListeners.forEach(
+                            listener -> listener.event(event));
+                    socketClosed = true;
+                    log.debug("Netconf device {} ERROR cInt == -1 socketClosed = true", netconfDeviceInfo);
+                }
+                char c = (char) cInt;
+                state = state.evaluateChar(c);
+                deviceReplyBuilder.append(c);
+                if (state == NetconfMessageState.END_PATTERN) {
+                    String deviceReply = deviceReplyBuilder.toString();
+                    if (deviceReply.equals(END_PATTERN)) {
                         socketClosed = true;
-                        log.debug("Netconf device {} ERROR cInt == -1 socketClosed = true", netconfDeviceInfo);
+                        close(deviceReply);
+                    } else {
+                        deviceReply = deviceReply.replace(END_PATTERN, "");
+                        dealWithReply(deviceReply);
+                        deviceReplyBuilder.setLength(0);
                     }
-                    char c = (char) cInt;
-                    state = state.evaluateChar(c);
-                    deviceReplyBuilder.append(c);
-                    if (state == NetconfMessageState.END_PATTERN) {
-                        String deviceReply = deviceReplyBuilder.toString();
-                        if (deviceReply.equals(END_PATTERN)) {
-                            socketClosed = true;
-                            log.debug("Netconf device {} socketClosed = true DEVICE_UNREGISTERED {}",
-                                     netconfDeviceInfo, deviceReply);
-                            NetconfDeviceOutputEvent event = new NetconfDeviceOutputEvent(
-                                    NetconfDeviceOutputEvent.Type.DEVICE_UNREGISTERED,
-                                    null, null, Optional.of(-2), netconfDeviceInfo);
-                            netconfDeviceEventListeners.forEach(
-                                    listener -> listener.event(event));
-                            this.interrupt();
-                        } else {
-                            deviceReply = deviceReply.replace(END_PATTERN, "");
-                            if (deviceReply.contains(RPC_REPLY) ||
-                                    deviceReply.contains(RPC_ERROR) ||
-                                    deviceReply.contains(HELLO)) {
-                                log.debug("Netconf device {} sessionDelegate.notify() DEVICE_REPLY {} {}",
-                                    netconfDeviceInfo, getMsgId(deviceReply), deviceReply);
-                                NetconfDeviceOutputEvent event = new NetconfDeviceOutputEvent(
-                                        NetconfDeviceOutputEvent.Type.DEVICE_REPLY,
-                                        null, deviceReply, getMsgId(deviceReply), netconfDeviceInfo);
-                                sessionDelegate.notify(event);
-                                netconfDeviceEventListeners.forEach(
-                                        listener -> listener.event(event));
-                            } else if (deviceReply.contains(NOTIFICATION_LABEL)) {
-                                log.debug("Netconf device {} DEVICE_NOTIFICATION {} {} {}",
-                                         netconfDeviceInfo, enableNotifications,
-                                         getMsgId(deviceReply), deviceReply);
-                                if (enableNotifications) {
-                                    log.debug("dispatching to {} listeners", netconfDeviceEventListeners.size());
-                                    final String finalDeviceReply = deviceReply;
-                                    netconfDeviceEventListeners.forEach(
-                                            listener -> listener.event(new NetconfDeviceOutputEvent(
-                                                    NetconfDeviceOutputEvent.Type.DEVICE_NOTIFICATION,
-                                                    null, finalDeviceReply, getMsgId(finalDeviceReply),
-                                                    netconfDeviceInfo)));
-                                }
-                            } else {
-                                log.debug("Error on reply from device {} {}", netconfDeviceInfo, deviceReply);
-                            }
-                            deviceReplyBuilder.setLength(0);
-                        }
+                } else if (state == NetconfMessageState.END_CHUNKED_PATTERN) {
+                    String deviceReply = deviceReplyBuilder.toString();
+                    if (!validateChunkedFraming(deviceReply)) {
+                        log.debug("Netconf device {} send badly framed message {}",
+                                netconfDeviceInfo, deviceReply);
+                        socketClosed = true;
+                        close(deviceReply);
+                    } else {
+                        deviceReply = deviceReply.replaceAll(MSGLEN_REGEX_PATTERN, "");
+                        deviceReply = deviceReply.replaceAll(CHUNKED_END_REGEX_PATTERN, "");
+                        dealWithReply(deviceReply);
+                        deviceReplyBuilder.setLength(0);
                     }
                 }
-            } catch (IOException e) {
-                log.warn("Error in reading from the session for device {} ", netconfDeviceInfo, e);
-                throw new RuntimeException(new NetconfException("Error in reading from the session for device {}" +
-                                                                        netconfDeviceInfo, e));
-                //TODO should we send a socket closed message to listeners ?
             }
+        } catch (IOException e) {
+            log.warn("Error in reading from the session for device {} ", netconfDeviceInfo, e);
+            throw new RuntimeException(new NetconfException("Error in reading from the session for device {}" +
+                    netconfDeviceInfo, e));
+            //TODO should we send a socket closed message to listeners ?
+        }
+    }
+
+    private void close(String deviceReply) {
+        log.debug("Netconf device {} socketClosed = true DEVICE_UNREGISTERED {}",
+                netconfDeviceInfo, deviceReply);
+        NetconfDeviceOutputEvent event = new NetconfDeviceOutputEvent(
+                NetconfDeviceOutputEvent.Type.DEVICE_UNREGISTERED,
+                null, null, Optional.of(-1), netconfDeviceInfo);
+        netconfDeviceEventListeners.forEach(
+                listener -> listener.event(event));
+        this.interrupt();
+    }
+
+    private void dealWithReply(String deviceReply) {
+        if (deviceReply.contains(RPC_REPLY) ||
+                deviceReply.contains(RPC_ERROR) ||
+                deviceReply.contains(HELLO)) {
+            log.debug("Netconf device {} sessionDelegate.notify() DEVICE_REPLY {} {}",
+                    netconfDeviceInfo, getMsgId(deviceReply), deviceReply);
+            NetconfDeviceOutputEvent event = new NetconfDeviceOutputEvent(
+                    NetconfDeviceOutputEvent.Type.DEVICE_REPLY,
+                    null, deviceReply, getMsgId(deviceReply), netconfDeviceInfo);
+            sessionDelegate.notify(event);
+            netconfDeviceEventListeners.forEach(
+                    listener -> listener.event(event));
+        } else if (deviceReply.contains(NOTIFICATION_LABEL)) {
+            log.debug("Netconf device {} DEVICE_NOTIFICATION {} {} {}",
+                    netconfDeviceInfo, enableNotifications,
+                    getMsgId(deviceReply), deviceReply);
+            if (enableNotifications) {
+                log.debug("dispatching to {} listeners", netconfDeviceEventListeners.size());
+                final String finalDeviceReply = deviceReply;
+                netconfDeviceEventListeners.forEach(
+                        listener -> listener.event(new NetconfDeviceOutputEvent(
+                                NetconfDeviceOutputEvent.Type.DEVICE_NOTIFICATION,
+                                null, finalDeviceReply, getMsgId(finalDeviceReply),
+                                netconfDeviceInfo)));
+            }
+        } else {
+            log.debug("Error on reply from device {} {}", netconfDeviceInfo, deviceReply);
+        }
+    }
+
+    static boolean validateChunkedFraming(String reply) {
+        Matcher matcher = CHUNKED_FRAMING_PATTERN.matcher(reply);
+        if (!matcher.matches()) {
+            log.debug("Error on reply {}", reply);
+            return false;
+        }
+        Matcher chunkM = CHUNKED_SIZE_PATTERN.matcher(reply);
+        List<MatchResult> chunks = new ArrayList<>();
+        String chunkdataStr = "";
+        while (chunkM.find()) {
+            chunks.add(chunkM.toMatchResult());
+            // extract chunk-data (and later) in bytes
+            int bytes = Integer.parseInt(chunkM.group(1));
+            byte[] chunkdata = reply.substring(chunkM.end()).getBytes(StandardCharsets.UTF_8);
+            if (bytes > chunkdata.length) {
+                log.debug("Error on reply - wrong chunk size {}", reply);
+                return false;
+            }
+            //check if after chunk-size bytes there is next chunk or message ending
+            if (chunkdata[bytes] != LF_CHAR || chunkdata[bytes + 1] != HASH_CHAR) {
+                log.debug("Error on reply - wrong chunk size {}", reply);
+                return false;
+            }
+            // convert (only) chunk-data part into String
+            chunkdataStr = new String(chunkdata, 0, bytes, StandardCharsets.UTF_8);
+            // skip chunk-data part from next match
+            chunkM.region(chunkM.end() + chunkdataStr.length(), reply.length());
+        }
+        if (!"\n##\n".equals(reply.substring(chunks.get(chunks.size() - 1).end() + chunkdataStr.length()))) {
+            log.debug("Error on reply {}", reply);
+            return false;
+        }
+        return true;
     }
 
     protected static Optional<Integer> getMsgId(String reply) {
@@ -284,4 +406,4 @@
     public void setEnableNotifications(boolean enableNotifications) {
         this.enableNotifications = enableNotifications;
     }
-}
+}
\ No newline at end of file
diff --git a/protocols/netconf/ctl/src/test/java/org/onosproject/netconf/ctl/impl/NetconfSessionImplTest.java b/protocols/netconf/ctl/src/test/java/org/onosproject/netconf/ctl/impl/NetconfSessionImplTest.java
index 8fdd5ff..1b5e7fa 100644
--- a/protocols/netconf/ctl/src/test/java/org/onosproject/netconf/ctl/impl/NetconfSessionImplTest.java
+++ b/protocols/netconf/ctl/src/test/java/org/onosproject/netconf/ctl/impl/NetconfSessionImplTest.java
@@ -27,7 +27,6 @@
 import java.io.File;
 import java.util.Arrays;
 import java.util.Collection;
-import java.util.List;
 import java.util.Optional;
 import java.util.concurrent.Callable;
 import java.util.concurrent.ExecutorService;
@@ -35,6 +34,7 @@
 import java.util.concurrent.FutureTask;
 import java.util.regex.Pattern;
 
+import com.google.common.collect.ImmutableList;
 import org.apache.sshd.common.NamedFactory;
 import org.apache.sshd.server.Command;
 import org.apache.sshd.server.SshServer;
@@ -53,7 +53,6 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.common.collect.ImmutableList;
 
 /**
  * Unit tests for NetconfSession.
@@ -89,22 +88,10 @@
                     + "</edit-config>\n"
                     + "</rpc>]]>]]>";
 
-    static final List<String> DEFAULT_CAPABILITIES = ImmutableList.<String>builder()
-            .add("urn:ietf:params:netconf:base:1.0")
-            .add("urn:ietf:params:netconf:base:1.1")
-            .add("urn:ietf:params:netconf:capability:writable-running:1.0")
-            .add("urn:ietf:params:netconf:capability:candidate:1.0")
-            .add("urn:ietf:params:netconf:capability:startup:1.0")
-            .add("urn:ietf:params:netconf:capability:rollback-on-error:1.0")
-            .add("urn:ietf:params:netconf:capability:interleave:1.0")
-            .add("urn:ietf:params:netconf:capability:notification:1.0")
-            .add("urn:ietf:params:netconf:capability:validate:1.0")
-            .add("urn:ietf:params:netconf:capability:validate:1.1")
-            .build();
-
-
     private static NetconfSession session1;
     private static NetconfSession session2;
+    private static NetconfSession session3;
+    private static NetconfSession session4;
     private static SshServer sshServerNetconf;
 
     @BeforeClass
@@ -132,17 +119,30 @@
         NetconfDeviceInfo deviceInfo = new NetconfDeviceInfo(
                 TEST_USERNAME, TEST_PASSWORD, Ip4Address.valueOf(TEST_HOSTNAME), PORT_NUMBER);
 
-        session1 = new NetconfSessionImpl(deviceInfo);
+        session1 = new NetconfSessionImpl(deviceInfo, ImmutableList.of("urn:ietf:params:netconf:base:1.0"));
         log.info("Started NETCONF Session {} with test SSHD server in Unit Test", session1.getSessionId());
         assertTrue("Incorrect sessionId", !session1.getSessionId().equalsIgnoreCase("-1"));
         assertTrue("Incorrect sessionId", !session1.getSessionId().equalsIgnoreCase("0"));
-        assertThat(session1.getDeviceCapabilitiesSet(), containsInAnyOrder(DEFAULT_CAPABILITIES.toArray()));
-
-        session2 = new NetconfSessionImpl(deviceInfo);
+        assertThat(session1.getDeviceCapabilitiesSet(), containsInAnyOrder(
+                NetconfSessionMinaImplTest.DEFAULT_CAPABILITIES.toArray()));
+        session2 = new NetconfSessionImpl(deviceInfo, ImmutableList.of("urn:ietf:params:netconf:base:1.0"));
         log.info("Started NETCONF Session {} with test SSHD server in Unit Test", session2.getSessionId());
         assertTrue("Incorrect sessionId", !session2.getSessionId().equalsIgnoreCase("-1"));
         assertTrue("Incorrect sessionId", !session2.getSessionId().equalsIgnoreCase("0"));
-        assertThat(session2.getDeviceCapabilitiesSet(), containsInAnyOrder(DEFAULT_CAPABILITIES.toArray()));
+        assertThat(session2.getDeviceCapabilitiesSet(), containsInAnyOrder(
+                NetconfSessionMinaImplTest.DEFAULT_CAPABILITIES.toArray()));
+        session3 = new NetconfSessionImpl(deviceInfo);
+        log.info("Started NETCONF Session {} with test SSHD server in Unit Test", session3.getSessionId());
+        assertTrue("Incorrect sessionId", !session3.getSessionId().equalsIgnoreCase("-1"));
+        assertTrue("Incorrect sessionId", !session3.getSessionId().equalsIgnoreCase("0"));
+        assertThat(session3.getDeviceCapabilitiesSet(), containsInAnyOrder(
+                NetconfSessionMinaImplTest.DEFAULT_CAPABILITIES_1_1.toArray()));
+        session4 = new NetconfSessionImpl(deviceInfo);
+        log.info("Started NETCONF Session {} with test SSHD server in Unit Test", session4.getSessionId());
+        assertTrue("Incorrect sessionId", !session4.getSessionId().equalsIgnoreCase("-1"));
+        assertTrue("Incorrect sessionId", !session4.getSessionId().equalsIgnoreCase("0"));
+        assertThat(session4.getDeviceCapabilitiesSet(), containsInAnyOrder(
+                NetconfSessionMinaImplTest.DEFAULT_CAPABILITIES_1_1.toArray()));
     }
 
     @AfterClass
@@ -153,6 +153,12 @@
         if (session2 != null) {
             session2.close();
         }
+        if (session3 != null) {
+            session3.close();
+        }
+        if (session4 != null) {
+            session4.close();
+        }
 
         sshServerNetconf.stop();
     }
@@ -163,8 +169,23 @@
         assertNotNull("Incorrect sessionId", session1.getSessionId());
         try {
             assertTrue("NETCONF edit-config command failed",
-                       session1.editConfig(DatastoreId.RUNNING,
-                                           null, SAMPLE_REQUEST));
+                    session1.editConfig(DatastoreId.RUNNING,
+                            null, SAMPLE_REQUEST));
+        } catch (NetconfException e) {
+            e.printStackTrace();
+            fail("NETCONF edit-config test failed: " + e.getMessage());
+        }
+        log.info("Finishing edit-config async");
+    }
+
+    @Test
+    public void testEditConfigRequestWithChunkedFraming() {
+        log.info("Starting edit-config async");
+        assertNotNull("Incorrect sessionId", session3.getSessionId());
+        try {
+            assertTrue("NETCONF edit-config command failed",
+                    session3.editConfig(DatastoreId.RUNNING,
+                            null, SAMPLE_REQUEST));
         } catch (NetconfException e) {
             e.printStackTrace();
             fail("NETCONF edit-config test failed: " + e.getMessage());
@@ -178,7 +199,21 @@
         assertNotNull("Incorrect sessionId", session1.getSessionId());
         try {
             assertTrue("NETCONF edit-config command failed",
-                       session1.editConfig(EDIT_CONFIG_REQUEST));
+                    session1.editConfig(NetconfSessionMinaImplTest.EDIT_CONFIG_REQUEST));
+        } catch (NetconfException e) {
+            e.printStackTrace();
+            fail("NETCONF edit-config test failed: " + e.getMessage());
+        }
+        log.info("Finishing edit-config async");
+    }
+
+    @Test
+    public void testEditConfigRequestWithOnlyNewConfigurationWithChunkedFraming() {
+        log.info("Starting edit-config async");
+        assertNotNull("Incorrect sessionId", session3.getSessionId());
+        try {
+            assertTrue("NETCONF edit-config command failed",
+                    session3.editConfig(NetconfSessionMinaImplTest.EDIT_CONFIG_REQUEST));
         } catch (NetconfException e) {
             e.printStackTrace();
             fail("NETCONF edit-config test failed: " + e.getMessage());
@@ -192,7 +227,21 @@
         assertNotNull("Incorrect sessionId", session1.getSessionId());
         try {
             assertFalse("NETCONF delete-config command failed",
-                        session1.deleteConfig(DatastoreId.RUNNING));
+                    session1.deleteConfig(DatastoreId.RUNNING));
+        } catch (NetconfException e) {
+            e.printStackTrace();
+            fail("NETCONF delete-config test failed: " + e.getMessage());
+        }
+        log.info("Finishing delete-config async");
+    }
+
+    @Test
+    public void testDeleteConfigRequestWithRunningTargetConfigurationWithChunkedFraming() {
+        log.info("Starting delete-config async");
+        assertNotNull("Incorrect sessionId", session3.getSessionId());
+        try {
+            assertFalse("NETCONF delete-config command failed",
+                    session3.deleteConfig(DatastoreId.RUNNING));
         } catch (NetconfException e) {
             e.printStackTrace();
             fail("NETCONF delete-config test failed: " + e.getMessage());
@@ -206,8 +255,23 @@
         assertNotNull("Incorrect sessionId", session1.getSessionId());
         try {
             assertTrue("NETCONF copy-config command failed",
-                       session1.copyConfig(DatastoreId.RUNNING,
-                                           DatastoreId.CANDIDATE));
+                    session1.copyConfig(DatastoreId.RUNNING,
+                            DatastoreId.CANDIDATE));
+        } catch (NetconfException e) {
+            e.printStackTrace();
+            fail("NETCONF copy-config test failed: " + e.getMessage());
+        }
+        log.info("Finishing copy-config async");
+    }
+
+    @Test
+    public void testCopyConfigRequestWithChunkedFraming() {
+        log.info("Starting copy-config async");
+        assertNotNull("Incorrect sessionId", session3.getSessionId());
+        try {
+            assertTrue("NETCONF copy-config command failed",
+                    session3.copyConfig(DatastoreId.RUNNING,
+                            DatastoreId.CANDIDATE));
         } catch (NetconfException e) {
             e.printStackTrace();
             fail("NETCONF copy-config test failed: " + e.getMessage());
@@ -221,8 +285,23 @@
         assertNotNull("Incorrect sessionId", session1.getSessionId());
         try {
             assertTrue("NETCONF copy-config command failed",
-                       session1.copyConfig(DatastoreId.RUNNING,
-                                           "<configuration><device-specific/></configuration>"));
+                    session1.copyConfig(DatastoreId.RUNNING,
+                            "<configuration><device-specific/></configuration>"));
+        } catch (NetconfException e) {
+            e.printStackTrace();
+            fail("NETCONF copy-config test failed: " + e.getMessage());
+        }
+        log.info("Finishing copy-config XML async");
+    }
+
+    @Test
+    public void testCopyConfigXmlWithChunkedFraming() {
+        log.info("Starting copy-config XML async");
+        assertNotNull("Incorrect sessionId", session3.getSessionId());
+        try {
+            assertTrue("NETCONF copy-config command failed",
+                    session3.copyConfig(DatastoreId.RUNNING,
+                            "<configuration><device-specific/></configuration>"));
         } catch (NetconfException e) {
             e.printStackTrace();
             fail("NETCONF copy-config test failed: " + e.getMessage());
@@ -237,10 +316,27 @@
         assertNotNull("Incorrect sessionId", session1.getSessionId());
         try {
             assertTrue("NETCONF copy-config command failed",
-                       session1.copyConfig(DatastoreId.RUNNING,
-                                           "<config>"
-                                           + "<configuration><device-specific/></configuration>"
-                                         + "</config>"));
+                    session1.copyConfig(DatastoreId.RUNNING,
+                            "<config>"
+                                    + "<configuration><device-specific/></configuration>"
+                                    + "</config>"));
+        } catch (NetconfException e) {
+            e.printStackTrace();
+            fail("NETCONF copy-config test failed: " + e.getMessage());
+        }
+        log.info("Finishing copy-config bare XML async");
+    }
+
+    @Test
+    public void testCopyConfigBareXmlWithChunkedFraming() {
+        log.info("Starting copy-config bare XML async");
+        assertNotNull("Incorrect sessionId", session3.getSessionId());
+        try {
+            assertTrue("NETCONF copy-config command failed",
+                    session3.copyConfig(DatastoreId.RUNNING,
+                            "<config>"
+                                    + "<configuration><device-specific/></configuration>"
+                                    + "</config>"));
         } catch (NetconfException e) {
             e.printStackTrace();
             fail("NETCONF copy-config test failed: " + e.getMessage());
@@ -254,10 +350,32 @@
         assertNotNull("Incorrect sessionId", session1.getSessionId());
         try {
             assertTrue("NETCONF get-config running command failed. ",
-                       GET_REPLY_PATTERN.matcher(session1.getConfig(RUNNING, SAMPLE_REQUEST)).matches());
+                    NetconfSessionMinaImplTest.GET_REPLY_PATTERN.matcher(session1.getConfig(RUNNING,
+                            SAMPLE_REQUEST)).matches());
 
             assertTrue("NETCONF get-config candidate command failed. ",
-                       GET_REPLY_PATTERN.matcher(session1.getConfig(CANDIDATE, SAMPLE_REQUEST)).matches());
+                    NetconfSessionMinaImplTest.GET_REPLY_PATTERN.matcher(session1.getConfig(CANDIDATE,
+                            SAMPLE_REQUEST)).matches());
+
+        } catch (NetconfException e) {
+            e.printStackTrace();
+            fail("NETCONF get-config test failed: " + e.getMessage());
+        }
+        log.info("Finishing get-config async");
+    }
+
+    @Test
+    public void testGetConfigRequestWithChunkedFraming() {
+        log.info("Starting get-config async");
+        assertNotNull("Incorrect sessionId", session3.getSessionId());
+        try {
+            assertTrue("NETCONF get-config running command failed. ",
+                    NetconfSessionMinaImplTest.GET_REPLY_PATTERN.matcher(session3.getConfig(RUNNING,
+                            SAMPLE_REQUEST)).matches());
+
+            assertTrue("NETCONF get-config candidate command failed. ",
+                    NetconfSessionMinaImplTest.GET_REPLY_PATTERN.matcher(session3.getConfig(CANDIDATE,
+                            SAMPLE_REQUEST)).matches());
 
         } catch (NetconfException e) {
             e.printStackTrace();
@@ -272,7 +390,23 @@
         assertNotNull("Incorrect sessionId", session1.getSessionId());
         try {
             assertTrue("NETCONF get running command failed. ",
-                       GET_REPLY_PATTERN.matcher(session1.get(SAMPLE_REQUEST, null)).matches());
+                    NetconfSessionMinaImplTest.GET_REPLY_PATTERN.matcher(session1.get(SAMPLE_REQUEST,
+                            null)).matches());
+
+        } catch (NetconfException e) {
+            e.printStackTrace();
+            fail("NETCONF get test failed: " + e.getMessage());
+        }
+        log.info("Finishing get async");
+    }
+
+    @Test
+    public void testGetRequestWithChunkedFraming() {
+        log.info("Starting get async");
+        assertNotNull("Incorrect sessionId", session3.getSessionId());
+        try {
+            assertTrue("NETCONF get running command failed. ",
+                    NetconfSessionMinaImplTest.GET_REPLY_PATTERN.matcher(session3.get(SAMPLE_REQUEST, null)).matches());
 
         } catch (NetconfException e) {
             e.printStackTrace();
@@ -295,6 +429,19 @@
     }
 
     @Test
+    public void testLockRequestWithChunkedFraming() {
+        log.info("Starting lock async");
+        assertNotNull("Incorrect sessionId", session3.getSessionId());
+        try {
+            assertTrue("NETCONF lock request failed", session3.lock());
+        } catch (NetconfException e) {
+            e.printStackTrace();
+            fail("NETCONF lock test failed: " + e.getMessage());
+        }
+        log.info("Finishing lock async");
+    }
+
+    @Test
     public void testUnLockRequest() {
         log.info("Starting unlock async");
         assertNotNull("Incorrect sessionId", session1.getSessionId());
@@ -307,6 +454,19 @@
         log.info("Finishing unlock async");
     }
 
+    @Test
+    public void testUnLockRequestWithChunkedFraming() {
+        log.info("Starting unlock async");
+        assertNotNull("Incorrect sessionId", session3.getSessionId());
+        try {
+            assertTrue("NETCONF unlock request failed", session3.unlock());
+        } catch (NetconfException e) {
+            e.printStackTrace();
+            fail("NETCONF unlock test failed: " + e.getMessage());
+        }
+        log.info("Finishing unlock async");
+    }
+
 
     @Test
     public void testConcurrentSameSessionAccess() throws InterruptedException {
@@ -335,6 +495,32 @@
     }
 
     @Test
+    public void testConcurrentSameSessionAccessWithChunkedFraming() throws InterruptedException {
+        NCCopyConfigCallable testCopyConfig1 = new NCCopyConfigCallable(session3, RUNNING, "candidate");
+        NCCopyConfigCallable testCopyConfig2 = new NCCopyConfigCallable(session3, RUNNING, "startup");
+
+        FutureTask<Boolean> futureCopyConfig1 = new FutureTask<>(testCopyConfig1);
+        FutureTask<Boolean> futureCopyConfig2 = new FutureTask<>(testCopyConfig2);
+
+        ExecutorService executor = Executors.newFixedThreadPool(2);
+        log.info("Starting concurrent execution of copy-config through same session");
+        executor.execute(futureCopyConfig1);
+        executor.execute(futureCopyConfig2);
+
+        int count = 0;
+        while (count < 10) {
+            if (futureCopyConfig1.isDone() && futureCopyConfig2.isDone()) {
+                executor.shutdown();
+                log.info("Finished concurrent same session execution");
+                return;
+            }
+            Thread.sleep(100L);
+            count++;
+        }
+        fail("NETCONF test failed to complete.");
+    }
+
+    @Test
     public void test2SessionAccess() throws InterruptedException {
         NCCopyConfigCallable testCopySession1 = new NCCopyConfigCallable(session1, RUNNING, "candidate");
         NCCopyConfigCallable testCopySession2 = new NCCopyConfigCallable(session2, RUNNING, "candidate");
@@ -360,9 +546,39 @@
         fail("NETCONF test failed to complete.");
     }
 
+    @Test
+    public void test2SessionAccessWithChunkedFraming() throws InterruptedException {
+        NCCopyConfigCallable testCopySession1 = new NCCopyConfigCallable(session3, RUNNING, "candidate");
+        NCCopyConfigCallable testCopySession2 = new NCCopyConfigCallable(session4, RUNNING, "candidate");
 
-    public static String getTestHelloReply(Optional<Long> sessionId) {
-        return getTestHelloReply(DEFAULT_CAPABILITIES, sessionId);
+        FutureTask<Boolean> futureCopySession1 = new FutureTask<>(testCopySession1);
+        FutureTask<Boolean> futureCopySession2 = new FutureTask<>(testCopySession2);
+
+        ExecutorService executor = Executors.newFixedThreadPool(2);
+        log.info("Starting concurrent execution of copy-config through 2 different sessions");
+        executor.execute(futureCopySession1);
+        executor.execute(futureCopySession2);
+
+        int count = 0;
+        while (count < 10) {
+            if (futureCopySession1.isDone() && futureCopySession2.isDone()) {
+                executor.shutdown();
+                log.info("Finished concurrent 2 session execution");
+                return;
+            }
+            Thread.sleep(100L);
+            count++;
+        }
+        fail("NETCONF test failed to complete.");
+    }
+
+
+    public static String getTestHelloReply(Optional<Long> sessionId, boolean useChunkedFraming) {
+        if (useChunkedFraming) {
+            return getTestHelloReply(NetconfSessionMinaImplTest.DEFAULT_CAPABILITIES_1_1, sessionId);
+        } else {
+            return getTestHelloReply(NetconfSessionMinaImplTest.DEFAULT_CAPABILITIES, sessionId);
+        }
     }
 
     public static String getTestHelloReply(Collection<String> capabilities, Optional<Long> sessionId) {
@@ -414,11 +630,21 @@
 
     public static final Pattern HELLO_REQ_PATTERN =
             Pattern.compile("(<\\?xml).*"
-                    + "(<hello xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">)\\R?"
-                    + "( *)(<capabilities>)\\R?"
-                    + "( *)(<capability>urn:ietf:params:netconf:base:1.0</capability>)\\R?"
-                    + "( *)(</capabilities>)\\R?"
-                    + "(</hello>)\\R? *",
+                            + "(<hello xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">)\\R?"
+                            + "( *)(<capabilities>)\\R?"
+                            + "( *)(<capability>urn:ietf:params:netconf:base:1.0</capability>)\\R?"
+                            + "( *)(</capabilities>)\\R?"
+                            + "(</hello>)\\R? *",
+                    Pattern.DOTALL);
+
+    public static final Pattern HELLO_REQ_PATTERN_1_1 =
+            Pattern.compile("(<\\?xml).*"
+                            + "(<hello xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">)\\R?"
+                            + "( *)(<capabilities>)\\R?"
+                            + "( *)(<capability>urn:ietf:params:netconf:base:1.0</capability>)\\R?"
+                            + "( *)(<capability>urn:ietf:params:netconf:base:1.1</capability>)\\R?"
+                            + "( *)(</capabilities>)\\R?"
+                            + "(</hello>)\\R? *",
                     Pattern.DOTALL);
 
     public static final Pattern EDIT_CONFIG_REQ_PATTERN =
@@ -426,8 +652,8 @@
                     + "(<rpc message-id=\")[0-9]*(\") *(xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">)\\R?"
                     + "(<edit-config>)\\R?"
                     + "(<target>\\R?((<" + DatastoreId.CANDIDATE.toString() + "/>)|"
-                                    + "(<" + DatastoreId.RUNNING.toString() + "/>)|"
-                                    + "(<" + DatastoreId.STARTUP.toString() + "/>))\\R?</target>)\\R?"
+                    + "(<" + DatastoreId.RUNNING.toString() + "/>)|"
+                    + "(<" + DatastoreId.STARTUP.toString() + "/>))\\R?</target>)\\R?"
                     + "(<config xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">)\\R?"
                     + ".*"
                     + "(</config>)\\R?(</edit-config>)\\R?(</rpc>)\\R?", Pattern.DOTALL);
@@ -435,23 +661,23 @@
 
     public static final Pattern LOCK_REQ_PATTERN =
             Pattern.compile("(<\\?xml).*"
-                                    + "(<rpc xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\" "
-                                    + "message-id=\")[0-9]*(\">)\\R?"
-                                    + "(<lock>)\\R?"
-                                    + "(<target>\\R?((<" + DatastoreId.CANDIDATE.toString() + "/>)|"
-                                    + "(<" + DatastoreId.RUNNING.toString() + "/>)|"
-                                    + "(<" + DatastoreId.STARTUP.toString() + "/>))\\R?</target>)\\R?"
-                                    + "(</lock>)\\R?(</rpc>)\\R?", Pattern.DOTALL);
+                    + "(<rpc xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\" "
+                    + "message-id=\")[0-9]*(\">)\\R?"
+                    + "(<lock>)\\R?"
+                    + "(<target>\\R?((<" + DatastoreId.CANDIDATE.toString() + "/>)|"
+                    + "(<" + DatastoreId.RUNNING.toString() + "/>)|"
+                    + "(<" + DatastoreId.STARTUP.toString() + "/>))\\R?</target>)\\R?"
+                    + "(</lock>)\\R?(</rpc>)\\R?", Pattern.DOTALL);
 
     public static final Pattern UNLOCK_REQ_PATTERN =
             Pattern.compile("(<\\?xml).*"
-                                    + "(<rpc xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\" "
-                                    + "message-id=\")[0-9]*(\">)\\R?"
-                                    + "(<unlock>)\\R?"
-                                    + "(<target>\\R?((<" + DatastoreId.CANDIDATE.toString() + "/>)|"
-                                    + "(<" + DatastoreId.RUNNING.toString() + "/>)|"
-                                    + "(<" + DatastoreId.STARTUP.toString() + "/>))\\R?</target>)\\R?"
-                                    + "(</unlock>)\\R?(</rpc>)\\R?", Pattern.DOTALL);
+                    + "(<rpc xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\" "
+                    + "message-id=\")[0-9]*(\">)\\R?"
+                    + "(<unlock>)\\R?"
+                    + "(<target>\\R?((<" + DatastoreId.CANDIDATE.toString() + "/>)|"
+                    + "(<" + DatastoreId.RUNNING.toString() + "/>)|"
+                    + "(<" + DatastoreId.STARTUP.toString() + "/>))\\R?</target>)\\R?"
+                    + "(</unlock>)\\R?(</rpc>)\\R?", Pattern.DOTALL);
 
     public static final Pattern COPY_CONFIG_REQ_PATTERN =
             Pattern.compile("(<\\?xml).*"
@@ -459,17 +685,17 @@
                     + "(<copy-config>)\\R?"
                     + "(<target>\\R?"
                     + "("
-                        + "(<" + DatastoreId.CANDIDATE.toString() + "/>)|"
-                        + "(<" + DatastoreId.RUNNING.toString() + "/>)|"
-                        + "(<" + DatastoreId.STARTUP.toString() + "/>)"
+                    + "(<" + DatastoreId.CANDIDATE.toString() + "/>)|"
+                    + "(<" + DatastoreId.RUNNING.toString() + "/>)|"
+                    + "(<" + DatastoreId.STARTUP.toString() + "/>)"
                     + ")\\R?"
                     + "</target>)\\R?"
                     + "(<source>)\\R?"
                     + "("
-                        + "(<config>)(.*)(</config>)|"
-                        + "(<" + DatastoreId.CANDIDATE.toString() + "/>)|"
-                        + "(<" + DatastoreId.RUNNING.toString() + "/>)|"
-                        + "(<" + DatastoreId.STARTUP.toString() + "/>)"
+                    + "(<config>)(.*)(</config>)|"
+                    + "(<" + DatastoreId.CANDIDATE.toString() + "/>)|"
+                    + "(<" + DatastoreId.RUNNING.toString() + "/>)|"
+                    + "(<" + DatastoreId.STARTUP.toString() + "/>)"
                     + ")\\R?"
                     + "(</source>)\\R?"
                     + "(</copy-config>)\\R?(</rpc>)\\R?", Pattern.DOTALL);
@@ -478,18 +704,14 @@
             Pattern.compile("(<\\?xml).*"
                     + "(<rpc message-id=\")[0-9]*(\"  xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">)\\R?"
                     + "(<get-config>)\\R?" + "(<source>)\\R?((<"
-                                    + DatastoreId.CANDIDATE.toString()
-                                    + "/>)|(<" + DatastoreId.RUNNING.toString()
-                                    + "/>)|(<" + DatastoreId.STARTUP.toString()
-                                    + "/>))\\R?(</source>)\\R?"
+                    + DatastoreId.CANDIDATE.toString()
+                    + "/>)|(<" + DatastoreId.RUNNING.toString()
+                    + "/>)|(<" + DatastoreId.STARTUP.toString()
+                    + "/>))\\R?(</source>)\\R?"
                     + "(<filter type=\"subtree\">).*(</filter>)\\R?"
                     + "(</get-config>)\\R?(</rpc>)\\R?", Pattern.DOTALL);
 
-    public static final Pattern GET_REPLY_PATTERN =
-            Pattern.compile("(<\\?xml).*"
-                    + "(<rpc-reply xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\" message-id=\")[0-9]*(\">)\\R?"
-                    + "(<data>).*(</data>)\\R?"
-                    + "(</rpc-reply>)\\R?", Pattern.DOTALL);
+
 
     public static final Pattern GET_REQ_PATTERN =
             Pattern.compile("(<\\?xml).*"
@@ -514,4 +736,4 @@
             return session.copyConfig(target, source);
         }
     }
-}
+}
\ No newline at end of file
diff --git a/protocols/netconf/ctl/src/test/java/org/onosproject/netconf/ctl/impl/NetconfSessionMinaImplTest.java b/protocols/netconf/ctl/src/test/java/org/onosproject/netconf/ctl/impl/NetconfSessionMinaImplTest.java
index 4665125..8fd4a86 100644
--- a/protocols/netconf/ctl/src/test/java/org/onosproject/netconf/ctl/impl/NetconfSessionMinaImplTest.java
+++ b/protocols/netconf/ctl/src/test/java/org/onosproject/netconf/ctl/impl/NetconfSessionMinaImplTest.java
@@ -26,11 +26,11 @@
 import org.junit.BeforeClass;
 import org.junit.Test;
 import org.onlab.junit.TestTools;
-import org.onlab.packet.Ip4Address;
 import org.onosproject.netconf.NetconfDeviceInfo;
 import org.onosproject.netconf.NetconfException;
 import org.onosproject.netconf.NetconfSession;
-import org.onosproject.netconf.TargetConfig;
+import org.onosproject.netconf.DatastoreId;
+import org.onlab.packet.Ip4Address;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -46,9 +46,14 @@
 import java.util.regex.Pattern;
 
 import static org.hamcrest.Matchers.containsInAnyOrder;
-import static org.junit.Assert.*;
-import static org.onosproject.netconf.TargetConfig.CANDIDATE;
-import static org.onosproject.netconf.TargetConfig.RUNNING;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+import static org.junit.Assert.assertFalse;
+import static org.onosproject.netconf.DatastoreId.CANDIDATE;
+import static org.onosproject.netconf.DatastoreId.RUNNING;
+import static org.onosproject.netconf.DatastoreId.STARTUP;
 
 /**
  * Unit tests for NetconfSession.
@@ -73,7 +78,7 @@
                     + "<some-child-element/>"
                     + "</some-yang-element>";
 
-    private static final String EDIT_CONFIG_REQUEST =
+    protected static final String EDIT_CONFIG_REQUEST =
             "<?xml version=\"1.0\" encoding=\"UTF-8\"?><rpc message-id=\"6\"  "
                     + "xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n"
                     + "<edit-config>\n"
@@ -86,6 +91,18 @@
 
     static final List<String> DEFAULT_CAPABILITIES = ImmutableList.<String>builder()
             .add("urn:ietf:params:netconf:base:1.0")
+            .add("urn:ietf:params:netconf:capability:writable-running:1.0")
+            .add("urn:ietf:params:netconf:capability:candidate:1.0")
+            .add("urn:ietf:params:netconf:capability:startup:1.0")
+            .add("urn:ietf:params:netconf:capability:rollback-on-error:1.0")
+            .add("urn:ietf:params:netconf:capability:interleave:1.0")
+            .add("urn:ietf:params:netconf:capability:notification:1.0")
+            .add("urn:ietf:params:netconf:capability:validate:1.0")
+            .add("urn:ietf:params:netconf:capability:validate:1.1")
+            .build();
+
+    static final List<String> DEFAULT_CAPABILITIES_1_1 = ImmutableList.<String>builder()
+            .add("urn:ietf:params:netconf:base:1.0")
             .add("urn:ietf:params:netconf:base:1.1")
             .add("urn:ietf:params:netconf:capability:writable-running:1.0")
             .add("urn:ietf:params:netconf:capability:candidate:1.0")
@@ -100,6 +117,8 @@
 
     private static NetconfSession session1;
     private static NetconfSession session2;
+    private static NetconfSession session3;
+    private static NetconfSession session4;
     private static SshServer sshServerNetconf;
 
     @BeforeClass
@@ -127,17 +146,29 @@
         NetconfDeviceInfo deviceInfo = new NetconfDeviceInfo(
                 TEST_USERNAME, TEST_PASSWORD, Ip4Address.valueOf(TEST_HOSTNAME), PORT_NUMBER);
 
-        session1 = new NetconfSessionMinaImpl(deviceInfo);
+        session1 = new NetconfSessionMinaImpl(deviceInfo, ImmutableList.of("urn:ietf:params:netconf:base:1.0"));
         log.info("Started NETCONF Session {} with test SSHD server in Unit Test", session1.getSessionId());
         assertTrue("Incorrect sessionId", !session1.getSessionId().equalsIgnoreCase("-1"));
         assertTrue("Incorrect sessionId", !session1.getSessionId().equalsIgnoreCase("0"));
         assertThat(session1.getDeviceCapabilitiesSet(), containsInAnyOrder(DEFAULT_CAPABILITIES.toArray()));
 
-        session2 = new NetconfSessionMinaImpl(deviceInfo);
+        session2 = new NetconfSessionMinaImpl(deviceInfo, ImmutableList.of("urn:ietf:params:netconf:base:1.0"));
         log.info("Started NETCONF Session {} with test SSHD server in Unit Test", session2.getSessionId());
         assertTrue("Incorrect sessionId", !session2.getSessionId().equalsIgnoreCase("-1"));
         assertTrue("Incorrect sessionId", !session2.getSessionId().equalsIgnoreCase("0"));
         assertThat(session2.getDeviceCapabilitiesSet(), containsInAnyOrder(DEFAULT_CAPABILITIES.toArray()));
+
+        session3 = new NetconfSessionMinaImpl(deviceInfo);
+        log.info("Started NETCONF Session {} with test SSHD server in Unit Test", session3.getSessionId());
+        assertTrue("Incorrect sessionId", !session3.getSessionId().equalsIgnoreCase("-1"));
+        assertTrue("Incorrect sessionId", !session3.getSessionId().equalsIgnoreCase("0"));
+        assertThat(session3.getDeviceCapabilitiesSet(), containsInAnyOrder(DEFAULT_CAPABILITIES_1_1.toArray()));
+
+        session4 = new NetconfSessionMinaImpl(deviceInfo);
+        log.info("Started NETCONF Session {} with test SSHD server in Unit Test", session4.getSessionId());
+        assertTrue("Incorrect sessionId", !session4.getSessionId().equalsIgnoreCase("-1"));
+        assertTrue("Incorrect sessionId", !session4.getSessionId().equalsIgnoreCase("0"));
+        assertThat(session4.getDeviceCapabilitiesSet(), containsInAnyOrder(DEFAULT_CAPABILITIES_1_1.toArray()));
     }
 
     @AfterClass
@@ -148,6 +179,12 @@
         if (session2 != null) {
             session2.close();
         }
+        if (session3 != null) {
+            session3.close();
+        }
+        if (session4 != null) {
+            session4.close();
+        }
 
         sshServerNetconf.stop();
     }
@@ -158,8 +195,24 @@
         assertNotNull("Incorrect sessionId", session1.getSessionId());
         try {
             assertTrue("NETCONF edit-config command failed",
-                       session1.editConfig(TargetConfig.RUNNING.toString(),
-                                           null, SAMPLE_REQUEST));
+                    session1.editConfig(RUNNING.toString(),
+                            null, SAMPLE_REQUEST));
+        } catch (NetconfException e) {
+            e.printStackTrace();
+            fail("NETCONF edit-config test failed: " + e.getMessage());
+        }
+        log.info("Finishing edit-config async");
+    }
+
+    @Test
+    public void testEditConfigRequestWithChunkedFraming() {
+        log.info("Starting edit-config async");
+
+        assertNotNull("Incorrect sessionId", session3.getSessionId());
+        try {
+            assertTrue("NETCONF edit-config command failed",
+                    session3.editConfig(RUNNING.toString(),
+                            null, SAMPLE_REQUEST));
         } catch (NetconfException e) {
             e.printStackTrace();
             fail("NETCONF edit-config test failed: " + e.getMessage());
@@ -173,7 +226,7 @@
         assertNotNull("Incorrect sessionId", session1.getSessionId());
         try {
             assertTrue("NETCONF edit-config command failed",
-                       session1.editConfig(EDIT_CONFIG_REQUEST));
+                    session1.editConfig(EDIT_CONFIG_REQUEST));
         } catch (NetconfException e) {
             e.printStackTrace();
             fail("NETCONF edit-config test failed: " + e.getMessage());
@@ -182,12 +235,40 @@
     }
 
     @Test
-    public void testDeleteConfigRequestWithRunningTargetConfiguration() {
+    public void testEditConfigRequestWithOnlyNewConfigurationWithChunkedFraming() {
+        log.info("Starting edit-config async");
+        assertNotNull("Incorrect sessionId", session3.getSessionId());
+        try {
+            assertTrue("NETCONF edit-config command failed",
+                    session3.editConfig(EDIT_CONFIG_REQUEST));
+        } catch (NetconfException e) {
+            e.printStackTrace();
+            fail("NETCONF edit-config test failed: " + e.getMessage());
+        }
+        log.info("Finishing edit-config async");
+    }
+
+    @Test
+    public void testDeleteConfigRequestWithRunningDatastoreIdDuration() {
         log.info("Starting delete-config async");
         assertNotNull("Incorrect sessionId", session1.getSessionId());
         try {
             assertFalse("NETCONF delete-config command failed",
-                        session1.deleteConfig(TargetConfig.RUNNING));
+                    session1.deleteConfig(RUNNING));
+        } catch (NetconfException e) {
+            e.printStackTrace();
+            fail("NETCONF delete-config test failed: " + e.getMessage());
+        }
+        log.info("Finishing delete-config async");
+    }
+
+    @Test
+    public void testDeleteConfigRequestWithRunningDatastoreIdDurationWithChunkedFraming() {
+        log.info("Starting delete-config async");
+        assertNotNull("Incorrect sessionId", session3.getSessionId());
+        try {
+            assertFalse("NETCONF delete-config command failed",
+                    session3.deleteConfig(RUNNING));
         } catch (NetconfException e) {
             e.printStackTrace();
             fail("NETCONF delete-config test failed: " + e.getMessage());
@@ -201,8 +282,23 @@
         assertNotNull("Incorrect sessionId", session1.getSessionId());
         try {
             assertTrue("NETCONF copy-config command failed",
-                       session1.copyConfig(TargetConfig.RUNNING.toString(),
-                                           "candidate"));
+                    session1.copyConfig(RUNNING.toString(),
+                            "candidate"));
+        } catch (NetconfException e) {
+            e.printStackTrace();
+            fail("NETCONF edit-config test failed: " + e.getMessage());
+        }
+        log.info("Finishing copy-config async");
+    }
+
+    @Test
+    public void testCopyConfigRequestWithChunkedFraming() {
+        log.info("Starting copy-config async");
+        assertNotNull("Incorrect sessionId", session3.getSessionId());
+        try {
+            assertTrue("NETCONF copy-config command failed",
+                    session3.copyConfig(RUNNING.toString(),
+                            "candidate"));
         } catch (NetconfException e) {
             e.printStackTrace();
             fail("NETCONF edit-config test failed: " + e.getMessage());
@@ -216,10 +312,28 @@
         assertNotNull("Incorrect sessionId", session1.getSessionId());
         try {
             assertTrue("NETCONF get-config running command failed. ",
-                       GET_REPLY_PATTERN.matcher(session1.getConfig(RUNNING, SAMPLE_REQUEST)).matches());
+                    GET_REPLY_PATTERN.matcher(session1.getConfig(RUNNING, SAMPLE_REQUEST)).matches());
 
             assertTrue("NETCONF get-config candidate command failed. ",
-                       GET_REPLY_PATTERN.matcher(session1.getConfig(CANDIDATE, SAMPLE_REQUEST)).matches());
+                    GET_REPLY_PATTERN.matcher(session1.getConfig(CANDIDATE, SAMPLE_REQUEST)).matches());
+
+        } catch (NetconfException e) {
+            e.printStackTrace();
+            fail("NETCONF get-config test failed: " + e.getMessage());
+        }
+        log.info("Finishing get-config async");
+    }
+
+    @Test
+    public void testGetConfigRequestWithChunkedFraming() {
+        log.info("Starting get-config async");
+        assertNotNull("Incorrect sessionId", session3.getSessionId());
+        try {
+            assertTrue("NETCONF get-config running command failed. ",
+                    GET_REPLY_PATTERN.matcher(session3.getConfig(RUNNING, SAMPLE_REQUEST)).matches());
+
+            assertTrue("NETCONF get-config candidate command failed. ",
+                    GET_REPLY_PATTERN.matcher(session3.getConfig(CANDIDATE, SAMPLE_REQUEST)).matches());
 
         } catch (NetconfException e) {
             e.printStackTrace();
@@ -234,7 +348,22 @@
         assertNotNull("Incorrect sessionId", session1.getSessionId());
         try {
             assertTrue("NETCONF get running command failed. ",
-                       GET_REPLY_PATTERN.matcher(session1.get(SAMPLE_REQUEST, null)).matches());
+                    GET_REPLY_PATTERN.matcher(session1.get(SAMPLE_REQUEST, null)).matches());
+
+        } catch (NetconfException e) {
+            e.printStackTrace();
+            fail("NETCONF get test failed: " + e.getMessage());
+        }
+        log.info("Finishing get async");
+    }
+
+    @Test
+    public void testGetRequestWithChunkedFraming() {
+        log.info("Starting get async");
+        assertNotNull("Incorrect sessionId", session3.getSessionId());
+        try {
+            assertTrue("NETCONF get running command failed. ",
+                    GET_REPLY_PATTERN.matcher(session3.get(SAMPLE_REQUEST, null)).matches());
 
         } catch (NetconfException e) {
             e.printStackTrace();
@@ -257,6 +386,19 @@
     }
 
     @Test
+    public void testLockRequestWithChunkedFraming() {
+        log.info("Starting lock async");
+        assertNotNull("Incorrect sessionId", session3.getSessionId());
+        try {
+            assertTrue("NETCONF lock request failed", session3.lock());
+        } catch (NetconfException e) {
+            e.printStackTrace();
+            fail("NETCONF lock test failed: " + e.getMessage());
+        }
+        log.info("Finishing lock async");
+    }
+
+    @Test
     public void testUnLockRequest() {
         log.info("Starting unlock async");
         assertNotNull("Incorrect sessionId", session1.getSessionId());
@@ -269,6 +411,19 @@
         log.info("Finishing unlock async");
     }
 
+    @Test
+    public void testUnLockRequestWithChunkedFraming() {
+        log.info("Starting unlock async");
+        assertNotNull("Incorrect sessionId", session3.getSessionId());
+        try {
+            assertTrue("NETCONF unlock request failed", session3.unlock());
+        } catch (NetconfException e) {
+            e.printStackTrace();
+            fail("NETCONF unlock test failed: " + e.getMessage());
+        }
+        log.info("Finishing unlock async");
+    }
+
 
     @Test
     public void testConcurrentSameSessionAccess() throws InterruptedException {
@@ -297,6 +452,32 @@
     }
 
     @Test
+    public void testConcurrentSameSessionAccessWithChunkedFraming() throws InterruptedException {
+        NCCopyConfigCallable testCopyConfig1 = new NCCopyConfigCallable(session3, RUNNING, "candidate");
+        NCCopyConfigCallable testCopyConfig2 = new NCCopyConfigCallable(session3, RUNNING, "startup");
+
+        FutureTask<Boolean> futureCopyConfig1 = new FutureTask<>(testCopyConfig1);
+        FutureTask<Boolean> futureCopyConfig2 = new FutureTask<>(testCopyConfig2);
+
+        ExecutorService executor = Executors.newFixedThreadPool(2);
+        log.info("Starting concurrent execution of copy-config through same session");
+        executor.execute(futureCopyConfig1);
+        executor.execute(futureCopyConfig2);
+
+        int count = 0;
+        while (count < 10) {
+            if (futureCopyConfig1.isDone() && futureCopyConfig2.isDone()) {
+                executor.shutdown();
+                log.info("Finished concurrent same session execution");
+                return;
+            }
+            Thread.sleep(100L);
+            count++;
+        }
+        fail("NETCONF test failed to complete.");
+    }
+
+    @Test
     public void test2SessionAccess() throws InterruptedException {
         NCCopyConfigCallable testCopySession1 = new NCCopyConfigCallable(session1, RUNNING, "candidate");
         NCCopyConfigCallable testCopySession2 = new NCCopyConfigCallable(session2, RUNNING, "candidate");
@@ -322,6 +503,32 @@
         fail("NETCONF test failed to complete.");
     }
 
+    @Test
+    public void test2SessionAccessWithChunkedFraming() throws InterruptedException {
+        NCCopyConfigCallable testCopySession1 = new NCCopyConfigCallable(session3, RUNNING, "candidate");
+        NCCopyConfigCallable testCopySession2 = new NCCopyConfigCallable(session4, RUNNING, "candidate");
+
+        FutureTask<Boolean> futureCopySession1 = new FutureTask<>(testCopySession1);
+        FutureTask<Boolean> futureCopySession2 = new FutureTask<>(testCopySession2);
+
+        ExecutorService executor = Executors.newFixedThreadPool(2);
+        log.info("Starting concurrent execution of copy-config through 2 different sessions");
+        executor.execute(futureCopySession1);
+        executor.execute(futureCopySession2);
+
+        int count = 0;
+        while (count < 10) {
+            if (futureCopySession1.isDone() && futureCopySession2.isDone()) {
+                executor.shutdown();
+                log.info("Finished concurrent 2 session execution");
+                return;
+            }
+            Thread.sleep(100L);
+            count++;
+        }
+        fail("NETCONF test failed to complete.");
+    }
+
 
     public static String getTestHelloReply(Optional<Long> sessionId) {
         return getTestHelloReply(DEFAULT_CAPABILITIES, sessionId);
@@ -376,20 +583,21 @@
 
     public static final Pattern HELLO_REQ_PATTERN =
             Pattern.compile("(<\\?xml).*"
-                    + "(<hello xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">)\\R?"
-                    + "( *)(<capabilities>)\\R?"
-                    + "( *)(<capability>urn:ietf:params:netconf:base:1.0</capability>)\\R?"
-                    + "( *)(</capabilities>)\\R?"
-                    + "(</hello>)\\R? *",
+                            + "(<hello xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">)\\R?"
+                            + "( *)(<capabilities>)\\R?"
+                            + "( *)(<capability>urn:ietf:params:netconf:base:1.0</capability>)\\R?"
+                            + "( *)(<capability>urn:ietf:params:netconf:base:1.1</capability>)\\R?"
+                            + "( *)(</capabilities>)\\R?"
+                            + "(</hello>)\\R? *",
                     Pattern.DOTALL);
 
     public static final Pattern EDIT_CONFIG_REQ_PATTERN =
             Pattern.compile("(<\\?xml).*"
                     + "(<rpc message-id=\")[0-9]*(\") *(xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">)\\R?"
                     + "(<edit-config>)\\R?"
-                    + "(<target>\\R?((<" + TargetConfig.CANDIDATE.toString() + "/>)|"
-                                    + "(<" + TargetConfig.RUNNING.toString() + "/>)|"
-                                    + "(<" + TargetConfig.STARTUP.toString() + "/>))\\R?</target>)\\R?"
+                    + "(<target>\\R?((<" + CANDIDATE.toString() + "/>)|"
+                    + "(<" + RUNNING.toString() + "/>)|"
+                    + "(<" + STARTUP.toString() + "/>))\\R?</target>)\\R?"
                     + "(<config xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">)\\R?"
                     + ".*"
                     + "(</config>)\\R?(</edit-config>)\\R?(</rpc>)\\R?", Pattern.DOTALL);
@@ -397,46 +605,46 @@
 
     public static final Pattern LOCK_REQ_PATTERN =
             Pattern.compile("(<\\?xml).*"
-                                    + "(<rpc xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\" "
-                                    + "message-id=\")[0-9]*(\">)\\R?"
-                                    + "(<lock>)\\R?"
-                                    + "(<target>\\R?((<" + TargetConfig.CANDIDATE.toString() + "/>)|"
-                                    + "(<" + TargetConfig.RUNNING.toString() + "/>)|"
-                                    + "(<" + TargetConfig.STARTUP.toString() + "/>))\\R?</target>)\\R?"
-                                    + "(</lock>)\\R?(</rpc>)\\R?", Pattern.DOTALL);
+                    + "(<rpc xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\" "
+                    + "message-id=\")[0-9]*(\">)\\R?"
+                    + "(<lock>)\\R?"
+                    + "(<target>\\R?((<" + CANDIDATE.toString() + "/>)|"
+                    + "(<" + RUNNING.toString() + "/>)|"
+                    + "(<" + STARTUP.toString() + "/>))\\R?</target>)\\R?"
+                    + "(</lock>)\\R?(</rpc>)\\R?", Pattern.DOTALL);
 
     public static final Pattern UNLOCK_REQ_PATTERN =
             Pattern.compile("(<\\?xml).*"
-                                    + "(<rpc xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\" "
-                                    + "message-id=\")[0-9]*(\">)\\R?"
-                                    + "(<unlock>)\\R?"
-                                    + "(<target>\\R?((<" + TargetConfig.CANDIDATE.toString() + "/>)|"
-                                    + "(<" + TargetConfig.RUNNING.toString() + "/>)|"
-                                    + "(<" + TargetConfig.STARTUP.toString() + "/>))\\R?</target>)\\R?"
-                                    + "(</unlock>)\\R?(</rpc>)\\R?", Pattern.DOTALL);
+                    + "(<rpc xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\" "
+                    + "message-id=\")[0-9]*(\">)\\R?"
+                    + "(<unlock>)\\R?"
+                    + "(<target>\\R?((<" + CANDIDATE.toString() + "/>)|"
+                    + "(<" + RUNNING.toString() + "/>)|"
+                    + "(<" + STARTUP.toString() + "/>))\\R?</target>)\\R?"
+                    + "(</unlock>)\\R?(</rpc>)\\R?", Pattern.DOTALL);
 
     public static final Pattern COPY_CONFIG_REQ_PATTERN =
             Pattern.compile("(<\\?xml).*"
                     + "(<rpc xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\" message-id=\")[0-9]*(\">)\\R?"
                     + "(<copy-config>)\\R?"
-                    + "(<target>\\R?((<" + TargetConfig.CANDIDATE.toString() + "/>)|"
-                                    + "(<" + TargetConfig.RUNNING.toString() + "/>)|"
-                                    + "(<" + TargetConfig.STARTUP.toString() + "/>))\\R?</target>)\\R?"
-                                    + "(<source>)\\R?(<config>)(("
-                                    + TargetConfig.CANDIDATE.toString() + ")|("
-                                    + TargetConfig.RUNNING.toString() + ")|("
-                                    + TargetConfig.STARTUP.toString()
-                                    + "))(</config>)\\R?(</source>)\\R?"
-                                    + "(</copy-config>)\\R?(</rpc>)\\R?", Pattern.DOTALL);
+                    + "(<target>\\R?((<" + CANDIDATE.toString() + "/>)|"
+                    + "(<" + RUNNING.toString() + "/>)|"
+                    + "(<" + STARTUP.toString() + "/>))\\R?</target>)\\R?"
+                    + "(<source>)\\R?(<config>)(("
+                    + CANDIDATE.toString() + ")|("
+                    + RUNNING.toString() + ")|("
+                    + STARTUP.toString()
+                    + "))(</config>)\\R?(</source>)\\R?"
+                    + "(</copy-config>)\\R?(</rpc>)\\R?", Pattern.DOTALL);
 
     public static final Pattern GET_CONFIG_REQ_PATTERN =
             Pattern.compile("(<\\?xml).*"
                     + "(<rpc message-id=\")[0-9]*(\"  xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">)\\R?"
                     + "(<get-config>)\\R?" + "(<source>)\\R?((<"
-                                    + TargetConfig.CANDIDATE.toString()
-                                    + "/>)|(<" + TargetConfig.RUNNING.toString()
-                                    + "/>)|(<" + TargetConfig.STARTUP.toString()
-                                    + "/>))\\R?(</source>)\\R?"
+                    + CANDIDATE.toString()
+                    + "/>)|(<" + RUNNING.toString()
+                    + "/>)|(<" + STARTUP.toString()
+                    + "/>))\\R?(</source>)\\R?"
                     + "(<filter type=\"subtree\">).*(</filter>)\\R?"
                     + "(</get-config>)\\R?(</rpc>)\\R?", Pattern.DOTALL);
 
@@ -455,10 +663,10 @@
 
     public class NCCopyConfigCallable implements Callable<Boolean> {
         private NetconfSession session;
-        private TargetConfig target;
+        private DatastoreId target;
         private String source;
 
-        public NCCopyConfigCallable(NetconfSession session, TargetConfig target, String source) {
+        public NCCopyConfigCallable(NetconfSession session, DatastoreId target, String source) {
             this.session = session;
             this.target = target;
             this.source = source;
@@ -469,4 +677,4 @@
             return session.copyConfig(target, source);
         }
     }
-}
+}
\ No newline at end of file
diff --git a/protocols/netconf/ctl/src/test/java/org/onosproject/netconf/ctl/impl/NetconfSshdTestSubsystem.java b/protocols/netconf/ctl/src/test/java/org/onosproject/netconf/ctl/impl/NetconfSshdTestSubsystem.java
index f13f17c..27e4247 100644
--- a/protocols/netconf/ctl/src/test/java/org/onosproject/netconf/ctl/impl/NetconfSshdTestSubsystem.java
+++ b/protocols/netconf/ctl/src/test/java/org/onosproject/netconf/ctl/impl/NetconfSshdTestSubsystem.java
@@ -15,13 +15,15 @@
  */
 package org.onosproject.netconf.ctl.impl;
 
+
 import java.io.BufferedReader;
-import java.io.EOFException;
-import java.io.IOException;
 import java.io.InputStream;
-import java.io.InputStreamReader;
 import java.io.OutputStream;
 import java.io.PrintWriter;
+import java.io.UnsupportedEncodingException;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.EOFException;
 import java.nio.Buffer;
 import java.nio.ByteBuffer;
 import java.util.Collection;
@@ -29,6 +31,7 @@
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Future;
 
+import org.apache.commons.lang3.tuple.Pair;
 import org.apache.sshd.common.NamedFactory;
 import org.apache.sshd.common.util.threads.ThreadUtils;
 import org.apache.sshd.server.Command;
@@ -111,6 +114,11 @@
      */
     private static final String CLOSE_SESSION = "<close-session";
     private static final String END_PATTERN = "]]>]]>";
+    private static final String HASH = "#";
+    private static final String LF = "\n";
+    private static final String MSGLEN_REGEX_PATTERN = "\n#\\d+\n";
+    private static final String MSGLEN_PART_REGEX_PATTERN = "\\d+\n";
+    private static final String CHUNKED_END_REGEX_PATTERN = "\n##\n";
 
     private ExecutorService executors;
     private boolean shutdownExecutor;
@@ -191,34 +199,68 @@
                         log.info("Client Request on session {}. MsgId {}: {}",
                                 session.getSessionId(), messageId, deviceRequest);
                         synchronized (outputStream) {
+
                             if (NetconfSessionImplTest.HELLO_REQ_PATTERN.matcher(deviceRequest).matches()) {
+
                                 String helloReply =
                                         NetconfSessionImplTest.getTestHelloReply(Optional.of(ByteBuffer.wrap(
-                                                session.getSessionId()).asLongBuffer().get()));
+                                                session.getSessionId()).asLongBuffer().get()), false);
                                 outputStream.write(helloReply + END_PATTERN);
                                 outputStream.flush();
-                            } else if (NetconfSessionImplTest.EDIT_CONFIG_REQ_PATTERN.matcher(deviceRequest).matches()
-                                 || NetconfSessionImplTest.COPY_CONFIG_REQ_PATTERN.matcher(deviceRequest).matches()
-                                    || NetconfSessionImplTest.LOCK_REQ_PATTERN.matcher(deviceRequest).matches()
-                                    || NetconfSessionImplTest.UNLOCK_REQ_PATTERN.matcher(deviceRequest).matches()) {
-                                outputStream.write(NetconfSessionImplTest.getOkReply(messageId) + END_PATTERN);
-                                outputStream.flush();
-                            } else if (NetconfSessionImplTest.GET_CONFIG_REQ_PATTERN.matcher(deviceRequest).matches()
-                                    || NetconfSessionImplTest.GET_REQ_PATTERN.matcher(deviceRequest).matches()) {
-                                outputStream.write(NetconfSessionImplTest.getGetReply(messageId) + END_PATTERN);
-                                outputStream.flush();
-                            } else if (deviceRequest.contains(CLOSE_SESSION)) {
-                                socketClosed = true;
-                                outputStream.write(NetconfSessionImplTest.getOkReply(messageId) + END_PATTERN);
+                            } else if (NetconfSessionImplTest.HELLO_REQ_PATTERN_1_1.matcher(deviceRequest).matches()) {
+
+                                String helloReply =
+                                        NetconfSessionImplTest.getTestHelloReply(Optional.of(ByteBuffer.wrap(
+                                                session.getSessionId()).asLongBuffer().get()), true);
+                                outputStream.write(helloReply + END_PATTERN);
                                 outputStream.flush();
                             } else {
-                                log.error("Unexpected NETCONF message structure on session {} : {}",
-                                          ByteBuffer.wrap(
-                                                  session.getSessionId()).asLongBuffer().get(), deviceRequest);
+                                Pair replyClosedPair = dealWithRequest(deviceRequest, messageId);
+                                String reply = (String) replyClosedPair.getLeft();
+                                if (reply != null) {
+                                    Boolean newSockedClosed = (Boolean) replyClosedPair.getRight();
+                                    socketClosed = newSockedClosed.booleanValue();
+                                    outputStream.write(reply + END_PATTERN);
+                                    outputStream.flush();
+                                }
                             }
                         }
                         deviceRequestBuilder.setLength(0);
                     }
+                } else if (state == NetconfMessageState.END_CHUNKED_PATTERN) {
+                    String deviceRequest = deviceRequestBuilder.toString();
+                    if (!validateChunkedFraming(deviceRequest)) {
+                        log.error("Netconf client send badly framed message {}",
+                                deviceRequest);
+                    } else {
+                        deviceRequest = deviceRequest.replaceAll(MSGLEN_REGEX_PATTERN, "");
+                        deviceRequest = deviceRequest.replaceAll(CHUNKED_END_REGEX_PATTERN, "");
+                        Optional<Integer> messageId = NetconfStreamThread.getMsgId(deviceRequest);
+                        log.info("Client Request on session {}. MsgId {}: {}",
+                                session.getSessionId(), messageId, deviceRequest);
+
+                        synchronized (outputStream) {
+
+                            if (NetconfSessionImplTest.HELLO_REQ_PATTERN.matcher(deviceRequest).matches()) {
+                                String helloReply =
+                                        NetconfSessionImplTest.getTestHelloReply(Optional.of(ByteBuffer.wrap(
+                                                session.getSessionId()).asLongBuffer().get()), true);
+                                outputStream.write(helloReply + END_PATTERN);
+                                outputStream.flush();
+                            } else {
+                                Pair replyClosedPair = dealWithRequest(deviceRequest, messageId);
+                                String reply = (String) replyClosedPair.getLeft();
+                                if (reply != null) {
+                                    Boolean newSockedClosed = (Boolean) replyClosedPair.getRight();
+                                    socketClosed = newSockedClosed.booleanValue();
+                                    outputStream.write(formatChunkedMessage(reply));
+                                    outputStream.flush();
+                                }
+                            }
+                        }
+
+                    }
+                    deviceRequestBuilder.setLength(0);
                 }
             }
         } catch (Throwable t) {
@@ -236,6 +278,69 @@
         }
     }
 
+    private boolean validateChunkedFraming(String reply) {
+        String[] strs = reply.split(LF + HASH);
+        int strIndex = 0;
+        while (strIndex < strs.length) {
+            String str = strs[strIndex];
+            if ((str.equals(HASH + LF))) {
+                return true;
+            }
+            if (!str.equals("")) {
+                try {
+                    if (str.equals(LF)) {
+                        return false;
+                    }
+                    int len = Integer.parseInt(str.split(LF)[0]);
+                    if (str.split(MSGLEN_PART_REGEX_PATTERN)[1].getBytes("UTF-8").length != len) {
+                        return false;
+                    }
+                } catch (NumberFormatException e) {
+                    return false;
+                } catch (UnsupportedEncodingException e) {
+                    e.printStackTrace();
+                }
+            }
+            strIndex++;
+        }
+        return true;
+    }
+
+    private Pair<String, Boolean> dealWithRequest(String deviceRequest, Optional<Integer> messageId) {
+        if (NetconfSessionImplTest.EDIT_CONFIG_REQ_PATTERN.matcher(deviceRequest).matches()
+                || NetconfSessionImplTest.COPY_CONFIG_REQ_PATTERN.matcher(deviceRequest).matches()
+                || NetconfSessionImplTest.LOCK_REQ_PATTERN.matcher(deviceRequest).matches()
+                || NetconfSessionImplTest.UNLOCK_REQ_PATTERN.matcher(deviceRequest).matches()) {
+            return Pair.of(NetconfSessionImplTest.getOkReply(messageId), false);
+
+        } else if (NetconfSessionImplTest.GET_CONFIG_REQ_PATTERN.matcher(deviceRequest).matches()
+                || NetconfSessionImplTest.GET_REQ_PATTERN.matcher(deviceRequest).matches()) {
+            return Pair.of(NetconfSessionImplTest.getGetReply(messageId), false);
+        } else if (deviceRequest.contains(CLOSE_SESSION)) {
+            return Pair.of(NetconfSessionImplTest.getOkReply(messageId), true);
+        } else {
+            log.error("Unexpected NETCONF message structure on session {} : {}",
+                    ByteBuffer.wrap(
+                            session.getSessionId()).asLongBuffer().get(), deviceRequest);
+            return null;
+        }
+    }
+
+    private String formatChunkedMessage(String message) {
+        if (message.endsWith(END_PATTERN)) {
+            message = message.split(END_PATTERN)[0];
+        }
+        if (!message.startsWith(LF + HASH)) {
+            try {
+                message = LF + HASH + message.getBytes("UTF-8").length + LF + message + LF + HASH + HASH + LF;
+            } catch (UnsupportedEncodingException e) {
+                e.printStackTrace();
+            }
+        }
+        return message;
+    }
+
+
     @Override
     public void setInputStream(InputStream in) {
         this.in = in;
@@ -310,4 +415,4 @@
     protected void process(Buffer buffer) throws IOException {
         log.warn("Receieved buffer:" + buffer);
     }
-}
+}
\ No newline at end of file