diff --git a/Package.swift b/Package.swift
index 1fac7df..2b1d98e 100644
--- a/Package.swift
+++ b/Package.swift
@@ -9,15 +9,14 @@ let package = Package(
         .macOS(.v11)
     ],
     dependencies: [
-        .package(url: "https://github.com/Local-Connectivity-Lab/lcl-ping.git", from: "1.0.0"),
+        .package(url: "https://github.com/Local-Connectivity-Lab/lcl-ping.git", from: "1.0.3"),
         .package(url: "https://github.com/apple/swift-argument-parser.git", from: "1.2.3"),
-        .package(url: "https://github.com/jpsim/Yams.git", from: "5.0.6"),
         .package(url: "https://github.com/scottrhoyt/SwiftyTextTable.git", from: "0.9.0"),
-        .package(url: "https://github.com/johnnzhou/lcl-auth.git", branch: "main"),
-        .package(url: "https://github.com/apple/swift-nio.git", from: "2.63.0"),
+        .package(url: "https://github.com/Local-Connectivity-Lab/lcl-auth.git", branch: "main"),
+        .package(url: "https://github.com/apple/swift-nio.git", from: "2.73.0"),
         .package(url: "https://github.com/apple/swift-nio-ssl.git", from: "2.25.0"),
-        .package(url: "https://github.com/johnnzhou/lcl-speedtest.git", branch: "main"),
-        .package(url: "https://github.com/pakLebah/ANSITerminal", from: "0.0.3")
+        .package(url: "https://github.com/Local-Connectivity-Lab/lcl-speedtest.git", from: "1.0.4"),
+        .package(url: "https://github.com/johnnzhou/ANSITerminal.git", from: "0.0.4"),
     ],
     targets: [
         .executableTarget(
@@ -25,7 +24,6 @@ let package = Package(
             dependencies: [
                 .product(name: "ArgumentParser", package: "swift-argument-parser"),
                 .product(name: "LCLPing", package: "lcl-ping"),
-                .product(name: "Yams", package: "Yams"),
                 .product(name: "SwiftyTextTable", package: "SwiftyTextTable"),
                 .product(name: "LCLAuth", package: "lcl-auth"),
                 .product(name: "NIO", package: "swift-nio"),
@@ -33,7 +31,7 @@ let package = Package(
                 .product(name: "NIOCore", package: "swift-nio"),
                 .product(name: "NIOHTTP1", package: "swift-nio"),
                 .product(name: "NIOSSL", package: "swift-nio-ssl"),
-                .product(name: "LCLSpeedTest", package: "lcl-speedtest"),
+                .product(name: "LCLSpeedtest", package: "lcl-speedtest"),
                 .product(name: "ANSITerminal", package: "ANSITerminal")
             ],
             path: "Sources")
diff --git a/README.md b/README.md
index 2c14150..b30cc63 100644
--- a/README.md
+++ b/README.md
@@ -3,4 +3,42 @@
 </div>
 
 ---
-# lcl CLI
\ No newline at end of file
+# LCL CLI
+LCL CLI is a cross-platform cli tool written in Swift. It is designed to measure the network performance and latency through LCL's cellular network measurement testbed. While this tool is design for Local Connectivity Lab researchers and Seattle Community Network volunteers and users, everyone is welcome to use this tool to measure their network performance.
+
+## Usage
+
+```
+OVERVIEW: A command-line tool from Local Connectivity Lab @UWCSE
+
+USAGE: lcl <subcommand>
+
+OPTIONS:
+  -h, --help              Show help information.
+
+SUBCOMMANDS:
+  register                Register with SCN server to report test data.
+  ping                    Run Ping Latency and Reachability Test.
+  speedtest               Run speedtest using the NDT test infrastructure.
+  measure                 Run SCN test suite and optionally report the measurement result to SCN.
+  interfaces              List available network interfaces on the machine.
+  cellular-sites          Get info on SCN cellular sites
+
+  See 'lcl help <subcommand>' for detailed help.
+``` 
+
+## Features
+- ICMP and HTTP test with `Server-Timing` support.
+- Speedtest on top of NDT7 protocol with TCP-level and Application-level measurement
+- Automatically upload test result to SCN's backend server (this option is available to SCN users and volunteers).
+- Check available interfaces on the machine.
+
+## Platform Support
+LCL CLI is designed to support various platforms that Swift supports, including Linux (Debian and Ubuntu), macOS. Those who are interested in other platforms can download and compile the binary from the source. 
+
+
+## Contributing
+Any contribution and pull requests are welcome! However, before you plan to implement some features or try to fix an uncertain issue, it is recommended to open a discussion first. You can also join our [Discord channel](https://discord.com/invite/gn4DKF83bP), or visit our [website](https://seattlecommunitynetwork.org/).
+
+## License
+LCL CLI is released under Apache License. See [LICENSE](/LICENSE) for more details.
diff --git a/Sources/Command/Interfaces.swift b/Sources/Command/Interfaces.swift
index 2c34500..7876517 100644
--- a/Sources/Command/Interfaces.swift
+++ b/Sources/Command/Interfaces.swift
@@ -11,7 +11,7 @@
 //
 
 import ArgumentParser
-import LCLPing
+import NIOCore
 
 struct NetworkInterfaceCommand: AsyncParsableCommand {
     static var configuration: CommandConfiguration = CommandConfiguration(
@@ -24,7 +24,7 @@ struct NetworkInterfaceCommand: AsyncParsableCommand {
         for interface in availableInterfaces {
             let sortedHostNames = interface.value.sorted()
             let interfaceName = interface.key
-            print("\(interfaceName)      \(sortedHostNames)")
+            print("\(interfaceName)\t\(sortedHostNames)")
         }
     }
 }
diff --git a/Sources/Command/Measure.swift b/Sources/Command/Measure.swift
index 69ec10f..65bc1cb 100644
--- a/Sources/Command/Measure.swift
+++ b/Sources/Command/Measure.swift
@@ -15,10 +15,14 @@ import ArgumentParser
 import LCLPing
 import LCLAuth
 import Crypto
+import LCLSpeedtest
 
 extension LCLCLI {
     struct MeasureCommand: AsyncParsableCommand {
 
+        @Option(name: .long, help: "Specify the device name to which the data will be sent.")
+        var deviceName: String?
+
         @Option(name: .shortAndLong, help: "Show datapoint on SCN's public visualization. Your contribution will help others better understand our coverage.")
         var showData: Bool = false
 
@@ -36,6 +40,7 @@ extension LCLCLI {
             let result: Result<[CellularSite]?, CLIError> = await NetworkingAPI.get(from: NetworkingAPI.Endpoint.site.url)
             switch result {
             case .failure(let error):
+
                 throw error
             case .success(let cs):
                 if let s = cs {
@@ -47,24 +52,16 @@ extension LCLCLI {
             }
             var picker = Picker<CellularSite>(title: "Choose the cellular site you are currently at.", options: sites)
 
-            let homeURL = FileIO.default.home.appendingPathComponent(".lcl")
+            let homeURL = FileIO.default.home.appendingPathComponent(Constants.cliDirectory)
             let skURL = homeURL.appendingPathComponent("sk")
             let sigURL = homeURL.appendingPathComponent("sig")
             let rURL = homeURL.appendingPathComponent("r")
             let hpkrURL = homeURL.appendingPathComponent("hpkr")
-            let keyURL = homeURL.appendingPathComponent("key")
-            let keyData = try loadData(keyURL)
-
-            let symmetricKeyRecovered = SymmetricKey(data: keyData)
-
-            let skDataEncrypted = try loadData(skURL)
-            let skData = try decrypt(cipher: skDataEncrypted, key: symmetricKeyRecovered)
-            let sigDataEncrypted = try loadData(sigURL)
-            let sigData = try decrypt(cipher: sigDataEncrypted, key: symmetricKeyRecovered)
-            let rDataEncrypted = try loadData(rURL)
-            let rData = try decrypt(cipher: rDataEncrypted, key: symmetricKeyRecovered)
-            let hpkrDataEncrypted = try loadData(hpkrURL)
-            let hpkrData = try decrypt(cipher: hpkrDataEncrypted, key: symmetricKeyRecovered)
+
+            let skData = try loadData(skURL)
+            let sigData = try loadData(sigURL)
+            let rData = try loadData(rURL)
+            let hpkrData = try loadData(hpkrURL)
             let validationResultJSON = try encoder.encode(ValidationResult(R: rData, skT: skData, hPKR: hpkrData))
 
             let ecPrivateKey = try ECDSA.deserializePrivateKey(raw: skData)
@@ -73,7 +70,7 @@ extension LCLCLI {
                 throw CLIError.contentCorrupted
             }
 
-            let pingConfig = try ICMPPingClient.Configuration(endpoint: .ipv4("google.com", 0))
+            let pingConfig = try ICMPPingClient.Configuration(endpoint: .ipv4("google.com", 0), deviceName: deviceName)
             let outputFormats: Set<OutputFormat> = [.default]
 
             let client = ICMPPingClient(configuration: pingConfig)
@@ -98,9 +95,12 @@ extension LCLCLI {
 
             let summary = try await client.start().get()
 
-            let speedTestResults = try await speedTest.run()
-            let downloadSummary = prepareSpeedTestSummary(data: speedTestResults.download, unit: .Mbps)
-            let uploadSummary = prepareSpeedTestSummary(data: speedTestResults.upload, unit: .Mbps)
+            let speedTestResults = try await speedTest.run(deviceName: deviceName)
+            let downloadMeasurement = computeLatencyAndRetransmission(speedTestResults.downloadTCPMeasurement, for: .download)
+            let uploadMeasurement = computeLatencyAndRetransmission(speedTestResults.uploadTCPMeasurement, for: .upload)
+
+            let downloadSummary = prepareSpeedTestSummary(data: speedTestResults.downloadSpeed, tcpInfos: speedTestResults.downloadTCPMeasurement, for: .download, unit: .Mbps)
+            let uploadSummary = prepareSpeedTestSummary(data: speedTestResults.uploadSpeed, tcpInfos: speedTestResults.uploadTCPMeasurement, for: .upload, unit: .Mbps)
 
             generatePingSummary(summary, for: .icmp, formats: outputFormats)
             generateSpeedTestSummary(downloadSummary, kind: .download, formats: outputFormats, unit: .Mbps)
@@ -116,10 +116,10 @@ extension LCLCLI {
                     uploadSpeed: uploadSummary.avg,
                     latitude: selectedSite.latitude,
                     longitude: selectedSite.longitude,
-                    packetLoss: Double(summary.timeout.count) / Double(summary.totalCount),
-                    ping: summary.avg,
+                    packetLoss: (downloadMeasurement.retransmit + uploadMeasurement.retransmit) / 2,
+                    ping: (downloadMeasurement.latency + uploadMeasurement.latency) / 2,
                     timestamp: Date.getCurrentTime(),
-                    jitter: summary.jitter
+                    jitter: (downloadMeasurement.variance + uploadMeasurement.variance) / 2
                 )
                 let serialized = try encoder.encode(report)
                 let sig_m = try ECDSA.sign(message: serialized, privateKey: ECDSA.deserializePrivateKey(raw: skData))
diff --git a/Sources/Command/PingCommand.swift b/Sources/Command/PingCommand.swift
index 0d531bb..6c54462 100644
--- a/Sources/Command/PingCommand.swift
+++ b/Sources/Command/PingCommand.swift
@@ -49,9 +49,6 @@ extension LCLCLI {
         @Flag(help: "Export the Ping result in JSON format.")
         var json: Bool = false
 
-        @Flag(help: "Export the Ping result in YAML format.")
-        var yaml: Bool = false
-
         static var configuration: CommandConfiguration = CommandConfiguration(
             commandName: "icmp",
             abstract: "Run ICMP Ping Latency and Reachability Test."
@@ -78,10 +75,6 @@ extension LCLCLI {
                     outputFormats.insert(.json)
                 }
 
-                if yaml {
-                    outputFormats.insert(.yaml)
-                }
-
                 if outputFormats.isEmpty {
                     outputFormats.insert(.default)
                 }
@@ -131,19 +124,19 @@ extension LCLCLI {
         @Flag(help: "Use URLSession on Apple platform for underlying networking and measurement. This flag has no effect on Linux platform.")
         var useURLSession: Bool = false
 
+        @Option(name: .long, help: "Specify the device name to which the data will be sent.")
+        var deviceName: String?
+
         @Flag(help: "Export the Ping result in JSON format.")
         var json: Bool = false
 
-        @Flag(help: "Export the Ping result in YAML format.")
-        var yaml: Bool = false
-
         static var configuration: CommandConfiguration = CommandConfiguration(
             commandName: "http",
             abstract: "Run ICMP Ping Latency and Reachability Test."
         )
 
         func run() throws {
-            var config = try HTTPPingClient.Configuration(url: url)
+            var config = try HTTPPingClient.Configuration(url: url, deviceName: deviceName)
             if let count = count {
                 config.count = Int(count)
             }
@@ -177,10 +170,6 @@ extension LCLCLI {
                 outputFormats.insert(.json)
             }
 
-            if yaml {
-                outputFormats.insert(.yaml)
-            }
-
             if outputFormats.isEmpty {
                 outputFormats.insert(.default)
             }
diff --git a/Sources/Command/RegisterCommand.swift b/Sources/Command/RegisterCommand.swift
index afb3fa1..352fa51 100644
--- a/Sources/Command/RegisterCommand.swift
+++ b/Sources/Command/RegisterCommand.swift
@@ -21,16 +21,15 @@ extension LCLCLI {
         @Option(name: .shortAndLong, help: "Path to the SCN credential file given by the SCN administrator.")
         var filePath: String
 
-        static let configuration = CommandConfiguration(
-                                                            commandName: "register",
-                                                            abstract: "Register with SCN server to report test data."
-                                                        )
+        static let configuration = CommandConfiguration(commandName: "register",
+                                                        abstract: "Register with SCN server to report test data.")
 
         func run() async throws {
             guard let filePathURL = URL(string: filePath), let credentialCode = try FileIO.default.loadFrom(filePathURL) else {
                 throw CLIError.failedToReadFile("Fail to read content from path '\(filePath)'. Exit.")
             }
-            let homeURL = FileIO.default.home.appendingPathComponent(".lcl")
+            
+            let homeURL = FileIO.default.home.appendingPathComponent(Constants.cliDirectory)
             let skURL = homeURL.appendingPathComponent("sk")
             let sigURL = homeURL.appendingPathComponent("sig")
             let rURL = homeURL.appendingPathComponent("r")
@@ -79,14 +78,14 @@ extension LCLCLI {
             let sk_t = try ECDSA.deserializePrivateKey(raw: validationResult.skT)
             let pk_t = ECDSA.derivePublicKey(from: sk_t)
             outputData.append(pk_t.derRepresentation)
-            let h_sec = digest(data: outputData, algorithm: .SHA256)
+            var h_sec = digest(data: outputData, algorithm: .SHA256)
             outputData.removeAll()
             outputData.append(validationResult.hPKR)
             outputData.append(h_sec)
-            let h_concat = Data(outputData)
-            let sigma_r = try ECDSA.sign(message: h_concat, privateKey: sk_t)
+            var h_concat = Data(outputData)
+            var sigma_r = try ECDSA.sign(message: h_concat, privateKey: sk_t)
             let registration = RegistrationModel(sigmaR: sigma_r.hex, h: h_concat.hex, R: validationResult.R.hex)
-            let registrationJson = try encoder.encode(registration)
+            var registrationJson = try encoder.encode(registration)
             switch await NetworkingAPI.send(to: NetworkingAPI.Endpoint.register.url, using: registrationJson) {
             case .success:
                 print("Registration complete!")
@@ -97,24 +96,18 @@ extension LCLCLI {
             let validationJson = try encoder.encode(validationResult)
             let privateKey = try ECDSA.deserializePrivateKey(raw: validationResult.skT)
             let signature = try ECDSA.sign(message: validationJson, privateKey: privateKey)
-
-            let symmetricKey = SymmetricKey(size: .bits256)
-            try encryptAndWriteData(validationResult.R, to: rURL, using: symmetricKey)
-            try encryptAndWriteData(validationResult.hPKR, to: hpkrURL, using: symmetricKey)
-            try encryptAndWriteData(validationResult.skT, to: skURL, using: symmetricKey)
-            try encryptAndWriteData(signature, to: sigURL, using: symmetricKey)
-
-            let symmetricKeyData = symmetricKey.withUnsafeBytes { pointer in
-                return Data(pointer)
-            }
-
-            try FileIO.default.write(data: symmetricKeyData, to: keyURL)
-        }
-
-        private func encryptAndWriteData(_ data: Data, to fileURL: URL, using key: SymmetricKey) throws {
-            var encrypted = try LCLAuth.encrypt(plainText: data, key: key)
-            try FileIO.default.write(data: encrypted, to: fileURL)
-            encrypted.removeAll()
+            
+            try FileIO.default.write(data: validationResult.R, to: rURL)
+            try FileIO.default.write(data: validationResult.hPKR, to: hpkrURL)
+            try FileIO.default.write(data: validationResult.skT, to: skURL)
+            try FileIO.default.write(data: signature, to: sigURL)
+            
+            // cleanup
+            outputData.removeAll()
+            h_concat.removeAll()
+            sigma_r.removeAll()
+            h_sec.removeAll()
+            registrationJson.removeAll()
         }
     }
 }
diff --git a/Sources/Command/SpeedTestCommand.swift b/Sources/Command/SpeedTestCommand.swift
index 0f4f128..57b86ca 100644
--- a/Sources/Command/SpeedTestCommand.swift
+++ b/Sources/Command/SpeedTestCommand.swift
@@ -12,7 +12,7 @@
 
 import Foundation
 import ArgumentParser
-import LCLSpeedTest
+import LCLSpeedtest
 
 extension LCLCLI {
     struct SpeedTestCommand: AsyncParsableCommand {
@@ -23,12 +23,12 @@ extension LCLCLI {
         @Option(name: .shortAndLong, help: "Specify the direction of the test. A test can be of three types: download, upload or downloadAndUpload")
         var type: TestType
 
+        @Option(name: .long, help: "Specify the device name to which the data will be sent.")
+        var deviceName: String?
+
         @Flag(help: "Export the Speed Test result in JSON format.")
         var json: Bool = false
 
-        @Flag(help: "Export the Speed Test result in YAML format.")
-        var yaml: Bool = false
-
         static let configuration = CommandConfiguration(commandName: "speedtest", abstract: "Run speedtest using the NDT test infrastructure.")
 
         func run() async throws {
@@ -47,27 +47,23 @@ extension LCLCLI {
             signal(SIGINT, SIG_IGN)
             let stopSignal = DispatchSource.makeSignalSource(signal: SIGINT, queue: .main)
             stopSignal.setEventHandler {
-                print("Exit from Speed Test")
+                print("Exit from Speedtest")
                 speedTest.stop()
                 return
             }
 
             stopSignal.resume()
 
-            let speedTestResults = try await speedTest.run()
+            let speedTestResults = try await speedTest.run(deviceName: deviceName)
 
-            let downloadSummary = prepareSpeedTestSummary(data: speedTestResults.download, unit: speedTestUnit)
-            let uploadSummary = prepareSpeedTestSummary(data: speedTestResults.upload, unit: speedTestUnit)
+            let downloadSummary = prepareSpeedTestSummary(data: speedTestResults.downloadSpeed, tcpInfos: speedTestResults.downloadTCPMeasurement, for: .download, unit: speedTestUnit)
+            let uploadSummary = prepareSpeedTestSummary(data: speedTestResults.uploadSpeed, tcpInfos: speedTestResults.uploadTCPMeasurement, for: .upload, unit: speedTestUnit)
 
             var outputFormats: Set<OutputFormat> = []
             if json {
                 outputFormats.insert(.json)
             }
 
-            if yaml {
-                outputFormats.insert(.yaml)
-            }
-
             if outputFormats.isEmpty {
                 outputFormats.insert(.default)
             }
diff --git a/Sources/IO/IO+File.swift b/Sources/IO/IO+File.swift
index 95be55d..5940b3d 100644
--- a/Sources/IO/IO+File.swift
+++ b/Sources/IO/IO+File.swift
@@ -15,7 +15,6 @@ import Foundation
 // File IO needs to handle
 // read file
 // write to file
-
 class FileIO {
 
     static let `default`: FileIO = .init()
@@ -34,45 +33,6 @@ class FileIO {
         return self.fileManager.contents(atPath: url.relativePath)
     }
 
-    func readLines(from url: URL) throws -> [Data] {
-        let fd = try FileHandle(forReadingFrom: url)
-        var results = [Data]()
-        let newline = UInt8(ascii: "\n")
-        var buffer = Data()
-        var startIndex = 0
-
-        while true {
-            let temp = fd.readData(ofLength: 1024)
-            if temp.isEmpty { break } // EOF
-
-            buffer.append(temp)
-
-            var currentIndex = startIndex
-            // INV: buffer[startIndex : currentIndex - 1] contains all the data before new line character
-            while currentIndex != buffer.count {
-                if buffer[currentIndex] == newline {
-                    // Process the line from startIndex to currentIndex
-                    let lineData = buffer[startIndex..<currentIndex]
-                    if !lineData.isEmpty {
-                        results.append(lineData)
-                    }
-                    startIndex = currentIndex + 1
-                }
-                currentIndex += 1
-            }
-
-            // Remove processed data from buffer up to the last startIndex
-            if startIndex > 0 {
-                buffer.removeSubrange(0..<startIndex)
-                currentIndex -= startIndex
-                startIndex = 0
-            }
-        }
-
-        try fd.close()
-        return results
-    }
-
     func fileExists(_ url: URL) -> Bool {
         return self.fileManager.fileExists(atPath: url.relativePath)
     }
@@ -95,7 +55,7 @@ class FileIO {
     }
 
     func write(data: Data, to fileURL: URL) throws {
-        try data.write(to: fileURL, options: [.atomic])
+        try FileHandle(forWritingTo: fileURL).write(contentsOf: data)
     }
 
     func remove(at fileURL: URL) throws {
diff --git a/Sources/IO/IO+Network.swift b/Sources/IO/IO+Network.swift
index 24cf88e..cd1055b 100644
--- a/Sources/IO/IO+Network.swift
+++ b/Sources/IO/IO+Network.swift
@@ -11,78 +11,21 @@
 //
 
 import Foundation
-#if canImport(Darwin)
-import Darwin   // Apple platforms
-#elseif canImport(Glibc)
-import Glibc    // GlibC Linux platforms
-#endif
+import NIOCore
 
 internal func getAvailableInterfaces() throws -> [String: Set<String>] {
-    var ifaddr: UnsafeMutablePointer<ifaddrs>?
-    guard getifaddrs(&ifaddr) == 0 else {
-        throw CLIError.failedToReadAvailableNetworkInterfaces(errno)
-    }
-
     var res = [String: Set<String>]()
-
-    guard let first = ifaddr else {
-        print("no interfaces available")
-        return res
-    }
-
-    for ifaddr in sequence(first: first, next: {$0.pointee.ifa_next}) {
-        guard let addr = ifaddr.pointee.ifa_addr else {
-            continue
+    
+    for device in try System.enumerateDevices() {
+        let name = device.name
+        if !res.keys.contains(name) {
+            res[name] = Set()
         }
-
-        #if canImport(Darwin) // macOS
-        if (Int32(ifaddr.pointee.ifa_flags) & IFF_LOOPBACK) != 0 ||
-            (Int32(ifaddr.pointee.ifa_flags) & IFF_UP) == 0 {
-            // skip loopback and inactive interfaces
+        guard let addr = device.address?.ipAddress else {
             continue
         }
-        #else
-        if (Int(ifaddr.pointee.ifa_flags) & IFF_LOOPBACK) != 0 ||
-            (Int(ifaddr.pointee.ifa_flags) & IFF_UP) == 0 {
-            // skip loopback and inactive interfaces
-            continue
-        }
-        #endif
-
-        #if canImport(Darwin) // macOS
-        let isKnownFamilyType = addr.pointee.sa_family == UInt8(AF_INET) ||
-                                        addr.pointee.sa_family == UInt8(AF_INET6) ||
-                                        addr.pointee.sa_family == UInt8(AF_LINK)
-        #else // Linux
-        let isKnownFamilyType = addr.pointee.sa_family == UInt8(AF_INET) ||
-                                addr.pointee.sa_family == UInt8(AF_INET6) ||
-                                addr.pointee.sa_family == UInt8(AF_PACKET)
-        #endif
-
-        if isKnownFamilyType {
-            var cHostName = [CChar](repeating: 0, count: Int(NI_MAXHOST))
-            let ret = getnameinfo(
-                                addr,
-                                (addr.pointee.sa_family == AF_INET) ? socklen_t(MemoryLayout<sockaddr_in>.size) : socklen_t(MemoryLayout<sockaddr_in6>.size),
-                                &cHostName,
-                                socklen_t(cHostName.count),
-                                nil,
-                                0,
-                                NI_NUMERICHOST
-                            )
-            if ret == 0 {
-                let addrName = String(cString: ifaddr.pointee.ifa_name)
-                let hostName = String(cString: cHostName)
-                if !res.keys.contains(addrName) {
-                    res[addrName] = Set()
-                }
-                if !hostName.isEmpty {
-                    res[addrName]?.insert(hostName)
-                }
-            }
-        }
+        res[name]?.insert(addr)
     }
-
-    freeifaddrs(ifaddr)
+    
     return res
 }
diff --git a/Sources/IO/IO+Utils.swift b/Sources/IO/IO+Utils.swift
index fc4e6fa..572db56 100644
--- a/Sources/IO/IO+Utils.swift
+++ b/Sources/IO/IO+Utils.swift
@@ -11,9 +11,8 @@
 //
 
 import Foundation
-import Yams
 import LCLPing
-import LCLSpeedTest
+import LCLSpeedtest
 
 internal func generatePingSummary(
     _ pingSummary: PingSummary,
@@ -24,8 +23,6 @@ internal func generatePingSummary(
         switch format {
         case .json:
             generateSummaryInJSON(summary: pingSummary)
-        case .yaml:
-            generateSummaryInYAML(summary: pingSummary)
         case .default:
             generatePingSummaryDefault(pingSummary: pingSummary, type: type)
         }
@@ -42,8 +39,6 @@ internal func generateSpeedTestSummary(
         switch format {
         case .json:
             generateSummaryInJSON(summary: speedTestSummary)
-        case .yaml:
-            generateSummaryInYAML(summary: speedTestSummary)
         case .default:
             generateSpeedTestSummaryDefault(speedTestSummary: speedTestSummary, kind: kind, unit: unit)
         }
@@ -61,16 +56,6 @@ private func generateSummaryInJSON(summary: Encodable) {
     print(String(data: result, encoding: .utf8)!)
 }
 
-private func generateSummaryInYAML(summary: Encodable) {
-    let yamlEncoder = YAMLEncoder()
-    yamlEncoder.options = .init(sortKeys: true)
-    guard let result = try? yamlEncoder.encode(summary) else {
-        print("PingSummary is corrupted and unable to output in YAML format.")
-        return
-    }
-    print(result)
-}
-
 private func generatePingSummaryDefault(pingSummary: PingSummary, type: LCLPing.PingType) {
     print("====== Ping Result ======")
     let protocolType = ProtocolType(rawValue: pingSummary.protocol)
@@ -113,4 +98,7 @@ private func generateSpeedTestSummaryDefault(
     print("Average: \(speedTestSummary.avg.round(to: 2)) \(unit.string)")
     print("Medium: \(speedTestSummary.median.round(to: 2)) \(unit.string)")
     print("Standard Deviation: \(speedTestSummary.stdDev.round(to: 2)) \(unit.string)")
+    print("Latency: \(speedTestSummary.latency.round(to: 2)) ms")
+    print("Latency Variance: \(speedTestSummary.latencyVariance.round(to: 2)) ms")
+    print("Retransmit Rate: \((speedTestSummary.retransmit * 100.0).round(to: 2)) %")
 }
diff --git a/Sources/IO/SpeedTest.swift b/Sources/IO/SpeedTest.swift
index 38c7ed3..4f2d170 100644
--- a/Sources/IO/SpeedTest.swift
+++ b/Sources/IO/SpeedTest.swift
@@ -11,35 +11,59 @@
 //
 
 import Foundation
-import LCLSpeedTest
+import LCLSpeedtest
 
 class SpeedTest {
     private let testType: TestType
-    private var uploadResults: [MeasurementProgress]
-    private var downloadResults: [MeasurementProgress]
+    private var uploadSpeed: [MeasurementProgress]
+    private var downloadSpeed: [MeasurementProgress]
+    private var uploadTCPMeasurement: [TCPInfo]
+    private var downloadTCPMeasurement: [TCPInfo]
+
     private var testClient: SpeedTestClient
 
     struct TestResult {
-        let upload: [MeasurementProgress]
-        let download: [MeasurementProgress]
+        let uploadSpeed: [MeasurementProgress]
+        let downloadSpeed: [MeasurementProgress]
+        let uploadTCPMeasurement: [TCPInfo]
+        let downloadTCPMeasurement: [TCPInfo]
     }
 
     init(testType: TestType) {
         self.testType = testType
-        self.uploadResults = []
-        self.downloadResults = []
+        self.uploadSpeed = []
+        self.downloadSpeed = []
+        self.uploadTCPMeasurement = []
+        self.downloadTCPMeasurement = []
         self.testClient = SpeedTestClient()
     }
 
-    func run() async throws -> TestResult {
-        self.testClient.onDownloadProgress = { measurement in
-            self.downloadResults.append(measurement)
+    func run(deviceName: String? = nil) async throws -> TestResult {
+        self.testClient.onDownloadProgress = { progress in
+            self.downloadSpeed.append(progress)
+        }
+        self.testClient.onDownloadMeasurement = { measurement in
+            guard let tcpInfo = measurement.tcpInfo else {
+                return
+            }
+            self.downloadTCPMeasurement.append(tcpInfo)
+        }
+        self.testClient.onUploadProgress = { progress in
+            self.uploadSpeed.append(progress)
         }
-        self.testClient.onUploadProgress = { measurement in
-            self.uploadResults.append(measurement)
+        self.testClient.onUploadMeasurement = { measurement in
+            guard let tcpInfo = measurement.tcpInfo else {
+                return
+            }
+            self.downloadTCPMeasurement.append(tcpInfo)
         }
-        try await testClient.start(with: self.testType)
-        return TestResult(upload: self.uploadResults, download: self.downloadResults)
+        try await testClient.start(with: self.testType, deviceName: deviceName)
+        return TestResult(
+            uploadSpeed: self.uploadSpeed,
+            downloadSpeed: self.downloadSpeed,
+            uploadTCPMeasurement: self.uploadTCPMeasurement,
+            downloadTCPMeasurement: self.downloadTCPMeasurement
+        )
     }
 
     func stop() {
diff --git a/Sources/Models/OutputFormat.swift b/Sources/Models/OutputFormat.swift
index 74692e7..524102b 100644
--- a/Sources/Models/OutputFormat.swift
+++ b/Sources/Models/OutputFormat.swift
@@ -12,6 +12,5 @@
 
 enum OutputFormat: String {
     case json
-    case yaml
     case `default`
 }
diff --git a/Sources/Models/SpeedTestSummary.swift b/Sources/Models/SpeedTestSummary.swift
index 33e4614..a179e53 100644
--- a/Sources/Models/SpeedTestSummary.swift
+++ b/Sources/Models/SpeedTestSummary.swift
@@ -21,6 +21,11 @@ struct SpeedTestSummary: Encodable {
     public let stdDev: Double
     public let jitter: Double
     public let details: [SpeedTestElement] // in mbps
+
+    public let latency: Double
+    public let latencyVariance: Double
+    public let retransmit: Double
+
     public let totalCount: Int
 }
 
diff --git a/Sources/Utils/Constants.swift b/Sources/Utils/Constants.swift
new file mode 100644
index 0000000..ace3a2b
--- /dev/null
+++ b/Sources/Utils/Constants.swift
@@ -0,0 +1,17 @@
+//
+// This source file is part of the LCL open source project
+//
+// Copyright (c) 2021-2024 Local Connectivity Lab and the project authors
+// Licensed under Apache License v2.0
+//
+// See LICENSE for license information
+// See CONTRIBUTORS for the list of project authors
+//
+// SPDX-License-Identifier: Apache-2.0
+//
+
+import Foundation
+
+struct Constants {
+    static let cliDirectory = ".lcl"
+}
diff --git a/Sources/Utils/Measurement+Extension.swift b/Sources/Utils/Measurement+Extension.swift
index bf6f74d..7829a81 100644
--- a/Sources/Utils/Measurement+Extension.swift
+++ b/Sources/Utils/Measurement+Extension.swift
@@ -11,7 +11,7 @@
 //
 
 import Foundation
-import LCLSpeedTest
+import LCLSpeedtest
 
 /// The network measurement unit used by the speed test framework
 enum MeasurementUnit: String, CaseIterable, Identifiable, Encodable {
@@ -24,7 +24,7 @@ enum MeasurementUnit: String, CaseIterable, Identifiable, Encodable {
     var string: String {
         switch self {
         case .Mbps:
-            return "mbps"
+            return "Mbit/s"
         case .MBps:
             return "MB/s"
         }
@@ -71,7 +71,7 @@ extension MeasurementProgress {
     }
 }
 
-internal func prepareSpeedTestSummary(data: [MeasurementProgress], unit: MeasurementUnit) -> SpeedTestSummary {
+internal func prepareSpeedTestSummary(data: [MeasurementProgress], tcpInfos: [TCPInfo], for: TestDirection, unit: MeasurementUnit) -> SpeedTestSummary {
     var localMin: Double = .greatestFiniteMagnitude
     var localMax: Double = .zero
     var consecutiveDiffSum: Double = .zero
@@ -92,6 +92,9 @@ internal func prepareSpeedTestSummary(data: [MeasurementProgress], unit: Measure
     let avg = measurementResults.avg
     let stdDev = measurementResults.stdDev
     let median = measurementResults.median
+
+    let tcpMeasurement = computeLatencyAndRetransmission(tcpInfos, for: `for`)
+
     let jitter = data.isEmpty ? 0.0 : consecutiveDiffSum / Double(data.count)
     return SpeedTestSummary(min: localMin,
                             max: localMax,
@@ -100,6 +103,32 @@ internal func prepareSpeedTestSummary(data: [MeasurementProgress], unit: Measure
                             stdDev: stdDev,
                             jitter: jitter,
                             details: measurementResults,
+                            latency: tcpMeasurement.latency,
+                            latencyVariance: tcpMeasurement.variance,
+                            retransmit: tcpMeasurement.retransmit,
                             totalCount: data.count
                             )
 }
+
+internal func computeLatencyAndRetransmission(_ tcpInfos: [TCPInfo], for direction: TestDirection) -> (latency: Double, variance: Double, retransmit: Double) {
+    if tcpInfos.isEmpty {
+        return (0, 0, 0)
+    }
+    var latency: Int64 = 0
+    var latencyVariance: Int64 = 0
+    var retransmit: Int64 = 0
+    var total: Int64 = 0
+    tcpInfos.forEach { tcpInfo in
+        latency += tcpInfo.rtt ?? 0
+        latencyVariance += tcpInfo.rttVar ?? 0
+        retransmit += tcpInfo.bytesRetrans ?? 0
+        switch direction {
+        case .download:
+            total += tcpInfo.bytesSent ?? 0
+        case .upload:
+            total += tcpInfo.bytesReceived ?? 0
+        }
+    }
+
+    return (Double(latency / 1000) / Double(tcpInfos.count), Double(latencyVariance / 1000) / Double(tcpInfos.count), Double(retransmit) / Double(total))
+}
