Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adhoc network support #845

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions bin/tessel-2.js
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,7 @@ makeCommand('version')

makeCommand('ap')
.callback(options => {
options.mode = 'ap';
log.level(options.loglevel);

if (options.on || options.off) {
Expand All @@ -529,6 +530,9 @@ makeCommand('ap')
abbr: 's',
help: 'Encryption to use on network (i.e. wep, psk, psk2, wpa, wpa2).'
})
.option('ip', {
help: 'Set the IP address of the network, i.e. "192.168.1.101"'
})
.option('off', {
flag: true,
help: 'Disable the access point'
Expand All @@ -539,6 +543,48 @@ makeCommand('ap')
})
.help('Configure the Tessel as an access point');

makeCommand('adhoc')
.callback(options => {
options.mode = 'adhoc';
log.level(options.loglevel);

if (options.on || options.off) {
if (options.on) {
callControllerWith('enableAccessPoint', options);
} else {
callControllerWith('disableAccessPoint', options);
}
} else if (options.ssid) {
callControllerWith('createAccessPoint', options);
} else {
callControllerWith('getAccessPointInfo', options);
}
})
.option('ssid', {
abbr: 'n',
help: 'Name of the network.'
})
.option('password', {
abbr: 'p',
help: 'Password to access network.'
})
.option('security', {
abbr: 's',
help: 'Encryption used on network (i.e. wep, psk, psk2, wpa, wpa2).'
})
.option('ip', {
help: 'Set the IP address of the network, i.e. "192.168.1.101"'
})
.option('off', {
flag: true,
help: 'Disable the adhoc network'
})
.option('on', {
flag: true,
help: 'Enable the adhoc network'
})
.help('Configure the Tessel as an adhoc network');

makeCommand('root')
.callback(options => {
log.level(options.loglevel);
Expand Down
11 changes: 9 additions & 2 deletions lib/controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -720,9 +720,11 @@ controller.setWiFiState = function(opts) {
controller.createAccessPoint = function(opts) {
opts.authorized = true;
var ssid = opts.ssid;
var ip = opts.ip;
var password = opts.password;
var security = opts.security;
var securityOptions = ['none', 'wep', 'psk', 'psk2'];
var ipRegex = /^([0-1]?[0-9]?[0-9]|[2][0-4][0-9]|25[0-5])\.([0-1]?[0-9]?[0-9]|[2][0-4][0-9]|25[0-5])\.([0-1]?[0-9]?[0-9]|[2][0-4][0-9]|25[0-5])\.([0-1]?[0-9]?[0-9]|[2][0-4][0-9]|25[0-5])$/;

return new Promise((resolve, reject) => {
if (!ssid) {
Expand Down Expand Up @@ -763,6 +765,11 @@ controller.createAccessPoint = function(opts) {
return reject('Invalid passphrase: WPA/WPA2-PSK passkeys must be 8-63 ASCII characters, or 64 hexadecimal digits.');
}
}

if (ip && ipRegex.test(ip) === false) {
return reject(`Invalid IP address: the IP must 4 sets of numbers between 0 and 255, separate by a '.', like '192.168.1.101' or '255.255.255.255'`);
}

resolve();
})
.then(() => {
Expand All @@ -774,12 +781,12 @@ controller.createAccessPoint = function(opts) {

controller.enableAccessPoint = function(opts) {
opts.authorized = true;
return controller.standardTesselCommand(opts, (tessel) => tessel.enableAccessPoint());
return controller.standardTesselCommand(opts, (tessel) => tessel.enableAccessPoint(opts));
};

controller.disableAccessPoint = function(opts) {
opts.authorized = true;
return controller.standardTesselCommand(opts, (tessel) => tessel.disableAccessPoint());
return controller.standardTesselCommand(opts, (tessel) => tessel.disableAccessPoint(opts));
};

controller.getAccessPointInfo = function(opts) {
Expand Down
59 changes: 44 additions & 15 deletions lib/tessel/access-point.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ var commands = require('./commands');
var log = require('../log');
var Tessel = require('./tessel');

var defaultIP = '192.168.1.101';

function commitAndClose(tessel, status, resolve, reject) {

Expand All @@ -27,8 +28,8 @@ function commitAndClose(tessel, status, resolve, reject) {
.catch(reject);
}

Tessel.prototype.enableAccessPoint = function() {
var status = 'Access Point successfully enabled.';
Tessel.prototype.enableAccessPoint = function(opts) {
var status = `${opts.mode === 'ap' ? 'Access Point' : 'Adhoc Network'} successfully enabled.`;

return new Promise((resolve, reject) => {
return this.getAccessPointInfo()
Expand Down Expand Up @@ -59,8 +60,8 @@ Tessel.prototype.enableAccessPoint = function() {
});
};

Tessel.prototype.disableAccessPoint = function() {
var status = 'Access Point successfully disabled.';
Tessel.prototype.disableAccessPoint = function(opts) {
var status = `${opts.mode === 'ap' ? 'Access Point' : 'Adhoc Network'} successfully disabled.`;

return new Promise((resolve, reject) => {
return this.simpleExec(commands.turnAccessPointOff())
Expand All @@ -84,7 +85,7 @@ Tessel.prototype.getAccessPointInfo = function() {

info = {
ssid: values[0],
key: values[1],
key: values[2] !== 'none' ? values[1] : null, // the password for a previous configuration could still exist, so omit this info if the encryption is 'none'
encryption: values[2],
disabled: values[3]
};
Expand All @@ -102,21 +103,27 @@ Tessel.prototype.getAccessPointInfo = function() {

Tessel.prototype.createAccessPoint = function(opts) {
var ssid = opts.ssid;
var password = opts.pass;
var password = opts.password;
var security = opts.security;
var status = 'Created Access Point successfully. ';
var mode = opts.mode;
var ip = opts.ip;
var status = `Created ${mode === 'ap' ? 'Access Point' : 'Adhoc Network'} successfully. `;


var setupAccessPoint = () => {
if (password && !security) {
security = 'psk2';
}

if (!ip) {
ip = defaultIP;
}

if (password && security) {
status += `SSID: ${ssid}, password ${password}, security mode: ${security}`;
status += `SSID: ${ssid}, password ${password}, security mode: ${security}, IP address: ${ip}`;
} else if (!password && !security) {
security = 'none';
status += `SSID: ${ssid}`;
status += `SSID: ${ssid}, IP address: ${ip}`;
}

var setSSID = () => this.simpleExec(commands.setAccessPointSSID(ssid));
Expand All @@ -125,6 +132,10 @@ Tessel.prototype.createAccessPoint = function(opts) {

var setAccessPointSecurity = () => this.simpleExec(commands.setAccessPointSecurity(security));

var setAccessPointMode = () => this.simpleExec(commands.setAccessPointMode(mode));

var setAccessPointIP = () => this.simpleExec(commands.setLanNetworkIP(ip));

var turnAccessPointOn = () => this.simpleExec(commands.turnAccessPointOn());

var commitAndClosePromise = () => {
Expand All @@ -143,32 +154,50 @@ Tessel.prototype.createAccessPoint = function(opts) {
};

return setup()
.then(setAccessPointMode)
.then(setAccessPointIP)
.then(turnAccessPointOn)
.then(commitAndClosePromise);
};

return this.simpleExec(commands.getAccessPoint())
return this.simpleExec(commands.getWifiSettings())
.then((settings) => {
var regexDisabled = /disabled='(\d)'/;
var disabledMatcher = settings.match(regexDisabled);

// because an adhoc network both connects and emits,
// wifi cannot be enabled to when creating an adhoc network
if (mode === 'adhoc' && disabledMatcher[1] === '0') {
throw new Error(`Tessel must have wifi disabled before creating an adhoc network. Please run 't2 wifi --off' and try again.`);
}

return true;
})

.then(this.simpleExec(commands.getAccessPoint()))
.then(() => {

// When an AP exists, change the status to
// reflect an "update" vs. "create":
status = 'Updated Access Point successfully. ';
status = `Updated ${mode === 'ap' ? 'Access Point' : 'Adhoc Network'} successfully. `;
return setupAccessPoint();
})
.catch(() => {
.catch((error) => {
// this error was thrown when checking on the wifi status above
if (error && error.message.includes('adhoc')) {
return Promise.reject(error);
}

var setAccessPoint = () => {
return this.simpleExec(commands.setAccessPoint())
.then(() => this.simpleExec(commands.setAccessPointDevice()))
.then(() => this.simpleExec(commands.setAccessPointNetwork()))
.then(() => this.simpleExec(commands.setAccessPointMode()));
.then(() => this.simpleExec(commands.setAccessPointNetwork()));
};

var setLanNetwork = () => {
return this.simpleExec(commands.setLanNetwork())
.then(() => this.simpleExec(commands.setLanNetworkIfname()))
.then(() => this.simpleExec(commands.setLanNetworkProto()))
.then(() => this.simpleExec(commands.setLanNetworkIP()))
.then(() => this.simpleExec(commands.setLanNetworkNetmask()));
};

Expand Down
11 changes: 7 additions & 4 deletions lib/tessel/commands.js
Original file line number Diff line number Diff line change
Expand Up @@ -125,15 +125,18 @@ module.exports.setLanNetworkIfname = function() {
module.exports.setLanNetworkProto = function() {
return ['uci', 'set', 'network.lan.proto=static'];
};
module.exports.setLanNetworkIP = function() {
return ['uci', 'set', 'network.lan.ipaddr=192.168.1.101'];
module.exports.setLanNetworkIP = function(ip) {
return ['uci', 'set', `network.lan.ipaddr=${ip}`];
};
module.exports.setLanNetworkNetmask = function() {
return ['uci', 'set', 'network.lan.netmask=255.255.255.0'];
};
module.exports.commitNetwork = function() {
return ['uci', 'commit', 'network'];
};
module.exports.getWifiSettings = function() {
return ['uci', 'show', 'wireless.@wifi-iface[0]'];
};
module.exports.getAccessPoint = function() {
return ['uci', 'get', 'wireless.@wifi-iface[1]'];
};
Expand All @@ -149,8 +152,8 @@ module.exports.setAccessPointDevice = function() {
module.exports.setAccessPointNetwork = function() {
return ['uci', 'set', 'wireless.@wifi-iface[1].network=lan'];
};
module.exports.setAccessPointMode = function() {
return ['uci', 'set', 'wireless.@wifi-iface[1].mode=ap'];
module.exports.setAccessPointMode = function(mode) {
return ['uci', 'set', `wireless.@wifi-iface[1].mode=${mode}`];
};
module.exports.setAccessPointSSID = function(ssid) {
return ['uci', 'set', 'wireless.@wifi-iface[1].ssid=' + ssid];
Expand Down
17 changes: 16 additions & 1 deletion lib/tessel/wifi.js
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,22 @@ Tessel.prototype.connectToNetwork = function(opts) {
};


return setup()
return this.simpleExec(commands.getAccessPointConfig())
.then((config) => {
var regexDisabled = /disabled='(\d)'/;
var regexMode = /mode='(.+)'/;
var disabledMatcher = config.match(regexDisabled);
var modeMatcher = config.match(regexMode);

// because an adhoc network both connects and emits,
// adhoc cannot be enabled to when connecting to a wifi network
if (modeMatcher[1] === 'adhoc' && disabledMatcher[1] === '0') {
throw new Error(`Tessel must have adhoc disabled before connecting to a wifi network. Please run 't2 adhoc --off' and try again.`);
}

return true;
})
.then(setup)
.then(turnWifiOn)
.then(logStatus);
};
Expand Down
Loading