6

My goal is to convincingly emulate a well known brand of USB Flash Disk, using Raspberry Pi Zero (with or without Wifi). For the sake of this example, I want to emulate a 4GB Sandisk Cruzer Edge, but generally speaking I want the ability to have full control of idVendor, idProduct, iProduct, iManufacturer, iSerial (and any other subtle variables of a USB flash disk)

I only want USB Mass Storage, not a composite device (with HID, or ethernet or serial or anything else)

My target USB Host devices range from: Linux AMD64, Linux MIPS, Linux ARM, Windows x86 I've activated dwc2, partitioned and formatted the file that is to be used as the storage & filesystem and loaded g_mass_storage. It is working fine from the perspective that it successfully mounts the Storage on all targets - I can connect and see the contents, add/delete files, eject and reconnect, seeing changes fine.

I use this to launch the USB Mass Storage gadget:

sudo modprobe g_mass_storage file=/home/pi/piusb_fat32.bin nofua=1 luns=1 ro=0 stall=0 removable=1 cdrom=0 idVendor=0x0781 idProduct=0x556e bcdDevice=0x0103 iManufacturer="SanDisk" iProduct="Cruzer Edge" iSerialNumber="990431108215FFF05368"

The problem is that the name of the device remains as Linux File-Stor Gadget. Under Linux & Windows respectively:

  • Linux File-Stor Gadget 0414
  • USBSTOR\DISK&VEN_LINUX&PROD_FILE-STOR_GADGET&REV_0414

When the pi is connected to Windows 10 1903 x86 laptop, I see two devices appear:

Get-WmiObject Win32_USBControllerDevice -ComputerName localhost -Impersonation Impersonate -Authentication PacketPrivacy | Foreach-Object { [Wmi]$_.Dependent } | Sort-Object PNPClass | ft Name, PNPClass, PNPDeviceID

Name                                  PNPClass      PNPDeviceID                                                                 
----                                  --------      -----------                                                                                         
Linux File-Stor Gadget USB Device     DiskDrive     USBSTOR\DISK&VEN_LINUX&PROD_FILE-STOR_GADGET&REV_0414\990431108215FFF05368&0                
USB Mass Storage Device               USB           USB\VID_0781&PID_556E\990431108215FFF05368

Whereas with the real Sandisk USB Flash Disk:

Name                                  PNPClass      PNPDeviceID                                                              
----                                  --------      -----------                                                              
SanDisk Cruzer Edge USB Device        DiskDrive     USBSTOR\DISK&VEN_SANDISK&PROD_CRUZER_EDGE&REV_1.20\200431108215FFF05367&0
USB Mass Storage Device               USB           USB\VID_0781&PID_556B\200431108215FFF05367                               

The "USB Mass Storage Device" has the correct VID, PID, SerialNumber, but the DiskDrive device does not. Linux targets see the same two devices (see below for lsusb & dmesg examples)

From the source, It looks to me like the vendor=”Linux” and model=“File-Stor Gadget” is being set in the function fsg_common_set_inquiry_string in f_mass_storage.c https://github.com/raspberrypi/linux/blob/rpi-4.19.y/drivers/usb/gadget/function/f_mass_storage.c

  • I would like to know the best way to override that behaviour (preferably without having to recompile f_mass_storage module every time!)?
  • Is there a way that the gadget could pass through iManufacturer, iProduct parameters to use as Vendor and Model?

The steps I used to create the Raspbian environment are: Clean flash Rasbian onto SD card using Balena Etch

sudo su
echo "dtoverlay=dwc2" | sudo tee -a /boot/config.txt
echo "dwc2" | sudo tee -a /etc/modules  
echo "g_mass_storage" | sudo tee -a /etc/modules
sudo dd if=/dev/zero of=/home/pi/piusb_fat32.bin bs=1 count=0 seek=128M
sudo mkdosfs /home/pi/piusb_fat32.bin -n FAT32VOL11
reboot now

I have tried:

  • On Windows, deleting the cached reg key for the device: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\usbflags\keyname Where keyname is the concatenation of VID+PID+BCD_RELEASE_NUMBER
  • Changing the serial number of the device each time I create the gadget, so eliminate caching as the cause.
  • Reformatting the USB disk from Windows, as Fat32, with a different volume name (rather than using mkdosfs)
  • Multiple versions of raspbian
    • 2019-09-26-raspbian-buster-lite (with & without running apt full-upgrade)
    • 2018-06-27-raspbian-stretch-lite (with & without running apt full-upgrade)
    • 2019-04-08-raspbian-stretch-lite (with & without running apt full-upgrade)

I’m certainly no USB or Linux expert, so this is what I have tried to piece together about how the Raspberry Pi USB ‘gadget’ Storage stack works. There are Five things of relevance:

  • dwc2 module (does the OTG host/gadget flip dictated by OTG_SENSE)
  • usb_f_mass_storage.ko module (Mass Storage Functions, handles the SCSI stuff to interface between USB & the file that acts as the storage for our USB disk)
  • g_mass_storage.ko module (The Mass Storage Gadget)
  • the file on the Pi that acts as the storage. this holds the filesystem and data that is read/writen to the emulated USB storage.
  • The parameters that we pass to g_mass_storage module when loading it via modprobe

There is a very similar post here, but it hasn’t been active for more than 2 years now, and it didn’t solve my issue, so I’m re-posting here with more info:

And someone else had the same problem, unresolved from 2017:

----On a Kali x86 Laptop: ----------

dmesg (output snipped to show relevant stuff)
[66925.017786] usb 1-4.3: New USB device found, idVendor=0781, idProduct=556e
[66925.017794] usb 1-4.3: New USB device strings: Mfr=3, Product=4, SerialNumber=5
[66925.017799] usb 1-4.3: Product: Cruzer Edge
[66925.017804] usb 1-4.3: Manufacturer: SanDisk
[66925.017808] usb 1-4.3: SerialNumber: 990431108215FFF05368
[66925.019129] usb-storage 1-4.3:1.0: USB Mass Storage device detected
[66925.019542] scsi host3: usb-storage 1-4.3:1.0
[66926.021250] scsi 3:0:0:0: Direct-Access     Linux    File-Stor Gadget 0414 PQ: 0 ANSI: 2
[66926.022471] sd 3:0:0:0: Attached scsi generic sg1 type 0
[66926.023505] sd 3:0:0:0: [sdb] 262144 512-byte logical blocks: (134 MB/128 MiB)
[66926.023729] sd 3:0:0:0: [sdb] Write Protect is off
[66926.023736] sd 3:0:0:0: [sdb] Mode Sense: 0f 00 00 00
[66926.023932] sd 3:0:0:0: [sdb] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[66926.034208]  sdb:
[66926.035170] sd 3:0:0:0: [sdb] Attached SCSI removable disk

------lsusb of RPi from kali --

root@kali:~# lsusb -d 0781:556e -v

Bus 001 Device 031: ID 0781:556e SanDisk Corp.
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               2.00
  bDeviceClass            0 (Defined at Interface level)
  bDeviceSubClass         0
  bDeviceProtocol         0
  bMaxPacketSize0        64
  idVendor           0x0781 SanDisk Corp.
  idProduct          0x556e
  bcdDevice            1.03
  iManufacturer           3 SanDisk
  iProduct                4 Cruzer Edge
  iSerial                 5 990431108215FFF05368
  bNumConfigurations      1
  Configuration Descriptor:
    bLength                 9
    bDescriptorType         2
    wTotalLength           32
    bNumInterfaces          1
    bConfigurationValue     1
    iConfiguration          0
    bmAttributes         0xc0
      Self Powered
    MaxPower                2mA
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        0
      bAlternateSetting       0
      bNumEndpoints           2
      bInterfaceClass         8 Mass Storage
      bInterfaceSubClass      6 SCSI
      bInterfaceProtocol     80 Bulk-Only
      iInterface              1 Mass Storage
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x81  EP 1 IN
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0200  1x 512 bytes
        bInterval               0
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x01  EP 1 OUT
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0200  1x 512 bytes
        bInterval               1
Device Qualifier (for other device speed):
  bLength                10
  bDescriptorType         6
  bcdUSB               2.00
  bDeviceClass            0 (Defined at Interface level)
  bDeviceSubClass         0
  bDeviceProtocol         0
  bMaxPacketSize0        64
  bNumConfigurations      1
Device Status:     0x0000
  (Bus Powered)

------- Kali's view of the USB Device from /sys/bus/usb ----

root@kali:~# cat /sys/bus/usb/devices/1-4.2/* 
cat: /sys/bus/usb/devices/1-4.2/ep_00: Is a directory
556e
0781
no
SanDisk
0
cat: /sys/bus/usb/devices/1-4.2/port: Is a directory
cat: /sys/bus/usb/devices/1-4.2/power: Is a directory
Cruzer Edge
0x0
unknown
cat: /sys/bus/usb/devices/1-4.2/remove: Permission denied
990431108215FFF05368
480
cat: /sys/bus/usb/devices/1-4.2/subsystem: Is a directory
MAJOR=189
MINOR=29
DEVNAME=bus/usb/001/030
DEVTYPE=usb_device
DRIVER=usb
PRODUCT=781/556e/103
TYPE=0/0/0
BUSNUM=001
DEVNUM=030
426
 2.00

----------How Kali see's the RPi SCSI vendor & model strings ---------

root@kali:~# cat /sys/bus/scsi/devices/target3\:0\:0/3\:0\:0\:0/vendor
Linux
root@kali:~# cat /sys/bus/scsi/devices/target3\:0\:0/3\:0\:0\:0/model
File-Stor Gadget

-------- dmesg from Pi Zero after connecting to Windows -----------------

[  409.446304] dwc2 20980000.usb: new device is high-speed
[  409.479146] dwc2 20980000.usb: new address 9
[  439.684939] dwc2 20980000.usb: new device is high-speed
[  439.717958] dwc2 20980000.usb: new address 10
[  439.748612] g_mass_storage gadget: high-speed config #1: Linux File-Backed Storage

Based on feedback from @Ephemeral (many thanks...). I have now tested using libcomposite and conclude it is the best answer.

The problem boils down to inquiry_string being unchangeable with g_mass_storage (unless you want to re-compile the module yourself with a different inquiry_string), but libcomposite gives full control of it, and many other parameters of the usb device.

One downside of libcomposite is that its not a one-liner to instantiate the gadget, it requires a bit more work. But after the gadget is created, the inquiry_string can be changed on the fly, which is quite cool! echo 'ABCDEFGH123456789ABCDEFGWXYZ' >> /sys/kernel/config/usb_gadget/gadget1/functions/mass_storage.usb0/lun.0/inquiry_string

inquirystring is tokenized by the host OS into: vendor(len 8) + model(len 16) + rev(len 4) which is what we see in Windows in PNPDeviceID as VEN_ PROD_ REV_

Name                                  PNPClass      PNPDeviceID                                                              
----                                  --------      -----------                                                              
SanDisk Cruzer Edge USB Device        DiskDrive     USBSTOR\DISK&VEN_SANDISK&PROD_CRUZER_EDGE&REV_1.20\200431108215FFF05367&0

and in OpenWRT Linux as vendor, model, rev in:

/sys/class/block/sda/device/vendor
/sys/class/block/sda/device/model
/sys/class/block/sda/device/rev

or x86 Kali Linux as vendor, model, rev in:

/sys/bus/scsi/devices/target3\:0\:0/3\:0\:0\:0/vendor
/sys/bus/scsi/devices/target3\:0\:0/3\:0\:0\:0/model
/sys/bus/scsi/devices/target3\:0\:0/3\:0\:0\:0/rev

I found this article quite useful to get a better understanding of the architecture of USB composite devices: https://lwn.net/Articles/395712/

This is the full script I use now:

#!/bin/bash
# libcomposite USB mass storage device gadget for raspberry pi zero
# Call this script on Pi Zero startup by adding its full path to /etc/rc.local
# Assumes you have created the backing file for the storage device with something like this:
#  sudo dd if=/dev/zero of=/home/pi/piusb_fat32.bin bs=1 count=0 seek=128M
#  sudo mkdosfs /home/pi/piusb_fat32.bin -n FAT32VOL11

# And done these two steps once:
#  sudo echo "dtoverlay=dwc2" | sudo tee -a /boot/config.txt
#  sudo echo "dwc2" | sudo tee -a /etc/modules  

# Do some simple logging so we know the script is launching at startup
date | tee -a /home/pi/startup_script.log
echo Starting startup_script | tee -a /home/pi/startup_script.log

#Load the kernel module
modprobe libcomposite

#Gadget name (gadget1 is just an arbitrary name)
mkdir /sys/kernel/config/usb_gadget/gadget1
cd /sys/kernel/config/usb_gadget/gadget1

#hardware id
echo 0x0419 > bcdDevice
echo 0x0200 > bcdUSB
echo 0x0781 > idVendor # Sandisk
echo 0x556e > idProduct # Cruzer Edge

#device config
echo 0xEF > bDeviceClass
echo 0x02 > bDeviceSubClass
echo 0x01 > bDeviceProtocol
echo 0x08 > bMaxPacketSize0

#More stuff
mkdir strings/0x409
mkdir strings/0x407
cd strings/0x409
echo 'Sandisk' > manufacturer
echo 'Cruzer Edge' > product
echo 'Serial123456789' > serialnumber
cd ../../
cd strings/0x407
echo 'Sandisk' > manufacturer
echo 'Cruzer Edge' > product
echo 'Serial123456789' > serialnumber

cd ../../

mkdir functions/mass_storage.usb0

#Mass Storage 0 config settings
cd functions/mass_storage.usb0
echo 0 > stall
echo 1 > lun.0/removable
echo 0 > lun.0/ro
echo /home/pi/piusb_fat32.bin > lun.0/file
#Note, the next line is important. Host OS will tokenize it as: vendor(len 8) + model(len 16) + rev(len 4)
#Example here: vendor = ABCDEFGH  model = 123456789ABCDEFG  rev = WXYZ
echo 'ABCDEFGH123456789ABCDEFGWXYZ' > lun.0/inquiry_string
cd ../../

#OS Descriptor for Windows
cd os_desc
echo 1 > use
echo 0xcd > b_vendor_code
echo MSFT100 > qw_sign
cd ../

#Bus Hardware Config
mkdir configs/c.1
cd configs/c.1
echo 0x80 > bmAttributes
echo 100 > MaxPower
mkdir strings/0x409
echo "0" > strings/0x409/configuration
mkdir strings/0x407
echo "1" > strings/0x407/configuration
cd ../../
ln -s functions/mass_storage.usb0 configs/c.1
ln -s configs/c.1 os_desc

#Activate the gadget
ls /sys/class/udc > UDC

This is what it generates in dmesg on Kali x86:

[  279.856039] usb 1-4.4: new high-speed USB device number 8 using xhci_hcd
[  279.957788] usb 1-4.4: New USB device found, idVendor=0781, idProduct=556e
[  279.957796] usb 1-4.4: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[  279.957801] usb 1-4.4: Product: Cruzer Edge
[  279.957805] usb 1-4.4: Manufacturer: Sandisk
[  279.957809] usb 1-4.4: SerialNumber: Serial123456789
[  279.978012] usb-storage 1-4.4:1.0: USB Mass Storage device detected
[  279.978128] scsi host3: usb-storage 1-4.4:1.0
[  279.978232] usbcore: registered new interface driver usb-storage
[  279.979998] usbcore: registered new interface driver uas
[  280.989354] scsi 3:0:0:0: Direct-Access     ABCDEFGH 123456789ABCDEFG WXYZ PQ: 0 ANSI: 2
[  280.990460] sd 3:0:0:0: Attached scsi generic sg1 type 0
[  280.990906] sd 3:0:0:0: [sdb] 262144 512-byte logical blocks: (134 MB/128 MiB)
[  280.991089] sd 3:0:0:0: [sdb] Write Protect is off
[  280.991095] sd 3:0:0:0: [sdb] Mode Sense: 0f 00 00 00
[  280.991271] sd 3:0:0:0: [sdb] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[  280.999942]  sdb: sdb1
[  281.001878] sd 3:0:0:0: [sdb] Attached SCSI removable disk

And lsusb -vv on kali x86:

root@kali:~# lsusb -vv -d 0781:556e

Bus 001 Device 008: ID 0781:556e SanDisk Corp.
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               2.00
  bDeviceClass          239 Miscellaneous Device
  bDeviceSubClass         2 ?
  bDeviceProtocol         1 Interface Association
  bMaxPacketSize0        64
  idVendor           0x0781 SanDisk Corp.
  idProduct          0x556e
  bcdDevice            4.19
  iManufacturer           1 Sandisk
  iProduct                2 Cruzer Edge
  iSerial                 3 Serial123456789
  bNumConfigurations      1
  Configuration Descriptor:
    bLength                 9
    bDescriptorType         2
    wTotalLength           32
    bNumInterfaces          1
    bConfigurationValue     1
    iConfiguration          4 0
    bmAttributes         0x80
      (Bus Powered)
    MaxPower              100mA
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        0
      bAlternateSetting       0
      bNumEndpoints           2
      bInterfaceClass         8 Mass Storage
      bInterfaceSubClass      6 SCSI
      bInterfaceProtocol     80 Bulk-Only
      iInterface              5 Mass Storage
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x81  EP 1 IN
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0200  1x 512 bytes
        bInterval               0
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x01  EP 1 OUT
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0200  1x 512 bytes
        bInterval               1
Device Qualifier (for other device speed):
  bLength                10
  bDescriptorType         6
  bcdUSB               2.00
  bDeviceClass          239 Miscellaneous Device
  bDeviceSubClass         2 ?
  bDeviceProtocol         1 Interface Association
  bMaxPacketSize0        64
  bNumConfigurations      1
Device Status:     0x0000
  (Bus Powered)
JayKay5532
  • 106
  • 1
  • 6

1 Answers1

7

The parameter is : inquiry_string, if this parameter is not defined the value is empty/null then : Linux File-Stor Gadget 0414 is used (where 0x0414 is the langage).More info here

After some research : (tree /sys/kernel/config/usb_gadget/mygadget when the gadget is activated) I have found an empty file named inquiry_string in functions/mass_storage.usb0/lun.0/ that I did not create in my conf. I use libcomposite.

You have :

[..] usb-storage 1-1.2:1.4: USB Mass Storage device detected
[..] scsi host0: usb-storage 1-1.2:1.4
[..] scsi 0:0:0:0: Direct-Access     Linux    File-Stor Gadget 0414 PQ: 0 ANSI: 2

On Raspbian, when the UMS gadget is plugged without inquiry_string defined :

enter image description here


Using libcompiste :

New Configuration Adding inquiry_string:

mkdir -p functions/mass_storage.usb0
echo 1 > functions/mass_storage.usb0/stall              # allow bulk EPs
echo 0 > functions/mass_storage.usb0/lun.0/cdrom        # don't emulate CD-ROm
echo 0 > functions/mass_storage.usb0/ro                 # write access
echo 0 > functions/mass_storage.usb0/lun.0/nofua        # enable Force Unit Access (FUA)    
echo 1 > functions/mass_storage.usb0/lun.0/removable
echo "ScanDisk" > functions/mass_storage.usb0/lun.0/inquiry_string

Now you have :

[..] usb-storage 1-1.2:1.4: USB Mass Storage device detected
[..] scsi host0: usb-storage 1-1.2:1.4
[..] scsi 0:0:0:0: Direct-Access     ScanDisk                       PQ: 0 ANSI: 2

Where ScanDisk can be anything.

Ref: f_mass_storage


Also you can set label name of your vfat : sudo mkdosfs -n "RASPBERRYPI" /vfat.fs.bin


Now on the host your device is recognized (when you click on top right of the desktop on the Remove icon on Raspbian :

ScanDisk Cruzer Edge (RASPBERRYPI)

enter image description here

"ScanDisk"      → functions/mass_storage.usb0/lun.0/inquiry_string

"Cruzer Edge"   → strings/0x409/product

"(RASPBERRYPI)" → volume label

Using g_mass_storage Mass Storage Gadget (MSG) :

sudo modprobe g_mass_storage --show-config|grep inquiry
alias symbol:fsg_common_set_inquiry_string usb_f_mass_storage
alias symbol:fsg_show_inquiry_string usb_f_mass_storage
alias symbol:fsg_store_inquiry_string usb_f_mass_storage

And

sudo modinfo g_mass_storage|grep parm|awk -F ':' '{print $2}'
           idVendor
           idProduct
           bcdDevice
           iSerialNumber
           iManufacturer
           iProduct
           file
           ro
           removable
           cdrom
           nofua
           luns
           stall

As you can see the parameters of module not contains any inquiry_string parameter but usb_f_mass_storage symbol contain some availables related functions.

In your case using g_mass_storage you must use:

sudo modprobe g_mass_storage file=/home/pi/piusb_fat32.bin nofua=1 luns=1 ro=0 stall=0 removable=1 cdrom=0 idVendor=0x0781 idProduct=0x556e bcdDevice=0x0103 iManufacturer="SanDisk" iProduct="Cruzer Edge" iSerialNumber="990431108215FFF05368"

And read this related paper.

Other then those, as usual, the values of module parameters can be
read from /sys/module/g_mass_storage/parameters/* files.

Then :

root@raspberrypi:~# modprobe g_mass_storage file=/home/pi/Desktop/usbdisk.bin nofua=1 luns=1 ro=0 stall=0 removable=1 cdrom=0 idVendor=0x0781 idProduct=0x556e bcdDevice=0x0103 iManufacturer="SanDisk" iProduct="Cruzer Edge" iSerialNumber="990431108215FFF05368"

root@raspberrypi:~# echo test > /sys/module/g_mass_storage/parameters/inquiry_string
-bash: /sys/module/g_mass_storage/parameters/inquiry_string: Permission denied

root@raspberrypi:~# ls -l /sys/module/g_mass_storage/parameters/
total 0
-r--r--r-- 1 root root 4096 déc.  18 03:23 bcdDevice
-r--r--r-- 1 root root 4096 déc.  18 03:23 cdrom
-r--r--r-- 1 root root 4096 déc.  18 03:23 file
-r--r--r-- 1 root root 4096 déc.  18 03:23 idProduct
-r--r--r-- 1 root root 4096 déc.  18 03:23 idVendor
-r--r--r-- 1 root root 4096 déc.  18 03:23 iManufacturer
-r--r--r-- 1 root root 4096 déc.  18 03:23 iProduct
-r--r--r-- 1 root root 4096 déc.  18 03:23 iSerialNumber
-r--r--r-- 1 root root 4096 déc.  18 03:23 luns
-r--r--r-- 1 root root 4096 déc.  18 03:23 nofua
-r--r--r-- 1 root root 4096 déc.  18 03:23 removable
-r--r--r-- 1 root root 4096 déc.  18 03:23 ro
-r--r--r-- 1 root root 4096 déc.  18 03:23 stall

But as you can see the directory is ReadOnly, then you cannot set any parameters, only read parameters.

Maybe a solution can be found here.But here I can read :

...FSG's module parameters are not supported. ...

and remember you have:

alias symbol:fsg_common_set_inquiry_string usb_f_mass_storage

So, finally I think you cannot set the inquiry_string FS parameter if you not use libcomposite (libcomposite seems to create a NULL inquiry_string file then you can set any value in this file as my screenshots show very well)

And sorry for the typo , in my tests I use ScanDisk instance of SanDisk but it is not important.

Ephemeral
  • 2,167
  • 1
  • 8
  • 19