Advertisement
Guest User

create_ap for Intel AX200 (github.com/lakinduakash/linux-wifi-hotspot)

a guest
Sep 24th, 2021
709
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Bash 58.71 KB | None | 0 0
  1. #!/bin/bash
  2.  
  3. # general dependencies:
  4. #    bash (to run this script)
  5. #    util-linux (for getopt)
  6. #    procps or procps-ng
  7. #    hostapd
  8. #    iproute2
  9. #    iw
  10. #    iwconfig (you only need this if 'iw' can not recognize your adapter)
  11. #    haveged (optional)
  12.  
  13. # dependencies for 'nat' or 'none' Internet sharing method
  14. #    dnsmasq
  15. #    iptables
  16.  
  17. VERSION=0.4.6
  18. PROGNAME="$(basename $0)"
  19.  
  20. # make sure that all command outputs are in english
  21. # so we can parse them correctly
  22. export LC_ALL=C
  23.  
  24. # all new files and directories must be readable only by root.
  25. # in special cases we must use chmod to give any other permissions.
  26. SCRIPT_UMASK=0077
  27. umask $SCRIPT_UMASK
  28.  
  29. usage() {
  30.     echo "Usage: "$PROGNAME" [options] <wifi-interface> [<interface-with-internet>] [<access-point-name> [<passphrase>]]"
  31.     echo
  32.     echo "Options:"
  33.     echo "  -h, --help              Show this help"
  34.     echo "  --version               Print version number"
  35.     echo "  -c <channel>            Channel number (default: 1)"
  36.     echo "  -w <WPA version>        Use 1 for WPA, use 2 for WPA2, use 1+2 for both (default: 2)"
  37.     echo "  -n                      Disable Internet sharing (if you use this, don't pass"
  38.     echo "                          the <interface-with-internet> argument)"
  39.     echo "  -m <method>             Method for Internet sharing."
  40.     echo "                          Use: 'nat' for NAT (default)"
  41.     echo "                               'bridge' for bridging"
  42.     echo "                               'none' for no Internet sharing (equivalent to -n)"
  43.     echo "  --psk                   Use 64 hex digits pre-shared-key instead of passphrase"
  44.     echo "  --hidden                Make the Access Point hidden (do not broadcast the SSID)"
  45.     echo "  --mac-filter            Enable MAC address filtering"
  46.     echo "  --mac-filter-accept     Location of MAC address filter list (defaults to /etc/hostapd/hostapd.accept)"
  47.     echo "  --redirect-to-localhost If -n is set, redirect every web request to localhost (useful for public information networks)"
  48.     echo "  --hostapd-debug <level> With level between 1 and 2, passes arguments -d or -dd to hostapd for debugging."
  49.     echo "  --isolate-clients       Disable communication between clients"
  50.     echo "  --ieee80211n            Enable IEEE 802.11n (HT)"
  51.     echo "  --ieee80211ac           Enable IEEE 802.11ac (VHT)"
  52.     echo "  --ht_capab <HT>         HT capabilities (default: [HT40+])"
  53.     echo "  --vht_capab <VHT>       VHT capabilities"
  54.     echo "  --country <code>        Set two-letter country code for regularity (example: US)"
  55.     echo "  --freq-band <GHz>       Set frequency band. Valid inputs: 2.4, 5 (default: 2.4)"
  56.     echo "  --driver                Choose your WiFi adapter driver (default: nl80211)"
  57.     echo "  --no-virt               Do not create virtual interface"
  58.     echo "  --no-haveged            Do not run 'haveged' automatically when needed"
  59.     echo "  --fix-unmanaged         If NetworkManager shows your interface as unmanaged after you"
  60.     echo "                          close create_ap, then use this option to switch your interface"
  61.     echo "                          back to managed"
  62.     echo "  --mac <MAC>             Set MAC address"
  63.     echo "  --dhcp-dns <IP1[,IP2]>  Set DNS returned by DHCP"
  64.     echo "  --daemon                Run create_ap in the background"
  65.     echo "  --pidfile <pidfile>     Save daemon PID to file"
  66.     echo "  --logfile <logfile>     Save daemon messages to file"
  67.     echo "  --stop <id>             Send stop command to an already running create_ap. For an <id>"
  68.     echo "                          you can put the PID of create_ap or the WiFi interface. You can"
  69.     echo "                          get them with --list-running"
  70.     echo "  --list-running          Show the create_ap processes that are already running"
  71.     echo "  --list-clients <id>     List the clients connected to create_ap instance associated with <id>."
  72.     echo "                          For an <id> you can put the PID of create_ap or the WiFi interface."
  73.     echo "                          If virtual WiFi interface was created, then use that one."
  74.     echo "                          You can get them with --list-running"
  75.     echo "  --mkconfig <conf_file>  Store configs in conf_file"
  76.     echo "  --config <conf_file>    Load configs from conf_file"
  77.     echo
  78.     echo "Non-Bridging Options:"
  79.     echo "  --no-dns                Disable dnsmasq DNS server"
  80.     echo "  --no-dnsmasq            Disable dnsmasq server completely"
  81.     echo "  -g <gateway>            IPv4 Gateway for the Access Point (default: 192.168.12.1)"
  82.     echo "  -d                      DNS server will take into account /etc/hosts"
  83.     echo "  -e <hosts_file>         DNS server will take into account additional hosts file"
  84.     echo
  85.     echo "Useful informations:"
  86.     echo "  * If you're not using the --no-virt option, then you can create an AP with the same"
  87.     echo "    interface you are getting your Internet connection."
  88.     echo "  * You can pass your SSID and password through pipe or through arguments (see examples)."
  89.     echo "  * On bridge method if the <interface-with-internet> is not a bridge interface, then"
  90.     echo "    a bridge interface is created automatically."
  91.     echo
  92.     echo "Examples:"
  93.     echo "  "$PROGNAME" wlan0 eth0 MyAccessPoint MyPassPhrase"
  94.     echo "  echo -e 'MyAccessPoint\nMyPassPhrase' | "$PROGNAME" wlan0 eth0"
  95.     echo "  "$PROGNAME" wlan0 eth0 MyAccessPoint"
  96.     echo "  echo 'MyAccessPoint' | "$PROGNAME" wlan0 eth0"
  97.     echo "  "$PROGNAME" wlan0 wlan0 MyAccessPoint MyPassPhrase"
  98.     echo "  "$PROGNAME" -n wlan0 MyAccessPoint MyPassPhrase"
  99.     echo "  "$PROGNAME" -m bridge wlan0 eth0 MyAccessPoint MyPassPhrase"
  100.     echo "  "$PROGNAME" -m bridge wlan0 br0 MyAccessPoint MyPassPhrase"
  101.     echo "  "$PROGNAME" --driver rtl871xdrv wlan0 eth0 MyAccessPoint MyPassPhrase"
  102.     echo "  "$PROGNAME" --daemon wlan0 eth0 MyAccessPoint MyPassPhrase"
  103.     echo "  "$PROGNAME" --stop wlan0"
  104. }
  105.  
  106. # Busybox polyfills
  107. if cp --help 2>&1 | grep -q -- --no-clobber; then
  108.     cp_n() {
  109.         cp -n "$@"
  110.     }
  111. else
  112.     cp_n() {
  113.         yes n | cp -i "$@"
  114.     }
  115. fi
  116.  
  117. # on success it echos a non-zero unused FD
  118. # on error it echos 0
  119. get_avail_fd() {
  120.     local x
  121.     for x in $(seq 1 $(ulimit -n)); do
  122.         if [[ ! -a "/proc/$BASHPID/fd/$x" ]]; then
  123.             echo $x
  124.             return
  125.         fi
  126.     done
  127.     echo 0
  128. }
  129.  
  130. # lock file for the mutex counter
  131. COUNTER_LOCK_FILE=/tmp/create_ap.$$.lock
  132.  
  133. cleanup_lock() {
  134.     rm -f $COUNTER_LOCK_FILE
  135. }
  136.  
  137. init_lock() {
  138.     local LOCK_FILE=/tmp/create_ap.all.lock
  139.  
  140.     # we initialize only once
  141.     [[ $LOCK_FD -ne 0 ]] && return 0
  142.  
  143.     LOCK_FD=$(get_avail_fd)
  144.     [[ $LOCK_FD -eq 0 ]] && return 1
  145.  
  146.     # open/create lock file with write access for all users
  147.     # otherwise normal users will not be able to use it.
  148.     # to avoid race conditions on creation, we need to
  149.     # use umask to set the permissions.
  150.     umask 0555
  151.     eval "exec $LOCK_FD>$LOCK_FILE" > /dev/null 2>&1 || return 1
  152.     umask $SCRIPT_UMASK
  153.  
  154.     # there is a case where lock file was created from a normal
  155.     # user. change the owner to root as soon as we can.
  156.     [[ $(id -u) -eq 0 ]] && chown 0:0 $LOCK_FILE
  157.  
  158.     # create mutex counter lock file
  159.     echo 0 > $COUNTER_LOCK_FILE
  160.  
  161.     return $?
  162. }
  163.  
  164. # recursive mutex lock for all create_ap processes
  165. mutex_lock() {
  166.     local counter_mutex_fd
  167.     local counter
  168.  
  169.     # lock local mutex and read counter
  170.     counter_mutex_fd=$(get_avail_fd)
  171.     if [[ $counter_mutex_fd -ne 0 ]]; then
  172.         eval "exec $counter_mutex_fd<>$COUNTER_LOCK_FILE"
  173.         flock $counter_mutex_fd
  174.         read -u $counter_mutex_fd counter
  175.     else
  176.         echo "Failed to lock mutex counter" >&2
  177.         return 1
  178.     fi
  179.  
  180.     # lock global mutex and increase counter
  181.     [[ $counter -eq 0 ]] && flock $LOCK_FD
  182.     counter=$(( $counter + 1 ))
  183.  
  184.     # write counter and unlock local mutex
  185.     echo $counter > /proc/$BASHPID/fd/$counter_mutex_fd
  186.     eval "exec ${counter_mutex_fd}<&-"
  187.     return 0
  188. }
  189.  
  190. # recursive mutex unlock for all create_ap processes
  191. mutex_unlock() {
  192.     local counter_mutex_fd
  193.     local counter
  194.  
  195.     # lock local mutex and read counter
  196.     counter_mutex_fd=$(get_avail_fd)
  197.     if [[ $counter_mutex_fd -ne 0 ]]; then
  198.         eval "exec $counter_mutex_fd<>$COUNTER_LOCK_FILE"
  199.         flock $counter_mutex_fd
  200.         read -u $counter_mutex_fd counter
  201.     else
  202.         echo "Failed to lock mutex counter" >&2
  203.         return 1
  204.     fi
  205.  
  206.     # decrease counter and unlock global mutex
  207.     if [[ $counter -gt 0 ]]; then
  208.         counter=$(( $counter - 1 ))
  209.         [[ $counter -eq 0 ]] && flock -u $LOCK_FD
  210.     fi
  211.  
  212.     # write counter and unlock local mutex
  213.     echo $counter > /proc/$BASHPID/fd/$counter_mutex_fd
  214.     eval "exec ${counter_mutex_fd}<&-"
  215.     return 0
  216. }
  217.  
  218. # it takes 2 arguments
  219. # returns:
  220. #  0 if v1 (1st argument) and v2 (2nd argument) are the same
  221. #  1 if v1 is less than v2
  222. #  2 if v1 is greater than v2
  223. version_cmp() {
  224.     local V1 V2 VN x
  225.     [[ ! $1 =~ ^[0-9]+(\.[0-9]+)*$ ]] && die "Wrong version format!"
  226.     [[ ! $2 =~ ^[0-9]+(\.[0-9]+)*$ ]] && die "Wrong version format!"
  227.  
  228.     V1=( $(echo $1 | tr '.' ' ') )
  229.     V2=( $(echo $2 | tr '.' ' ') )
  230.     VN=${#V1[@]}
  231.     [[ $VN -lt ${#V2[@]} ]] && VN=${#V2[@]}
  232.  
  233.     for ((x = 0; x < $VN; x++)); do
  234.         [[ ${V1[x]} -lt ${V2[x]} ]] && return 1
  235.         [[ ${V1[x]} -gt ${V2[x]} ]] && return 2
  236.     done
  237.  
  238.     return 0
  239. }
  240.  
  241. USE_IWCONFIG=0
  242.  
  243. is_interface() {
  244.     [[ -z "$1" ]] && return 1
  245.     [[ -d "/sys/class/net/${1}" ]]
  246. }
  247.  
  248. is_wifi_interface() {
  249.     which iw > /dev/null 2>&1 && iw dev $1 info > /dev/null 2>&1 && return 0
  250.     if which iwconfig > /dev/null 2>&1 && iwconfig $1 > /dev/null 2>&1; then
  251.         USE_IWCONFIG=1
  252.         return 0
  253.     fi
  254.     return 1
  255. }
  256.  
  257. is_bridge_interface() {
  258.     [[ -z "$1" ]] && return 1
  259.     [[ -d "/sys/class/net/${1}/bridge" ]]
  260. }
  261.  
  262. get_phy_device() {
  263.     local x
  264.     for x in /sys/class/ieee80211/*; do
  265.         [[ ! -e "$x" ]] && continue
  266.         if [[ "${x##*/}" = "$1" ]]; then
  267.             echo $1
  268.             return 0
  269.         elif [[ -e "$x/device/net/$1" ]]; then
  270.             echo ${x##*/}
  271.             return 0
  272.         elif [[ -e "$x/device/net:$1" ]]; then
  273.             echo ${x##*/}
  274.             return 0
  275.         fi
  276.     done
  277.     echo "Failed to get phy interface" >&2
  278.     return 1
  279. }
  280.  
  281. get_adapter_info() {
  282.     local PHY
  283.     PHY=$(get_phy_device "$1")
  284.     [[ $? -ne 0 ]] && return 1
  285.     iw phy $PHY info
  286. }
  287.  
  288. get_adapter_kernel_module() {
  289.     local MODULE
  290.     MODULE=$(readlink -f "/sys/class/net/$1/device/driver/module")
  291.     echo ${MODULE##*/}
  292. }
  293.  
  294. can_be_sta_and_ap() {
  295.     # iwconfig does not provide this information, assume false
  296.     [[ $USE_IWCONFIG -eq 1 ]] && return 1
  297.     if [[ "$(get_adapter_kernel_module "$1")" == "brcmfmac" ]]; then
  298.         echo "WARN: brmfmac driver doesn't work properly with virtual interfaces and" >&2
  299.         echo "      it can cause kernel panic. For this reason we disallow virtual" >&2
  300.         echo "      interfaces for your adapter." >&2
  301.         echo "      For more info: https://github.com/oblique/create_ap/issues/203" >&2
  302.         return 1
  303.     fi
  304.     get_adapter_info "$1" | grep -E '{.* managed.* AP.*}' > /dev/null 2>&1 && return 0
  305.     get_adapter_info "$1" | grep -E '{.* AP.* managed.*}' > /dev/null 2>&1 && return 0
  306.     return 1
  307. }
  308.  
  309. can_be_ap() {
  310.     # iwconfig does not provide this information, assume true
  311.     [[ $USE_IWCONFIG -eq 1 ]] && return 0
  312.     get_adapter_info "$1" | grep -E '\* AP$' > /dev/null 2>&1 && return 0
  313.     return 1
  314. }
  315.  
  316. can_transmit_to_channel() {
  317.     local IFACE CHANNEL_NUM CHANNEL_INFO
  318.     IFACE=$1
  319.     CHANNEL_NUM=$2
  320.  
  321.     if [[ $USE_IWCONFIG -eq 0 ]]; then
  322.         if [[ $FREQ_BAND == 2.4 ]]; then
  323.             CHANNEL_INFO=$(get_adapter_info ${IFACE} | grep " 24[0-9][0-9] MHz \[${CHANNEL_NUM}\]")
  324.         else
  325.             CHANNEL_INFO=$(get_adapter_info ${IFACE} | grep " \(49[0-9][0-9]\|5[0-9]\{3\}\) MHz \[${CHANNEL_NUM}\]")
  326.         fi
  327.         [[ -z "${CHANNEL_INFO}" ]] && return 1
  328.         [[ "${CHANNEL_INFO}" == *no\ IR* ]] && return 1
  329.         [[ "${CHANNEL_INFO}" == *disabled* ]] && return 1
  330.         return 0
  331.     else
  332.         CHANNEL_NUM=$(printf '%02d' ${CHANNEL_NUM})
  333.         CHANNEL_INFO=$(iwlist ${IFACE} channel | grep -E "Channel[[:blank:]]${CHANNEL_NUM}[[:blank:]]?:")
  334.         [[ -z "${CHANNEL_INFO}" ]] && return 1
  335.         return 0
  336.     fi
  337. }
  338.  
  339. # taken from iw/util.c
  340. ieee80211_frequency_to_channel() {
  341.     local FREQ=$1
  342.     if [[ $FREQ -eq 2484 ]]; then
  343.         echo 14
  344.     elif [[ $FREQ -lt 2484 ]]; then
  345.         echo $(( ($FREQ - 2407) / 5 ))
  346.     elif [[ $FREQ -ge 4910 && $FREQ -le 4980 ]]; then
  347.         echo $(( ($FREQ - 4000) / 5 ))
  348.     elif [[ $FREQ -le 45000 ]]; then
  349.         echo $(( ($FREQ - 5000) / 5 ))
  350.     elif [[ $FREQ -ge 58320 && $FREQ -le 64800 ]]; then
  351.         echo $(( ($FREQ - 56160) / 2160 ))
  352.     else
  353.         echo 0
  354.     fi
  355. }
  356.  
  357. is_5ghz_frequency() {
  358.     [[ $1 =~ ^(49[0-9]{2})|(5[0-9]{3})$ ]]
  359. }
  360.  
  361. is_wifi_connected() {
  362.     if [[ $USE_IWCONFIG -eq 0 ]]; then
  363.         iw dev "$1" link 2>&1 | grep -E '^Connected to' > /dev/null 2>&1 && return 0
  364.     else
  365.         iwconfig "$1" 2>&1 | grep -E 'Access Point: [0-9a-fA-F]{2}:' > /dev/null 2>&1 && return 0
  366.     fi
  367.     return 1
  368. }
  369.  
  370. is_macaddr() {
  371.     echo "$1" | grep -E "^([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}$" > /dev/null 2>&1
  372. }
  373.  
  374. is_unicast_macaddr() {
  375.     local x
  376.     is_macaddr "$1" || return 1
  377.     x=$(echo "$1" | cut -d: -f1)
  378.     x=$(printf '%d' "0x${x}")
  379.     [[ $(expr $x % 2) -eq 0 ]]
  380. }
  381.  
  382. get_macaddr() {
  383.     is_interface "$1" || return
  384.     cat "/sys/class/net/${1}/address"
  385. }
  386.  
  387. get_mtu() {
  388.     is_interface "$1" || return
  389.     cat "/sys/class/net/${1}/mtu"
  390. }
  391.  
  392. alloc_new_iface() {
  393.     local prefix=$1
  394.     local i=0
  395.  
  396.     mutex_lock
  397.     while :; do
  398.         if ! is_interface $prefix$i && [[ ! -f $COMMON_CONFDIR/ifaces/$prefix$i ]]; then
  399.             mkdir -p $COMMON_CONFDIR/ifaces
  400.             touch $COMMON_CONFDIR/ifaces/$prefix$i
  401.             echo $prefix$i
  402.             mutex_unlock
  403.             return
  404.         fi
  405.         i=$((i + 1))
  406.     done
  407.     mutex_unlock
  408. }
  409.  
  410. dealloc_iface() {
  411.     rm -f $COMMON_CONFDIR/ifaces/$1
  412. }
  413.  
  414. get_all_macaddrs() {
  415.     cat /sys/class/net/*/address
  416. }
  417.  
  418. get_new_macaddr() {
  419.     local OLDMAC NEWMAC LAST_BYTE i
  420.     OLDMAC=$(get_macaddr "$1")
  421.     LAST_BYTE=$(printf %d 0x${OLDMAC##*:})
  422.     mutex_lock
  423.     for i in {1..255}; do
  424.         NEWMAC="${OLDMAC%:*}:$(printf %02x $(( ($LAST_BYTE + $i) % 256 )))"
  425.         (get_all_macaddrs | grep "$NEWMAC" > /dev/null 2>&1) || break
  426.     done
  427.     mutex_unlock
  428.     echo $NEWMAC
  429. }
  430.  
  431. # start haveged when needed
  432. haveged_watchdog() {
  433.     local show_warn=1
  434.     while :; do
  435.         mutex_lock
  436.         if [[ $(cat /proc/sys/kernel/random/entropy_avail) -lt 1000 ]]; then
  437.             if ! which haveged > /dev/null 2>&1; then
  438.                 if [[ $show_warn -eq 1 ]]; then
  439.                     echo "WARN: Low entropy detected. We recommend you to install \`haveged'"
  440.                    show_warn=0
  441.                fi
  442.            elif ! pidof haveged > /dev/null 2>&1; then
  443.                echo "Low entropy detected, starting haveged"
  444.                # boost low-entropy
  445.                haveged -w 1024 -p $COMMON_CONFDIR/haveged.pid
  446.            fi
  447.        fi
  448.        mutex_unlock
  449.        sleep 2
  450.    done
  451. }
  452.  
  453. NETWORKMANAGER_CONF=/etc/NetworkManager/NetworkManager.conf
  454. NM_OLDER_VERSION=1
  455.  
  456. networkmanager_exists() {
  457.    local NM_VER
  458.    which nmcli > /dev/null 2>&1 || return 1
  459.    NM_VER=$(nmcli -v | grep -m1 -oE '[0-9]+(\.[0-9]+)*\.[0-9]+')
  460.    version_cmp $NM_VER 0.9.9
  461.    if [[ $? -eq 1 ]]; then
  462.        NM_OLDER_VERSION=1
  463.    else
  464.        NM_OLDER_VERSION=0
  465.    fi
  466.    return 0
  467. }
  468.  
  469. networkmanager_is_running() {
  470.    local NMCLI_OUT
  471.    networkmanager_exists || return 1
  472.    if [[ $NM_OLDER_VERSION -eq 1 ]]; then
  473.        NMCLI_OUT=$(nmcli -t -f RUNNING nm 2>&1 | grep -E '^running$')
  474.    else
  475.        NMCLI_OUT=$(nmcli -t -f RUNNING g 2>&1 | grep -E '^running$')
  476.    fi
  477.    [[ -n "$NMCLI_OUT" ]]
  478. }
  479.  
  480. networkmanager_knows_iface() {
  481.    # check if the interface $1 is known to NetworkManager
  482.    # an interface may exist but may not be known to NetworkManager if it is in a different network namespace than NetworkManager
  483.    nmcli -t -f DEVICE d 2>&1 | grep -Fxq "$1"
  484. }
  485.  
  486. networkmanager_iface_is_unmanaged() {
  487.    is_interface "$1" || return 2
  488.    networkmanager_knows_iface "$1" || return 0
  489.    (nmcli -t -f DEVICE,STATE d 2>&1 | grep -E "^$1:unmanaged$" > /dev/null 2>&1) || return 1
  490. }
  491.  
  492. ADDED_UNMANAGED=
  493.  
  494. networkmanager_add_unmanaged() {
  495.    local MAC UNMANAGED WAS_EMPTY x
  496.    networkmanager_exists || return 1
  497.  
  498.    [[ -d ${NETWORKMANAGER_CONF%/*} ]] || mkdir -p ${NETWORKMANAGER_CONF%/*}
  499.    [[ -f ${NETWORKMANAGER_CONF} ]] || touch ${NETWORKMANAGER_CONF}
  500.  
  501.    if [[ $NM_OLDER_VERSION -eq 1 ]]; then
  502.        if [[ -z "$2" ]]; then
  503.            MAC=$(get_macaddr "$1")
  504.        else
  505.            MAC="$2"
  506.        fi
  507.        [[ -z "$MAC" ]] && return 1
  508.    fi
  509.  
  510.    mutex_lock
  511.    UNMANAGED=$(grep -m1 -Eo '^unmanaged-devices=[[:alnum:]:;,-]*' /etc/NetworkManager/NetworkManager.conf)
  512.  
  513.    WAS_EMPTY=0
  514.    [[ -z "$UNMANAGED" ]] && WAS_EMPTY=1
  515.    UNMANAGED=$(echo "$UNMANAGED" | sed 's/unmanaged-devices=//' | tr ';,' ' ')
  516.  
  517.    # if it exists, do nothing
  518.    for x in $UNMANAGED; do
  519.        if [[ $x == "mac:${MAC}" ]] ||
  520.               [[ $NM_OLDER_VERSION -eq 0 && $x == "interface-name:${1}" ]]; then
  521.            mutex_unlock
  522.            return 2
  523.        fi
  524.    done
  525.  
  526.    if [[ $NM_OLDER_VERSION -eq 1 ]]; then
  527.        UNMANAGED="${UNMANAGED} mac:${MAC}"
  528.    else
  529.        UNMANAGED="${UNMANAGED} interface-name:${1}"
  530.    fi
  531.  
  532.    UNMANAGED=$(echo $UNMANAGED | sed -e 's/^ //')
  533.    UNMANAGED="${UNMANAGED// /;}"
  534.    UNMANAGED="unmanaged-devices=${UNMANAGED}"
  535.  
  536.    if ! grep -E '^\[keyfile\]' ${NETWORKMANAGER_CONF} > /dev/null 2>&1; then
  537.        echo -e "\n\n[keyfile]\n${UNMANAGED}" >> ${NETWORKMANAGER_CONF}
  538.    elif [[ $WAS_EMPTY -eq 1 ]]; then
  539.        sed -e "s/^\(\[keyfile\].*\)$/\1\n${UNMANAGED}/" -i ${NETWORKMANAGER_CONF}
  540.    else
  541.        sed -e "s/^unmanaged-devices=.*/${UNMANAGED}/" -i ${NETWORKMANAGER_CONF}
  542.    fi
  543.  
  544.    ADDED_UNMANAGED="${ADDED_UNMANAGED} ${1} "
  545.    mutex_unlock
  546.  
  547.    local nm_pid=$(pidof NetworkManager)
  548.    [[ -n "$nm_pid" ]] && kill -HUP $nm_pid
  549.  
  550.    return 0
  551. }
  552.  
  553. networkmanager_rm_unmanaged() {
  554.    local MAC UNMANAGED
  555.    networkmanager_exists || return 1
  556.    [[ ! -f ${NETWORKMANAGER_CONF} ]] && return 1
  557.  
  558.    if [[ $NM_OLDER_VERSION -eq 1 ]]; then
  559.        if [[ -z "$2" ]]; then
  560.            MAC=$(get_macaddr "$1")
  561.        else
  562.            MAC="$2"
  563.        fi
  564.        [[ -z "$MAC" ]] && return 1
  565.    fi
  566.  
  567.    mutex_lock
  568.    UNMANAGED=$(grep -m1 -Eo '^unmanaged-devices=[[:alnum:]:;,-]*' /etc/NetworkManager/NetworkManager.conf | sed 's/unmanaged-devices=//' | tr ';,' ' ')
  569.  
  570.    if [[ -z "$UNMANAGED" ]]; then
  571.        mutex_unlock
  572.        return 1
  573.    fi
  574.  
  575.    [[ -n "$MAC" ]] && UNMANAGED=$(echo $UNMANAGED | sed -e "s/mac:${MAC}\( \|$\)//g")
  576.    UNMANAGED=$(echo $UNMANAGED | sed -e "s/interface-name:${1}\( \|$\)//g")
  577.    UNMANAGED=$(echo $UNMANAGED | sed -e 's/ $//')
  578.  
  579.    if [[ -z "$UNMANAGED" ]]; then
  580.        sed -e "/^unmanaged-devices=.*/d" -i ${NETWORKMANAGER_CONF}
  581.    else
  582.        UNMANAGED="${UNMANAGED// /;}"
  583.        UNMANAGED="unmanaged-devices=${UNMANAGED}"
  584.        sed -e "s/^unmanaged-devices=.*/${UNMANAGED}/" -i ${NETWORKMANAGER_CONF}
  585.    fi
  586.  
  587.    ADDED_UNMANAGED="${ADDED_UNMANAGED/ ${1} /}"
  588.    mutex_unlock
  589.  
  590.    local nm_pid=$(pidof NetworkManager)
  591.    [[ -n "$nm_pid" ]] && kill -HUP $nm_pid
  592.  
  593.    return 0
  594. }
  595.  
  596. networkmanager_fix_unmanaged() {
  597.    [[ -f ${NETWORKMANAGER_CONF} ]] || return
  598.  
  599.    mutex_lock
  600.    sed -e "/^unmanaged-devices=.*/d" -i ${NETWORKMANAGER_CONF}
  601.    mutex_unlock
  602.  
  603.    local nm_pid=$(pidof NetworkManager)
  604.    [[ -n "$nm_pid" ]] && kill -HUP $nm_pid
  605. }
  606.  
  607. networkmanager_rm_unmanaged_if_needed() {
  608.    [[ $ADDED_UNMANAGED =~ .*\ ${1}\ .* ]] && networkmanager_rm_unmanaged $1 $2
  609. }
  610.  
  611. networkmanager_wait_until_unmanaged() {
  612.    local RES
  613.    networkmanager_is_running || return 1
  614.    while :; do
  615.        networkmanager_iface_is_unmanaged "$1"
  616.        RES=$?
  617.        [[ $RES -eq 0 ]] && break
  618.        [[ $RES -eq 2 ]] && die "Interface '${1}' does not exist.
  619.       It's probably renamed by a udev rule."
  620.        sleep 1
  621.    done
  622.    sleep 2
  623.    return 0
  624. }
  625.  
  626.  
  627. CHANNEL=default
  628. GATEWAY=192.168.12.1
  629. WPA_VERSION=2
  630. ETC_HOSTS=0
  631. ADDN_HOSTS=
  632. DHCP_DNS=gateway
  633. NO_DNS=0
  634. NO_DNSMASQ=0
  635. DNS_PORT=
  636. HIDDEN=0
  637. MAC_FILTER=0
  638. MAC_FILTER_ACCEPT=/etc/hostapd/hostapd.accept
  639. ISOLATE_CLIENTS=0
  640. SHARE_METHOD=nat
  641. IEEE80211N=0
  642. IEEE80211AC=0
  643. IEEE80211AX=0
  644. HT_CAPAB='[HT40+]'
  645. VHT_CAPAB=
  646. DRIVER=nl80211
  647. NO_VIRT=0
  648. COUNTRY=
  649. FREQ_BAND=2.4
  650. NEW_MACADDR=
  651. DAEMONIZE=0
  652. DAEMON_PIDFILE=
  653. DAEMON_LOGFILE=/dev/null
  654. NO_HAVEGED=0
  655. USE_PSK=0
  656.  
  657. HOSTAPD_DEBUG_ARGS=
  658. REDIRECT_TO_LOCALHOST=0
  659.  
  660. CONFIG_OPTS=(CHANNEL GATEWAY WPA_VERSION ETC_HOSTS DHCP_DNS NO_DNS NO_DNSMASQ HIDDEN MAC_FILTER MAC_FILTER_ACCEPT ISOLATE_CLIENTS
  661.             SHARE_METHOD IEEE80211N IEEE80211AC IEEE80211AX HT_CAPAB VHT_CAPAB DRIVER NO_VIRT COUNTRY FREQ_BAND
  662.             NEW_MACADDR DAEMONIZE DAEMON_PIDFILE DAEMON_LOGFILE NO_HAVEGED WIFI_IFACE INTERNET_IFACE
  663.             SSID PASSPHRASE USE_PSK)
  664.  
  665. FIX_UNMANAGED=0
  666. LIST_RUNNING=0
  667. STOP_ID=
  668. LIST_CLIENTS_ID=
  669.  
  670. STORE_CONFIG=
  671. LOAD_CONFIG=
  672.  
  673. CONFDIR=
  674. WIFI_IFACE=
  675. VWIFI_IFACE=
  676. INTERNET_IFACE=
  677. BRIDGE_IFACE=
  678. OLD_MACADDR=
  679. IP_ADDRS=
  680. ROUTE_ADDRS=
  681.  
  682. HAVEGED_WATCHDOG_PID=
  683.  
  684. _cleanup() {
  685.    local PID x
  686.  
  687.    trap "" SIGINT SIGUSR1 SIGUSR2 EXIT
  688.    mutex_lock
  689.    disown -a
  690.  
  691.    # kill haveged_watchdog
  692.    [[ -n "$HAVEGED_WATCHDOG_PID" ]] && kill $HAVEGED_WATCHDOG_PID
  693.  
  694.    # kill processes
  695.    for x in $CONFDIR/*.pid; do
  696.        # even if the $CONFDIR is empty, the for loop will assign
  697.        # a value in $x. so we need to check if the value is a file
  698.        [[ -f $x ]] && kill -9 $(cat $x)
  699.    done
  700.  
  701.    rm -rf $CONFDIR
  702.  
  703.    local found=0
  704.    for x in $(list_running_conf); do
  705.        if [[ -f $x/nat_internet_iface && $(cat $x/nat_internet_iface) == $INTERNET_IFACE ]]; then
  706.            found=1
  707.            break
  708.        fi
  709.    done
  710.  
  711.    if [[ $found -eq 0 ]]; then
  712.        cp -f $COMMON_CONFDIR/${INTERNET_IFACE}_forwarding \
  713.           /proc/sys/net/ipv4/conf/$INTERNET_IFACE/forwarding
  714.        rm -f $COMMON_CONFDIR/${INTERNET_IFACE}_forwarding
  715.    fi
  716.  
  717.    # if we are the last create_ap instance then set back the common values
  718.    if ! has_running_instance; then
  719.        # kill common processes
  720.        for x in $COMMON_CONFDIR/*.pid; do
  721.            [[ -f $x ]] && kill -9 $(cat $x)
  722.        done
  723.  
  724.        # set old ip_forward
  725.        if [[ -f $COMMON_CONFDIR/ip_forward ]]; then
  726.            cp -f $COMMON_CONFDIR/ip_forward /proc/sys/net/ipv4
  727.            rm -f $COMMON_CONFDIR/ip_forward
  728.        fi
  729.  
  730.        # set old bridge-nf-call-iptables
  731.        if [[ -f $COMMON_CONFDIR/bridge-nf-call-iptables ]]; then
  732.            if [[ -e /proc/sys/net/bridge/bridge-nf-call-iptables ]]; then
  733.                cp -f $COMMON_CONFDIR/bridge-nf-call-iptables /proc/sys/net/bridge
  734.            fi
  735.            rm -f $COMMON_CONFDIR/bridge-nf-call-iptables
  736.        fi
  737.  
  738.        rm -rf $COMMON_CONFDIR
  739.    fi
  740.  
  741.    if [[ "$SHARE_METHOD" != "none" ]]; then
  742.        if [[ "$SHARE_METHOD" == "nat" ]]; then
  743.            iptables -w -t nat -D POSTROUTING -s ${GATEWAY%.*}.0/24 ! -o ${WIFI_IFACE} -j MASQUERADE
  744.            iptables -w -D FORWARD -i ${WIFI_IFACE} -s ${GATEWAY%.*}.0/24 -j ACCEPT
  745.            iptables -w -D FORWARD -i ${INTERNET_IFACE} -d ${GATEWAY%.*}.0/24 -j ACCEPT
  746.        elif [[ "$SHARE_METHOD" == "bridge" ]]; then
  747.            if ! is_bridge_interface $INTERNET_IFACE; then
  748.                ip link set dev $BRIDGE_IFACE down
  749.                ip link set dev $INTERNET_IFACE down
  750.                ip link set dev $INTERNET_IFACE promisc off
  751.                ip link set dev $INTERNET_IFACE nomaster
  752.                ip link delete $BRIDGE_IFACE type bridge
  753.                ip addr flush $INTERNET_IFACE
  754.                ip link set dev $INTERNET_IFACE up
  755.                dealloc_iface $BRIDGE_IFACE
  756.  
  757.                for x in "${IP_ADDRS[@]}"; do
  758.                    x="${x/inet/}"
  759.                    x="${x/secondary/}"
  760.                    x="${x/dynamic/}"
  761.                    x=$(echo $x | sed 's/\([0-9]\)sec/\1/g')
  762.                    x="${x/${INTERNET_IFACE}/}"
  763.                    ip addr add $x dev $INTERNET_IFACE
  764.                done
  765.  
  766.                ip route flush dev $INTERNET_IFACE
  767.  
  768.                for x in "${ROUTE_ADDRS[@]}"; do
  769.                    [[ -z "$x" ]] && continue
  770.                    [[ "$x" == default* ]] && continue
  771.                    ip route add $x dev $INTERNET_IFACE
  772.                done
  773.  
  774.                for x in "${ROUTE_ADDRS[@]}"; do
  775.                    [[ -z "$x" ]] && continue
  776.                    [[ "$x" != default* ]] && continue
  777.                    ip route add $x dev $INTERNET_IFACE
  778.                done
  779.  
  780.                networkmanager_rm_unmanaged_if_needed $INTERNET_IFACE
  781.            fi
  782.        fi
  783.    fi
  784.  
  785.    if [[ "$SHARE_METHOD" != "bridge" ]]; then
  786.        if [[ $NO_DNS -eq 0 ]]; then
  787.            iptables -w -D INPUT -p tcp -m tcp --dport $DNS_PORT -j ACCEPT
  788.            iptables -w -D INPUT -p udp -m udp --dport $DNS_PORT -j ACCEPT
  789.            iptables -w -t nat -D PREROUTING -s ${GATEWAY%.*}.0/24 -d ${GATEWAY} \
  790.                -p tcp -m tcp --dport 53 -j REDIRECT --to-ports $DNS_PORT
  791.            iptables -w -t nat -D PREROUTING -s ${GATEWAY%.*}.0/24 -d ${GATEWAY} \
  792.                -p udp -m udp --dport 53 -j REDIRECT --to-ports $DNS_PORT
  793.        fi
  794.        iptables -w -D INPUT -p udp -m udp --dport 67 -j ACCEPT
  795.    fi
  796.  
  797.    if [[ $NO_VIRT -eq 0 ]]; then
  798.        if [[ -n "$VWIFI_IFACE" ]]; then
  799.            ip link set down dev ${VWIFI_IFACE}
  800.            ip addr flush ${VWIFI_IFACE}
  801.            networkmanager_rm_unmanaged_if_needed ${VWIFI_IFACE} ${OLD_MACADDR}
  802.            iw dev ${VWIFI_IFACE} del
  803.            dealloc_iface $VWIFI_IFACE
  804.        fi
  805.    else
  806.        ip link set down dev ${WIFI_IFACE}
  807.        ip addr flush ${WIFI_IFACE}
  808.        if [[ -n "$NEW_MACADDR" ]]; then
  809.            ip link set dev ${WIFI_IFACE} address ${OLD_MACADDR}
  810.        fi
  811.        networkmanager_rm_unmanaged_if_needed ${WIFI_IFACE} ${OLD_MACADDR}
  812.    fi
  813.  
  814.    mutex_unlock
  815.    cleanup_lock
  816.  
  817.    if [[ $RUNNING_AS_DAEMON -eq 1 && -n "$DAEMON_PIDFILE" && -f "$DAEMON_PIDFILE" ]]; then
  818.        rm $DAEMON_PIDFILE
  819.    fi
  820. }
  821.  
  822. cleanup() {
  823.    echo
  824.    echo -n "Doing cleanup.. "
  825.    _cleanup > /dev/null 2>&1
  826.    echo "done"
  827. }
  828.  
  829. die() {
  830.    [[ -n "$1" ]] && echo -e "\nERROR: $1\n" >&2
  831.    # send die signal to the main process
  832.    [[ $BASHPID -ne $$ ]] && kill -USR2 $$
  833.    # we don't need to call cleanup because it's traped on EXIT
  834.    exit 1
  835. }
  836.  
  837. clean_exit() {
  838.    # send clean_exit signal to the main process
  839.    [[ $BASHPID -ne $$ ]] && kill -USR1 $$
  840.    # we don't need to call cleanup because it's traped on EXIT
  841.    exit 0
  842. }
  843.  
  844. list_running_conf() {
  845.    local x
  846.    mutex_lock
  847.    for x in /tmp/create_ap.*; do
  848.        if [[ -f $x/pid && -f $x/wifi_iface && -d /proc/$(cat $x/pid) ]]; then
  849.            echo $x
  850.        fi
  851.    done
  852.    mutex_unlock
  853. }
  854.  
  855. list_running() {
  856.    local IFACE wifi_iface x
  857.    mutex_lock
  858.    for x in $(list_running_conf); do
  859.        IFACE=${x#*.}
  860.        IFACE=${IFACE%%.*}
  861.        wifi_iface=$(cat $x/wifi_iface)
  862.  
  863.        if [[ $IFACE == $wifi_iface ]]; then
  864.            echo $(cat $x/pid) $IFACE
  865.        else
  866.            echo $(cat $x/pid) $IFACE '('$(cat $x/wifi_iface)')'
  867.        fi
  868.    done
  869.    mutex_unlock
  870. }
  871.  
  872. get_wifi_iface_from_pid() {
  873.    list_running | awk '{print $1 " " $NF}' | tr -d '\(\)' | grep -E "^${1} " | cut -d' ' -f2
  874. }
  875.  
  876. get_pid_from_wifi_iface() {
  877.    list_running | awk '{print $1 " " $NF}' | tr -d '\(\)' | grep -E " ${1}$" | cut -d' ' -f1
  878. }
  879.  
  880. get_confdir_from_pid() {
  881.    local IFACE x
  882.    mutex_lock
  883.    for x in $(list_running_conf); do
  884.        if [[ $(cat $x/pid) == "$1" ]]; then
  885.            echo $x
  886.            break
  887.        fi
  888.    done
  889.    mutex_unlock
  890. }
  891.  
  892. print_client() {
  893.    local line ipaddr hostname
  894.    local mac="$1"
  895.  
  896.    if [[ -f $CONFDIR/dnsmasq.leases ]]; then
  897.        line=$(grep " $mac " $CONFDIR/dnsmasq.leases | tail -n 1)
  898.        ipaddr=$(echo $line | cut -d' ' -f3)
  899.        hostname=$(echo "$line" | cut -d' ' -f4)
  900.    fi
  901.  
  902.    [[ -z "$ipaddr" ]] && ipaddr="*"
  903.    [[ -z "$hostname" ]] && hostname="*"
  904.  
  905.    printf "%-20s %-18s %s\n" "$mac" "$ipaddr" "$hostname"
  906. }
  907.  
  908. list_clients() {
  909.    local wifi_iface pid
  910.  
  911.    # If PID is given, get the associated wifi iface
  912.    if [[ "$1" =~ ^[1-9][0-9]*$ ]]; then
  913.        pid="$1"
  914.        wifi_iface=$(get_wifi_iface_from_pid "$pid")
  915.        [[ -z "$wifi_iface" ]] && die "'$pid' is not the pid of a running $PROGNAME instance."
  916.    fi
  917.  
  918.    [[ -z "$wifi_iface" ]] && wifi_iface="$1"
  919.    is_wifi_interface "$wifi_iface" || die "'$wifi_iface' is not a WiFi interface."
  920.  
  921.    [[ -z "$pid" ]] && pid=$(get_pid_from_wifi_iface "$wifi_iface")
  922.    [[ -z "$pid" ]] && die "'$wifi_iface' is not used from $PROGNAME instance.\n\
  923.       Maybe you need to pass the virtual interface instead.\n\
  924.       Use --list-running to find it out."
  925.    [[ -z "$CONFDIR" ]] && CONFDIR=$(get_confdir_from_pid "$pid")
  926.  
  927.    if [[ $USE_IWCONFIG -eq 0 ]]; then
  928.        local awk_cmd='($1 ~ /Station$/) {print $2}'
  929.        local client_list=$(iw dev "$wifi_iface" station dump | awk "$awk_cmd")
  930.  
  931.        if [[ -z "$client_list" ]]; then
  932.            echo "No clients connected"
  933.            return
  934.        fi
  935.  
  936.        printf "%-20s %-18s %s\n" "MAC" "IP" "Hostname"
  937.  
  938.        local mac
  939.        for mac in $client_list; do
  940.            print_client $mac
  941.        done
  942.    else
  943.        die "This option is not supported for the current driver."
  944.    fi
  945. }
  946.  
  947. has_running_instance() {
  948.    local PID x
  949.  
  950.    mutex_lock
  951.    for x in /tmp/create_ap.*; do
  952.        if [[ -f $x/pid ]]; then
  953.            PID=$(cat $x/pid)
  954.            if [[ -d /proc/$PID ]]; then
  955.                mutex_unlock
  956.                return 0
  957.            fi
  958.        fi
  959.    done
  960.    mutex_lock
  961.  
  962.    return 1
  963. }
  964.  
  965. is_running_pid() {
  966.    list_running | grep -E "^${1} " > /dev/null 2>&1
  967. }
  968.  
  969. send_stop() {
  970.    local x
  971.  
  972.    mutex_lock
  973.    # send stop signal to specific pid
  974.    if is_running_pid $1; then
  975.        kill -USR1 $1
  976.        mutex_unlock
  977.        return
  978.    fi
  979.  
  980.    # send stop signal to specific interface
  981.    for x in $(list_running | grep -E " \(?${1}( |\)?\$)" | cut -f1 -d' '); do
  982.        kill -USR1 $x
  983.    done
  984.    mutex_unlock
  985. }
  986.  
  987. # Storing configs
  988. write_config() {
  989.    local i=1
  990.  
  991.    if ! eval 'echo -n > "$STORE_CONFIG"' > /dev/null 2>&1; then
  992.        echo "ERROR: Unable to create config file $STORE_CONFIG" >&2
  993.        exit 1
  994.    fi
  995.  
  996.    WIFI_IFACE=$1
  997.    if [[ "$SHARE_METHOD" == "none" ]]; then
  998.        SSID="$2"
  999.        PASSPHRASE="$3"
  1000.    else
  1001.        INTERNET_IFACE="$2"
  1002.        SSID="$3"
  1003.        PASSPHRASE="$4"
  1004.    fi
  1005.  
  1006.    for config_opt in "${CONFIG_OPTS[@]}"; do
  1007.        eval echo $config_opt=\$$config_opt
  1008.    done >> "$STORE_CONFIG"
  1009.  
  1010.    echo -e "Config options written to '$STORE_CONFIG'"
  1011.    exit 0
  1012. }
  1013.  
  1014. is_config_opt() {
  1015.    local elem opt="$1"
  1016.  
  1017.    for elem in "${CONFIG_OPTS[@]}"; do
  1018.        if [[ "$elem" == "$opt" ]]; then
  1019.            return 0
  1020.        fi
  1021.    done
  1022.    return 1
  1023. }
  1024.  
  1025. # Load options from config file
  1026. read_config() {
  1027.    local opt_name opt_val line
  1028.  
  1029.    while read line; do
  1030.        # Read switches and their values
  1031.        opt_name="${line%%=*}"
  1032.        opt_val="${line#*=}"
  1033.        if is_config_opt "$opt_name" ; then
  1034.            eval $opt_name="\$opt_val"
  1035.        else
  1036.            echo "WARN: Unrecognized configuration entry $opt_name" >&2
  1037.        fi
  1038.    done < "$LOAD_CONFIG"
  1039. }
  1040.  
  1041.  
  1042. ARGS=( "$@" )
  1043.  
  1044. # Preprocessing for --config before option-parsing starts
  1045. for ((i=0; i<$#; i++)); do
  1046.    if [[ "${ARGS[i]}" = "--config" ]]; then
  1047.        if [[ -f "${ARGS[i+1]}" ]]; then
  1048.            LOAD_CONFIG="${ARGS[i+1]}"
  1049.            read_config
  1050.        else
  1051.            echo "ERROR: No config file found at given location" >&2
  1052.            exit 1
  1053.        fi
  1054.        break
  1055.    fi
  1056. done
  1057.  
  1058. GETOPT_ARGS=$(getopt -o hc:w:g:de:nm: -l "help","hidden","hostapd-debug:","redirect-to-localhost","mac-filter","mac-filter-accept:","isolate-clients","ieee80211n","ieee80211ac","ieee80211ax","ht_capab:","vht_capab:","driver:","no-virt","fix-unmanaged","country:","freq-band:","mac:","dhcp-dns:","daemon","pidfile:","logfile:","stop:","list","list-running","list-clients:","version","psk","no-haveged","no-dns","no-dnsmasq","mkconfig:","config:" -n "$PROGNAME" -- "$@")
  1059. [[ $? -ne 0 ]] && exit 1
  1060. eval set -- "$GETOPT_ARGS"
  1061.  
  1062. FREQ_BAND_SET=0
  1063.  
  1064. while :; do
  1065.    case "$1" in
  1066.        -h|--help)
  1067.            usage
  1068.            exit 0
  1069.            ;;
  1070.        --version)
  1071.            echo $VERSION
  1072.            exit 0
  1073.            ;;
  1074.        --hidden)
  1075.            shift
  1076.            HIDDEN=1
  1077.            ;;
  1078.        --mac-filter)
  1079.            shift
  1080.            MAC_FILTER=1
  1081.            ;;
  1082.        --mac-filter-accept)
  1083.            shift
  1084.            MAC_FILTER_ACCEPT="$1"
  1085.            shift
  1086.            ;;
  1087.        --isolate-clients)
  1088.            shift
  1089.            ISOLATE_CLIENTS=1
  1090.            ;;
  1091.        -c)
  1092.            shift
  1093.            CHANNEL="$1"
  1094.            shift
  1095.            ;;
  1096.        -w)
  1097.            shift
  1098.            WPA_VERSION="$1"
  1099.            [[ "$WPA_VERSION" == "2+1" ]] && WPA_VERSION=1+2
  1100.            shift
  1101.            ;;
  1102.        -g)
  1103.            shift
  1104.            GATEWAY="$1"
  1105.            shift
  1106.            ;;
  1107.        -d)
  1108.            shift
  1109.            ETC_HOSTS=1
  1110.            ;;
  1111.        -e)
  1112.            shift
  1113.            ADDN_HOSTS="$1"
  1114.            shift
  1115.            ;;
  1116.        -n)
  1117.            shift
  1118.            SHARE_METHOD=none
  1119.            ;;
  1120.        -m)
  1121.            shift
  1122.            SHARE_METHOD="$1"
  1123.            shift
  1124.            ;;
  1125.        --ieee80211n)
  1126.            shift
  1127.            IEEE80211N=1
  1128.            ;;
  1129.        --ieee80211ac)
  1130.            shift
  1131.            IEEE80211AC=1
  1132.            ;;
  1133.        --ieee80211ax)
  1134.            shift
  1135.            IEEE80211AX=1
  1136.            ;;
  1137.        --ht_capab)
  1138.            shift
  1139.            HT_CAPAB="$1"
  1140.            shift
  1141.            ;;
  1142.        --vht_capab)
  1143.            shift
  1144.            VHT_CAPAB="$1"
  1145.            shift
  1146.            ;;
  1147.        --driver)
  1148.            shift
  1149.            DRIVER="$1"
  1150.            shift
  1151.            ;;
  1152.        --no-virt)
  1153.            shift
  1154.            NO_VIRT=1
  1155.            ;;
  1156.        --fix-unmanaged)
  1157.            shift
  1158.            FIX_UNMANAGED=1
  1159.            ;;
  1160.        --country)
  1161.            shift
  1162.            COUNTRY="$1"
  1163.            shift
  1164.            ;;
  1165.        --freq-band)
  1166.            shift
  1167.            FREQ_BAND="$1"
  1168.            FREQ_BAND_SET=1
  1169.            shift
  1170.            ;;
  1171.        --mac)
  1172.            shift
  1173.            NEW_MACADDR="$1"
  1174.            shift
  1175.            ;;
  1176.        --dhcp-dns)
  1177.            shift
  1178.            DHCP_DNS="$1"
  1179.            shift
  1180.            ;;
  1181.        --daemon)
  1182.            shift
  1183.            DAEMONIZE=1
  1184.            ;;
  1185.        --pidfile)
  1186.            shift
  1187.            DAEMON_PIDFILE="$1"
  1188.            shift
  1189.            ;;
  1190.        --logfile)
  1191.            shift
  1192.            DAEMON_LOGFILE="$1"
  1193.            shift
  1194.            ;;
  1195.        --stop)
  1196.            shift
  1197.            STOP_ID="$1"
  1198.            shift
  1199.            ;;
  1200.        --list)
  1201.            shift
  1202.            LIST_RUNNING=1
  1203.            echo -e "WARN: --list is deprecated, use --list-running instead.\n" >&2
  1204.            ;;
  1205.        --list-running)
  1206.            shift
  1207.            LIST_RUNNING=1
  1208.            ;;
  1209.        --list-clients)
  1210.            shift
  1211.            LIST_CLIENTS_ID="$1"
  1212.            shift
  1213.            ;;
  1214.        --no-haveged)
  1215.            shift
  1216.            NO_HAVEGED=1
  1217.            ;;
  1218.        --psk)
  1219.            shift
  1220.            USE_PSK=1
  1221.            ;;
  1222.        --no-dns)
  1223.            shift
  1224.            NO_DNS=1
  1225.            ;;
  1226.        --no-dnsmasq)
  1227.            shift
  1228.            NO_DNSMASQ=1
  1229.            ;;
  1230.        --redirect-to-localhost)
  1231.            shift
  1232.            REDIRECT_TO_LOCALHOST=1
  1233.            ;;
  1234.        --hostapd-debug)
  1235.            shift
  1236.            if [ "x$1" = "x1" ]; then
  1237.                HOSTAPD_DEBUG_ARGS="-d"
  1238.            elif [ "x$1" = "x2" ]; then
  1239.                HOSTAPD_DEBUG_ARGS="-dd"
  1240.            else
  1241.                printf "Error: argument for --hostapd-debug expected 1 or 2, got %s\n" "$1"
  1242.                exit 1
  1243.            fi
  1244.            shift
  1245.            ;;
  1246.        --mkconfig)
  1247.            shift
  1248.            STORE_CONFIG="$1"
  1249.            shift
  1250.            ;;
  1251.        --config)
  1252.            shift
  1253.            shift
  1254.            ;;
  1255.        --)
  1256.            shift
  1257.            break
  1258.            ;;
  1259.    esac
  1260. done
  1261.  
  1262. # Load positional args from config file, if needed
  1263. if [[ -n "$LOAD_CONFIG" && $# -eq 0 ]]; then
  1264.    i=0
  1265.    # set arguments in order
  1266.    for x in WIFI_IFACE INTERNET_IFACE SSID PASSPHRASE; do
  1267.        if eval "[[ -n \"\$${x}\" ]]"; then
  1268.            eval "set -- \"\${@:1:$i}\" \"\$${x}\""
  1269.            ((i++))
  1270.        fi
  1271.        # we unset the variable to avoid any problems later
  1272.        eval "unset $x"
  1273.    done
  1274. fi
  1275.  
  1276. # Check if required number of positional args are present
  1277. if [[ $# -lt 1 && $FIX_UNMANAGED -eq 0  && -z "$STOP_ID" &&
  1278.      $LIST_RUNNING -eq 0 && -z "$LIST_CLIENTS_ID" ]]; then
  1279.    usage >&2
  1280.    exit 1
  1281. fi
  1282.  
  1283. # Set NO_DNS, if dnsmasq is disabled
  1284. if [[ $NO_DNSMASQ -eq 1 ]]; then
  1285.  NO_DNS=1
  1286. fi
  1287.  
  1288. trap "cleanup_lock" EXIT
  1289.  
  1290. if ! init_lock; then
  1291.    echo "ERROR: Failed to initialize lock" >&2
  1292.    exit 1
  1293. fi
  1294.  
  1295. # if the user press ctrl+c or we get USR1 signal
  1296. # then run clean_exit()
  1297. trap "clean_exit" SIGINT SIGUSR1
  1298. # if we get USR2 signal then run die().
  1299. trap "die" SIGUSR2
  1300.  
  1301. [[ -n "$STORE_CONFIG" ]] && write_config "$@"
  1302.  
  1303. if [[ $LIST_RUNNING -eq 1 ]]; then
  1304.    #echo -e "List of running $PROGNAME instances:\n"
  1305.    list_running
  1306.    exit 0
  1307. fi
  1308.  
  1309. if [[ -n "$LIST_CLIENTS_ID" ]]; then
  1310.    list_clients "$LIST_CLIENTS_ID"
  1311.    exit 0
  1312. fi
  1313.  
  1314. if [[ $(id -u) -ne 0 ]]; then
  1315.    echo "create_ap must be run as root." >&2
  1316.    exit 1
  1317. fi
  1318.  
  1319. if [[ -n "$STOP_ID" ]]; then
  1320.    echo "Trying to kill $PROGNAME instance associated with $STOP_ID..."
  1321.    send_stop "$STOP_ID"
  1322.    exit 0
  1323. fi
  1324.  
  1325. if [[ $FIX_UNMANAGED -eq 1 ]]; then
  1326.    echo "Trying to fix unmanaged status in NetworkManager..."
  1327.    networkmanager_fix_unmanaged
  1328.    exit 0
  1329. fi
  1330.  
  1331. if [[ $DAEMONIZE -eq 1 && $RUNNING_AS_DAEMON -eq 0 ]]; then
  1332.    # Assume we're running underneath a service manager if PIDFILE is set
  1333.    # and don't clobber it's output with a useless message
  1334.    if [ -z "$DAEMON_PIDFILE" ]; then
  1335.        echo "Running as Daemon..."
  1336.    fi
  1337.    # run a detached create_ap
  1338.    RUNNING_AS_DAEMON=1 setsid "$0" "${ARGS[@]}" >>$DAEMON_LOGFILE 2>&1 &
  1339.    exit 0
  1340. elif [[ $RUNNING_AS_DAEMON -eq 1 && -n "$DAEMON_PIDFILE" ]]; then
  1341.    echo $$ >$DAEMON_PIDFILE
  1342. fi
  1343.  
  1344. if [[ $FREQ_BAND != 2.4 && $FREQ_BAND != 5 ]]; then
  1345.    echo "ERROR: Invalid frequency band" >&2
  1346.    exit 1
  1347. fi
  1348.  
  1349. if [[ $CHANNEL == default ]]; then
  1350.    if [[ $FREQ_BAND == 2.4 ]]; then
  1351.        CHANNEL=1
  1352.    else
  1353.        CHANNEL=36
  1354.    fi
  1355. fi
  1356.  
  1357. if [[ $FREQ_BAND != 5 && $CHANNEL -gt 14 ]]; then
  1358.    echo "Channel number is greater than 14, assuming 5GHz frequency band"
  1359.    FREQ_BAND=5
  1360. fi
  1361.  
  1362. WIFI_IFACE=$1
  1363.  
  1364. if ! is_wifi_interface ${WIFI_IFACE}; then
  1365.    echo "ERROR: '${WIFI_IFACE}' is not a WiFi interface" >&2
  1366.    exit 1
  1367. fi
  1368.  
  1369. if ! can_be_ap ${WIFI_IFACE}; then
  1370.    echo "ERROR: Your adapter does not support AP (master) mode" >&2
  1371.    exit 1
  1372. fi
  1373.  
  1374. if ! can_be_sta_and_ap ${WIFI_IFACE}; then
  1375.    if is_wifi_connected ${WIFI_IFACE}; then
  1376.        echo "ERROR: Your adapter can not be a station (i.e. be connected) and an AP at the same time" >&2
  1377.        exit 1
  1378.    elif [[ $NO_VIRT -eq 0 ]]; then
  1379.        echo "WARN: Your adapter does not fully support AP virtual interface, enabling --no-virt" >&2
  1380.        NO_VIRT=1
  1381.    fi
  1382. fi
  1383.  
  1384. HOSTAPD=$(which hostapd)
  1385.  
  1386. if [[ ! -x "$HOSTAPD" ]]; then
  1387.    echo "ERROR: hostapd not found." >&2
  1388.    exit 1
  1389. fi
  1390.  
  1391. if [[ $(get_adapter_kernel_module ${WIFI_IFACE}) =~ ^(8192[cd][ue]|8723a[sue])$ ]]; then
  1392.    if ! strings "$HOSTAPD" | grep -m1 rtl871xdrv > /dev/null 2>&1; then
  1393.        echo "ERROR: You need to patch your hostapd with rtl871xdrv patches." >&2
  1394.        exit 1
  1395.    fi
  1396.  
  1397.    if [[ $DRIVER != "rtl871xdrv" ]]; then
  1398.        echo "WARN: Your adapter needs rtl871xdrv, enabling --driver=rtl871xdrv" >&2
  1399.        DRIVER=rtl871xdrv
  1400.    fi
  1401. fi
  1402.  
  1403. if [[ "$SHARE_METHOD" != "nat" && "$SHARE_METHOD" != "bridge" && "$SHARE_METHOD" != "none" ]]; then
  1404.    echo "ERROR: Wrong Internet sharing method" >&2
  1405.    echo
  1406.    usage >&2
  1407.    exit 1
  1408. fi
  1409.  
  1410. if [[ -n "$NEW_MACADDR" ]]; then
  1411.    if ! is_macaddr "$NEW_MACADDR"; then
  1412.        echo "ERROR: '${NEW_MACADDR}' is not a valid MAC address" >&2
  1413.        exit 1
  1414.    fi
  1415.  
  1416.    if ! is_unicast_macaddr "$NEW_MACADDR"; then
  1417.        echo "ERROR: The first byte of MAC address (${NEW_MACADDR}) must be even" >&2
  1418.        exit 1
  1419.    fi
  1420.  
  1421.    if [[ $(get_all_macaddrs | grep -c ${NEW_MACADDR}) -ne 0 ]]; then
  1422.        echo "WARN: MAC address '${NEW_MACADDR}' already exists. Because of this, you may encounter some problems" >&2
  1423.    fi
  1424. fi
  1425.  
  1426. if [[ "$SHARE_METHOD" != "none" ]]; then
  1427.    MIN_REQUIRED_ARGS=2
  1428. else
  1429.    MIN_REQUIRED_ARGS=1
  1430. fi
  1431.  
  1432. if [[ $# -gt $MIN_REQUIRED_ARGS ]]; then
  1433.    if [[ "$SHARE_METHOD" != "none" ]]; then
  1434.        if [[ $# -ne 3 && $# -ne 4 ]]; then
  1435.            usage >&2
  1436.            exit 1
  1437.        fi
  1438.        INTERNET_IFACE="$2"
  1439.        SSID="$3"
  1440.        PASSPHRASE="$4"
  1441.    else
  1442.        if [[ $# -ne 2 && $# -ne 3 ]]; then
  1443.            usage >&2
  1444.            exit 1
  1445.        fi
  1446.        SSID="$2"
  1447.        PASSPHRASE="$3"
  1448.    fi
  1449. else
  1450.    if [[ "$SHARE_METHOD" != "none" ]]; then
  1451.        if [[ $# -ne 2 ]]; then
  1452.            usage >&2
  1453.            exit 1
  1454.        fi
  1455.        INTERNET_IFACE="$2"
  1456.    fi
  1457.    if tty -s; then
  1458.        while :; do
  1459.            read -p "SSID: " SSID
  1460.            if [[ ${#SSID} -lt 1 || ${#SSID} -gt 32 ]]; then
  1461.                echo "ERROR: Invalid SSID length ${#SSID} (expected 1..32)" >&2
  1462.                continue
  1463.            fi
  1464.            break
  1465.        done
  1466.        while :; do
  1467.            if [[ $USE_PSK -eq 0 ]]; then
  1468.                read -p "Passphrase: " -s PASSPHRASE
  1469.                echo
  1470.                if [[ ${#PASSPHRASE} -gt 0 && ${#PASSPHRASE} -lt 8 ]] || [[ ${#PASSPHRASE} -gt 63 ]]; then
  1471.                    echo "ERROR: Invalid passphrase length ${#PASSPHRASE} (expected 8..63)" >&2
  1472.                    continue
  1473.                fi
  1474.                read -p "Retype passphrase: " -s PASSPHRASE2
  1475.                echo
  1476.                if [[ "$PASSPHRASE" != "$PASSPHRASE2" ]]; then
  1477.                    echo "Passphrases do not match."
  1478.                else
  1479.                    break
  1480.                fi
  1481.            else
  1482.                read -p "PSK: " PASSPHRASE
  1483.                echo
  1484.                if [[ ${#PASSPHRASE} -gt 0 && ${#PASSPHRASE} -ne 64 ]]; then
  1485.                    echo "ERROR: Invalid pre-shared-key length ${#PASSPHRASE} (expected 64)" >&2
  1486.                    continue
  1487.                fi
  1488.            fi
  1489.        done
  1490.    else
  1491.        read SSID
  1492.        read PASSPHRASE
  1493.    fi
  1494. fi
  1495.  
  1496. if [[ "$SHARE_METHOD" != "none" ]] && ! is_interface $INTERNET_IFACE; then
  1497.    echo "ERROR: '${INTERNET_IFACE}' is not an interface" >&2
  1498.    exit 1
  1499. fi
  1500.  
  1501. if [[ ${#SSID} -lt 1 || ${#SSID} -gt 32 ]]; then
  1502.    echo "ERROR: Invalid SSID length ${#SSID} (expected 1..32)" >&2
  1503.    exit 1
  1504. fi
  1505.  
  1506. if [[ $USE_PSK -eq 0 ]]; then
  1507.    if [[ ${#PASSPHRASE} -gt 0 && ${#PASSPHRASE} -lt 8 ]] || [[ ${#PASSPHRASE} -gt 63 ]]; then
  1508.        echo "ERROR: Invalid passphrase length ${#PASSPHRASE} (expected 8..63)" >&2
  1509.        exit 1
  1510.    fi
  1511. elif [[ ${#PASSPHRASE} -gt 0 && ${#PASSPHRASE} -ne 64 ]]; then
  1512.    echo "ERROR: Invalid pre-shared-key length ${#PASSPHRASE} (expected 64)" >&2
  1513.    exit 1
  1514. fi
  1515.  
  1516. if [[ $(get_adapter_kernel_module ${WIFI_IFACE}) =~ ^rtl[0-9].*$ ]]; then
  1517.    if [[ -n "$PASSPHRASE" ]]; then
  1518.        echo "WARN: Realtek drivers usually have problems with WPA1, enabling -w 2" >&2
  1519.        WPA_VERSION=2
  1520.    fi
  1521.    echo "WARN: If AP doesn't work, please read: howto/realtek.md" >&2
  1522. fi
  1523.  
  1524. if [[ $NO_VIRT -eq 1 && "$WIFI_IFACE" == "$INTERNET_IFACE" ]]; then
  1525.    echo -n "ERROR: You can not share your connection from the same" >&2
  1526.    echo " interface if you are using --no-virt option." >&2
  1527.    exit 1
  1528. fi
  1529.  
  1530. mutex_lock
  1531. trap "cleanup" EXIT
  1532. CONFDIR=$(mktemp -d /tmp/create_ap.${WIFI_IFACE}.conf.XXXXXXXX)
  1533. echo "Config dir: $CONFDIR"
  1534. echo "PID: $$"
  1535. echo $$ > $CONFDIR/pid
  1536.  
  1537. # to make --list-running work from any user, we must give read
  1538. # permissions to $CONFDIR and $CONFDIR/pid
  1539. chmod 755 $CONFDIR
  1540. chmod 444 $CONFDIR/pid
  1541.  
  1542. COMMON_CONFDIR=/tmp/create_ap.common.conf
  1543. mkdir -p $COMMON_CONFDIR
  1544.  
  1545. if [[ "$SHARE_METHOD" == "nat" ]]; then
  1546.    echo $INTERNET_IFACE > $CONFDIR/nat_internet_iface
  1547.    cp_n /proc/sys/net/ipv4/conf/$INTERNET_IFACE/forwarding \
  1548.       $COMMON_CONFDIR/${INTERNET_IFACE}_forwarding
  1549. fi
  1550. cp_n /proc/sys/net/ipv4/ip_forward $COMMON_CONFDIR
  1551. if [[ -e /proc/sys/net/bridge/bridge-nf-call-iptables ]]; then
  1552.    cp_n /proc/sys/net/bridge/bridge-nf-call-iptables $COMMON_CONFDIR
  1553. fi
  1554. mutex_unlock
  1555.  
  1556. if [[ "$SHARE_METHOD" == "bridge" ]]; then
  1557.    if is_bridge_interface $INTERNET_IFACE; then
  1558.        BRIDGE_IFACE=$INTERNET_IFACE
  1559.    else
  1560.        BRIDGE_IFACE=$(alloc_new_iface br)
  1561.    fi
  1562. fi
  1563.  
  1564. if [[ $USE_IWCONFIG -eq 0 ]]; then
  1565.    iw dev ${WIFI_IFACE} set power_save off
  1566. fi
  1567.  
  1568. if [[ $NO_VIRT -eq 0 ]]; then
  1569.    VWIFI_IFACE=$(alloc_new_iface ap)
  1570.  
  1571.    # in NetworkManager 0.9.9 and above we can set the interface as unmanaged without
  1572.    # the need of MAC address, so we set it before we create the virtual interface.
  1573.    if networkmanager_is_running && [[ $NM_OLDER_VERSION -eq 0 ]]; then
  1574.        echo -n "Network Manager found, set ${VWIFI_IFACE} as unmanaged device... "
  1575.        networkmanager_add_unmanaged ${VWIFI_IFACE}
  1576.        # do not call networkmanager_wait_until_unmanaged because interface does not
  1577.        # exist yet
  1578.        echo "DONE"
  1579.    fi
  1580.  
  1581.  
  1582.    if is_wifi_connected ${WIFI_IFACE} && [[ $FREQ_BAND_SET -eq 0 ]]; then
  1583.        WIFI_IFACE_FREQ=$(iw dev ${WIFI_IFACE} link | grep -i freq | awk '{print $2}')
  1584.        WIFI_IFACE_CHANNEL=$(ieee80211_frequency_to_channel ${WIFI_IFACE_FREQ})
  1585.        echo -n "${WIFI_IFACE} is already associated with channel ${WIFI_IFACE_CHANNEL} (${WIFI_IFACE_FREQ} MHz)"
  1586.        if is_5ghz_frequency $WIFI_IFACE_FREQ; then
  1587.            FREQ_BAND=5
  1588.        else
  1589.            FREQ_BAND=2.4
  1590.        fi
  1591.        if [[ $WIFI_IFACE_CHANNEL -ne $CHANNEL ]]; then
  1592.            if ( get_adapter_info ${IFACE} | grep "#channels <= 2" -q )
  1593.            then
  1594.                echo -e "\nmultiple channels supported"
  1595.            else
  1596.                echo -e  "\nmultiple channels not supported",
  1597.                echo -e  "\nfallback to channel ${WIFI_IFACE_CHANNEL}"
  1598.                CHANNEL=$WIFI_IFACE_CHANNEL
  1599.            fi
  1600.        else
  1601.            echo "channel------------------ ${CHANNEL}"
  1602.        fi
  1603.    elif is_wifi_connected ${WIFI_IFACE} && [[ $FREQ_BAND_SET -eq 1 ]]; then
  1604.        echo "Custom frequency band set with ${FREQ_BAND}Mhz with channel ${CHANNEL}"
  1605.    fi
  1606.  
  1607.  
  1608.    VIRTDIEMSG="Maybe your WiFi adapter does not fully support virtual interfaces.
  1609.       Try again with --no-virt."
  1610.    echo -n "Creating a virtual WiFi interface... "
  1611.  
  1612.    if iw dev ${WIFI_IFACE} interface add ${VWIFI_IFACE} type __ap; then
  1613.        # now we can call networkmanager_wait_until_unmanaged
  1614.        networkmanager_is_running && [[ $NM_OLDER_VERSION -eq 0 ]] && networkmanager_wait_until_unmanaged ${VWIFI_IFACE}
  1615.        echo "${VWIFI_IFACE} created."
  1616.    else
  1617.        VWIFI_IFACE=
  1618.        die "$VIRTDIEMSG"
  1619.    fi
  1620.    OLD_MACADDR=$(get_macaddr ${VWIFI_IFACE})
  1621.    if [[ -z "$NEW_MACADDR" && $(get_all_macaddrs | grep -c ${OLD_MACADDR}) -ne 1 ]]; then
  1622.        NEW_MACADDR=$(get_new_macaddr ${VWIFI_IFACE})
  1623.    fi
  1624.    WIFI_IFACE=${VWIFI_IFACE}
  1625. else
  1626.    OLD_MACADDR=$(get_macaddr ${WIFI_IFACE})
  1627. fi
  1628.  
  1629. mutex_lock
  1630. echo $WIFI_IFACE > $CONFDIR/wifi_iface
  1631. chmod 444 $CONFDIR/wifi_iface
  1632. mutex_unlock
  1633.  
  1634. if [[ -n "$COUNTRY" && $USE_IWCONFIG -eq 0 ]]; then
  1635.    iw reg set "$COUNTRY"
  1636. fi
  1637.  
  1638. can_transmit_to_channel ${WIFI_IFACE} ${CHANNEL} || die "Your adapter can not transmit to channel ${CHANNEL}, frequency band ${FREQ_BAND}GHz."
  1639.  
  1640. if networkmanager_exists && ! networkmanager_iface_is_unmanaged ${WIFI_IFACE}; then
  1641.    echo -n "Network Manager found, set ${WIFI_IFACE} as unmanaged device... "
  1642.    networkmanager_add_unmanaged ${WIFI_IFACE}
  1643.  
  1644.    if networkmanager_is_running; then
  1645.        networkmanager_wait_until_unmanaged ${WIFI_IFACE}
  1646.    fi
  1647.  
  1648.    echo "DONE"
  1649. fi
  1650.  
  1651. [[ $HIDDEN -eq 1 ]] && echo "Access Point's SSID is hidden!"
  1652.  
  1653. [[ $MAC_FILTER -eq 1 ]] && echo "MAC address filtering is enabled!"
  1654.  
  1655. [[ $ISOLATE_CLIENTS -eq 1 ]] && echo "Access Point's clients will be isolated!"
  1656.  
  1657. # hostapd config
  1658. cat << EOF > $CONFDIR/hostapd.conf
  1659. beacon_int=100
  1660. ssid=${SSID}
  1661. interface=${WIFI_IFACE}
  1662. driver=${DRIVER}
  1663. channel=${CHANNEL}
  1664. ctrl_interface=$CONFDIR/hostapd_ctrl
  1665. ctrl_interface_group=0
  1666. ignore_broadcast_ssid=$HIDDEN
  1667. ap_isolate=$ISOLATE_CLIENTS
  1668. EOF
  1669.  
  1670. if [[ -n "$COUNTRY" ]]; then
  1671.    cat << EOF >> $CONFDIR/hostapd.conf
  1672. country_code=${COUNTRY}
  1673. ieee80211d=1
  1674. ieee80211h=1
  1675. EOF
  1676. fi
  1677.  
  1678. if [[ $FREQ_BAND == 2.4 ]]; then
  1679.    echo "hw_mode=g" >> $CONFDIR/hostapd.conf
  1680. else
  1681.    echo "hw_mode=a" >> $CONFDIR/hostapd.conf
  1682. fi
  1683.  
  1684. if [[ $MAC_FILTER -eq 1 ]]; then
  1685.    cat << EOF >> $CONFDIR/hostapd.conf
  1686. macaddr_acl=${MAC_FILTER}
  1687. accept_mac_file=${MAC_FILTER_ACCEPT}
  1688. EOF
  1689. fi
  1690.  
  1691. if [[ $IEEE80211N -eq 1 ]]; then
  1692.    cat << EOF >> $CONFDIR/hostapd.conf
  1693. ieee80211n=1
  1694. ht_capab=${HT_CAPAB}
  1695. EOF
  1696. fi
  1697.  
  1698. if [[ $IEEE80211AC -eq 1 ]]; then
  1699.    echo "ieee80211ac=1" >> $CONFDIR/hostapd.conf
  1700. fi
  1701.  
  1702. if [[ $IEEE80211AX -eq 1 ]]; then
  1703.    echo "ieee80211ax=1" >> $CONFDIR/hostapd.conf
  1704.    echo "he_oper_chwidth=1" >> $CONFDIR/hostapd.conf
  1705.    echo "he_oper_centr_freq_seg0_idx=42" >> $CONFDIR/hostapd.conf
  1706.    echo "he_su_beamformee=1" >> $CONFDIR/hostapd.conf
  1707. fi
  1708.  
  1709. if [[ -n "$VHT_CAPAB" ]]; then
  1710.    echo "vht_capab=${VHT_CAPAB}" >> $CONFDIR/hostapd.conf
  1711.    echo "vht_oper_chwidth=1" >> $CONFDIR/hostapd.conf
  1712.    echo "vht_oper_centr_freq_seg0_idx=42" >> $CONFDIR/hostapd.conf
  1713.    #echo "vht_oper_centr_freq_seg1_idx=155" >> $CONFDIR/hostapd.conf
  1714.    fi
  1715.  
  1716. if [[ $IEEE80211N -eq 1 ]] || [[ $IEEE80211AC ]] || [[ $IEEE80211AX -eq 1 ]]; then
  1717.    echo "wmm_enabled=1" >> $CONFDIR/hostapd.conf
  1718. fi
  1719.  
  1720. if [[ -n "$PASSPHRASE" ]]; then
  1721.    [[ "$WPA_VERSION" == "1+2" ]] && WPA_VERSION=3
  1722.    if [[ $USE_PSK -eq 0 ]]; then
  1723.        WPA_KEY_TYPE=passphrase
  1724.    else
  1725.        WPA_KEY_TYPE=psk
  1726.    fi
  1727.    cat << EOF >> $CONFDIR/hostapd.conf
  1728. wpa=${WPA_VERSION}
  1729. wpa_${WPA_KEY_TYPE}=${PASSPHRASE}
  1730. wpa_key_mgmt=WPA-PSK
  1731. wpa_pairwise=TKIP CCMP
  1732. rsn_pairwise=CCMP
  1733. EOF
  1734. fi
  1735.  
  1736. if [[ "$SHARE_METHOD" == "bridge" ]]; then
  1737.    echo "bridge=${BRIDGE_IFACE}" >> $CONFDIR/hostapd.conf
  1738. elif [[ $NO_DNSMASQ -eq 0 ]]; then
  1739.    # dnsmasq config (dhcp + dns)
  1740.    DNSMASQ_VER=$(dnsmasq -v | grep -m1 -oE '[0-9]+(\.[0-9]+)*\.[0-9]+')
  1741.    version_cmp $DNSMASQ_VER 2.63
  1742.    if [[ $? -eq 1 ]]; then
  1743.        DNSMASQ_BIND=bind-interfaces
  1744.    else
  1745.        DNSMASQ_BIND=bind-dynamic
  1746.    fi
  1747.    if [[ "$DHCP_DNS" == "gateway" ]]; then
  1748.        DHCP_DNS="$GATEWAY"
  1749.    fi
  1750.    cat << EOF > $CONFDIR/dnsmasq.conf
  1751. listen-address=${GATEWAY}
  1752. ${DNSMASQ_BIND}
  1753. dhcp-range=${GATEWAY%.*}.1,${GATEWAY%.*}.254,255.255.255.0,24h
  1754. dhcp-option-force=option:router,${GATEWAY}
  1755. dhcp-option-force=option:dns-server,${DHCP_DNS}
  1756. EOF
  1757.    MTU=$(get_mtu $INTERNET_IFACE)
  1758.    [[ -n "$MTU" ]] && echo "dhcp-option-force=option:mtu,${MTU}" >> $CONFDIR/dnsmasq.conf
  1759.    [[ $ETC_HOSTS -eq 0 ]] && echo no-hosts >> $CONFDIR/dnsmasq.conf
  1760.    [[ -n "$ADDN_HOSTS" ]] && echo "addn-hosts=${ADDN_HOSTS}" >> $CONFDIR/dnsmasq.conf
  1761.    if [[ "$SHARE_METHOD" == "none" && "$REDIRECT_TO_LOCALHOST" == "1" ]]; then
  1762.        cat << EOF >> $CONFDIR/dnsmasq.conf
  1763. address=/#/$GATEWAY
  1764. EOF
  1765.    fi
  1766. fi
  1767.  
  1768. # initialize WiFi interface
  1769. if [[ $NO_VIRT -eq 0 && -n "$NEW_MACADDR" ]]; then
  1770.    ip link set dev ${WIFI_IFACE} address ${NEW_MACADDR} || die "$VIRTDIEMSG"
  1771. fi
  1772.  
  1773. ip link set down dev ${WIFI_IFACE} || die "$VIRTDIEMSG"
  1774. ip addr flush ${WIFI_IFACE} || die "$VIRTDIEMSG"
  1775.  
  1776. if [[ $NO_VIRT -eq 1 && -n "$NEW_MACADDR" ]]; then
  1777.    ip link set dev ${WIFI_IFACE} address ${NEW_MACADDR} || die
  1778. fi
  1779.  
  1780. if [[ "$SHARE_METHOD" != "bridge" ]]; then
  1781.    ip link set up dev ${WIFI_IFACE} || die "$VIRTDIEMSG"
  1782.    ip addr add ${GATEWAY}/24 broadcast ${GATEWAY%.*}.255 dev ${WIFI_IFACE} || die "$VIRTDIEMSG"
  1783. fi
  1784.  
  1785. # enable Internet sharing
  1786. if [[ "$SHARE_METHOD" != "none" ]]; then
  1787.    echo "Sharing Internet using method: $SHARE_METHOD"
  1788.    if [[ "$SHARE_METHOD" == "nat" ]]; then
  1789.        iptables -w -t nat -I POSTROUTING -s ${GATEWAY%.*}.0/24 ! -o ${WIFI_IFACE} -j MASQUERADE || die
  1790.        iptables -w -I FORWARD -i ${WIFI_IFACE} -s ${GATEWAY%.*}.0/24 -j ACCEPT || die
  1791.        iptables -w -I FORWARD -i ${INTERNET_IFACE} -d ${GATEWAY%.*}.0/24 -j ACCEPT || die
  1792.        echo 1 > /proc/sys/net/ipv4/conf/$INTERNET_IFACE/forwarding || die
  1793.        echo 1 > /proc/sys/net/ipv4/ip_forward || die
  1794.        # to enable clients to establish PPTP connections we must
  1795.        # load nf_nat_pptp module
  1796.        modprobe nf_nat_pptp > /dev/null 2>&1
  1797.    elif [[ "$SHARE_METHOD" == "bridge" ]]; then
  1798.        # disable iptables rules for bridged interfaces
  1799.        if [[ -e /proc/sys/net/bridge/bridge-nf-call-iptables ]]; then
  1800.            echo 0 > /proc/sys/net/bridge/bridge-nf-call-iptables
  1801.        fi
  1802.  
  1803.        # to initialize the bridge interface correctly we need to do the following:
  1804.        #
  1805.        # 1) save the IPs and route table of INTERNET_IFACE
  1806.        # 2) if NetworkManager is running set INTERNET_IFACE as unmanaged
  1807.        # 3) create BRIDGE_IFACE and attach INTERNET_IFACE to it
  1808.        # 4) set the previously saved IPs and route table to BRIDGE_IFACE
  1809.        #
  1810.        # we need the above because BRIDGE_IFACE is the master interface from now on
  1811.        # and it must know where is connected, otherwise connection is lost.
  1812.        if ! is_bridge_interface $INTERNET_IFACE; then
  1813.            echo -n "Create a bridge interface... "
  1814.            OLD_IFS="$IFS"
  1815.            IFS=$'\n'
  1816.  
  1817.            IP_ADDRS=( $(ip addr show $INTERNET_IFACE | grep -A 1 -E 'inet[[:blank:]]' | paste - -) )
  1818.            ROUTE_ADDRS=( $(ip route show dev $INTERNET_IFACE) )
  1819.  
  1820.            IFS="$OLD_IFS"
  1821.  
  1822.            if networkmanager_is_running; then
  1823.                networkmanager_add_unmanaged $INTERNET_IFACE
  1824.                networkmanager_wait_until_unmanaged $INTERNET_IFACE
  1825.            fi
  1826.  
  1827.            # create bridge interface
  1828.            ip link add name $BRIDGE_IFACE type bridge || die
  1829.            ip link set dev $BRIDGE_IFACE up || die
  1830.            # set 0ms forward delay
  1831.            echo -n 0 > /sys/class/net/$BRIDGE_IFACE/bridge/forward_delay
  1832.  
  1833.            # attach internet interface to bridge interface
  1834.            ip link set dev $INTERNET_IFACE promisc on || die
  1835.            ip link set dev $INTERNET_IFACE up || die
  1836.            ip link set dev $INTERNET_IFACE master $BRIDGE_IFACE || die
  1837.  
  1838.            ip addr flush $INTERNET_IFACE
  1839.            for x in "${IP_ADDRS[@]}"; do
  1840.                x="${x/inet/}"
  1841.                x="${x/secondary/}"
  1842.                x="${x/dynamic/}"
  1843.                x=$(echo $x | sed 's/\([0-9]\)sec/\1/g')
  1844.                x="${x/${INTERNET_IFACE}/}"
  1845.                ip addr add $x dev $BRIDGE_IFACE || die
  1846.            done
  1847.  
  1848.            # remove any existing entries that were added from 'ip addr add'
  1849.            ip route flush dev $INTERNET_IFACE
  1850.            ip route flush dev $BRIDGE_IFACE
  1851.  
  1852.            # we must first add the entries that specify the subnets and then the
  1853.            # gateway entry, otherwise 'ip addr add' will return an error
  1854.            for x in "${ROUTE_ADDRS[@]}"; do
  1855.                [[ "$x" == default* ]] && continue
  1856.                ip route add $x dev $BRIDGE_IFACE || die
  1857.            done
  1858.  
  1859.            for x in "${ROUTE_ADDRS[@]}"; do
  1860.                [[ "$x" != default* ]] && continue
  1861.                ip route add $x dev $BRIDGE_IFACE || die
  1862.            done
  1863.  
  1864.            echo "$BRIDGE_IFACE created."
  1865.        fi
  1866.    fi
  1867. else
  1868.    echo "No Internet sharing"
  1869. fi
  1870.  
  1871. # start dhcp + dns (optional)
  1872. if [[ "$SHARE_METHOD" != "bridge" ]]; then
  1873.    if [[ $NO_DNS -eq 0 ]]; then
  1874.        DNS_PORT=5353
  1875.        iptables -w -I INPUT -p tcp -m tcp --dport $DNS_PORT -j ACCEPT || die
  1876.        iptables -w -I INPUT -p udp -m udp --dport $DNS_PORT -j ACCEPT || die
  1877.        iptables -w -t nat -I PREROUTING -s ${GATEWAY%.*}.0/24 -d ${GATEWAY} \
  1878.            -p tcp -m tcp --dport 53 -j REDIRECT --to-ports $DNS_PORT || die
  1879.        iptables -w -t nat -I PREROUTING -s ${GATEWAY%.*}.0/24 -d ${GATEWAY} \
  1880.            -p udp -m udp --dport 53 -j REDIRECT --to-ports $DNS_PORT || die
  1881.    else
  1882.        DNS_PORT=0
  1883.    fi
  1884.  
  1885.    if [[ $NO_DNSMASQ -eq 0 ]]; then
  1886.      iptables -w -I INPUT -p udp -m udp --dport 67 -j ACCEPT || die
  1887.  
  1888.      if which complain > /dev/null 2>&1; then
  1889.          # openSUSE's apparmor does not allow dnsmasq to read files.
  1890.          # remove restriction.
  1891.          complain dnsmasq
  1892.      fi
  1893.  
  1894.      umask 0033
  1895.      dnsmasq -C $CONFDIR/dnsmasq.conf -x $CONFDIR/dnsmasq.pid -l $CONFDIR/dnsmasq.leases -p $DNS_PORT || die
  1896.      umask $SCRIPT_UMASK
  1897.    fi
  1898. fi
  1899.  
  1900. # start access point
  1901. echo "hostapd command-line interface: hostapd_cli -p $CONFDIR/hostapd_ctrl"
  1902.  
  1903. if [[ $NO_HAVEGED -eq 0 ]]; then
  1904.    haveged_watchdog &
  1905.    HAVEGED_WATCHDOG_PID=$!
  1906. fi
  1907.  
  1908. # start hostapd (use stdbuf when available for no delayed output in programs that redirect stdout)
  1909. STDBUF_PATH=`which stdbuf`
  1910. if [ $? -eq 0 ]; then
  1911.    STDBUF_PATH=$STDBUF_PATH" -oL"
  1912. fi
  1913. $STDBUF_PATH $HOSTAPD $HOSTAPD_DEBUG_ARGS $CONFDIR/hostapd.conf &
  1914. HOSTAPD_PID=$!
  1915. echo $HOSTAPD_PID > $CONFDIR/hostapd.pid
  1916.  
  1917. if ! wait $HOSTAPD_PID; then
  1918.    echo -e "\nError: Failed to run hostapd, maybe a program is interfering." >&2
  1919.    if networkmanager_is_running; then
  1920.        echo "If an error like 'n80211: Could not configure driver mode' was thrown" >&2
  1921.        echo "try running the following before starting create_ap:" >&2
  1922.        if [[ $NM_OLDER_VERSION -eq 1 ]]; then
  1923.            echo "    nmcli nm wifi off" >&2
  1924.        else
  1925.            echo "    nmcli r wifi off" >&2
  1926.        fi
  1927.        echo "    rfkill unblock wlan" >&2
  1928.    fi
  1929.    die
  1930. fi
  1931.  
  1932. clean_exit
  1933.  
  1934. # Local Variables:
  1935. # tab-width: 4
  1936. # indent-tabs-mode: nil
  1937. # End:
  1938.  
  1939. # vim: et sts=4 sw=4
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement