Merge ~morphis/snappy-hwe-snaps/+git/wifi-ap:dual-mode into ~snappy-hwe-team/snappy-hwe-snaps/+git/wifi-ap:master

Proposed by Simon Fels
Status: Merged
Approved by: Simon Fels
Approved revision: 97b8fc0672d50f64b5a58e08e97bbc6b18a1157d
Merged at revision: 0ae0aecaf9ac38ee1cbe614f340f3aec2293b616
Proposed branch: ~morphis/snappy-hwe-snaps/+git/wifi-ap:dual-mode
Merge into: ~snappy-hwe-team/snappy-hwe-snaps/+git/wifi-ap:master
Diff against target: 557 lines (+253/-106)
5 files modified
bin/ap.sh (+72/-69)
bin/config.sh (+118/-32)
bin/helper.sh (+52/-0)
conf/default-config (+2/-1)
snapcraft.yaml (+9/-4)
Reviewer Review Type Date Requested Status
Matteo Croce (community) Approve
Jim Hodapp (community) code Needs Fixing
Konrad Zapałowicz (community) code Approve
Review via email: mp+303806@code.launchpad.net

Description of the change

This namely brings support for simultaneous operating the STA and AP modes. This is depends basically on the hardware and needs to be configured with setting 'wifi-interface-mode' to 'virtual' which is the default. The service will create a virtual interface of type '__ap' and tells hostapd to operate on this. To avoid confusion with a possible running network-manager instance we're marking the interface as temporarily unmanaged through the nmcli utility regardless which 'wifi-interface-mode' is configured.

Next to the changes above this contains some small cleanups and changes the command line arguments of the config script slightly.

Default WiFi passphrase is now 'UbuntuAP'.

Handle errors in different cases correctly.

Fix NAT routing via iptables to forward connections from the right network interface.

This doesn't use yet the existing 'network-manager' part to include nmcli in the snap as its not clear yet if that will pass the snap builds on launchpad.

CI build: https://jenkins.canonical.com/system-enablement/job/generic-build-snap/32/ (ignore the network-manager*.snap artifact, the job is not that stable yet as it doesn't cleanup correctly)

To post a comment you must log in.
Revision history for this message
Konrad Zapałowicz (kzapalowicz) wrote :

Sweet

review: Approve (code)
Revision history for this message
Jim Hodapp (jhodapp) wrote :

See comments inline below.

review: Needs Fixing (code)
Revision history for this message
Matteo Croce (teknoraver) :
review: Needs Fixing
Revision history for this message
Matteo Croce (teknoraver) :
Revision history for this message
Simon Fels (morphis) :
Revision history for this message
Matteo Croce (teknoraver) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/bin/ap.sh b/bin/ap.sh
2index 33f20f0..66aa782 100755
3--- a/bin/ap.sh
4+++ b/bin/ap.sh
5@@ -16,7 +16,13 @@
6
7 set -x
8
9+if [ $(id -u) -ne 0 ] ; then
10+ echo "ERROR: $0 needs to be executed as root!"
11+ exit 1
12+fi
13+
14 . $SNAP/bin/config-internal.sh
15+. $SNAP/bin/helper.sh
16
17 DEFAULT_ACCESS_POINT_INTERFACE="ap0"
18
19@@ -25,58 +31,7 @@ if [ "$DISABLED" == "1" ] ; then
20 exit 0
21 fi
22
23-generate_dnsmasq_config() {
24- (
25- iface=$WIFI_INTERFACE
26- if [ "$WIFI_INTERFACE_MODE" == "virtual" ] ; then
27- iface=$DEFAULT_ACCESS_POINT_INTERFACE
28- fi
29-
30- cat<<-EOF
31- port=53
32- all-servers
33- interface=$iface
34- except-interface=lo
35- listen-address=$WIFI_ADDRESS
36- bind-interfaces
37- dhcp-range=$DHCP_RANGE_START,$DHCP_RANGE_STOP,$DHCP_LEASE_TIME
38- dhcp-option=6, $WIFI_ADDRESS
39- EOF
40- ) > $SNAP_DATA/dnsmasq.conf
41-}
42-
43-start_dnsmasq() {
44- iface=$WIFI_INTERFACE
45-
46- # If WiFi interface is managed by ifupdown leave it as is
47- if [ -e /etc/network/interfaces.d/$iface ]; then
48- exit 0
49- fi
50-
51- # Create our AP interface if required
52- if [ "$WIFI_INTERFACE_MODE" == "virtual" ] ; then
53- iface=$DEFAULT_ACCESS_POINT_INTERFACE
54- $SNAP/bin/iw dev $WIFI_INTERFACE interface add $iface type __ap
55- sleep 2
56- fi
57-
58- # Initial wifi interface configuration
59- ifconfig $iface up
60- ifconfig $iface $WIFI_ADDRESS netmask 255.255.255.0
61- sleep 2
62-
63- if [ "$SHARE_NETWORK_INTERFACE" != "none" ] ; then
64- # Enable NAT to forward our network connection
65- iptables --table nat --append POSTROUTING --out-interface $ETHERNET_INTERFACE -j MASQUERADE
66- iptables --append FORWARD --in-interface $iface -j ACCEPT
67-
68- sysctl -w net.ipv4.ip_forward=1
69- fi
70-
71- $SNAP/bin/dnsmasq -k -C $SNAP_DATA/dnsmasq.conf -l $SNAP_DATA/dnsmasq.leases -x $SNAP_DATA/dnsmasq.pid &
72-}
73-
74-stop_dnsmasq() {
75+shutdown() {
76 DNSMASQ_PID=$(cat $SNAP_DATA/dnsmasq.pid)
77 kill -TERM $DNSMASQ_PID
78 wait $DNSMASQ_PID
79@@ -88,40 +43,90 @@ stop_dnsmasq() {
80
81 if [ "$SHARE_NETWORK_INTERFACE" != "none" ] ; then
82 # flush forwarding rules out
83- iptables --table nat --delete POSTROUTING --out-interface $ETHERNET_INTERFACE -j MASQUERADE
84+ iptables --table nat --delete POSTROUTING --out-interface $SHARE_NETWORK_INTERFACE -j MASQUERADE
85 iptables --delete FORWARD --in-interface $iface -j ACCEPT
86+ sysctl -w net.ipv4.ip_forward=0
87 fi
88
89 if [ "$WIFI_INTERFACE_MODE" == "virtual" ] ; then
90 $SNAP/bin/iw dev $iface del
91 fi
92-
93- # disable ipv4 forward
94- sysctl -w net.ipv4.ip_forward=0
95 }
96
97-generate_dnsmasq_config
98-start_dnsmasq
99-
100 iface=$WIFI_INTERFACE
101 if [ "$WIFI_INTERFACE_MODE" == "virtual" ] ; then
102 iface=$DEFAULT_ACCESS_POINT_INTERFACE
103+
104+ # Make sure if the real wifi interface is connected we use
105+ # the same channel for our AP as otherwise the created AP
106+ # will not work.
107+ channel_in_use=$(iw dev $WIFI_INTERFACE info |awk '/channel/{print$2}')
108+ if [ $channel_in_use != $WIFI_CHANNEL ] ; then
109+ echo "ERROR: You configured a different channel than the WiFi device"
110+ echo " is currently using. This will not work as most devices"
111+ echo " require you to operate for AP and STA on the same channel."
112+ exit 1
113+ fi
114+fi
115+
116+# Create our AP interface if required
117+if [ "$WIFI_INTERFACE_MODE" = "virtual" ] ; then
118+ iface=$DEFAULT_ACCESS_POINT_INTERFACE
119+ $SNAP/bin/iw dev $WIFI_INTERFACE interface add $iface type __ap
120+ sleep 2
121+fi
122+if [ "$WIFI_INTERFACE_MODE" = "direct" ] ; then
123+ # If WiFi interface is managed by ifupdown or network-manager leave it as is
124+ assert_not_managed_by_ifupdown $iface
125 fi
126
127+# Prevent network-manager from touching the interface we want to use. If
128+# network-manager was configured to use the interface its nothing we want
129+# to prevent here as this is how the user configured the system.
130+$SNAP/bin/nmcli d set $iface managed no
131+
132+# Initial wifi interface configuration
133+ifconfig $iface up
134+if [ $? -ne 0 ] ; then
135+ echo "ERROR: Failed to enable WiFi network interface '$iface'"
136+
137+ # Remove virtual interface again if we created one
138+ if [ "$WIFI_INTERFACE_MODE" = "virtual" ] ; then
139+ $SNAP/bin/iw dev $iface del
140+ fi
141+
142+ # Hand interface back to network-manager. This will also trigger the
143+ # auto connection process inside network-manager to get connected
144+ # with the previous network.
145+ $SNAP/bin/nmcli d set $iface managed yes
146+
147+ exit 1
148+fi
149+
150+# Configure interface and give it a moment to settle
151+ifconfig $iface $WIFI_ADDRESS netmask $WIFI_NETMASK
152+sleep 2
153+
154+if [ "$SHARE_NETWORK_INTERFACE" != "none" ] ; then
155+ # Enable NAT to forward our network connection
156+ iptables --table nat --append POSTROUTING --out-interface $SHARE_NETWORK_INTERFACE -j MASQUERADE
157+ iptables --append FORWARD --in-interface $iface -j ACCEPT
158+ sysctl -w net.ipv4.ip_forward=1
159+fi
160+
161+generate_dnsmasq_config $SNAP_DATA/dnsmasq.conf
162+$SNAP/bin/dnsmasq -k -C $SNAP_DATA/dnsmasq.conf -l $SNAP_DATA/dnsmasq.leases -x $SNAP_DATA/dnsmasq.pid &
163+
164 # Wait a bit until our WiFi network interface is correctly
165 # setup by dnsmasq
166-grep $iface /proc/net/dev &> /dev/null
167-while [ $? != 0 ] ; do
168- sleep 5
169- grep $iface /proc/net/dev &> /dev/null
170-done
171+wait_until_interface_is_available $iface
172
173 driver=$WIFI_HOSTAPD_DRIVER
174 if [ "$driver" == "rtl8188" ] ; then
175 driver=rtl871xdrv
176 fi
177
178-# Generate our configuration file
179+# Generate our hostapd configuration file
180 cat <<EOF > $SNAP_DATA/hostapd.conf
181 interface=$iface
182 driver=$driver
183@@ -132,8 +137,6 @@ wmm_enabled=1
184 ieee80211n=1
185 ssid=$WIFI_SSID
186 hw_mode=$WIFI_OPERATION_MODE
187-# Enable 40MHz channels with 20ns guard interval
188-ht_capab=[HT40][SHORT-GI-20][DSSS_CCK-40]
189 EOF
190
191 case "$WIFI_SECURITY" in
192@@ -182,9 +185,9 @@ function exit_handler() {
193 # Wait until hostapd is correctly terminated before we continue
194 # doing anything
195 wait $HOSTAPD_PID
196- stop_dnsmasq
197+ shutdown
198 exit 0
199 }
200
201 wait $HOSTAPD_PID
202-stop_dnsmasq
203\ No newline at end of file
204+shutdown
205\ No newline at end of file
206diff --git a/bin/config.sh b/bin/config.sh
207index 4c5bb41..0bf7839 100755
208--- a/bin/config.sh
209+++ b/bin/config.sh
210@@ -17,12 +17,21 @@
211 . $SNAP/bin/config-internal.sh
212
213 set_item() {
214+ if [ -z "$1" ] || [ -z "$2" ] ; then
215+ echo "ERROR: You need to provide a key and a value to set"
216+ echo
217+ echo "You can call '$0 get' to list of all possible keys"
218+ exit 1
219+ fi
220 case $1 in
221 disabled)
222 DISABLED=$2
223 if [ "$DISABLED" == "0" ] ; then
224- echo "To really startup the service you have to start the"
225- echo "relevant service components on your own:"
226+ echo "You have successfully enabled the access point but you still"
227+ echo "need to either reboot the device or restart the systemd"
228+ echo "service to make the service reloading its configuration."
229+ echo "You can just run the following command (as root) if you"
230+ echo "do not want to reboot your device:"
231 echo
232 echo " $ systemctl restart snap.wifi-ap.backend"
233 fi
234@@ -30,73 +39,131 @@ set_item() {
235 debug)
236 DEBUG=$2
237 ;;
238- wifi-interface)
239+ wifi.interface)
240 WIFI_INTERFACE=$2
241 ;;
242- wifi-address)
243+ wifi.address)
244 WIFI_ADDRESS=$2
245 ;;
246- wifi-interface-mode)
247+ wifi.netmask)
248+ WIFI_NETMASK=$2
249+ ;;
250+ wifi.interface-mode)
251 WIFI_INTERFACE_MODE=$2
252 ;;
253- wifi-hostapd-driver)
254+ wifi.hostapd-driver)
255 WIFI_HOSTAPD_DRIVER=$2
256 if [ "$WIFI_HOSTAPD_DRIVER" == "rtl8188" ] ; then
257 # Select correct mode for the rtl8188 driver
258 WIFI_INTERFACE_MODE=direct
259 fi
260 ;;
261- wifi-ssid)
262+ wifi.ssid)
263 WIFI_SSID=$2
264 ;;
265- wifi-security)
266+ wifi.security)
267 WIFI_SECURITY=$2
268 ;;
269- wifi-security-passphrase)
270+ wifi.security-passphrase)
271 WIFI_SECURITY_PASSPHRASE=$2
272 ;;
273- wifi-channel)
274+ wifi.channel)
275 WIFI_CHANNEL=$2
276 ;;
277- wifi-operation-mode)
278+ wifi.operation-mode)
279 WIFI_OPERATION_MODE=$2
280 ;;
281- share-network-interface)
282+ share.network-interface)
283 SHARE_NETWORK_INTERFACE=$2
284 ;;
285- dhcp-range-start)
286+ dhcp.range-start)
287 DHCP_RANGE_START=$2
288 ;;
289- dhcp-range-stop)
290+ dhcp.range-stop)
291 DHCP_RANGE_STOP=$2
292 ;;
293- dhcp-lease-time)
294+ dhcp.lease-time)
295 DHCP_LEASE_TIME=$2
296 ;;
297 *)
298+ echo "ERROR: Unknown config item '$1'"
299+ exit 1
300+ esac
301+}
302+
303+get_item() {
304+ case $1 in
305+ disabled)
306+ echo $DISABLED
307+ ;;
308+ debug)
309+ echo $DEBUG
310+ ;;
311+ wifi.interface)
312+ echo $WIFI_INTERFACE
313+ ;;
314+ wifi.address)
315+ echo $WIFI_ADDRESS
316+ ;;
317+ wifi.netmask)
318+ echo $WIFI_NETMASK
319+ ;;
320+ wifi.interface-mode)
321+ echo $WIFI_INTERFACE_MODE
322+ ;;
323+ wifi.hostapd-driver)
324+ echo $WIFI_HOSTAPD_DRIVER
325+ ;;
326+ wifi.ssid)
327+ echo $WIFI_SSID
328+ ;;
329+ wifi.security)
330+ echo $WIFI_SECURITY
331+ ;;
332+ wifi.security-passphrase)
333+ echo $WIFI_SECURITY_PASSPHRASE
334+ ;;
335+ wifi.channel)
336+ echo $WIFI_CHANNEL
337+ ;;
338+ wifi.operation-mode)
339+ echo $WIFI_OPERATION_MODE
340+ ;;
341+ share.network-interface)
342+ echo $SHARE_NETWORK_INTERFACE
343+ ;;
344+ dhcp.range-start)
345+ echo $DHCP_RANGE_START
346+ ;;
347+ dhcp.range-stop)
348+ echo $DHCP_RANGE_STOP
349+ ;;
350+ dhcp.lease-time)
351+ echo $DHCP_LEASE_TIME
352+ ;;
353+ *)
354 echo "Unknown config item '$1'"
355 exit 1
356 esac
357 }
358
359 dump_config() {
360- echo "Current configuration:"
361- echo "==========================================================="
362 echo "disabled: $DISABLED"
363 echo "debug: $DEBUG"
364- echo "wifi-interface: $WIFI_INTERFACE"
365- echo "wifi-address: $WIFI_ADDRESS"
366- echo "wifi-interface-mode: $WIFI_INTERFACE_MODE"
367- echo "wifi-hostapd-driver: $WIFI_HOSTAPD_DRIVER"
368- echo "wifi-ssid: $WIFI_SSID"
369- echo "wifi-security: $WIFI_SECURITY"
370- echo "wifi-security-passphrase: $WIFI_SECURITY_PASSPHRASE"
371- echo "wifi-channel: $WIFI_CHANNEL"
372- echo "wifi-operation-mode: $WIFI_OPERATION_MODE"
373- echo "share-network-interface: $SHARE_NETWORK_INTERFACE"
374- echo "dhcp-range-start: $DHCP_RANGE_START"
375- echo "dhcp-range-stop: $DHCP_RANGE_STOP"
376- echo "dhcp-lease-time: $DHCP_LEASE_TIME"
377+ echo "wifi.interface: $WIFI_INTERFACE"
378+ echo "wifi.address: $WIFI_ADDRESS"
379+ echo "wifi.netmask: $WIFI_NETMASK"
380+ echo "wifi.interface-mode: $WIFI_INTERFACE_MODE"
381+ echo "wifi.hostapd-driver: $WIFI_HOSTAPD_DRIVER"
382+ echo "wifi.ssid: $WIFI_SSID"
383+ echo "wifi.security: $WIFI_SECURITY"
384+ echo "wifi.security-passphrase: $WIFI_SECURITY_PASSPHRASE"
385+ echo "wifi.channel: $WIFI_CHANNEL"
386+ echo "wifi.operation-mode: $WIFI_OPERATION_MODE"
387+ echo "share.network-interface: $SHARE_NETWORK_INTERFACE"
388+ echo "dhcp.range-start: $DHCP_RANGE_START"
389+ echo "dhcp.range-stop: $DHCP_RANGE_STOP"
390+ echo "dhcp.lease-time: $DHCP_LEASE_TIME"
391 }
392
393 write_configuration() {
394@@ -109,6 +176,7 @@ write_configuration() {
395 DEBUG=$DEBUG
396 WIFI_INTERFACE=$WIFI_INTERFACE
397 WIFI_ADDRESS=$WIFI_ADDRESS
398+ WIFI_NETMASK=$WIFI_NETMASK
399 WIFI_INTERFACE_MODE=$WIFI_INTERFACE_MODE
400 WIFI_HOSTAPD_DRIVER=$WIFI_HOSTAPD_DRIVER
401 WIFI_SSID=$WIFI_SSID
402@@ -123,8 +191,21 @@ write_configuration() {
403 EOF
404 }
405
406+if [ -z "$1" ] ; then
407+ echo "Usage: $0 get|set <key> [<value>]"
408+ echo
409+ echo "You can call '$0 get' to list of all possible keys"
410+ exit
411+fi
412+
413+
414+
415 case "$1" in
416 set)
417+ if [ $(id -u) -ne 0 ] ; then
418+ echo "ERROR: '$@' needs to be executed as root!"
419+ exit 1
420+ fi
421 shift
422 key=$1
423 shift
424@@ -133,8 +214,13 @@ case "$1" in
425 set_item $key $value
426 write_configuration
427 ;;
428- dump)
429- dump_config
430+ get)
431+ shift
432+ if [ "$1" = "" ] ; then
433+ dump_config
434+ else
435+ echo "$1: $(get_item $1)"
436+ fi
437 shift
438 ;;
439 *)
440diff --git a/bin/helper.sh b/bin/helper.sh
441new file mode 100644
442index 0000000..df56715
443--- /dev/null
444+++ b/bin/helper.sh
445@@ -0,0 +1,52 @@
446+#!/bin/bash
447+#
448+# Copyright (C) 2015, 2016 Canonical Ltd
449+#
450+# This program is free software: you can redistribute it and/or modify
451+# it under the terms of the GNU General Public License version 3 as
452+# published by the Free Software Foundation.
453+#
454+# This program is distributed in the hope that it will be useful,
455+# but WITHOUT ANY WARRANTY; without even the implied warranty of
456+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
457+# GNU General Public License for more details.
458+#
459+# You should have received a copy of the GNU General Public License
460+# along with this program. If not, see <http://www.gnu.org/licenses/>.
461+
462+set -x
463+
464+wait_until_interface_is_available() {
465+ grep $1 /proc/net/dev &> /dev/null
466+ while [ $? != 0 ] ; do
467+ sleep 5
468+ grep $1 /proc/net/dev &> /dev/null
469+ done
470+}
471+
472+assert_not_managed_by_ifupdown() {
473+ if [ -e /etc/network/interfaces.d/$1 ]; then
474+ echo "ERROR: Interface $1 is managed by ifupdown and can't be used"
475+ exit 1
476+ fi
477+}
478+
479+generate_dnsmasq_config() {
480+ {
481+ iface=$WIFI_INTERFACE
482+ if [ "$WIFI_INTERFACE_MODE" = "virtual" ] ; then
483+ iface=$DEFAULT_ACCESS_POINT_INTERFACE
484+ fi
485+
486+ cat<<-EOF
487+ port=53
488+ all-servers
489+ interface=$iface
490+ except-interface=lo
491+ listen-address=$WIFI_ADDRESS
492+ bind-interfaces
493+ dhcp-range=$DHCP_RANGE_START,$DHCP_RANGE_STOP,$DHCP_LEASE_TIME
494+ dhcp-option=6, $WIFI_ADDRESS
495+ EOF
496+ } > $1
497+}
498diff --git a/conf/default-config b/conf/default-config
499index 8259e90..1fa5c4f 100644
500--- a/conf/default-config
501+++ b/conf/default-config
502@@ -22,6 +22,7 @@ DEBUG=0
503 # Default configuration
504 WIFI_INTERFACE=wlan0
505 WIFI_ADDRESS=192.168.7.1
506+WIFI_NETMASK=255.255.255.0
507
508 # Possible options are: uap, direct
509 # virtual:
510@@ -40,7 +41,7 @@ WIFI_SSID="Ubuntu"
511 # Can be 'open' or 'wpa2'
512 WIFI_SECURITY="open"
513 # WIFI_SECURITY="wpa2"
514-# WIFI_SECURITY_PASSPHRASE="Ubuntu16.04"
515+# WIFI_SECURITY_PASSPHRASE="UbuntuAP"
516
517 WIFI_CHANNEL=6
518 # Operation mode (a = IEEE 802.11a (5 GHz), b = IEEE 802.11b (2.4 GHz),
519diff --git a/snapcraft.yaml b/snapcraft.yaml
520index 3d583eb..8733027 100644
521--- a/snapcraft.yaml
522+++ b/snapcraft.yaml
523@@ -17,6 +17,7 @@ apps:
524 - network-control
525 - firewall-control
526 - network-bind
527+ - network-manager
528 config:
529 command: bin/config.sh
530
531@@ -24,14 +25,12 @@ parts:
532 scripts:
533 plugin: dump
534 source: .
535- filesets:
536- all:
537+ snap:
538 - bin/config.sh
539 - bin/config-internal.sh
540 - bin/ap.sh
541+ - bin/helper.sh
542 - conf/default-config
543- snap:
544- - $all
545 network-utils:
546 plugin: nil
547 stage-packages:
548@@ -100,3 +99,9 @@ parts:
549 - rtl8188/hostapd
550 snap:
551 - $binaries
552+ nmlci:
553+ plugin: nil
554+ stage-packages:
555+ - network-manager
556+ organize:
557+ usr/bin/nmcli: bin/nmcli

Subscribers

People subscribed via source and target branches

to all changes: