PSI Report

2024-07-03

Background of this project

Working at a university means a lot of things, but also a lot of external dependencies and factors that can support the work. But those same things can also make it more difficult. One of them is Wifi. However, if we focus on the wifi at our university, we can assume that hardly anyone will claim that it works perfectly. To be more precise, many students and others who depend on it will confirm the existing lack of proper wifi connection. As a result, students (myself included) are unable to work for several hours. Therefore, the goal of this project is to understand if this is a subjective perception or if the wifi is really as bad as described.

Under these circumstances, an extensive measurement would be quite interesting, but since the effort (both financial and time) had to be limited, the following limitations were set:

  • we only measure our location (ERBA), which is only one of about 50 locations of the University of Bamberg
  • we measure the wifi connection with devices that are connected to the wifi 24/7 (in the optimal case)
  • We define the usability of the WLAN network later.
  • We measure in about 10 locations of the ERBA (mainly locations where there are a lot of students). Since the university has many locations, we can’t assume that the values we experience here are about the same in other locations, for this I want to countercheck my results with the official eduroam statistics, which we’ll take a look at in the next section.

Structure of the eduroam network

Before we start measuring data, let us have a quick look at the structure of Eduroam, because it is not as simple as a normal home network. Eduroam (short for education roaming) is a global network that provides WLAN access for researchers and educators in more than a hundred countries. In Germany alone, there are 2925 service locations with 2925 independent Identity Providers (1 location = 1 IdP, because each university has its own IdP). Compared to other countries, Germany has the most IdPs and ranks third in terms of service locations (behind Brazil and the USA). In Germany alone, there are over 700,000 requests per 2 hours at peak times. (over the last week of 10.06.2024 - 16.06.2024 [1]):

graphs.png

To get an idea of how active the German eduroam usage is, we compare the events reported to the central eduroam monitor (known as F-ticks). F-Ticks is a modular solution which provides a standardised message syntax for event reporting [3]. Looking at the event count table for the same period [2] , we see that Germany is in first place with over 27,000,000 requests.

Pasted image 20240617112533.png

Overall, we can see that Germany is an active user of eduroam, but we can also confirm our suspicion that the eduroam network does not work all the time (27M okay ticks and 5M fail ticks, resulting in ~16.88% failure).

Data mining - How and what we collected

What was the plan?

For a long time measurement (about 6 months) I wanted to reduce the effort of maintainability, which means that the software should be as simple as possible and store all the raw data so that the data analysis part can be done at the end, external dependencies on packages etc. should be kept as low as possible and the hardware should be placed in places where the risk of being stolen or manipulated is low. Since I did not need any specific hardware or high computing power, I decided to use Raspberry Pi 3 Model B, since it is based on a Linux operating system and has embedded wifi chips (which was the only requirement we had). In addition, each Pi came with a SanDisk SD card, a case, and an external power supply.

IMG_20240617_135709374.jpg

For the script on the pis, I wanted to reduce the amount of dependencies and possible integration problems, so I used bash with mostly basic linux tools. All logs were parsed into a single log file named {timestamp}-{hostname}.txt and uploaded at the end of the script to a simple php script on a central server which would then send a confirmation code, if this confirmation code was received the pi would delete the local log file, otherwise the log file would be saved for the next iteration and then the upload would be retried.

For the first version of the script, I measured the following parameters:

  • internal ping (server @ erba)
  • external ping (server @ cloudflare)
  • traceroute to external server
  • DNS check
  • Download file test (external server)
#!/bin/bash

host=pi01


externalFileDownloadUrl=https://psi-project.jochenmehlich.de/10MB.zip
testFileHash=f1c9645dbc14efddc7d8a322685f26eb

internalPingHost=141.13.129.225

logName=$(date +%s)"-"$host.txt

currentDay=$(date)
currentTime=$(uptime | head -n1 | cut -d " " -f2)
currentMinute=$(uptime | head -n1 | cut -d " " -f2 | cut -d ":" -f2)


echo "#*#NEWTEST " $currentDay >> $logName

# External Ping test
echo "#*#E-PingStart " $currentTime >> $logName
ping -c 20 1.1.1.1 >> $logName
echo "#*#E-PingEND" >> $logName

# External Ping Test End

# Internal Ping Test 
echo "#*#IPingStart" >> $logName
ping -c 20 $internalPingHost >> $logName
echo "#*#IPingEnd" >> $logName


# TraceRoute
echo "#*#TraceRouteStart" >> $logName
traceroute 1.1.1.1 >> $logName
echo "#*#TraceRouteEnd" >> $logName

# DNS Check
echo "#*#DNSCheckStart" >> $logName
dig jochenmehlich.de >> $logName
echo "#*#DNSCheckFinished" >> $logName

# 5-Minute Testing
if ! (($currentMinute % 5)); then

# External Download Test (5 Min)
SECONDS=0
echo "#*#EDOWNSTART Starting external Download test" >> $logName
wget $externalFileDownloadUrl --content-disposition -a $logName
echo "#*#EDOWNLOAD took: " $SECONDS >> $logName

fileHash=$(md5sum 10MB.zip | head -n1 | cut -d " " -f1)
rm 10MB.zip
[[ $testFileHash == $fileHash ]] && downloadValid=true || downloadValid=false

echo "#*#EDOWNLOADValid: " $downloadValid >> $logName

fi

echo "#*#TESTEND" >> $logName

# Try uploading logfile to main server
for filename in $(find . -maxdepth 1 -name \*.txt)
do
    if curl -F "uploadedfile=@./$filename" https://psi-project.jochenmehlich.de/upload.php | grep "uploadDone";
    then
        echo $filename "uploaded, deleting now"
        rm $filename
    else
        echo $filename "failed"
    fi
done

With a new version of the script, I added a full wifi range scan so that any wifi network within range of the raspi is logged, and also changed the download file from a 10MB file to a 1MB file to reduce bandwidth usage (10 measurements per minute x 10MB x 24h x 60 = 144GB). The reduction in bandwidth usage was implemented to be both responsible and less noticeable, as has often been preached at various Chaos Computer Club talks.

New version of the script:

#!/bin/bash

host=pi012_dekanat


externalFileDownloadUrl=https://psi-project.jochenmehlich.de/1MB.zip
testFileHash=63c75b582ff65e5d913bb495baff44f6

internalPingHost=141.13.129.225

logName=$(date +%s)"-"$host.txt

currentDay=$(date)
currentTime=$(uptime | head -n1 | cut -d " " -f2)
currentMinute=$(uptime | head -n1 | cut -d " " -f2 | cut -d ":" -f2)


echo "#*#NEWTEST " $currentDay >> $logName
echo "#*#WIFIScanStart" >> $logName

sudo iwlist wlan0 scan >> $logName

echo "#*#WIFIScanEnd" >> $logName
# External Ping test
echo "#*#E-PingStart " $currentTime >> $logName
ping -c 20 1.1.1.1 >> $logName
echo "#*#E-PingEND" >> $logName

# External Ping Test End

# Internal Ping Test 
echo "#*#IPingStart" >> $logName
ping -c 20 $internalPingHost >> $logName
echo "#*#IPingEnd" >> $logName


# TraceRoute
echo "#*#TraceRouteStart" >> $logName
traceroute 1.1.1.1 >> $logName
echo "#*#TraceRouteEnd" >> $logName

# DNS Check
echo "#*#DNSCheckStart" >> $logName
dig jochenmehlich.de >> $logName
echo "#*#DNSCheckFinished" >> $logName

# 5-Minute Testing
#if ! (($currentMinute % 5)); then

# External Download Test (5 Min)
SECONDS=0
fileTime=$(date +%s)
echo "#*#EDOWNSTART Starting external Download test" >> $logName
timeout 20s wget $externalFileDownloadUrl -O /root/$fileTime --content-disposition -a $logName
echo "#*#EDOWNLOAD took: " $SECONDS >> $logName

fileHash=$(md5sum /root/$fileTime | head -n1 | cut -d " " -f1)
rm /root/$fileTime
[[ $testFileHash == $fileHash ]] && downloadValid=true || downloadValid=false

echo "#*#EDOWNLOADValid: " $downloadValid >> $logName

#fi

echo "#*#TESTEND" >> $logName

# Try uploading logfile to main server
for filename in $(find . -maxdepth 1 -name \*.txt)
do
    if curl -F "uploadedfile=@./$filename" https://psi-project.jochenmehlich.de/upload.php | grep "uploadDone";
    then
        echo $filename "uploaded, deleting now"
        rm $filename
    else
        echo $filename "failed"
    fi
done

What data did we get?

If we look at the log file of a measurement, we get the following output:

#*#NEWTEST  Thu 19 Oct 11:41:01 BST 2023
#*#WIFIScanStart
wlan0     Scan completed :
          Cell 01 - Address: 9C:8C:D8:73:53:20
                    Channel:1
                    Frequency:2.412 GHz (Channel 1)
                    Quality=44/70  Signal level=-66 dBm  
                    Encryption key:on
                    ESSID:"eduroam"
                    Bit Rates:1 Mb/s; 2 Mb/s; 5.5 Mb/s; 11 Mb/s; 6 Mb/s
                              9 Mb/s; 12 Mb/s; 18 Mb/s
                    Bit Rates:24 Mb/s; 36 Mb/s; 48 Mb/s; 54 Mb/s
                    Mode:Master
                    Extra:tsf=0000000000000000
                    Extra: Last beacon: 40ms ago
                    IE: Unknown: 0007656475726F616D
                    IE: Unknown: 010802040B160C121824
                    IE: Unknown: 030101
                    IE: Unknown: 0706444520010D14
                    IE: Unknown: 200100
                    IE: Unknown: 23020800
                    IE: Unknown: 2A0103
                    IE: Unknown: 3204B0C8E0EC
                    IE: IEEE 802.11i/WPA2 Version 1
                        Group Cipher : CCMP
                        Pairwise Ciphers (1) : CCMP
                        Authentication Suites (2) : 802.1x unknown (5)
                    IE: Unknown: 0B0501001DA46C
                    IE: Unknown: 460573D001000D
                    IE: Unknown: 3305040105090D
                    IE: Unknown: 4306000CA46CA46C
                    IE: Unknown: 2D1AAD0903FFFFFFFF00000000000000000100000000000000000000
                    IE: Unknown: 3D1601000400000000000000000000000000000000000000
                    IE: Unknown: 7F0A04000800000000400040
                    IE: Unknown: FF1D230501081A4010006008881FC3831C010800AAFFAAFF1B1CC7711CC771
                    IE: Unknown: FF0724F43F0028FCFF
                    IE: Unknown: FF0E260F03A4FF27A4FF4243FF6232FF
                    IE: Unknown: DD180050F20201018F0003A4000027A4000042435E0062322F00
                    IE: Unknown: DD168CFDF0040000494C51030209720100000000FEFF0000
                    IE: Unknown: DD078CFDF004010100
          Cell 02 - Address: 9C:8C:D8:73:53:21
                    Channel:1
                    Frequency:2.412 GHz (Channel 1)
                    Quality=44/70  Signal level=-66 dBm  
                    Encryption key:off
                    ESSID:"@BayernWLAN "
                    Bit Rates:12 Mb/s; 18 Mb/s; 24 Mb/s; 36 Mb/s; 48 Mb/s
                              54 Mb/s
                    Mode:Master
                    Extra:tsf=0000000000000000
                    Extra: Last beacon: 40ms ago
                    IE: Unknown: 000C4042617965726E574C414E20
                    IE: Unknown: 01069824B048606C
                    IE: Unknown: 030101
                    IE: Unknown: 0706444520010D14
                    IE: Unknown: 200100
                    IE: Unknown: 23020800
                    IE: Unknown: 2A0103
                    IE: Unknown: 0B0501001DA46C
                    IE: Unknown: 460573D001000D
                    IE: Unknown: 3305040105090D
                    IE: Unknown: 4306000CA46CA46C
                    IE: Unknown: 2D1AAD0903FFFFFFFF00000000000000000100000000000000000000
                    IE: Unknown: 3D1601000400000000000000000000000000000000000000
                    IE: Unknown: 7F0A04000800000000400040
                    IE: Unknown: FF1D230501081A4010006008881FC3831C010800AAFFAAFF1B1CC7711CC771
                    IE: Unknown: FF0724F43F0028FCFF
                    IE: Unknown: DD28506F9A1C9C8CD87353221D5F6F7765746D5F4042617965726E574C414E2031393138373231323833
                    IE: Unknown: FF0E260F03A4FF27A4FF4243FF6232FF
                    IE: Unknown: DD180050F20201018F0003A4000027A4000042435E0062322F00
                    IE: Unknown: DD168CFDF0040000494C51030209720100000000FEFF0000
                    IE: Unknown: DD078CFDF004010100
          Cell 03 - Address: 9C:8C:D8:73:6E:20
                    Channel:9
                    Frequency:2.452 GHz (Channel 9)
                    Quality=45/70  Signal level=-65 dBm  
                    Encryption key:on
                    ESSID:"eduroam"
                    Bit Rates:1 Mb/s; 2 Mb/s; 5.5 Mb/s; 11 Mb/s; 6 Mb/s
                              9 Mb/s; 12 Mb/s; 18 Mb/s
                    Bit Rates:24 Mb/s; 36 Mb/s; 48 Mb/s; 54 Mb/s
                    Mode:Master
                    Extra:tsf=0000000000000000
                    Extra: Last beacon: 40ms ago
                    IE: Unknown: 0007656475726F616D
                    IE: Unknown: 010802040B160C121824
                    IE: Unknown: 030109
                    IE: Unknown: 050400010100
                    IE: Unknown: 0706444520010D14
                    IE: Unknown: 200100
                    IE: Unknown: 23020800
                    IE: Unknown: 2A0103
                    IE: Unknown: 3204B0C8E0EC
                    IE: IEEE 802.11i/WPA2 Version 1
                        Group Cipher : CCMP
                        Pairwise Ciphers (1) : CCMP
                        Authentication Suites (2) : 802.1x unknown (5)
                    IE: Unknown: 0B0502002A8A66
                    IE: Unknown: 3305040105090D
                    IE: Unknown: 4306000CA177A177
                    IE: Unknown: 460573D001000D
                    IE: Unknown: 2D1AAD0903FFFFFFFF00000000000000000100000000000000000000
                    IE: Unknown: 3D1609000400000000000000000000000000000000000000
                    IE: Unknown: 7F0A04000800000000400040
                    IE: Unknown: FF1D230501081A4010006008881FC3831C010800AAFFAAFF1B1CC7711CC771
                    IE: Unknown: FF0724F43F000AFCFF
                    IE: Unknown: FF0E260703A4FF27A4FF4243FF6232FF
                    IE: Unknown: DD180050F2020101870003A4000027A4000042435E0062322F00
                    IE: Unknown: DD168CFDF0040000494C51030209720100000000FEFF0000
                    IE: Unknown: DD078CFDF004010100
                    IE: Unknown: DD07000B8601040808
          Cell 04 - Address: 9C:8C:D8:73:6E:21
                    Channel:9
                    Frequency:2.452 GHz (Channel 9)
                    Quality=45/70  Signal level=-65 dBm  
                    Encryption key:off
                    ESSID:"@BayernWLAN "
                    Bit Rates:12 Mb/s; 18 Mb/s; 24 Mb/s; 36 Mb/s; 48 Mb/s
                              54 Mb/s
                    Mode:Master
                    Extra:tsf=0000000000000000
                    Extra: Last beacon: 40ms ago
                    IE: Unknown: 000C4042617965726E574C414E20
                    IE: Unknown: 01069824B048606C
                    IE: Unknown: 030109
                    IE: Unknown: 0706444520010D14
                    IE: Unknown: 200100
                    IE: Unknown: 23020800
                    IE: Unknown: 2A0103
                    IE: Unknown: 0B0501002E8A66
                    IE: Unknown: 460573D001000D
                    IE: Unknown: 3305040105090D
                    IE: Unknown: 4306000C8A668A66
                    IE: Unknown: 2D1AAD0903FFFFFFFF00000000000000000100000000000000000000
                    IE: Unknown: 3D1609000400000000000000000000000000000000000000
                    IE: Unknown: 7F0A04000800000000400040
                    IE: Unknown: FF1D230501081A4010006008881FC3831C010800AAFFAAFF1B1CC7711CC771
                    IE: Unknown: FF0724F43F000AFCFF
                    IE: Unknown: DD28506F9A1C9C8CD8736E221D5F6F7765746D5F4042617965726E574C414E2031393138373231323833
                    IE: Unknown: FF0E260703A4FF27A4FF4243FF6232FF
                    IE: Unknown: DD180050F2020101870003A4000027A4000042435E0062322F00
                    IE: Unknown: DD168CFDF0040000494C51030209720100000000FEFF0000
                    IE: Unknown: DD078CFDF004010100
          Cell 05 - Address: FA:72:A1:31:19:C1
                    Channel:6
                    Frequency:2.437 GHz (Channel 6)
                    Quality=45/70  Signal level=-65 dBm  
                    Encryption key:on
                    ESSID:"Hannah01"
                    Bit Rates:1 Mb/s; 2 Mb/s; 5.5 Mb/s; 11 Mb/s
                    Bit Rates:6 Mb/s; 9 Mb/s; 12 Mb/s; 18 Mb/s; 24 Mb/s
                              36 Mb/s; 48 Mb/s; 54 Mb/s
                    Mode:Master
                    Extra:tsf=0000000000000000
                    Extra: Last beacon: 40ms ago
                    IE: Unknown: 000848616E6E61683031
                    IE: Unknown: 010482848B96
                    IE: Unknown: 030106
                    IE: Unknown: 050400020000
                    IE: Unknown: 0706444504010D14
                    IE: Unknown: 3B055153548081
                    IE: Unknown: 2A0100
                    IE: Unknown: 32080C1218243048606C
                    IE: IEEE 802.11i/WPA2 Version 1
                        Group Cipher : CCMP
                        Pairwise Ciphers (1) : CCMP
                        Authentication Suites (1) : PSK
                    IE: Unknown: 2D1A6F0913FF00000000000000000000000000000000000000000000
                    IE: Unknown: 3D1606000600000000000000000000000000000000000000
                    IE: Unknown: DD180050F2020101810003A4000027A4000042435E0062322F00
                    IE: Unknown: BF0C12718033FEFF8601FEFF8601
                    IE: Unknown: C005000000FEFF
                    IE: Unknown: C3020014
                    IE: Unknown: 7F080500000000000040
                    IE: Unknown: DD088CFDF00101020100
                    IE: Unknown: DD0A0017F206010103010000
          Cell 06 - Address: 12:62:E5:28:1C:7B
                    Channel:6
                    Frequency:2.437 GHz (Channel 6)
                    Quality=28/70  Signal level=-82 dBm  
                    Encryption key:on
                    ESSID:"DIRECT-7B-HP PageWide Pro 477dw"
                    Bit Rates:6 Mb/s; 9 Mb/s; 12 Mb/s; 18 Mb/s; 24 Mb/s
                              36 Mb/s; 48 Mb/s; 54 Mb/s
                    Mode:Master
                    Extra:tsf=0000000000000000
                    Extra: Last beacon: 40ms ago
                    IE: Unknown: 001F4449524543542D37422D48502050616765576964652050726F203437376477
                    IE: Unknown: 01088C129824B048606C
                    IE: Unknown: 030106
                    IE: Unknown: 200100
                    IE: Unknown: 23021100
                    IE: Unknown: 2A0100
                    IE: Unknown: 2F0100
                    IE: IEEE 802.11i/WPA2 Version 1
                        Group Cipher : CCMP
                        Pairwise Ciphers (1) : CCMP
                        Authentication Suites (1) : PSK
                    IE: Unknown: 2D1A20001AFF00000000000000000000000000000000000000000000
                    IE: Unknown: 3D1606080000000000000000000000000000000000000000
                    IE: Unknown: DD090010180200000C0000
                    IE: Unknown: DD180050F202010184000364000027A4000041435E0061322F00
                    IE: Unknown: DD9E0050F204104A0001101044000102103B00010310470010759C538A7CD059DB990621EFB04DD92B1021000248501023001948502050616765576964652050726F203437376477204D4650102400064433513230421042000A434E3841344A593042541054000800030050F204000110110001201008000240081049000600372A0001201049001700013710060010759C538A7CD059DB990621EFB04DD92B
                    IE: Unknown: DD6408000900040000000001020100031A48502050616765576964652050726F203437376477204D4650000406343737647700050B434E3841344A593042540006108A539C75D07CDB59990621EFB04DD92B070400000000080200D40902003B0A0400000000

#*#WIFIScanEnd
#*#E-PingStart  11:41:01
PING 1.1.1.1 (1.1.1.1) 56(84) bytes of data.
64 bytes from 1.1.1.1: icmp_seq=1 ttl=52 time=14.4 ms
64 bytes from 1.1.1.1: icmp_seq=2 ttl=52 time=15.0 ms
64 bytes from 1.1.1.1: icmp_seq=3 ttl=52 time=15.2 ms
64 bytes from 1.1.1.1: icmp_seq=4 ttl=52 time=17.5 ms
64 bytes from 1.1.1.1: icmp_seq=5 ttl=52 time=16.1 ms
64 bytes from 1.1.1.1: icmp_seq=6 ttl=52 time=16.9 ms
64 bytes from 1.1.1.1: icmp_seq=7 ttl=52 time=20.2 ms
64 bytes from 1.1.1.1: icmp_seq=8 ttl=52 time=13.8 ms
64 bytes from 1.1.1.1: icmp_seq=9 ttl=52 time=14.3 ms
64 bytes from 1.1.1.1: icmp_seq=10 ttl=52 time=15.6 ms
64 bytes from 1.1.1.1: icmp_seq=11 ttl=52 time=14.8 ms
64 bytes from 1.1.1.1: icmp_seq=12 ttl=52 time=15.7 ms
64 bytes from 1.1.1.1: icmp_seq=13 ttl=52 time=18.3 ms
64 bytes from 1.1.1.1: icmp_seq=14 ttl=52 time=17.4 ms
64 bytes from 1.1.1.1: icmp_seq=15 ttl=52 time=36.7 ms
64 bytes from 1.1.1.1: icmp_seq=16 ttl=52 time=16.7 ms
64 bytes from 1.1.1.1: icmp_seq=17 ttl=52 time=14.2 ms
64 bytes from 1.1.1.1: icmp_seq=18 ttl=52 time=15.1 ms
64 bytes from 1.1.1.1: icmp_seq=19 ttl=52 time=16.5 ms
64 bytes from 1.1.1.1: icmp_seq=20 ttl=52 time=14.2 ms

--- 1.1.1.1 ping statistics ---
20 packets transmitted, 20 received, 0% packet loss, time 19026ms
rtt min/avg/max/mdev = 13.822/16.933/36.728/4.805 ms
#*#E-PingEND
#*#IPingStart
PING 141.13.129.225 (141.13.129.225) 56(84) bytes of data.
64 bytes from 141.13.129.225: icmp_seq=1 ttl=245 time=3.12 ms
64 bytes from 141.13.129.225: icmp_seq=2 ttl=245 time=9.00 ms
64 bytes from 141.13.129.225: icmp_seq=3 ttl=245 time=3.64 ms
64 bytes from 141.13.129.225: icmp_seq=4 ttl=245 time=3.75 ms
64 bytes from 141.13.129.225: icmp_seq=5 ttl=245 time=15.1 ms
64 bytes from 141.13.129.225: icmp_seq=6 ttl=245 time=3.39 ms
64 bytes from 141.13.129.225: icmp_seq=7 ttl=245 time=4.51 ms
64 bytes from 141.13.129.225: icmp_seq=8 ttl=245 time=3.50 ms
64 bytes from 141.13.129.225: icmp_seq=9 ttl=245 time=6.51 ms
64 bytes from 141.13.129.225: icmp_seq=10 ttl=245 time=129 ms
64 bytes from 141.13.129.225: icmp_seq=11 ttl=245 time=3.82 ms
64 bytes from 141.13.129.225: icmp_seq=12 ttl=245 time=6.91 ms
64 bytes from 141.13.129.225: icmp_seq=13 ttl=245 time=3.77 ms
64 bytes from 141.13.129.225: icmp_seq=14 ttl=245 time=9.14 ms
64 bytes from 141.13.129.225: icmp_seq=15 ttl=245 time=3.21 ms
64 bytes from 141.13.129.225: icmp_seq=16 ttl=245 time=3.26 ms
64 bytes from 141.13.129.225: icmp_seq=17 ttl=245 time=4.26 ms
64 bytes from 141.13.129.225: icmp_seq=18 ttl=245 time=3.25 ms
64 bytes from 141.13.129.225: icmp_seq=19 ttl=245 time=3.15 ms
64 bytes from 141.13.129.225: icmp_seq=20 ttl=245 time=6.66 ms

--- 141.13.129.225 ping statistics ---
20 packets transmitted, 20 received, 0% packet loss, time 19026ms
rtt min/avg/max/mdev = 3.115/11.444/128.992/27.124 ms
#*#IPingEnd
#*#TraceRouteStart
#*#TraceRouteEnd
#*#DNSCheckStart
#*#DNSCheckFinished
#*#EDOWNSTART Starting external Download test
--2023-10-19 11:41:40--  https://psi-project.jochenmehlich.de/1MB.zip
Resolving psi-project.jochenmehlich.de (psi-project.jochenmehlich.de)... 88.99.93.158
Connecting to psi-project.jochenmehlich.de (psi-project.jochenmehlich.de)|88.99.93.158|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 1048576 (1.0M) [application/zip]
Saving to: ‘/root/1697712100’

     0K .......... .......... .......... .......... ..........  4%  871K 1s
    50K .......... .......... .......... .......... ..........  9% 1.24M 1s
   100K .......... .......... .......... .......... .......... 14% 1.71M 1s
   150K .......... .......... .......... .......... .......... 19% 1.79M 1s
   200K .......... .......... .......... .......... .......... 24% 1.34M 1s
   250K .......... .......... .......... .......... .......... 29% 1.57M 1s
   300K .......... .......... .......... .......... .......... 34%  932K 1s
   350K .......... .......... .......... .......... .......... 39%  998K 1s
   400K .......... .......... .......... .......... .......... 43% 1.80M 0s
   450K .......... .......... .......... .......... .......... 48% 1.64M 0s
   500K .......... .......... .......... .......... .......... 53% 1.92M 0s
   550K .......... .......... .......... .......... .......... 58% 2.59M 0s
   600K .......... .......... .......... .......... .......... 63% 1.89M 0s
   650K .......... .......... .......... .......... .......... 68% 1.29M 0s
   700K .......... .......... .......... .......... .......... 73% 1.33M 0s
   750K .......... .......... .......... .......... .......... 78% 1.37M 0s
   800K .......... .......... .......... .......... .......... 83% 1.32M 0s
   850K .......... .......... .......... .......... .......... 87% 1.87M 0s
   900K .......... .......... .......... .......... .......... 92% 2.47M 0s
   950K .......... .......... .......... .......... .......... 97% 2.21M 0s
  1000K .......... .......... ....                            100% 2.86M=0.7s

2023-10-19 11:41:41 (1.48 MB/s) - ‘/root/1697712100’ saved [1048576/1048576]

#*#EDOWNLOAD took:  1
#*#EDOWNLOADValid:  true
#*#TESTEND

We can see that I used the prefix #*# for the location markers, the idea behind this action was that when extracting the data I can separate the log file by these markers, since the probability that these will occur naturally is very low. For further evaluation we split the log files into the individual test parameters and then have the values read out (usually via regex) and written into a database, in this case we use a python script for the extraction and write into a sqlite database, also we validate the log files in case something happened to the log output and corrupted the file. The file will be moved to another directory and listed in an invalid file. The biggest type of corrupted files were caused by write errors (mostly when the power connection is suddenly lost).

import sqlite3, zipfile, time, os, shutil
from pathlib import Path
from deepdiff import DeepDiff

from datetime import datetime

os.makedirs(os.path.dirname("data/invalid/not.txt"), exist_ok=True)
os.makedirs(os.path.dirname("data/done/not.txt"), exist_ok=True)

con = sqlite3.connect("data/dev.db")
con.row_factory = lambda cursor, row: row[0]
cur = con.cursor()

cur.execute("""create table zips
(
    id          integer                            not null
        constraint zips_pk
            primary key autoincrement,
    filename    varchar                            not null
        constraint zips_pk_2
            unique,
    extractedAt datetime default current_timestamp not null
);""")

con.commit()

res = cur.execute("SELECT filename from zips")
scannedFiles = res.fetchall()

start_time = time.time()
for p in Path("zips/").rglob("*.zip"):
    if str(p) not in scannedFiles:
        print("Extracting {}".format(p))
        with zipfile.ZipFile("{}".format(p), "r") as zip_ref:
            zip_ref.extractall("data/raw")
            cur.execute("INSERT INTO zips(filename) values ('{}')".format(p))
            con.commit()
        print("finished")
    else:
        print("Skipped {} (Already in database)".format(p))

print("--- %s seconds ---" % (time.time() - start_time))

cur.execute("""create table files
(
    id         integer not null
        constraint files_pk
            primary key autoincrement,
    filename   varchar not null
        constraint files_pk_2
            unique,
    analyzedAt timestamp default CURRENT_TIMESTAMP
);""")
con.commit()
cur.execute("""create table nodes(
    nodename    varchar,
    displayname varchar,
    id          integer
        constraint nodes_pk
            primary key autoincrement
);""")
con.commit()
cur.execute("""create table measurement
(
    id            integer
        constraint measurement_pk
            primary key,
    node          integer
        constraint measurement_nodes_id_fk
            references nodes,
    timestamp     timestamp not null,
    num_wifis     integer,
    eping_avg     float,
    eping_max     float,
    eping_min     float,
    iping_avg     float,
    iping_max     float,
    iping_min     float,
    eping_loss    integer,
    iping_loss    integer,
    downloadValid boolean,
    downloadTime  integer,
    logs          text
);""")
con.commit()
cur.execute("""create table wifis
(
    id          integer
        constraint wifis_pk
            primary key autoincrement,
    cellID      varchar,
    address     varchar,
    frequency   integer,
    channel     integer,
    quality     integer,
    signalLevel integer,
    ssid        varchar,
    bitrates    varchar,
   measurement integer
       constraint wifis_measurement_id_fk
           references measurement
);
""")

con.commit()

res = cur.execute("SELECT filename from files")
scannedFiles = res.fetchall()
start_time = time.time()

verifier = {}

def verifierincrease(value):
    global verifier
    verifier[value] = verifier[value] + 1

validFormat = {
    "newtest": 1,
    "epingstart": 1,
    "epingend": 1,
    "ipingstart": 1,
    "ipingend": 1,
    "traceroutestart": 1,
    "tracerouteend": 1,
    "dnsstart": 1,
    "dnsend": 1,
    "edownloadstart": 1,
    "edownloadvalid": 1,
    "edownloadtime": 1,
    "testend": 1
}

def verifierreset():
    global verifier
    verifier = {
        "newtest": 0,
        "wifiscanstart": 0,
        "wifiscanend": 0,
        "epingstart": 0,
        "epingend": 0,
        "ipingstart": 0, 
        "ipingend": 0,
        "traceroutestart": 0,
        "tracerouteend": 0,
        "dnsstart": 0,
        "dnsend": 0,
        "edownloadstart": 0,
        "edownloadvalid": 0,
        "edownloadtime": 0,
        "testend": 0
    }

sublogs = {}
logStatus = -1

def getOperations(line):
    global logStatus
    if "#*#NEWTEST" in line:
        verifierincrease("newtest")
    elif "#*#WIFIScanStart" in line:
        logStatus = 0
        verifierincrease("wifiscanstart")
    elif "#*#WIFIScanEnd" in line:
        logStatus = -1
        verifierincrease("wifiscanend")
    elif "#*#E-PingStart" in line:
        logStatus = 1
        verifierincrease("epingstart")
    elif "#*#E-PingEND" in line:
        logStatus = -1
        verifierincrease("epingend")
    elif "#*#IPingStart" in line:
        logStatus = 2
        verifierincrease("ipingstart")
    elif "#*#IPingEnd" in line:
        logStatus = -1
        verifierincrease("ipingend")
    elif "#*#TraceRouteStart" in line:
        verifierincrease("traceroutestart")
    elif "#*#TraceRouteEnd" in line:
        verifierincrease("tracerouteend")
    elif "#*#DNSCheckStart" in line:
        verifierincrease("dnsstart")
    elif "#*#DNSCheckFinished" in line:
        verifierincrease("dnsend")
    elif "#*#EDOWNSTART" in line:
        verifierincrease("edownloadstart")
    elif "#*#EDOWNLOAD took:" in line:
        verifierincrease("edownloadtime")
        sublogs["downloadtime"] = int(line.split(":")[-1])
    elif "#*#EDOWNLOADValid" in line:
        verifierincrease("edownloadvalid")
        sublogs["downloadvalid"] = "true" in line.split(":")[-1]
    elif "#*#TESTEND" in line:
        verifierincrease("testend")

    if logStatus == 0:
        sublogs["wifi"] = sublogs["wifi"] + line
    elif logStatus == 1:
        sublogs["eping"] = sublogs["eping"] + line
    elif logStatus == 2:
        sublogs["iping"] = sublogs["iping"] + line

def fileValid():
    global verifier
    if verifier["wifiscanend"] != verifier["wifiscanstart"]:
        return False
    wifi = verifier.pop("wifiscanstart")
    verifier.pop("wifiscanend")
    if validFormat == verifier:
        verifier["hasWIFI"] = wifi == 1
        return True
    else:
        print(DeepDiff(validFormat, verifier))
        return False
    
def getWifiNum():
    try:
        networks = sublogs["wifi"].split("Cell")
        networks.pop(0)
        return len(networks)
    except:
        return 0

def getNodeId(nodename):
    results = cur.execute("SELECT id from nodes where nodename = '{}'".format(nodename))
    results = results.fetchall()
    if len(results) == 1:
        return results[0]
    else:
        cur.execute("INSERT INTO nodes(nodename) values ('{}')".format(nodename))
        con.commit()
        return cur.lastrowid


def addWifis(mID):
    global sublogs
    networks = sublogs["wifi"].split("Cell")
    networks.pop(0)
    for network in networks:
        data = {}
        data["cellID"] = int(network[:network.index("-")])
        data["address"] = network[network.index("Address:")+9 : network.index("\n")]
        data["frequency"] = int(float(network[network.index("Frequency:")+10: network.index("GHz")]) * 1000)
        data["channel"] = int(network[network.index("(Channel ") +9 : network.index(")")])
        data["quality"] = int(network[network.index("Quality=")+8:network.index("/70")])
        data["signalLevel"] = int(network[network.index("Signal level=") +13 : network.index("dBm")])
        if "SSID:" in network:
            ssid = network[network.index("SSID:")+7 : network.index("Bit Rates")]
            if '"' in ssid:
                data["ssid"] = ssid[:ssid.index('"')]
            else:
                data["ssid"] = ""
        else:
            data["ssid"] = "#*#NOSSID"
        if "Bit" in network:
            bitrates = network[network.index("Bit") + 10: network.index("Mode")]
            bitrates = bitrates.replace(";", "")
            bitrates = bitrates.replace("\n", "")
            bitrates = bitrates.replace (" ", "")
            bitrates = bitrates.split("Mb/s")
            bitrates.pop()
            data["bitrates"] = bitrates
        else:
            data["bitrates"] = []
        query = """INSERT INTO wifis(cellID, address, frequency, channel, quality, signalLevel, ssid, bitrates, measurement) VALUES(
            {},"{}","{}",{},{},{},"{}","{}",{});""".format(
                data["cellID"],
                data["address"],
                data["frequency"],
                data["channel"],
                data["quality"],
                data["signalLevel"],
                data["ssid"],
                data["bitrates"],
                mID)
        cur.execute(query)
        con.commit()
    

for p in Path("data/raw/done/").rglob("*.txt"):
    if str(p) not in scannedFiles:
        verifierreset()
        logfile = open(p, "r").readlines()
        filename = str(p)
        sublogs = {
            "wifi": "",
            "eping": "",
            "iping": "",
            "downloadvalid": -1,
            "downloadtime": -1
        }
        for line in logfile:
             getOperations(line)
        if fileValid():
            node = filename.split("-", 1)[-1][:-4]
            node = getNodeId(node) # just handle with db ids
            
            eping = {}
            iping = {}
            
            epingTimes = sublogs["eping"].split("rtt")[-1].split("=")[-1].split("/")[0:3]
            try:                
                eping["min"] = epingTimes[0]
                eping["avg"] = epingTimes[1]
                eping["max"] = epingTimes[2]
                eping["loss"] = int(sublogs["eping"].split("received, ")[-1].split("% packet loss")[0].split("errors,")[-1])
            except:
                eping["min"] = -1
                eping["avg"] = -1
                eping["max"] = -1
                eping["loss"] = -1
            
            
            ipingTimes = sublogs["iping"].split("rtt")[-1].split("=")[-1].split("/")[0:3]
            try:                
                iping["min"] = ipingTimes[0]
                iping["avg"] = ipingTimes[1]
                iping["max"] = ipingTimes[2]
                iping["loss"] = int(sublogs["iping"].split("received, ")[-1].split("% packet loss")[0].split("errors,")[-1])
            except:
                iping["min"] = -1
                iping["avg"] = -1
                iping["max"] = -1
                iping["loss"] = -1
                
            timestamp = filename.split("/")[-1].split("-", 1)[0]
            timestamp = datetime.utcfromtimestamp(int(timestamp)).strftime("%Y-%m-%d %H:%M:00.000")
            
            num_wifis = getWifiNum()
            
            log = ""
            
            for line in logfile:
                log = log + line
                log = log.replace('"', "'")
            
            query = """INSERT INTO measurement(node, timestamp, num_wifis, eping_avg, eping_max, eping_min, eping_loss, iping_avg, 
                        iping_max, iping_min, iping_loss, downloadValid, downloadTime, logs) values (
                            {},'{}',{},{},{},{},{},{},{},{},{},{},{},"{}")""".format(
                                node,
                                timestamp,
                                num_wifis,
                                eping["avg"],
                                eping["max"],
                                eping["min"],
                                eping["loss"],
                                iping["avg"],
                                iping["max"],
                                iping["min"],
                                iping["loss"],
                                sublogs["downloadvalid"],
                                sublogs["downloadtime"],
                                log
                            )
                            
            cur.execute(query)
            con.commit()
            mID = cur.lastrowid
            
            if num_wifis != 0:
                addWifis(mID)
            cur.execute("INSERT into files(filename) values ('{}')".format(filename))
            shutil.move(filename, "data/done/{}".format(filename.split("/")[-1]))
            print("Done with {}".format(filename))
        else:
            print("File invalid")
            shutil.copy(filename, "data/invalid/{}".format(filename.split("/")[-1]))
    else:
        print("Skipped {} (Already in database)".format(p))

print("--- %s seconds ---" % (time.time() - start_time))

After successfully executing the script, we get 5 tables, but only 3 of them are important for further data analysis:

  • The nodes table (which matches the nodename with an identifier):

Pasted image 20240618105448.png

  • The measurement table (with all values):

Pasted image 20240618105558.png

  • The wifi table (with all wifi ssids and the extracted values)

Pasted image 20240618105652.png

Data analytics

The data was then manually cleaned. This means that the differences between ’eduroam’ and ’eduroam ’ were matched to the same ’eduroam’ case to make the analysis more precise. Let us play with the data. First, we want to see how many measurements we have where the file download was valid, this will give us an overview of how many measurements were successful on a basic view.

SELECT
	count(*) AS Total,
    sum(case when downloadvalid = true then 1 else 0 end) AS DownloadValid,
    sum(case when downloadvalid = false then 1 else 0 end) AS DownloadInvalid
FROM public.measurement

Pasted image 20240618113041.png

Out of about 2,300,603 measurements, only 67,338 failed the download tests (thats about 3%), which seems very good. But just because a 1MB file was successfully downloaded does not mean that the wifi is working, lets check it based on the external packet loss.

SELECT
	count(*) AS Total,
    sum(case when eping_loss = 0 then 1 else 0 end) AS NoPackageLoss,
    sum(case when eping_loss != 0 then 1 else 0 end) AS PackageLoss
FROM public.measurement

Pasted image 20240618113425.png

Now we are already at 238,323 measurements with packet loss (~11%). Lets have a look at the packet loss distribution

select count(*), eping_loss from public.measurement 
	where eping_loss != -1
	group by eping_loss;

Pasted image 20240620143220.png

Loss in % 0 5 10 15 20 25 30 35 40 45 50 55 60 65 70 75 80 85 90 95
count 2062280 136648 26150 6469 2590 1652 1318 1020 885 836 822 537 457 391 412 266 280 250 204 211

Lets define the unusability of the wifi if the ping (external) is about 100 and has a packageloss (eping_loss != 0) and the downloadfile test was invalid, even if the wifi technically works with some of these parameters, the overall experience is not very good.

SELECT
	count(*) AS Total,
    sum(case when downloadvalid = true and eping_loss = 0 and eping_avg < 100 and eping_avg != -1 then 1 else 0 end) AS Useable,
    sum(case when downloadvalid = false or eping_loss != 0 or eping_avg > 100 or eping_avg = -1 then 1 else 0 end) AS Unusable
FROM public.measurement

Pasted image 20240620144824.png

total useable unusable
2300603 2051236 249367

For better clarification, I divided the unusable into more cases so that we can understand why the measurement becomes unusable and how it correlates with other parameters, for this we have 7 cases:

  • Case 1: Every parameter fails
  • Case 2: Only the download fails
  • Case 3: Only the external ping fails
  • Case 4: Only the external ping averages about 100ms or is invalid (-1)
  • Case 5: The download fails and the external ping has a loss
  • Case 6: The download fails and the external ping averages about 100ms or is invalid (-1)
  • Case 7: The external ping has a loss and the external ping averages about 100ms or is invalid (-1)
SELECT
	count(*) AS Total,
    sum(case when downloadvalid = false and eping_loss != 0 and (eping_avg > 100 or eping_avg = -1) then 1 else 0 end) AS Case1, -- All invalid
	sum(case when downloadvalid = false and eping_loss = 0 and eping_avg < 100 and eping_avg != -1 then 1 else 0  end) AS Case2, -- Download invalid
	sum(case when downloadvalid = true and eping_loss != 0 and eping_avg < 100 and eping_avg != -1 then 1 else 0  end) AS Case3, -- Eping loss
	sum(case when downloadvalid = true and eping_loss = 0 and (eping_avg > 100 or eping_avg = -1) then 1 else 0 end) AS Case4, -- EPing AVG invalid
	sum(case when downloadvalid = false and eping_loss != 0 and eping_avg < 100 and eping_avg != -1 then 1 else 0  end) AS Case5, -- Download invalid und Eping loss
	sum(case when downloadvalid = false and eping_loss = 0 and (eping_avg > 100 or eping_avg = -1) then 1 else 0 end) AS Case6, -- Download invalid und Eping too high
	sum(case when downloadvalid = true and eping_loss != 0 and (eping_avg > 100 or eping_avg = -1) then 1 else 0 end) AS Case7 -- Eping Loss and Eping avg invalid
FROM public.measurement

Pasted image 20240701133410.png

total case1 case2 case3 case4 case5 case6 case7
2300603 57772 5049 171206 4517 3039 1478 6306

To make sure that all cases has been covered, we can simply add the values together and we should get the same number as in the previous query. (which is also true in this case)

It is often pointed out to the responsible committee (ICT Advisory Board (dt. IuK-Beirat)) that one of the major problems with WLAN is that there are so many other WLAN networks and these have a major impact on the performance of eduroam due to the not exactly large frequency range, which sounds quite logical. So let’s take a look at how the data reflects this.

SELECT count(*), num_wifis from public.measurement
    where downloadvalid = false or eping_loss != 0 or eping_avg > 100 or eping_avg = -1
	group by num_wifis

Pasted image 20240620150042.png

num_wifis 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 38 39 40
count 36463 2836 4313 10344 14951 18230 14715 13455 12631 13572 14883 15030 14498 13233 12406 10723 8150 5607 3579 2132 1501 1336 1262 1197 951 584 367 175 87 46 29 25 15 16 7 7 7 2 1 1

We can observe that as the number increases, in some cases the number of incorrect measurements actually increases. But here too, looking only at the absolute figures can lead to a fallacy, which is why the analysis should be carried out again with relative figures in any case.

Pasted image 20240620151828.png

num_wifis 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
total 775449 3556 25981 35675 67928 83435 97600 102781 112581 118742 119606 117246 107555 93637 84503 74056 63412 50973 39853 30702 24285 19651 16294 12938 9477 6071 3518 1718 776 291 147 76 36 20 14 8 7 1 2 1 1
unusable 36463 2836 4313 10344 14951 18230 14715 13455 12631 13572 14883 15030 14498 13233 12406 10723 8150 5607 3579 2132 1501 1336 1262 1197 951 584 367 175 87 46 29 25 15 16 7 7 7 0 2 1 1
usable 738986 720 21668 25331 52977 65205 82885 89326 99950 105170 104723 102216 93057 80404 72097 63333 55262 45366 36274 28570 22784 18315 15032 11741 8526 5487 3151 1543 689 245 118 51 21 4 7 1 0 1 0 0 0
failedrate (%) 4 79 16 28 22 21 15 13 11 11 12 12 13 14 14 14 12 10 8 6 6 6 7 9 10 9 10 10 11 15 19 32 41 80 50 87 100 0 100 100 100

Pasted image 20240620152408.png

The relative approach is much more meaningful for us; we observe here that the error rate is relatively high, especially with four SSIDS, and then levels off sharply. From 30 SSIDs onwards, the error rate rises extremely again.

with t1 as (select count(*) as num from public.wifis where ssid='eduroam' group by measurement)
select count(*), num from t1 group by num order by num;

Pasted image 20240625175705.png

num 1 2 3 4 5 6 7 8 9 10 11
count 306794 466511 377573 169725 96488 44786 23881 6333 15167 7093 7

Let us see how many of these measurements fail (= unusable) relative to the number of detected eduroam SSIDs (number of accesspoints providing the eduroam network in this area).

with t1 as (select count(*) as num from public.wifis inner join public.measurement on public.wifis.measurement = public.measurement.id where (public.measurement.downloadvalid = false or public.measurement.eping_loss != 0 or public.measurement.eping_avg > 100 or public.measurement.eping_avg = -1) and public.wifis.ssid = 'eduroam' group by public.wifis.measurement)
select count(*), num from t1 group by num order by num;

Pasted image 20240625175749.png

num 1 2 3 4 5 6 7 8 9 10
count 67471 55228 28570 16832 12426 10061 6497 1108 2694 1227

As before, this tells us relatively little about when the wifi is not working properly, it becomes much more interesting when we look at the relative frequencies, for which I have created a separate temporary table to avoid huge SQL queries.

SELECT * FROM public.tmp_eduroam_1 LIMIT 100;
num 1 2 3 4 5 6 7 8 9 10 11
total count 306794 466511 377573 169725 96488 44786 23881 6333 15167 7093 7
fail count 67471 55228 28570 16382 12426 10061 6497 1108 2694 1227 0
failrate (%) 22% 12% 8% 10% 13% 22% 27% 17% 18% 17% 0%

It is not really surprising that if there is only one SSID, the failure rate is relatively high, but above all we also see that if many access points provide eduroam, the failure rate quickly becomes very high. This measurement shows that 3 eduroam access points have the lowest failure rate.

select count(*) from public.wifis where ssid='eduroam' group by address;

A total of 94 different eduroam access points were recorded on the Erba site (depending on the SSID address). On the pretext that every access point that offers eduroam also offers bayernwlan, we can use the Bavarian government’s online list [4] to check whether we have recorded everything correctly.

Pasted image 20240703134954.png

We see that the WLAN is not as functional as promised, on average we have error rates of 11-16%. We also have several clear factors that differentiate the measurement stations from conventional devices:

  • They were stationary
  • They had a technical user who did not need to authenticate to the network via an easyroam certificate authority.
  • They were permanently connected to the WLAN

Whether you see these factors as negative or positive is up to you, but I would like to point out that I have often noticed in the log files of my laptop, for example, that the login went smoothly, but the DHCP server failed to assign an IP, especially when logging into the wifi.

What happens next? In order to collect data on a permanent basis, I have reduced the amount of data many times over, so that the PIs only send heartbeats to a central instance, which then creates an uptime history, which - mainly due to the smaller amount of data - can record the performance of the WLAN over a much longer period of time. It is also planned (and in some cases already agreed) to include fixed servers connected directly via LAN in the measurement to see if there are parallels between WLAN and LAN in terms of downtime.

Pasted image 20240703224745.png

Depending on how much work you want to do, you can consider how to optimize the method for reporting problems with the WLAN (e.g. without having Internet access). The integration of “normal” devices (i.e. laptops that move around the building and are verified by the easyroam authentication point) and the expansion to other campus locations could be other aspects.

Overall, you can clearly see that there is much more to be done to show that it doesn’t work. And even if we know why it doesn’t work, it would be exciting in the long run to know what needs to be done to make it work and to solve the problems that arise on an almost weekly - and depending on the period, even daily - basis.

The goal of the project, to show that it’s not all about you, was achieved. Personally, I would answer the question of whether it’s as bad as we thought with a big NO, but I also believe that everyone has to define the answer for themselves.

Some useless facts

  • 57 unique IPhone Hotspots were recorded during the time
  • 89 unique Samsumg Galaxy Hotspot were recorded during the time
  • 115 unique Audi Hotspots were recorded
  • 91 unique VW Hotspots were recorded
  • All measurements added up to over 4TB of network traffic (just for the file download tests)
  • No raspberry pi got stolen
  • One ssid had a rickroll

Sources


With the help of a selected number of language tools (e.g. DeepL) the quality of this report was improved.