Pi Zero als smart USB-stick 4

Door synoniem op vrijdag 27 december 2019 17:29 - Reacties (0)
Categorie: Raspberry Pi, Views: 1.713

Mijn doel voor de smart USB-stick is om hem als een deels niet ge-encrypte opslag en deels wel ge-encrypte opslag te gebruiken. En dat leverde redelijk wat gepuzzel op. Bijvoorbeeld hoe ga je de passphrase ingeven om de container te decrypten. Wanneer stel je het niet ge-encrypte deel beschikbaar? Direct bij het inpluggen of wacht je tot het ge-encrypte deel beschikbaar is?

Daarnaast kwam ik tot de ontdekking dat ik de module g_multi gelijk bij het opstarten moet laden om het goed te laten werken. Alleen werkt mijn vertragingstactiek voor de virtuele seriële port dan niet meer. Met als resultaat de terugkeer van de foutmelding "[24732.318969] cdc_acm 1-4:2.0: failed to set dtr/rts". In combinatie met g_multi dus geen mogelijkheid om in te loggen via de virtuele seriële poort.

Gelukkig werkt het met de virtuele ethernetpoort wel. Plus een virtuele netwerkverbinding biedt meer mogelijkheden zoals telnet, ssh maar ook http om een paar voorbeelden te noemen. Alleen wil je wel altijd hetzelfde ip-adres en bij voorkeur ook hostnaam hebben. Veel tutorials op het internet laten dat afhangen van de aanwezigheid van Bonjour of mDNS. Persoonlijk geef ik er de voorkeur aan om het zelf te regelen met dnsmasq als DHCPserver. Dnsmasq kan "statische" ip-adressen" afgeven op basis van het MAC-adres van de client. Alleen wordt dat MAC-adres standaard bij het laden willekeurig gegenereerd tenzij je ze hard mee geeft bij laden van g_multi.

Om te beginnen verwijderen we eerst de sporen van de module g_serial. Door de volgende regels te verwijderen uit /etc/rc.local:

code:
1
2
sleep 2
modprobe g_serial


en door het verwijderen van de inlogservice op de virtuele seriële poort:

code:
1
$ sudo systemctl disable getty@ttyGS0.service



Dan wordt het tijd om cmdline.txt aan te passen zodat dwc2 en g_multi geladen worden bij het booten:

code:
1
dwc_otg.lpm_enable=0 console=serial0,115200 console=tty1 root=PARTUUID=e934c5ce-02 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait modules-load=dwc2,g_multi



g_multi parameters
De parameters voor g_multi kun je meegeven in een configuratiebestand in /etc/modprobe.d. In mijn geval heb ik het usbgadget.conf genoemd maar het kan een willekeurige bestandsnaam hebben zolang het maar een conf extensie heeft:

code:
1
options g_multi host_addr=00:df:de:dd:dc:db dev_addr=00:df:de:dd:dc:da file=/usbshare.img removable=1,1 luns=2


Host_addr is het MAC-adres wat aan de 'host' en dev_addr het MAC-adres wat aan de Pi wordt toegewezen. De regel file=/usbshare.img removable=1,1 luns=2 is voor de volgende configuratie: het niet ge-encrypte deel wordt gelijk bij het starten geladen en is verwijderbaar. Daarnaast is er ruimte voor een tweede ge-encrypt deel wat later wordt toegewezen en daarom ook removable is. Totaal komen er maximaal twee virtuele HDD's vandaar luns=2. Let op, stel dat je drie virtuele HDD's beschikbaar wil stellen dan wordt het removable=1,1,1 en luns=3. Geef je niet removable op dan moet je een bestandsnaam of een blockdevice meegeven anders zal g_multi met een foutmelding afbreken. Geef je meer bestanden of blockdevices op dan het maximum van luns= dan worden de meerdere bestandsnamen genegeerd.

dnsmasq configuratie
We beginnen met het installeren van dnsmasq en de standaard configuratie veilig te stellen:

code:
1
2
$ sudo apt install dnsmasq
$ sudo cp /etc/dnsmasq.conf /etc/dnsmasq.old


En maken een nieuw configuratiebestand /etc/dnsmasq.conf aan met de volgende inhoud:

code:
1
2
3
4
5
listen-address=127.0.0.1,192.168.42.1
dhcp-range=192.168.42.2,192.168.42.10,255.255.255.0,12h
interface=usb0
no-hosts
dhcp-host=00:df:de:dd:dc:db,192.168.42.2


Zoals je ziet zal de 'host' op basis van options g_multi altijd het ip-adres 192.168.42.2 krijgen. Om te zorgen dat de Pi altijd 192.168.42.1 krijgt, maken we een nieuw configuratiebestand onder /etc/network/interfaces.d aan met de naam usb0 (Let op! Juist geen extensie gebruiken!) met de volgende inhoud:

code:
1
2
3
auto usb0
iface usb0 inet static
        address 192.168.42.1


Je kan hier uiteraard nog veel meer aan toevoegen om ook een internetverbinding op te bouwen via de 'host'. Mijn voorkeur is om voor een internetverbining wlan0 te blijven gebruiken en voor usb0 puur een één op één verbinding te maken.
Om interferentie te voorkomen van de dhcp instellingen tussen wlan0 en usb0 voegen we de volgende regels toe aan /etc/dhcpcd.conf:

code:
1
2
ipv4only
denyinterfaces usb0



dm-crypt met LUKS
Voor het maken van een ge-encrypte container gebruiken we dm-crypt met LUKS. Waarvan overigens het package in de repo van Raspbian "cryptsetup" heet. Hiervoor maken we eerst weer een bestandsimage aan, maar nu 4GiB, met:

code:
1
$ sudo dd if=/dev/zero of=/crypt.img bs=4M count=1024 status=progress


Waarna we vervolgens het image mounten als loopdevice, dm-crypt installeren, het loopdevice met cryptsetup initialiseren, openen en formatteren met FAT32 .

code:
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
$ sudo losetup -f
 /dev/loop0

$ sudo losetup /dev/loop0 /crypt.img

$ sudo apt install cryptsetup

$ sudo cryptsetup -y -v luksFormat /dev/loop0
WARNING!
========
This will overwrite data on /dev/loop0 irrevocably.
Are you sure? (Type uppercase yes): YES
Enter passphrase:
Verify passphrase:
Command successful

$ sudo cryptsetup luksOpen /dev/loop0 crypt  #je kan een willekeurige naam opgeven gemakshalve gebruik ik crypt

$ sudo cryptsetup -v status crypt
/dev/mapper/crypt is active and is in use.
  type:    LUKS1
  cipher:  aes-xts-plain64
  keysize: 256 bits
  device:  /dev/loop0
  loop:    /crypt.img
  offset:  4096 sectors
  size:    8384512 sectors
  mode:    read/write
Command successful.

$ sudo mkfs -t vfat /dev/mapper/crypt


Hiermee hebben we een geopende bestandscontainer die we aan de host beschikbaar kunnen stellen. Moeten we alleen weten waar we dat kunnen ingeven. Daarvoor zoeken we naar een lun1 in /sys de bestandsinterface van de kernel.

code:
1
2
$sudo find /sys -name lun1
/sys/devices/platform/soc/20980000.usb/gadget/lun1


We weten welke bestandsnaam we opgegeven hebben voor lun0 zodat we kunnen controleren of we hier de goede entry te pakken hebben.

code:
1
2
$ cat /sys/devices/platform/soc/20980000.usb/gadget/lun0/file
/usbshare.img


Ja, dit is de goede entry. Om de geopende container aan de host te koppelen kunnen we niet /crypt.img of /dev/loop0 meegeven want daar staat alleen maar random data. Wat we mee geven is de geopende container onder /dev/mapper/crypt. Dat doen we met het volgende commando:

code:
1
$ sudo bash -c "echo "/dev/mapper/crypt" > /sys/devices/platform/soc/20980000.usb/gadget/lun1/file"


En als alles goed gegaan is, zal er een nieuwe usbdrive van 4GiB verschijnen op de host.

Wat nu nog moet gebeuren is zo min mogelijk handmatige ingaves en liefst een webinterface om de USB-stick en encryptie in- en uit te schakelen. Wordt vervolgd...

Netwerk booten van een Raspberry 4

Door synoniem op vrijdag 13 december 2019 22:20 - Reacties (4)
Categorie: Raspberry Pi, Views: 2.062

Mijn eerste post gaat over het netwerkbooten van de Raspberry Pi 2B, 3B en 3B+. Ik had op dat moment nog geen Raspberry Pi 4B en ik werd er al snel op gewezen dat voor de 4B het op een andere manier werkt. Inmiddels is de Sint langs geweest en heb ik een Pi 4B ontvangen hoog tijd voor een aanvulling dus.

In tegenstelling tot de voorgaande Pi's heeft de 4B geen One Time Programmable geheugen maar een echte EEPROM waarin firmware en configuratie in opgeslagen kunenn worden. Alleen had de Pi 4 bij de lancering nog geen mogelijkheid om van het netwerk te booten. Dat is pas mogelijk met de beta firmware vanaf 26 september 2019. Koop je nu op het moment dat ik dit schrijf een Pi 4B dan is de firmware hoogst waarschijnlijk nog niet up to date.

Wat heb je nodig: server
Voor de inrichting van de tftp- en nfsserver veranderd er feitelijk niets ten opzichte van mijn eerste post. Het grote verschil is dat de Pi 4 niet het bestand bootcode.bin gebruikt maar het bestand start4.elf. Daarnaast bepaald een instelling in de bootconfiguratie van de Pi waar het bestand start4.elf verwacht wordt. Standaard is dat weer in een directory met als naam het serienummer van de Pi.

Wat heb je nodig: client
Voor de client is er wat meer nodig om het werkend te krijgen. Om de firmware bij te werken en configuratie aan te passen moet je altijd eerst twee keer met een SD-kaart opstarten. En in het geval dat je Raspbian/Debian gebruikt moet dat versie 10 (Buster) zijn. Oudere versie werken volgens opgave van Raspbian niet en dit keer ben ik niet zo eigenwijs geweest het toch te proberen. Na de image op de gebruikelijke wijze op een SD-kaart gekopieerd te hebben en de Pi geboot is, werken we het systeem bij en installeren de rpi-eeprom software.

code:
1
2
3
$ sudo apt update
$ sudo apt full-upgrade
$ sudo apt install rpi-eeprom


Standaard staat rpi-eeprom zo ingesteld ingesteld dat deze alleen naar kritieke updates kijkt. Zoals gezegd is de nieuwe firmware nu nog beta en wijzigen we /etc/default/rpi-eeprom-update:

code:
1
2
3
4
5
FIRMWARE_RELEASE_STATUS="critical"

in

FIRMWARE_RELEASE_STATUS="beta"


Daarna is het tijd om de updates te controleren met in mijn geval deze mededeling:

code:
1
2
3
4
5
$ sudo rpi-eeprom-update

*** UPDATE REQUIRED ***
CURRENT: Tue 10 Sep 10:41:50 UTC 2019 (1568112110)
LATEST: Mon Nov 18 11:06:55 UTC 2019 (1574075215)


Tijd voor een update want deze versie heeft zeker nog geen netboot ondersteuning.

code:
1
2
3
4
$ sudo rpi-eeprom-update -a

*** INSTALLING REQUIRED UPDATE ***
Bootloader EEPROM update pending. Please reboot to apply the update.


Doe een reboot en controleer of Pi nu up to date is.
Dan is nu de firmware up to date maar de bootconfiguratie is nog niet veranderd. Afhankelijk of je voor de eeprom het critical of beta update channel ingesteld hebt, ga je naar /lib/firmware/raspberrypi/bootloader/critical/ of /lib/firmware/raspberrypi/bootloader/beta/. Vanaf hier gaan we eerst de huidige configuratie achterhalen, deze aanpassen naar netwerkboot en dan weer terugschrijven:

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
$ cd /lib/firmware/raspberrypi/bootloader/beta/
$ sudo cp pieeprom-2019-11-18.bin new-pieeprom.bin
$ sudo rpi-eeprom-config new-pieeprom.bin > bootconf.txt
$ cat bootconf.txt

[all]
BOOT_UART=0
WAKE_ON_GPIO=1
POWER_OFF_ON_HALT=0
DHCP_TIMEOUT=45000
DHCP_REQ_TIMEOUT=4000
TFTP_FILE_TIMEOUT=30000
TFTP_IP=
TFTP_PREFIX=0
BOOT_ORDER=0x1
SD_BOOT_MAX_RETRIES=3
NET_BOOT_MAX_RETRIES=5
[none]
FREEZE_VERSION=0

$ sudo sed -i s/0x1/0x12/g bootconf.txt

$ sudo rpi-eeprom-config --out netboot-pieeprom.bin --config bootconf.txt new-pieeprom.bin
$ sudo rpi-eeprom-update -d -f ./netboot-pieeprom.bin


De bootvolgorde wordt bepaald aan de hand van de BOOT_ORDER variabele. 0x1 betekent boot van SD-kaart, 0x2 netboot. De waarde wordt van rechts naar links uitgelezen en in mijn geval wil ik eerst van het netwerk booten en dan eventueel van de SD-kaart. BOOT_ORDER wordt dan 0x12. Andersom, eerst SD-kaart en dan netwerk wordt 0x21 maar de wachttijd voordat er werkelijk gestart wordt vanaf het netwerk wordt dan behoorlijk langer.
TFTP_PREFIX bepaald waar er naar het bestand start4.elf gezocht wordt. De waarde 0 staat voor een directory met het serienummer. De waarde 2 voor een directory met het MAC adres van de netwerkinterface in de vorm van dc-a6-32-1c-5a-1a. En als laatste de waarde 1 gebruikt de tekst die je kan invullen bij TFTP_PREFIX_STR als waarde voor de directory.

Als alles goed gegaan is kun je je Pi 4 nu vanaf het netwerk booten.

Pi Zero als smart USB-stick 3

Door synoniem op vrijdag 6 december 2019 22:31 - Reacties (2)
Categorie: Raspberry Pi, Views: 2.232

Soms zit het mee, soms zit het tegen. Dat geldt ook voor mijn projectje met de Pi Zero. De uiteindelijke bedoeling is om een USB-stick te hebben met een ge-encrypte opslagmogelijkheid. Uitgerekend wanneer je daarmee bezig bent blijkt je SD-kaart het begeven te hebben. Gelukkig kon ik een voordelige 64 GB SD-kaart scoren met Black Friday.

De Pi om te toveren in een massaopslag is vrij eenvoudig. Dat is namelijk een kwestie van de module g_mass_storage laden met de juiste parameters. Er zijn twee maren:

1 - Je kunt betreffende fileimage of het block device niet gelijktijdig door de Pi en de host laten benaderen. Dit resulteert gegarandeerd in datacorruptie, als het al werkt. Ik heb het uiteraard wel geprobeerd met kopieeren maar bestanden stonden volgens de host op de stick maar de Pi leek ze volkomen te negeren. Maar zodra de Pi een keer ge-rebooted was bleken de bestanden verminkt te zijn. En volstrekt willekeurig of de data afkomstig is van de Pi of van de host.

2 - Je kunt de losse module g_serial en g_mass_storage niet gelijkertijd laden. Om dit laten werken moet je de module g_multi gebruiken met een configuratiebestand voor de parameters die je mee wil geven. Zoals gemeld in aflevering 2 is g_multi een composite driver en daarmee een combo van g_serial, g_ether en g_mass_storage. De parameters die je mee moet geven zijn overigens gelijk aan die van de losse g_ modules. Voor nu heb ik de parameters voor g_ether even gelaten voor wat het is.

Daarnaast was het mijn bedoeling om Veracrypt te gebruiken voor encryptie van de stick. Veracrypt is de opvolger van Truecrypt wat zowel onder Windows als Linux te gebruiken is. Het maakt standaard geen deel uit van Raspbian dus je moet het zelf downloaden en installeren. De laatste versie voor Raspbian is 1.21. Wil je versie 1.24 met hotfix dan zul je deze zelf moeten compileren (inclusief een patch aanbrengen en alle afhankelijkheden met de hand regelen).

Helaas is Veracrypt een maatje te groot voor de Pi Zero. Bij een ge-encrypte container van 8 GiB had de Zero bijna vijf minuten nodig om deze te openen. Mocht je Veracrypt willen gebruiken voor een Pi 3 of 4, versie 1.21 is te downloaden van Sourceforge.

De eerste stap nu is het maken van een fileimage op de Pi om te kijken of alles werkt zoals geadverteerd. Het aanmaken van een ge-encrypted deel komt hier na daarom begin ik met een imagefile van 8 GiB.

code:
1
2
3
4
5
$ sudo dd bs=4M if=/dev/zero of=/usbshare.img count=2048

  2048+0 records in
  2048+0 records out
  8589934592 bytes (8.6 GB, 8.0 GiB) copied, 506.236 s, 17.0 MB/s


Vervolgens willen we hier een bestandssysteem op maken. Dat doen we door de imagefile te 'mounten' als een loop device, deze te partitioneren en vervolgens met FAT32 te formatteren. FAT32 omdat die zowel in Windows als Linux goed ondersteund wordt.

code:
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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
$ sudo losetup -f 

  /dev/loop0

$ sudo losetup -P  /dev/loop0 /usbshare.img

$ sudo fdisk /dev/loop0

Welcome to fdisk (util-linux 2.29.2).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.


Command (m for help): p
Disk /dev/loop0: 8 GiB, 8589934592 bytes, 16777216 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x00000000

Command (m for help): n
Partition type
   p   primary (0 primary, 0 extended, 4 free)
   e   extended (container for logical partitions)
Select (default p): p
Partition number (1-4, default 1): 
First sector (2048-16777215, default 2048): 
Last sector, +sectors or +size{K,M,G,T,P} (2048-16777215, default 16777215): 

Created a new partition 1 of type 'Linux' and of size 8 GiB.

Command (m for help): t
Selected partition 1
Partition type (type L to list all types): L

 0  Empty           24  NEC DOS         81  Minix / old Lin bf  Solaris        
 1  FAT12           27  Hidden NTFS Win 82  Linux swap / So c1  DRDOS/sec (FAT-
 2  XENIX root      39  Plan 9          83  Linux           c4  DRDOS/sec (FAT-
 3  XENIX usr       3c  PartitionMagic  84  OS/2 hidden or  c6  DRDOS/sec (FAT-
 4  FAT16 <32M      40  Venix 80286     85  Linux extended  c7  Syrinx         
 5  Extended        41  PPC PReP Boot   86  NTFS volume set da  Non-FS data    
 6  FAT16           42  SFS             87  NTFS volume set db  CP/M / CTOS / .
 7  HPFS/NTFS/exFAT 4d  QNX4.x          88  Linux plaintext de  Dell Utility   
 8  AIX             4e  QNX4.x 2nd part 8e  Linux LVM       df  BootIt         
 9  AIX bootable    4f  QNX4.x 3rd part 93  Amoeba          e1  DOS access     
 a  OS/2 Boot Manag 50  OnTrack DM      94  Amoeba BBT      e3  DOS R/O        
 b  W95 FAT32       51  OnTrack DM6 Aux 9f  BSD/OS          e4  SpeedStor      
 c  W95 FAT32 (LBA) 52  CP/M            a0  IBM Thinkpad hi ea  Rufus alignment
 e  W95 FAT16 (LBA) 53  OnTrack DM6 Aux a5  FreeBSD         eb  BeOS fs        
 f  W95 Ext'd (LBA) 54  OnTrackDM6      a6  OpenBSD         ee  GPT            
10  OPUS            55  EZ-Drive        a7  NeXTSTEP        ef  EFI (FAT-12/16/
11  Hidden FAT12    56  Golden Bow      a8  Darwin UFS      f0  Linux/PA-RISC b
12  Compaq diagnost 5c  Priam Edisk     a9  NetBSD          f1  SpeedStor      
14  Hidden FAT16 <3 61  SpeedStor       ab  Darwin boot     f4  SpeedStor      
16  Hidden FAT16    63  GNU HURD or Sys af  HFS / HFS+      f2  DOS secondary  
17  Hidden HPFS/NTF 64  Novell Netware  b7  BSDI fs         fb  VMware VMFS    
18  AST SmartSleep  65  Novell Netware  b8  BSDI swap       fc  VMware VMKCORE 
1b  Hidden W95 FAT3 70  DiskSecure Mult bb  Boot Wizard hid fd  Linux raid auto
1c  Hidden W95 FAT3 75  PC/IX           bc  Acronis FAT32 L fe  LANstep        
1e  Hidden W95 FAT1 80  Old Minix       be  Solaris boot    ff  BBT            
Partition type (type L to list all types): c
Changed type of partition 'Linux' to 'W95 FAT32 (LBA)'.

Command (m for help):  w
The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.

$ sudo fdisk -l /dev/loop0
Disk /dev/loop0: 8 GiB, 8589934592 bytes, 16777216 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x00000000

Device       Boot Start      End  Sectors Size Id Type
/dev/loop0p1       2048 16777215 16775168   8G  c W95 FAT32 (LBA)

$ sudo mkfs -t vfat /dev/loop0p1
 mkfs.fat 4.1 (2017-01-24)


Vervolgens geven we in /etc/modprobe.d/usbgadget.conf de minimale parameters mee voor g_mass_storage:

code:
1
options g_multi file=/usbshare.img ro=0


De belangrijkste parameters voor g_mass_storage zijn file, removable, cdrom, ro en luns.
Hierbij is:
file=bestandsnaam|blockdevice
removable=0|1 Standaard 1 = ja
cdrom=0|1 Standaard 0 = nee tenzij één of meer cdroms wil emuleren
ro= 0|1 Standaard 0 tenzij het achterliggende bestand readonly is en als cdrom=1
luns=N Standaard 1 en specificeert het aantal logical units. Geef je twee bestandsnamen op bij file maar staat luns op 1 dan zal alleen het eerste bestand gebruikt worden.

En dan wordt het tijd om te testen door de module g_multi te laden:

code:
1
$ sudo modprobe g_multi


Is alles goed gegaan dan wordt op de host een USB-stick van 8 GiB zichtbaar. In de log op de Pi zie je dat de onderdelen van g_multi geladen worden:

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
$ dmesg | tail -n 21
[   65.931527] using random self ethernet address
[   65.931548] using random host ethernet address
[   65.969728] Mass Storage Function, version: 2009/09/11
[   65.969751] LUN: removable file: (no medium)
[   65.970047] LUN: file: /usbshare.img
[   65.970062] Number of LUNs=1
[   65.971623] usb0: HOST MAC 9e:24:65:b1:c8:43
[   65.973026] usb0: MAC d2:95:c9:62:75:98
[   65.981082] g_multi gadget: Multifunction Composite Gadget
[   65.981106] g_multi gadget: userspace failed to provide iSerialNumber
[   65.981113] g_multi gadget: g_multi ready
[   65.981131] dwc2 20980000.usb: bound driver g_multi
[   66.045852] dwc2 20980000.usb: new device is high-speed
[   66.114088] dwc2 20980000.usb: new device is high-speed
[   66.336422] IPv6: ADDRCONF(NETDEV_UP): usb0: link is not ready
[   66.491877] dwc2 20980000.usb: new device is full-speed
[   66.558093] dwc2 20980000.usb: new device is high-speed
[   66.830857] dwc2 20980000.usb: new device is high-speed
[   66.899169] dwc2 20980000.usb: new address 32
[   66.978538] g_multi gadget: high-speed config #1: Multifunction with RNDIS
[   66.978895] IPv6: ADDRCONF(NETDEV_CHANGE): usb0: link becomes ready

Pi Zero als smart USB-stick 2

Door synoniem op zaterdag 23 november 2019 20:00 - Reacties (0)
Categorie: Raspberry Pi, Views: 3.400

Om nog even terugkomen op de reactie bij aflevering 1 van Pi Zero als smart USB-stick wat kan je hier nu mee? Zoals gezegd heel veel. Hieronder een opsomming van de kernel modules die als linux gadget beschikbaar zijn.
  • Serial (g_serial), virtuele terminal ttyACM0 onder linux COM3 e.v. onder Windows
  • Ethernet (g_ether), virtuele ethernet adapter
  • Mass storage (g_mass_storage),virtuele USB-stick
  • MIDI (g_midi), virtuele MIDI apparaat
  • Audio (g_audio), virtuele audioapparaat
  • Keyboard/Mouse (g_hid), virtuele toetsenbord en muis
  • Mass storage and Serial (g_acm_ms), zowel USB-stick als virtuele terminal
  • Ethernet and Serial (g_cdc), zowel virtuele terminal als virtuele ethernet adapter
  • Multi (g_multi), tegelijkertijd terminal, seriële en ethernetadapter
  • Webcam (g_webcam), een webcam
  • Printer (g_printer), een printer
  • Gadget tester (g_zero), en een testmodule
Het eerste doel wat ik nu met de Pi wil bereiken is een ge-encrypte USB-stick waarbij je via zowel het netwerk als de virtuele terminal kan inloggen om de partitie beschikbaar te stellen en weer af te sluiten na gebruik. Om dat te realiseren heb ik uiteindelijk de g_multi module nodig maar ik begin simpel met alleen de g_serial module dan misschien g_ether en als laatste g_mass_storage. Werkt elke module afzonderlijk dan ga ik g_multi configureren (en nadenken over mijn volgende project).

Zoals altijd als je bezig gaat met dit soort projectjes ga er vanuit dat je rare dingen tegen gaat komen.
Maar laten we beginnen met USB OTG aan te zetten op de Pi. Dit doe je door in het bestand config.txt op de boot partitie de volgende regel toe te voegen:

code:
1
dtoverlay=dwc2


Vervolgens moet de module dwc2 (en g_serial) geladen worden. Normaliter doe ik dat in het bestand /etc/modules maar dit levert, in mijn geval, wat vage foutmeldingen en soms wel, soms niet goed opstarten op. Hierover niet getreurd je kan de te laden modules ook meegeven bij het opstarten door modules-load=dwc2 toe te voegen aan het bestand cmdline.txt op de boot partitie. Mijn cmdline.txt ziet er nu zo uit:

code:
1
dwc_otg.lpm_enable=0 console=serial0,115200 console=tty1 root=PARTUUID=e934c5ce-02 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait modules-load=dwc2


Nu denk je misschien waarom laat je niet ook automatisch g_serial? Dat is een van de rare dingen waar ik tegenaan gelopen ben. Op het moment dat ik hier g_serial toevoeg zal het onder Windows gewoon werken maar onder Linux gaat het kennelijk iets te snel. In mijn logfile (dmesg) verscheen de volgende tekst:

code:
1
2
3
4
5
6
[24732.293784] usb 1-4: New USB device found, idVendor=0525, idProduct=a4a7, bcdDevice= 4.19
[24732.293787] usb 1-4: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[24732.293789] usb 1-4: Product: Gadget Serial v2.4
[24732.293791] usb 1-4: Manufacturer: Linux 4.19.85+ with 20980000.usb
[24732.317976] cdc_acm 1-4:2.0: ttyACM0: USB ACM device
[24732.318969] cdc_acm 1-4:2.0: failed to set dtr/rts


Met als gevolg dat het hele circus niet wil werken en minicom of screen een foutmelding geeft over device /dev/ttyACM0.

Het probleem heb ik ontweken door een vertragingstactiek toe te passen. Namelijk pas als laatste de module g_serial te laden in /etc/rc.local. Mijn rc.local ziet er nu zo uit:

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#!/bin/sh -e
#
# rc.local
#
# This script is executed at the end of each multiuser runlevel.
# Make sure that the script will "exit 0" on success or any other
# value on error.
#
# In order to enable or disable this script just change the execution
# bits.
#
# By default this script does nothing.

# Print the IP address
_IP=$(hostname -I) || true
if [ "$_IP" ]; then
  printf "My IP address is %s\n" "$_IP"
fi
sleep 2
modprobe g_serial
exit 0


Is dit alles goed gegaan en de driver laadt zonder foutmeldingen, blijft er nog één ding over. Namelijk de Pi vertellen dat hij op de virtuele seriële poort ook een login kan verwachten. Dat kan op de twee manieren. De simpelste manier is vanaf de Pi zelf:

code:
1
sudo systemctl enable getty@ttyGS0.service


De andere manier is op de SD-kaart van de Pi deze kopieeractie uit te voeren, er vanuit gaande dat de SD-kaart gemount is onder /media/synoniem/rootfs.

code:
1
sudo ln -s /media/synoniem/rootfs/lib/systemd/system/getty@.service /media/synoniem/rootfs/etc/systemd/system/getty.target.wants/getty@ttyGS0.service



Onder linux kun je aan de logfile zien of het allemaal gelukt is en welk devicenaam de USB-stick gekregen heeft. Dit kun je controleren met;

code:
1
2
3
4
sudo dmesg | grep cdc
[21998.393504] cdc_acm 1-4:2.0: ttyACM0: USB ACM device
[21998.397107] usbcore: registered new interface driver cdc_acm
[21998.397108] cdc_acm: USB Abstract Control Model driver for USB modems and ISDN adapters


In dit geval is de seriële devicenaam /dev/ttyACM0. Met device kun je vanaf een linux systeem nu verbinding maken door middel van screen of minicom. Onder debian-achtigen distro's installeer je die met sudo apt-get install screen (of minicom).

code:
1
screen /dev/ttyACM0 115200


En het resultaat https://tweakers.net/ext/f/z22wH0FOtiJy1B4kizmt915O/full.png

Onder Windows gebruik je Putty met de virtuele COM poort toegewezen aan de USB-stick. Dit kun je eventueel terugvinden bij Apparaatbeheer. In mijn geval is dat COM3 en putty staat ingesteld op: serial, 115200 8N1.

Pi Zero als smart USB-stick 1

Door synoniem op dinsdag 12 november 2019 22:24 - Reacties (10)
Categorie: Raspberry Pi, Views: 3.345

De hardware
De Pi Zero is letterlijk en figuurlijk de kleinste Pi uit de serie. Fysiek maar een halve creditcard en maar een processor met één core en maar 512 Mb geheugen. Daarmee is hij echt voor inbouw in projecten bedoeld en niet voor een mediaspeler of andere zwaardere toepassingen. Daarnaast zijn ook niet alle connectoren aanwezig. En de wel aanwezige connectoren zijn ook nog eens micro en mini versie. Allemaal bedoeld om het printje zo klein mogelijk te houden.

Maar het interessantste onderdeel van een Zero is dat hij een USB OTG microconnector heeft. Daarmee kan de Zero tegelijk zowel een randapparaat/gadget als een master device zijn. Dat maakte mij nieuwsgierig naar de mogelijkheden om van de Zero een smart USB-stick te maken. Bij het rond zoeken op het web zijn er diverse handleidingen te vinden maar niet altijd compleet of voor een oude versie van Raspbian. Vandaar dat ik het resultaat van mijn projectje voor de liefhebbers in twee of drie afleveringen hier op schrijf.

Om het maximale aan functionaliteit uit de Zero te halen heb ik gekozen voor de Pi Zero W. Dus de versie met Wifi en Bluetooth aan boord. Ik wil ook dat het op een USB-stick lijkt met een gewone connector. Hier zijn verschillende oplossingen voor te koop met de keuze om zelf te solderen of door een tweede printplaatje met kunststof moertjes en boutjes vast te klemmen aan de Zero.

https://tweakers.net/ext/f/UNMKD1uxlApnxWGARxX30Ifu/full.png
Zo ziet het printplaatje er uit, verkrijgbaar bij diverse leveranciers. De mijne heb ik op Aliexpress gekocht. (Geen affiliate je kan ook zelf zoeken op Pi Zero USB addon board).
https://tweakers.net/ext/f/NsvQQGifkJpJ525Hr7Dxfv6t/full.png
En hier kun je zien dat de contacten op de Zero geklemd worden.

Overigens heb ik hiervoor ook een 3D geprinte behuizing gevonden op Thinkiverse waarmee het geheel echt op een USB-stick uit de begintijd lijkt. Lomp en zonder verloopje geen twee naast of onder elkaar te gebruiken. Wil je dat wel kun natuurlijk ook gelijk een micro - USB A verloopkabeltje gebruiken zonder het extra addon boardje.

De installatie
Als eerste wilde ik ssh en een wifi verbinding configuren zodat ik achter mijn gewone PC alles kan installeren en configuren. Dit doe je voor ssh door op een nieuw gekopieerd SD-kaartje in de root van de bootpartitie een leeg bestand ssh aan te maken:

code:
1
$ touch /ssh



Voor het inschakelen van wifi maak je op dezelfde locatie het bestand wpa_supplicant.conf met de volgende inhoud:

code:
1
2
3
4
5
6
7
8
9
10
11
country=NL
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
network={
    ssid="APnaam"
    psk="Wachtwoord"
    key_mgmt=WPA-PSK
    proto=RSN
    group=CCMP
    pairwise=CCMP
}



Helaas ben ik na veel gedoe er achter gekomen dat dit voor Raspbian 10/Buster niet werkt. Misschien dat er inmiddels een workaround is maar ik heb, na een halve dag hier aan verspild te hebben, er voor gekozen om Raspbian 9/Stretch te gaan gebruiken. Dat werkte direct bij de eerste keer opstarten met deze instellingen.

Wordt vervolgd.