Serial port line discipline changes

I am working with a serial port BT transceiver (bcm4343w) and part of the bring-up process involves setting the line discipline.

Currently, the application inside the docker container reports that the port itself does not have the capability to set the line discipline. (Port on the host is set rwx to dialout group, docker user and host torizon user are also in the dialout group)

To narrow the issue, I tried to do the same thing as the torizon user on the host OS, and receive a similar error that the line discipline could not be set.

It only succeeds if the bringup command is run as the root user on the OS.

I haven’t had much luck finding information on how to grant a user this specific permission on a serial port. Is there a way to allow it? It appears everything else can be done without issue (baud rate, flow control, etc)

(Note: I’m aware we could let the host OS manage the device but this would require modifying the application code I am porting and I am trying to avoid that unless absolutely necessary).

Thanks!

Greetings @bw908,

Just to clarify how exactly are you trying to change the line discipline? And what do you see when it fails/does not work?

Best Regards,
Jeremias

I’ve tried three different ways. The first is as built into our application, this code fails and prints the error:

    if (ioctl(m_pPort->handle(), TIOCSETD, &i) < 0) {
        LOGERR("ttySC0 does not support setting line discipline!");
        return false;
    }

I’ve also tried with the brcm_patchram_plus tool, which reports “Can’t set line discipline”, as well as via hciattach which reports “Can’t set line discipline: Operation not permitted”.

When it is successful (i.e. as root in the host OS), the hci0 interface appears as expected.

I see, which specific line discipline are you trying to set this tty to?

I did a test on Torizon OS 6.X and it seems to work fine. Of course I don’t have your specific serial port BT transceiver so it’s not a perfect reproduction, but I used the built-in UARTs on our modules as a test. I used stty and ldattach to manipulate line disciplines since I’m more personally familiar with these tools:

torizon@apalis-imx8-06738453:~$ docker run --rm -it --rm --device /dev/apalis-uart4 --user torizon torizon/debian:3-bookworm
torizon@504e4ec5e964:/$ ldattach PPS /dev/apalis-uart4
torizon@504e4ec5e964:/$ stty -F /dev/apalis-uart4
speed 9600 baud; line = 18;
min = 1; time = 0;
-brkint -icrnl -imaxbel
-opost
-isig -icanon -iexten -echo

From this snippet I spun up our basic Debian container adding in the UART device. I then used ldattach to set the line discipline for this UART to PPS. I then used stty to check what the line discipline number of this UART is after changing it. As you can see it shows line = 18 which corresponds to PPS as seen here: ldattach: attach a line discipline to a serial line - Linux Manuals (8)

This also works the same outside of the container as the torizon user.

The only time I see an error similar to what you got is if I do something like this:

torizon@apalis-imx8-06738453:~$ ldattach SLIP /dev/apalis-uart4
ldattach: cannot set line discipline: Invalid argument

But this makes sense since our kernel does not have the SLIP kernel configuration enabled:

torizon@apalis-imx8-06738453:~$ zcat /proc/config.gz | grep SLIP
# CONFIG_SLIP is not set

Given this my only thoughts are either:

  • You’re trying to change the line discipline to something that is not supported/enabled in our current kernel.
  • The line discipline you’re trying to set requires root privileges for some reason.
  • There’s something special/different about your device that my test here can’t reproduce.

I didn’t exactly give an answer for your specific situation but I hope this helps clear things up somewhat.

Best Regards,
Jeremias

Interesting. In our case we are trying to set the discipline to HCI

As noted, it does work for root on the host OS, so it shouldn’t be an “unsupported” discipline, and is listed with ldattach --help

torizon@dev:/usr/lib$ /usr/sbin/ldattach --help

Usage:
 ldattach [options] <ldisc> <device>

Attach a line discipline to a serial line.

Options:
 -d, --debug             print verbose messages to stderr
 -s, --speed <value>     set serial line speed
 -c, --intro-command <string> intro sent before ldattach
 -p, --pause <seconds>   pause between intro and ldattach
 -7, --sevenbits         set character size to 7 bits
 -8, --eightbits         set character size to 8 bits
 -n, --noparity          set parity to none
 -e, --evenparity        set parity to even
 -o, --oddparity         set parity to odd
 -1, --onestopbit        set stop bits to one
 -2, --twostopbits       set stop bits to two
 -i, --iflag [-]<iflag>  set input mode flag

 -h, --help              display this help
 -V, --version           display version

Known <ldisc> names:
  TTY           SLIP          MOUSE         PPP           STRIP       
  AX25          X25           6PACK         R3964         IRDA        
  HDLC          SYNC_PPP      SYNCPPP       HCI           GIGASET_M101
  M101          GIGASET       PPS           GSM0710     

Known <iflag> names:
  IGNBRK        BRKINT        IGNPAR        PARMRK        INPCK       
  ISTRIP        INLCR         IGNCR         ICRNL         IUCLC       
  IXON          IXANY         IXOFF         IMAXBEL       IUTF8       

For more details see ldattach(8).

And, trying this out:

torizon@dev:/usr/lib$ /usr/sbin/ldattach HCI /dev/ttySC0
ldattach: cannot set line discipline: Operation not permitted
torizon@dev:/usr/lib$ ls -lh /dev/ttySC0
crwxrwx--- 1 torizon dialout 241, 0 Mar 19 13:30 /dev/ttySC0
torizon@dev:/usr/lib$ groups
adm dialout sudo audio video plugdev gpio i2cdev spidev pwm users input docker torizon lp5521

where you can see the permissions should be such that torizon “owns” that particular port and therefore able to do anything with it.

Sounds like I will have to poke at it more to figure things out - thanks for the insight.

That’s very strange, this works just fine on our module’s built-in UART ports:

torizon@apalis-imx8-06738453:~$ ldattach HCI /dev/apalis-uart4
torizon@apalis-imx8-06738453:~$ stty -F /dev/apalis-uart4
speed 9600 baud; line = 15;
min = 1; time = 0;
-brkint -icrnl -imaxbel
-opost
-isig -icanon -iexten -echo
torizon@apalis-imx8-06738453:~$ ls -l /dev/apalis-uart4
lrwxrwxrwx 1 root root 6 Mar 19 20:06 /dev/apalis-uart4 -> ttyLP2
torizon@apalis-imx8-06738453:~$ ls -l /dev/ttyLP2
crw-rw---- 1 root dialout 244, 2 Mar 19 20:06 /dev/ttyLP2

I was able to set it to HCI discipline with no issues as the torizon user. Makes me think there’s something special/unique about your device here, but it’s hard for me to say exactly.

Best Regards,
Jeremias

Interesting. I get the same error if I try the built-in ports, e.g.

torizon@dev:/usr/sbin/ldattach HCI /dev/ttymxc1 
ldattach: cannot set line discipline: Operation not permitted

We are using the stock imx6 apalis TorizonCore image on the imx6 as our base image with a handful of changes in the devicetree and some FS customization, but nothing that would seem to explain this.

We are using the stock imx6 apalis

Ahh okay this was the little hint I needed. So I tried this on my own Apalis iMX6 and I got the same error as you:

torizon@89dff19e5eb9:/$ ldattach HCI /dev/apalis-uart4
ldattach: cannot set line discipline: Operation not permitted

Strangely though this was only when trying to change the line discipline to HCI. For other disciplines I didn’t get an error. I did some digging and ended up in the Linux kernel to understand the code surrounding the HCI discipline, and I found something interesting. Look at this: Bluetooth: hci_ldisc: require CAP_NET_ADMIN to attach N_HCI ldisc · torvalds/linux@c05731d · GitHub

This commit makes it so that a process/thread needs to have the CAP_NET_ADMIN capability to change something to the HCI line discipline. This is why root user can do this since it bypasses such capability checks due to the nature of being the root user.

Now if you see this commit you’ll see it was added back in Linux kernel version 5.16. In my previous tests here I was using the Apalis i.MX8. Our Apalis i.MX8 uses a downstream 5.15 kernel and looking at the code here we see this CAP_NET_ADMIN check isn’t present here: hci_ldisc.c « bluetooth « drivers - linux-toradex.git - Linux kernel for Apalis, Colibri and Verdin modules

This is why you were seeing the issue on Apalis i.MX6 and I was not seeing it on Apalis i.MX8.

Alright, so knowing this what can we do? According to the commit a process needs to have CAP_NET_ADMIN capability to change line discipline to HCI. Here’s what I did:

  • First spin up a container with --cap-add NET_ADMIN this allows the container to manipulate this capability within itself:
docker run --rm -it --rm --device /dev/apalis-uart4 --cap-add NET_ADMIN torizon/debian:3-bookworm
  • Now in the container let’s install the setcap utility:
root@f5e0afc5f275:/# apt update && apt install libcap2-bin
  • Next, we add the CAP_NET_ADMIN capability to the binary/tool that we will use to change the line discipline:
root@f5e0afc5f275:/# setcap "cap_net_admin+eip" /usr/sbin/ldattach
  • Let’s switch to the torizon user now and test:
root@f5e0afc5f275:/# su torizon
$ whoami
torizon
$ ldattach HCI /dev/apalis-uart4
$ stty -F /dev/apalis-uart4
speed 9600 baud; line = 15;
min = 1; time = 0;
-brkint -icrnl -imaxbel
-opost
-isig -icanon -iexten -echo

Tada! We can now set the line discipline to HCI as the torizon user within the container.

Now for your case I imagine you’d want to try and add the CAP_NET_ADMIN capability to whatever application/tool/binary that will actually be changing the line discipline for your device.

Best Regards,
Jeremias

1 Like

Much appreciated, I’ll give that a try and let you know!

I can confirm this was the issue and let me get past the line discipline issue.

Thanks for the assist!

Perfect, thank you for confirming the solution.