CVE-2022-25916: Other (NVD-CWE-Other)
value: Versions of the package mt7688-wiscan before 0.8.3 are vulnerable to Command Injection due to improper input sanitization in the 'wiscan.scan' function. 
CWE description: NVD is only using a subset of CWE for mapping instead of the entire CWE, and the weakness type is not covered by that subset.
CVSS v3 base score: 7.8
Published: 2023-02-01T05:15Z
Repository: https://github.com/simenkid/mt7688-wiscan
Language: JSON
Files changed: README.md, index.js, package.json
Commit date: 2023-01-31 07:06:58 +0800
Commit message: v0.8.3 intf only accetps alphabets and numbers

Diff: diff --git a/README.md b/README.md
index 82a9d3b..0629029 100644
--- a/README.md
+++ b/README.md
@@ -1,183 +1,186 @@
 # mt7688-wiscan
 
 ## Table of Contents
 
-1. [Overiew](#Overiew)    
-2. [Installation](#Installation) 
+1. [Overiew](#Overiew)
+2. [Installation](#Installation)
 3. [Usage](#Usage)
 
 <a name="Overiew"></a>
+
 ## 1. Overview
 
-**mt7688-wiscan** is a wifi access points scanning tool which is running with node.js on MediaTek Linkit Smart 7688. This tool provides three APIs [lqi()](#API_lqi), [scan()](#API_scan), and [scanByEssid()](#API_scanByEssid) that help you with getting link quality indicator (LQI) to an specific AP, scanning neighbor wifi APs, and scanning a specific AP with its **essid**.  
+**mt7688-wiscan** is a wifi access points scanning tool which is running with node.js on MediaTek Linkit Smart 7688. This tool provides three APIs [lqi()](#API_lqi), [scan()](#API_scan), and [scanByEssid()](#API_scanByEssid) that help you with getting link quality indicator (LQI) to an specific AP, scanning neighbor wifi APs, and scanning a specific AP with its **essid**.
 
-I am using this tool on machine nodes in my LWM2M IoT project. On each machine, there is a panel to show some information about the machine and to show LQI between machine and its router as well.  
+I am using this tool on machine nodes in my LWM2M IoT project. On each machine, there is a panel to show some information about the machine and to show LQI between machine and its router as well.
 
 <a name="Installation"></a>
+
 ## 2. Installation
 
 > $ npm install mt7688-wiscan --save
-  
+
 <a name="Usage"></a>
+
 ## 3. Usage
 
 ### Require the module
 
 ```js
 var wiscan = require('mt7688-wiscan');
 ```
 
-********************************************
+---
+
 <a name="API_lqi"></a>
+
 ### .lqi([intf,] essid, callback)
-Query the LQI (link quality indicator) between your Linkit Smart 7688(in station mode) and its router(AP).  
 
-**Arguments:**  
+Query the LQI (link quality indicator) between your Linkit Smart 7688(in station mode) and its router(AP).
+
+**Arguments:**
+
+1. `intf` (_String_, optional): A default value of `'ra0'` will be used if not given.
+2. `essid` (_String_): The ESSID of the AP to scan for.
+3. `callback` (_Function_): `function(err, result) { ... }`. The `result` is a number between 0 and 100 to indicate the relative link quality between the station and access point. The value is bigger to show better link quality. If given 'essid' is not found after scan, `result` will be `null`.
 
-1. `intf` (_String_, optional): A default value of `'ra0'` will be used if not given.  
-2. `essid` (_String_): The ESSID of the AP to scan for.  
-3. `callback` (_Function_): `function(err, result) { ... }`. The `result` is a number between 0 and 100 to indicate the relative link quality between the station and access point. The value is bigger to show better link quality. If given 'essid' is not found after scan, `result` will be `null`.  
-  
-  
 **[Note]**
-* It takes around 5 seconds to accomplish a single scan.  
-* If you've changed the name of radio interface with OpenWrt configuration tool, you should give this method with the correct interface name, for example, `'myradio'`.  
-* You can also try this tool on other platforms, but be aware of that the radio interface name is subject to platforms. Use `iwconfig` command at console to get some hints.  
-  
-**Returns:**  
-  
-* _none_
 
-**Examples:**  
-  
+- It takes around 5 seconds to accomplish a single scan.
+- If you've changed the name of radio interface with OpenWrt configuration tool, you should give this method with the correct interface name, for example, `'myradio'`.
+- You can also try this tool on other platforms, but be aware of that the radio interface name is subject to platforms. Use `iwconfig` command at console to get some hints.
+
+**Returns:**
+
+- _none_
+
+**Examples:**
+
 ```js
 // scan with deafult radio interface, just give it an essid to scan for
 wiscan.lqi('my_office_ap', function (err, result) {
-    if (err)
-        console.log(err);       // null
-    else
-        console.log(result);    // 78
+  if (err) console.log(err); // null
+  else console.log(result); // 78
 });
 
 // if an AP with given essid is not around (result is nothing after scan)
 wiscan.lqi('ap_not_found', function (err, result) {
-    if (err)
-        console.log(err);       // null
-    else
-        console.log(result);    // null
+  if (err) console.log(err); // null
+  else console.log(result); // null
 });
 
 // scan with the given radio interface and essid
 wiscan.lqi('ra0', 'my_office_ap', function (err, result) {
-    if (err)
-        console.log(err);       // null
-    else
-        console.log(result);    // 82
+  if (err) console.log(err); // null
+  else console.log(result); // 82
 });
 
 // scan with the given radio interface, e.g. 'bad_ra', that doesn't exist
 wiscan.lqi('bad_ra', 'my_office_ap', function (err, result) {
-    if (err)
-        console.log(err);       // [Error: No such wireless device: bad_ra]
+  if (err) console.log(err); // [Error: No such wireless device: bad_ra]
 });
-
 ```
 
-********************************************
+---
 
 <a name="API_scan"></a>
+
 ### .scan([intf,] callback)
-Scan neighbor wifi access points.  
 
-**Arguments:**  
+Scan neighbor wifi access points.
+
+**Arguments:**
 
-1. `intf` (_String_, optional): A default value of `'ra0'` will be used if not given.  
+1. `intf` (_String_, optional): A default value of `'ra0'` will be used if not given.
 2. `callback` (_Function_): `function(err, result) { ... }`. The `result` is an array of scanned report objects. Each report object has the following format:
 
 ```js
-{ 
+{
     address: 'D8:FE:E3:E5:9F:3B',    // String. MAC address of the found AP
     essid: 'sivann',                 // String
     mode: 'Master',                  // String
     channel: 1,                      // Number
     frequency: '2.412 GHz',          // Number
     signal: -256,                    // Number. It seems MTK's driver does not report this value. Don't use it.
     quality: 78,                     // Number. Valued from 0 ~ 100, bigger is better.
     encryption: 'WPA2 PSK (AES-OCB)' // String
 }
 ```
-  
-**Returns:**  
-  
-* _none_
 
-**Examples:**  
-  
+**Returns:**
+
+- _none_
+
+**Examples:**
+
 ```js
 // scan with deafult radio interface
 wiscan.scan(function (err, result) {
-    console.log(result);
-
-    // [
-    //     { address: 'D8:FE:E3:E5:9F:3B',  essid: 'sivann', ...   },
-    //     { address: '20:0C:C8:01:1D:98',  essid: 'delta_01', ... },
-    //     { address: '9C:D6:43:01:7E:C7',  essid: 'AVIS', ...     },
-    //     ...
-    // ]
+  console.log(result);
+
+  // [
+  //     { address: 'D8:FE:E3:E5:9F:3B',  essid: 'sivann', ...   },
+  //     { address: '20:0C:C8:01:1D:98',  essid: 'delta_01', ... },
+  //     { address: '9C:D6:43:01:7E:C7',  essid: 'AVIS', ...     },
+  //     ...
+  // ]
 });
 
 // scan with given radio interface
 wiscan.scan('ra0', function (err, result) {
-    console.log(result);
+  console.log(result);
 });
 
 // given radio interface is not valid
 wiscan.scan('foo', function (err, result) {
-    console.log(err);   // [Error: No such wireless device: foo]
+  console.log(err); // [Error: No such wireless device: foo]
 });
 ```
 
-********************************************
+---
 
 <a name="API_scanByEssid"></a>
+
 ### .scanByEssid([intf,] essid, callback)
-Scan for a specific AP with its essid.  
 
-**Arguments:**  
+Scan for a specific AP with its essid.
 
-1. `intf` (_String_, optional): A default value of `'ra0'` will be used if not given.  
-2. `essid` (_String_): The ESSID of the AP to scan for.  
-3. `callback` (_Function_): `function(err, result) { ... }`. The result is a report object, otherwise `null` if not found.  
+**Arguments:**
+
+1. `intf` (_String_, optional): A default value of `'ra0'` will be used if not given.
+2. `essid` (_String_): The ESSID of the AP to scan for.
+3. `callback` (_Function_): `function(err, result) { ... }`. The result is a report object, otherwise `null` if not found.
 
 </br>
   
 **Returns:**  
   
 * _none_
 
-**Examples:**  
-  
+**Examples:**
+
 ```js
 wiscan.scanByEssid('sivann', function (err, result) {
-    console.log(result);
-
-    // { 
-    //     address: 'D8:FE:E3:E5:9F:3B',
-    //     essid: 'sivann',
-    //     mode: 'Master',
-    //     channel: 1,
-    //     frequency: '2.412 GHz',
-    //     signal: -256,
-    //     quality: 68,
-    //     encryption: 'WPA2 PSK (AES-OCB)' // String
-    // }
+  console.log(result);
+
+  // {
+  //     address: 'D8:FE:E3:E5:9F:3B',
+  //     essid: 'sivann',
+  //     mode: 'Master',
+  //     channel: 1,
+  //     frequency: '2.412 GHz',
+  //     signal: -256,
+  //     quality: 68,
+  //     encryption: 'WPA2 PSK (AES-OCB)' // String
+  // }
 });
 
 // AP not found
 wiscan.scanByEssid('no_such_ap', function (err, result) {
-    console.log(result);    // null
+  console.log(result); // null
 });
 ```
 
 ## License
+
 MIT
diff --git a/index.js b/index.js
index 06803fc..071f2f7 100644
--- a/index.js
+++ b/index.js
@@ -1,162 +1,166 @@
 var exec = require('child_process').exec;
 
 var defaultInterface = 'ra0',
-    freqs = [ '2.412', '2.417', '2.422', '2.427', '2.432', '2.437', '2.442', '2.447', '2.452', '2.457', '2.462' ];
+  freqs = [
+    '2.412',
+    '2.417',
+    '2.422',
+    '2.427',
+    '2.432',
+    '2.437',
+    '2.442',
+    '2.447',
+    '2.452',
+    '2.457',
+    '2.462',
+  ];
 
 var wiscan = {};
 
 wiscan.scan = function (intf, callback) {
-    var child;
+  var child;
 
-    if (typeof intf === 'function') {
-        callback = intf;
-        intf = defaultInterface;
-    }
+  if (typeof intf === 'function') {
+    callback = intf;
+    intf = defaultInterface;
+  }
 
-    intf = intf || defaultInterface;
-    callback = callback || function () {};
+  intf = intf || defaultInterface;
+  callback = callback || function () {};
 
-    if (typeof intf !== 'string')
-        return callback(new Error('intf should be a string.'));
+  if (typeof intf !== 'string')
+    return callback(new Error('intf should be a string.'));
 
-    child = exec('iwinfo ' + intf + ' scan', function (error, stdout, stderr) {
-        if (error) {
-            stderr = stderr.trim();
-            return callback(new Error(stderr));
-        }
+  if (!/[0-9a-zA-Z]/.test(intf.charAt(0)))
+    return callback(new Error('Bad intf.'));
+
+  child = exec('iwinfo ' + intf + ' scan', function (error, stdout, stderr) {
+    if (error) {
+      stderr = stderr.trim();
+      return callback(new Error(stderr));
+    }
 
-        var info = stdout,
-            parsed = [];
-
-        info = info.replace(/\n/g, ' ');
-        info = info.replace(/"/g, '');
-        info = info.split(' ');
-        info.forEach(function (char, i) {
-            if (char === 'ESSID' && info[i+1] === '')
-                info[i+1] = 'unknown';
-            else if (char !== '')
-                parsed.push(char);
-        });
-
-        parsed = parse(parsed);
-        callback(null, parsed);
+    var info = stdout,
+      parsed = [];
+
+    info = info.replace(/\n/g, ' ');
+    info = info.replace(/"/g, '');
+    info = info.split(' ');
+    info.forEach(function (char, i) {
+      if (char === 'ESSID' && info[i + 1] === '') info[i + 1] = 'unknown';
+      else if (char !== '') parsed.push(char);
     });
+
+    parsed = parse(parsed);
+    callback(null, parsed);
+  });
 };
 
 wiscan.scanByEssid = function (intf, essid, callback) {
-    var target = null;
+  var target = null;
 
-    if (arguments.length === 2) {
-        callback = essid;
-        essid = intf;
-        intf = defaultInterface;
-    }
+  if (arguments.length === 2) {
+    callback = essid;
+    essid = intf;
+    intf = defaultInterface;
+  }
 
-    intf = intf || defaultInterface;
+  intf = intf || defaultInterface;
 
-    if (typeof intf !== 'string')
-        return callback(new Error('intf should be a string.'));
-    else if (typeof essid !== 'string')
-        return callback(new Error('essid should be a string.'));
+  if (typeof intf !== 'string')
+    return callback(new Error('intf should be a string.'));
+  else if (typeof essid !== 'string')
+    return callback(new Error('essid should be a string.'));
 
-    callback = callback || function () {};
+  callback = callback || function () {};
 
-    wiscan.scan(intf, function (err, infos) {
-        if (err)
-            return callback(err);
+  wiscan.scan(intf, function (err, infos) {
+    if (err) return callback(err);
 
-        infos.forEach(function (info) {
-            if (info.essid === essid)
-                target = info;
-        });
-
-        callback(null, target);
+    infos.forEach(function (info) {
+      if (info.essid === essid) target = info;
     });
+
+    callback(null, target);
+  });
 };
 
 wiscan.lqi = function (intf, essid, callback) {
-    if (arguments.length === 2) {
-        callback = essid;
-        essid = intf;
-        intf = defaultInterface;
-    }
+  if (arguments.length === 2) {
+    callback = essid;
+    essid = intf;
+    intf = defaultInterface;
+  }
 
-    intf = intf || defaultInterface;
+  intf = intf || defaultInterface;
 
-    wiscan.scanByEssid(intf, essid, function (err, info) {
-        if (err)
-            return callback(err);
+  wiscan.scanByEssid(intf, essid, function (err, info) {
+    if (err) return callback(err);
 
-        if (info)
-            callback(null, info.quality);
-        else
-            callback(null, null);
-    });
+    if (info) callback(null, info.quality);
+    else callback(null, null);
+  });
 };
 
 function parse(items) {
-    var parsed = [],
-        len = items.length,
-        idx = 0;
-
-    if (items.length === 0)
-        return parsed;
-
-    items.forEach(function (c, i) {
-        var val;
-        if (c === 'Cell') {
-            //- [deleted: need not cell field] val = items[i+1];
-            //- [deleted: need not cell field] val = isNaN(parseInt(val)) ? val : parseInt(val);
-            parsed.push({});
-        } else if (c === 'Address:') {
-            parsed[idx].address = items[i+1];
-        } else if (c === 'ESSID:') {
-            parsed[idx].essid = items[i+1];
-        } else if (c === 'Mode:') {
-            parsed[idx].mode = items[i+1];
-        } else if (c === 'Channel:') {
-            val = items[i+1];
-            val = isNaN(parseInt(val)) ? val : parseInt(val);
-            parsed[idx].channel = val;
-            parsed[idx].frequency = getFrequency(val);
-        } else if (c === 'Signal:') {
-            val = items[i+1];
-            val = isNaN(parseInt(val)) ? val : parseInt(val);
-            parsed[idx].signal = val;
-        } else if (c === 'Quality:') {
-
-            val = items[i+1].split('/')[0];
-            val = isNaN(parseInt(val)) ? val : parseInt(val);
-            parsed[idx].quality = val;
-        } else if (c === 'Encryption:') {
-            var x = i + 1,
-                enc = '';
-
-            while (items[x] !== 'Cell') {
-                if (x !== len) {
-                    enc = enc + items[x] + ' ';
-                    x += 1;
-                } else {
-                    break;
-                }
-            }
-            enc = enc.trim();
-            parsed[idx].encryption = enc;
-            idx += 1;
+  var parsed = [],
+    len = items.length,
+    idx = 0;
+
+  if (items.length === 0) return parsed;
+
+  items.forEach(function (c, i) {
+    var val;
+    if (c === 'Cell') {
+      //- [deleted: need not cell field] val = items[i+1];
+      //- [deleted: need not cell field] val = isNaN(parseInt(val)) ? val : parseInt(val);
+      parsed.push({});
+    } else if (c === 'Address:') {
+      parsed[idx].address = items[i + 1];
+    } else if (c === 'ESSID:') {
+      parsed[idx].essid = items[i + 1];
+    } else if (c === 'Mode:') {
+      parsed[idx].mode = items[i + 1];
+    } else if (c === 'Channel:') {
+      val = items[i + 1];
+      val = isNaN(parseInt(val)) ? val : parseInt(val);
+      parsed[idx].channel = val;
+      parsed[idx].frequency = getFrequency(val);
+    } else if (c === 'Signal:') {
+      val = items[i + 1];
+      val = isNaN(parseInt(val)) ? val : parseInt(val);
+      parsed[idx].signal = val;
+    } else if (c === 'Quality:') {
+      val = items[i + 1].split('/')[0];
+      val = isNaN(parseInt(val)) ? val : parseInt(val);
+      parsed[idx].quality = val;
+    } else if (c === 'Encryption:') {
+      var x = i + 1,
+        enc = '';
+
+      while (items[x] !== 'Cell') {
+        if (x !== len) {
+          enc = enc + items[x] + ' ';
+          x += 1;
+        } else {
+          break;
         }
-    });
-    return parsed;
+      }
+      enc = enc.trim();
+      parsed[idx].encryption = enc;
+      idx += 1;
+    }
+  });
+  return parsed;
 }
 
 function getFrequency(ch) {
-    var f = freqs[ch - 1];
+  var f = freqs[ch - 1];
 
-    if (f)
-        f = f + ' GHz';
-    else
-        f = '';
+  if (f) f = f + ' GHz';
+  else f = '';
 
-    return f;
+  return f;
 }
 
 module.exports = wiscan;
diff --git a/package.json b/package.json
index 8f6df0d..4118c7a 100644
--- a/package.json
+++ b/package.json
@@ -1,8 +1,8 @@
 {
   "name": "mt7688-wiscan",
-  "version": "0.8.2",
+  "version": "0.8.3",
   "description": "A wifi access points scanning tool for MediaTek Linkit Smart 7688",
   "main": "index.js",
   "scripts": {
     "test": "echo \"Error: no test specified\" && exit 1"
   },

Vulnerable code: 1. [Overiew](#Overiew)    
2. [Installation](#Installation) 
**mt7688-wiscan** is a wifi access points scanning tool which is running with node.js on MediaTek Linkit Smart 7688. This tool provides three APIs [lqi()](#API_lqi), [scan()](#API_scan), and [scanByEssid()](#API_scanByEssid) that help you with getting link quality indicator (LQI) to an specific AP, scanning neighbor wifi APs, and scanning a specific AP with its **essid**.  
I am using this tool on machine nodes in my LWM2M IoT project. On each machine, there is a panel to show some information about the machine and to show LQI between machine and its router as well.  
  
********************************************
Query the LQI (link quality indicator) between your Linkit Smart 7688(in station mode) and its router(AP).  
**Arguments:**  
1. `intf` (_String_, optional): A default value of `'ra0'` will be used if not given.  
2. `essid` (_String_): The ESSID of the AP to scan for.  
3. `callback` (_Function_): `function(err, result) { ... }`. The `result` is a number between 0 and 100 to indicate the relative link quality between the station and access point. The value is bigger to show better link quality. If given 'essid' is not found after scan, `result` will be `null`.  
  
  
* It takes around 5 seconds to accomplish a single scan.  
* If you've changed the name of radio interface with OpenWrt configuration tool, you should give this method with the correct interface name, for example, `'myradio'`.  
* You can also try this tool on other platforms, but be aware of that the radio interface name is subject to platforms. Use `iwconfig` command at console to get some hints.  
  
**Returns:**  
  
* _none_
**Examples:**  
  
    if (err)
        console.log(err);       // null
    else
        console.log(result);    // 78
    if (err)
        console.log(err);       // null
    else
        console.log(result);    // null
    if (err)
        console.log(err);       // null
    else
        console.log(result);    // 82
    if (err)
        console.log(err);       // [Error: No such wireless device: bad_ra]

********************************************
Scan neighbor wifi access points.  
**Arguments:**  
1. `intf` (_String_, optional): A default value of `'ra0'` will be used if not given.  
{ 
  
**Returns:**  
  
* _none_
**Examples:**  
  
    console.log(result);

    // [
    //     { address: 'D8:FE:E3:E5:9F:3B',  essid: 'sivann', ...   },
    //     { address: '20:0C:C8:01:1D:98',  essid: 'delta_01', ... },
    //     { address: '9C:D6:43:01:7E:C7',  essid: 'AVIS', ...     },
    //     ...
    // ]
    console.log(result);
    console.log(err);   // [Error: No such wireless device: foo]
********************************************
Scan for a specific AP with its essid.  
**Arguments:**  
1. `intf` (_String_, optional): A default value of `'ra0'` will be used if not given.  
2. `essid` (_String_): The ESSID of the AP to scan for.  
3. `callback` (_Function_): `function(err, result) { ... }`. The result is a report object, otherwise `null` if not found.  
**Examples:**  
  
    console.log(result);

    // { 
    //     address: 'D8:FE:E3:E5:9F:3B',
    //     essid: 'sivann',
    //     mode: 'Master',
    //     channel: 1,
    //     frequency: '2.412 GHz',
    //     signal: -256,
    //     quality: 68,
    //     encryption: 'WPA2 PSK (AES-OCB)' // String
    // }
    console.log(result);    // null
    freqs = [ '2.412', '2.417', '2.422', '2.427', '2.432', '2.437', '2.442', '2.447', '2.452', '2.457', '2.462' ];
    var child;
    if (typeof intf === 'function') {
        callback = intf;
        intf = defaultInterface;
    }
    intf = intf || defaultInterface;
    callback = callback || function () {};
    if (typeof intf !== 'string')
        return callback(new Error('intf should be a string.'));
    child = exec('iwinfo ' + intf + ' scan', function (error, stdout, stderr) {
        if (error) {
            stderr = stderr.trim();
            return callback(new Error(stderr));
        }
        var info = stdout,
            parsed = [];

        info = info.replace(/\n/g, ' ');
        info = info.replace(/"/g, '');
        info = info.split(' ');
        info.forEach(function (char, i) {
            if (char === 'ESSID' && info[i+1] === '')
                info[i+1] = 'unknown';
            else if (char !== '')
                parsed.push(char);
        });

        parsed = parse(parsed);
        callback(null, parsed);
    var target = null;
    if (arguments.length === 2) {
        callback = essid;
        essid = intf;
        intf = defaultInterface;
    }
    intf = intf || defaultInterface;
    if (typeof intf !== 'string')
        return callback(new Error('intf should be a string.'));
    else if (typeof essid !== 'string')
        return callback(new Error('essid should be a string.'));
    callback = callback || function () {};
    wiscan.scan(intf, function (err, infos) {
        if (err)
            return callback(err);
        infos.forEach(function (info) {
            if (info.essid === essid)
                target = info;
        });

        callback(null, target);
    if (arguments.length === 2) {
        callback = essid;
        essid = intf;
        intf = defaultInterface;
    }
    intf = intf || defaultInterface;
    wiscan.scanByEssid(intf, essid, function (err, info) {
        if (err)
            return callback(err);
        if (info)
            callback(null, info.quality);
        else
            callback(null, null);
    });
    var parsed = [],
        len = items.length,
        idx = 0;

    if (items.length === 0)
        return parsed;

    items.forEach(function (c, i) {
        var val;
        if (c === 'Cell') {
            //- [deleted: need not cell field] val = items[i+1];
            //- [deleted: need not cell field] val = isNaN(parseInt(val)) ? val : parseInt(val);
            parsed.push({});
        } else if (c === 'Address:') {
            parsed[idx].address = items[i+1];
        } else if (c === 'ESSID:') {
            parsed[idx].essid = items[i+1];
        } else if (c === 'Mode:') {
            parsed[idx].mode = items[i+1];
        } else if (c === 'Channel:') {
            val = items[i+1];
            val = isNaN(parseInt(val)) ? val : parseInt(val);
            parsed[idx].channel = val;
            parsed[idx].frequency = getFrequency(val);
        } else if (c === 'Signal:') {
            val = items[i+1];
            val = isNaN(parseInt(val)) ? val : parseInt(val);
            parsed[idx].signal = val;
        } else if (c === 'Quality:') {

            val = items[i+1].split('/')[0];
            val = isNaN(parseInt(val)) ? val : parseInt(val);
            parsed[idx].quality = val;
        } else if (c === 'Encryption:') {
            var x = i + 1,
                enc = '';

            while (items[x] !== 'Cell') {
                if (x !== len) {
                    enc = enc + items[x] + ' ';
                    x += 1;
                } else {
                    break;
                }
            }
            enc = enc.trim();
            parsed[idx].encryption = enc;
            idx += 1;
    });
    return parsed;
    var f = freqs[ch - 1];
    if (f)
        f = f + ' GHz';
    else
        f = '';
    return f;
  "version": "0.8.2",
Fixed code: 1. [Overiew](#Overiew)
2. [Installation](#Installation)

**mt7688-wiscan** is a wifi access points scanning tool which is running with node.js on MediaTek Linkit Smart 7688. This tool provides three APIs [lqi()](#API_lqi), [scan()](#API_scan), and [scanByEssid()](#API_scanByEssid) that help you with getting link quality indicator (LQI) to an specific AP, scanning neighbor wifi APs, and scanning a specific AP with its **essid**.
I am using this tool on machine nodes in my LWM2M IoT project. On each machine, there is a panel to show some information about the machine and to show LQI between machine and its router as well.



---


Query the LQI (link quality indicator) between your Linkit Smart 7688(in station mode) and its router(AP).

**Arguments:**

1. `intf` (_String_, optional): A default value of `'ra0'` will be used if not given.
2. `essid` (_String_): The ESSID of the AP to scan for.
3. `callback` (_Function_): `function(err, result) { ... }`. The `result` is a number between 0 and 100 to indicate the relative link quality between the station and access point. The value is bigger to show better link quality. If given 'essid' is not found after scan, `result` will be `null`.
- It takes around 5 seconds to accomplish a single scan.
- If you've changed the name of radio interface with OpenWrt configuration tool, you should give this method with the correct interface name, for example, `'myradio'`.
- You can also try this tool on other platforms, but be aware of that the radio interface name is subject to platforms. Use `iwconfig` command at console to get some hints.

**Returns:**

- _none_

**Examples:**

  if (err) console.log(err); // null
  else console.log(result); // 78
  if (err) console.log(err); // null
  else console.log(result); // null
  if (err) console.log(err); // null
  else console.log(result); // 82
  if (err) console.log(err); // [Error: No such wireless device: bad_ra]
---

Scan neighbor wifi access points.

**Arguments:**
1. `intf` (_String_, optional): A default value of `'ra0'` will be used if not given.
{
**Returns:**

- _none_

**Examples:**

  console.log(result);

  // [
  //     { address: 'D8:FE:E3:E5:9F:3B',  essid: 'sivann', ...   },
  //     { address: '20:0C:C8:01:1D:98',  essid: 'delta_01', ... },
  //     { address: '9C:D6:43:01:7E:C7',  essid: 'AVIS', ...     },
  //     ...
  // ]
  console.log(result);
  console.log(err); // [Error: No such wireless device: foo]
---

Scan for a specific AP with its essid.
**Arguments:**

1. `intf` (_String_, optional): A default value of `'ra0'` will be used if not given.
2. `essid` (_String_): The ESSID of the AP to scan for.
3. `callback` (_Function_): `function(err, result) { ... }`. The result is a report object, otherwise `null` if not found.
**Examples:**

  console.log(result);

  // {
  //     address: 'D8:FE:E3:E5:9F:3B',
  //     essid: 'sivann',
  //     mode: 'Master',
  //     channel: 1,
  //     frequency: '2.412 GHz',
  //     signal: -256,
  //     quality: 68,
  //     encryption: 'WPA2 PSK (AES-OCB)' // String
  // }
  console.log(result); // null

  freqs = [
    '2.412',
    '2.417',
    '2.422',
    '2.427',
    '2.432',
    '2.437',
    '2.442',
    '2.447',
    '2.452',
    '2.457',
    '2.462',
  ];
  var child;
  if (typeof intf === 'function') {
    callback = intf;
    intf = defaultInterface;
  }
  intf = intf || defaultInterface;
  callback = callback || function () {};
  if (typeof intf !== 'string')
    return callback(new Error('intf should be a string.'));
  if (!/[0-9a-zA-Z]/.test(intf.charAt(0)))
    return callback(new Error('Bad intf.'));

  child = exec('iwinfo ' + intf + ' scan', function (error, stdout, stderr) {
    if (error) {
      stderr = stderr.trim();
      return callback(new Error(stderr));
    }
    var info = stdout,
      parsed = [];

    info = info.replace(/\n/g, ' ');
    info = info.replace(/"/g, '');
    info = info.split(' ');
    info.forEach(function (char, i) {
      if (char === 'ESSID' && info[i + 1] === '') info[i + 1] = 'unknown';
      else if (char !== '') parsed.push(char);

    parsed = parse(parsed);
    callback(null, parsed);
  });
  var target = null;
  if (arguments.length === 2) {
    callback = essid;
    essid = intf;
    intf = defaultInterface;
  }
  intf = intf || defaultInterface;
  if (typeof intf !== 'string')
    return callback(new Error('intf should be a string.'));
  else if (typeof essid !== 'string')
    return callback(new Error('essid should be a string.'));
  callback = callback || function () {};
  wiscan.scan(intf, function (err, infos) {
    if (err) return callback(err);
    infos.forEach(function (info) {
      if (info.essid === essid) target = info;

    callback(null, target);
  });
  if (arguments.length === 2) {
    callback = essid;
    essid = intf;
    intf = defaultInterface;
  }
  intf = intf || defaultInterface;
  wiscan.scanByEssid(intf, essid, function (err, info) {
    if (err) return callback(err);
    if (info) callback(null, info.quality);
    else callback(null, null);
  });
  var parsed = [],
    len = items.length,
    idx = 0;

  if (items.length === 0) return parsed;

  items.forEach(function (c, i) {
    var val;
    if (c === 'Cell') {
      //- [deleted: need not cell field] val = items[i+1];
      //- [deleted: need not cell field] val = isNaN(parseInt(val)) ? val : parseInt(val);
      parsed.push({});
    } else if (c === 'Address:') {
      parsed[idx].address = items[i + 1];
    } else if (c === 'ESSID:') {
      parsed[idx].essid = items[i + 1];
    } else if (c === 'Mode:') {
      parsed[idx].mode = items[i + 1];
    } else if (c === 'Channel:') {
      val = items[i + 1];
      val = isNaN(parseInt(val)) ? val : parseInt(val);
      parsed[idx].channel = val;
      parsed[idx].frequency = getFrequency(val);
    } else if (c === 'Signal:') {
      val = items[i + 1];
      val = isNaN(parseInt(val)) ? val : parseInt(val);
      parsed[idx].signal = val;
    } else if (c === 'Quality:') {
      val = items[i + 1].split('/')[0];
      val = isNaN(parseInt(val)) ? val : parseInt(val);
      parsed[idx].quality = val;
    } else if (c === 'Encryption:') {
      var x = i + 1,
        enc = '';

      while (items[x] !== 'Cell') {
        if (x !== len) {
          enc = enc + items[x] + ' ';
          x += 1;
        } else {
          break;
      }
      enc = enc.trim();
      parsed[idx].encryption = enc;
      idx += 1;
    }
  });
  return parsed;
  var f = freqs[ch - 1];
  if (f) f = f + ' GHz';
  else f = '';
  return f;
  "version": "0.8.3",