Tools: Embedded Linux Development - Part 6 (2026)
In this tutorial, I will continue to discuss embedded Linux development with ssh server activation. Previously, I've entered into BeagleBone Black over J1 serial header with a USB-UART converter. In here, I will show that how to enter into it with ssh command. Firstly, there are two important points that you have to do. I've already did these in previous tutorials. Firstly, I compiled the kernel with USB Gadget module and secondly, I installed openssh-server package into the rootfs. USB gadget module enables the USB connection as the virtual ethernet adapter. Let's do required settings for both side. Use the J1 serial header again to enter into the BeagleBone Black. Type the "root" and the password. Also creating a normal user is good practice. I've created a user named "can" and set the its password. After that go to the your home directory and create a bash script. I named it as setup-usb-gadget.sh. Open and copy this into that: In here, I loaded the g_ether module into the kernel. It's the name of USB gadget module. I will create usb0 interface. After that I set it as "up" and its IP address as "198.168.7.2". You can give any IP address, doesn't matter. But generally, "198.168.7.2" is used. Lastly make sure that ssh server is enabled. Set the executable permission: Lastly, list the available interface on BeagleBone Black: You see the "usb0" interface. That's enough for BeagleBone Black. Let's continue with host side. Open a new terminal and list the available interfaces on host: BeagleBone Black seems as "enxf6b084e3dcc2" for now. You probably see the different name. It doesn't matter. As wee did in BeagleBone Black, let's do the same things at host side: I assigned the IP address "198.168.7.1" to host (I did "198.168.7.2" for BeagleBone Black). Lastly, ping BeagleBone Black interface: That's okey 🥳🥳🥳🥳. You can connect to BeagleBone Black with ssh command for now: You don't need anymore J1 serial header. You can use it within the ssh terminal for now. Also you can set the setup-usb-gadget.sh as startup script so that it runs automatically after the boot. In next tutorial, I will inspect the uEnv.txt file and u-boot console. You can make many interesting tricks in there. Simmonds C., Mastering Embedded Linux Programming, Packt Publishing, 2015
Embedded Linux system development training, Bootlin, 2024 Templates let you quickly answer FAQs or store snippets for re-use. Hide child comments as well For further actions, you may consider blocking this person and/or reporting abuse
$ root@can:/# useradd -m -s /bin/bash can
root@can:/# passwd can
root@can:/# usermod -aG -weight: 600;">sudo can
root@can:/# useradd -m -s /bin/bash can
root@can:/# passwd can
root@can:/# usermod -aG -weight: 600;">sudo can
root@can:/# useradd -m -s /bin/bash can
root@can:/# passwd can
root@can:/# usermod -aG -weight: 600;">sudo can
root@can:/home/can# ls
setup-usb-gadget.sh
root@can:/home/can# ls
setup-usb-gadget.sh
root@can:/home/can# ls
setup-usb-gadget.sh
#!/bin/bash INTERFACE="usb0"
IP_ADDR="198.168.7.2/24" # Load the g_ether kernel module that creates the ethernet virtual link.
modprobe g_ether # Configure the link interface.
ip addr flush dev "$INTERFACE"
ip link set "$INTERFACE" up
ip addr add "$IP_ADDR" dev "$INTERFACE" # Ensure that SSH is running.
-weight: 500;">systemctl -weight: 500;">start ssh
#!/bin/bash INTERFACE="usb0"
IP_ADDR="198.168.7.2/24" # Load the g_ether kernel module that creates the ethernet virtual link.
modprobe g_ether # Configure the link interface.
ip addr flush dev "$INTERFACE"
ip link set "$INTERFACE" up
ip addr add "$IP_ADDR" dev "$INTERFACE" # Ensure that SSH is running.
-weight: 500;">systemctl -weight: 500;">start ssh
#!/bin/bash INTERFACE="usb0"
IP_ADDR="198.168.7.2/24" # Load the g_ether kernel module that creates the ethernet virtual link.
modprobe g_ether # Configure the link interface.
ip addr flush dev "$INTERFACE"
ip link set "$INTERFACE" up
ip addr add "$IP_ADDR" dev "$INTERFACE" # Ensure that SSH is running.
-weight: 500;">systemctl -weight: 500;">start ssh
root@can:/home/can# chmod +x ./setup-usb-gadget.sh
root@can:/home/can# chmod +x ./setup-usb-gadget.sh
root@can:/home/can# chmod +x ./setup-usb-gadget.sh
root@can:/home/can# ./setup-usb-gadget.sh [ 644.487501] g_ether gadget.0: HOST MAC f6:b0:84:e3:dc:c2
[ 644.493125] g_ether gadget.0: MAC e2:87:7a:43:97:1d
[ 644.498588] g_ether gadget.0: Ethernet Gadget, version: Memorial Day 2008
[ 644.505565] g_ether gadget.0: g_ether ready
[ 644.522283] PM: Cannot get wkup_m3_ipc handle
root@can:/home/can# ./setup-usb-gadget.sh [ 644.487501] g_ether gadget.0: HOST MAC f6:b0:84:e3:dc:c2
[ 644.493125] g_ether gadget.0: MAC e2:87:7a:43:97:1d
[ 644.498588] g_ether gadget.0: Ethernet Gadget, version: Memorial Day 2008
[ 644.505565] g_ether gadget.0: g_ether ready
[ 644.522283] PM: Cannot get wkup_m3_ipc handle
root@can:/home/can# ./setup-usb-gadget.sh [ 644.487501] g_ether gadget.0: HOST MAC f6:b0:84:e3:dc:c2
[ 644.493125] g_ether gadget.0: MAC e2:87:7a:43:97:1d
[ 644.498588] g_ether gadget.0: Ethernet Gadget, version: Memorial Day 2008
[ 644.505565] g_ether gadget.0: g_ether ready
[ 644.522283] PM: Cannot get wkup_m3_ipc handle
root@can:/home/can# ip addr show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host noprefixroute valid_lft forever preferred_lft forever
2: sit0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN group default qlen 1000 link/sit 0.0.0.0 brd 0.0.0.0
3: eth0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000 link/ether 64:8c:bb:f2:25:78 brd ff:ff:ff:ff:ff:ff
4: usb0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000 link/ether e2:87:7a:43:97:1d brd ff:ff:ff:ff:ff:ff inet 198.168.7.2/24 brd 198.168.7.255 scope global usb0 valid_lft forever preferred_lft forever inet6 fe80::e087:7aff:fe43:971d/64 scope link valid_lft forever preferred_lft forever
root@can:/home/can# ip addr show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host noprefixroute valid_lft forever preferred_lft forever
2: sit0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN group default qlen 1000 link/sit 0.0.0.0 brd 0.0.0.0
3: eth0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000 link/ether 64:8c:bb:f2:25:78 brd ff:ff:ff:ff:ff:ff
4: usb0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000 link/ether e2:87:7a:43:97:1d brd ff:ff:ff:ff:ff:ff inet 198.168.7.2/24 brd 198.168.7.255 scope global usb0 valid_lft forever preferred_lft forever inet6 fe80::e087:7aff:fe43:971d/64 scope link valid_lft forever preferred_lft forever
root@can:/home/can# ip addr show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host noprefixroute valid_lft forever preferred_lft forever
2: sit0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN group default qlen 1000 link/sit 0.0.0.0 brd 0.0.0.0
3: eth0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000 link/ether 64:8c:bb:f2:25:78 brd ff:ff:ff:ff:ff:ff
4: usb0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000 link/ether e2:87:7a:43:97:1d brd ff:ff:ff:ff:ff:ff inet 198.168.7.2/24 brd 198.168.7.255 scope global usb0 valid_lft forever preferred_lft forever inet6 fe80::e087:7aff:fe43:971d/64 scope link valid_lft forever preferred_lft forever
can@can:~$ ip addr show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host noprefixroute valid_lft forever preferred_lft forever
2: enp3s0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc fq_codel state DOWN group default qlen 1000 link/ether e8:6a:64:19:45:15 brd ff:ff:ff:ff:ff:ff
3: wlp2s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000 link/ether b0:fc:36:c1:cf:eb brd ff:ff:ff:ff:ff:ff inet 10.152.197.93/24 brd 10.152.197.255 scope global dynamic noprefixroute wlp2s0 valid_lft 3521sec preferred_lft 3521sec inet6 fe80::18fc:91fe:ea80:8fad/64 scope link noprefixroute valid_lft forever preferred_lft forever
4: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default link/ether fa:47:d4:7a:67:3e brd ff:ff:ff:ff:ff:ff inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0 valid_lft forever preferred_lft forever
13: enxf6b084e3dcc2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000 link/ether f6:b0:84:e3:dc:c2 brd ff:ff:ff:ff:ff:ff
can@can:~$ ip addr show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host noprefixroute valid_lft forever preferred_lft forever
2: enp3s0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc fq_codel state DOWN group default qlen 1000 link/ether e8:6a:64:19:45:15 brd ff:ff:ff:ff:ff:ff
3: wlp2s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000 link/ether b0:fc:36:c1:cf:eb brd ff:ff:ff:ff:ff:ff inet 10.152.197.93/24 brd 10.152.197.255 scope global dynamic noprefixroute wlp2s0 valid_lft 3521sec preferred_lft 3521sec inet6 fe80::18fc:91fe:ea80:8fad/64 scope link noprefixroute valid_lft forever preferred_lft forever
4: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default link/ether fa:47:d4:7a:67:3e brd ff:ff:ff:ff:ff:ff inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0 valid_lft forever preferred_lft forever
13: enxf6b084e3dcc2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000 link/ether f6:b0:84:e3:dc:c2 brd ff:ff:ff:ff:ff:ff
can@can:~$ ip addr show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host noprefixroute valid_lft forever preferred_lft forever
2: enp3s0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc fq_codel state DOWN group default qlen 1000 link/ether e8:6a:64:19:45:15 brd ff:ff:ff:ff:ff:ff
3: wlp2s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000 link/ether b0:fc:36:c1:cf:eb brd ff:ff:ff:ff:ff:ff inet 10.152.197.93/24 brd 10.152.197.255 scope global dynamic noprefixroute wlp2s0 valid_lft 3521sec preferred_lft 3521sec inet6 fe80::18fc:91fe:ea80:8fad/64 scope link noprefixroute valid_lft forever preferred_lft forever
4: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default link/ether fa:47:d4:7a:67:3e brd ff:ff:ff:ff:ff:ff inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0 valid_lft forever preferred_lft forever
13: enxf6b084e3dcc2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000 link/ether f6:b0:84:e3:dc:c2 brd ff:ff:ff:ff:ff:ff
can@can:~$ ip addr flush dev enxf6b084e3dcc2
can@can:~$ -weight: 600;">sudo ip link set enxf6b084e3dcc2 up
can@can:~$ -weight: 600;">sudo ip addr add 198.168.7.1/24 dev enxf6b084e3dcc2
can@can:~$ ip addr flush dev enxf6b084e3dcc2
can@can:~$ -weight: 600;">sudo ip link set enxf6b084e3dcc2 up
can@can:~$ -weight: 600;">sudo ip addr add 198.168.7.1/24 dev enxf6b084e3dcc2
can@can:~$ ip addr flush dev enxf6b084e3dcc2
can@can:~$ -weight: 600;">sudo ip link set enxf6b084e3dcc2 up
can@can:~$ -weight: 600;">sudo ip addr add 198.168.7.1/24 dev enxf6b084e3dcc2
can@can:~$ ping 198.168.7.2
PING 198.168.7.2 (198.168.7.2) 56(84) bytes of data.
64 bytes from 198.168.7.2: icmp_seq=1 ttl=64 time=0.904 ms
64 bytes from 198.168.7.2: icmp_seq=2 ttl=64 time=0.351 ms
64 bytes from 198.168.7.2: icmp_seq=3 ttl=64 time=0.449 ms
64 bytes from 198.168.7.2: icmp_seq=4 ttl=64 time=0.478 ms
64 bytes from 198.168.7.2: icmp_seq=5 ttl=64 time=0.585 ms
64 bytes from 198.168.7.2: icmp_seq=6 ttl=64 time=0.477 ms
^C
--- 198.168.7.2 ping statistics ---
6 packets transmitted, 6 received, 0% packet loss, time 5114ms
rtt min/avg/max/mdev = 0.351/0.540/0.904/0.176 ms
can@can:~$ ping 198.168.7.2
PING 198.168.7.2 (198.168.7.2) 56(84) bytes of data.
64 bytes from 198.168.7.2: icmp_seq=1 ttl=64 time=0.904 ms
64 bytes from 198.168.7.2: icmp_seq=2 ttl=64 time=0.351 ms
64 bytes from 198.168.7.2: icmp_seq=3 ttl=64 time=0.449 ms
64 bytes from 198.168.7.2: icmp_seq=4 ttl=64 time=0.478 ms
64 bytes from 198.168.7.2: icmp_seq=5 ttl=64 time=0.585 ms
64 bytes from 198.168.7.2: icmp_seq=6 ttl=64 time=0.477 ms
^C
--- 198.168.7.2 ping statistics ---
6 packets transmitted, 6 received, 0% packet loss, time 5114ms
rtt min/avg/max/mdev = 0.351/0.540/0.904/0.176 ms
can@can:~$ ping 198.168.7.2
PING 198.168.7.2 (198.168.7.2) 56(84) bytes of data.
64 bytes from 198.168.7.2: icmp_seq=1 ttl=64 time=0.904 ms
64 bytes from 198.168.7.2: icmp_seq=2 ttl=64 time=0.351 ms
64 bytes from 198.168.7.2: icmp_seq=3 ttl=64 time=0.449 ms
64 bytes from 198.168.7.2: icmp_seq=4 ttl=64 time=0.478 ms
64 bytes from 198.168.7.2: icmp_seq=5 ttl=64 time=0.585 ms
64 bytes from 198.168.7.2: icmp_seq=6 ttl=64 time=0.477 ms
^C
--- 198.168.7.2 ping statistics ---
6 packets transmitted, 6 received, 0% packet loss, time 5114ms
rtt min/avg/max/mdev = 0.351/0.540/0.904/0.176 ms
can@can:~$ ssh [email protected]
[email protected]'s password: Linux can 6.14.0-ge8b471285262 #1 SMP Mon Apr 13 12:31:38 +03 2026 armv7l The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright. Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Sat Jan 1 00:43:51 2000 from 198.168.7.1
can@can:~$ can@can:~$ ls
setup-usb-gadget.sh
can@can:~$ cd ..
can@can:/home$ cd ..
can@can:/$ ls
bin boot dev etc home lib lost+found media mnt opt proc root run sbin srv sys tmp usr var
can@can:~$ ssh [email protected]
[email protected]'s password: Linux can 6.14.0-ge8b471285262 #1 SMP Mon Apr 13 12:31:38 +03 2026 armv7l The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright. Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Sat Jan 1 00:43:51 2000 from 198.168.7.1
can@can:~$ can@can:~$ ls
setup-usb-gadget.sh
can@can:~$ cd ..
can@can:/home$ cd ..
can@can:/$ ls
bin boot dev etc home lib lost+found media mnt opt proc root run sbin srv sys tmp usr var
can@can:~$ ssh [email protected]
[email protected]'s password: Linux can 6.14.0-ge8b471285262 #1 SMP Mon Apr 13 12:31:38 +03 2026 armv7l The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright. Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Sat Jan 1 00:43:51 2000 from 198.168.7.1
can@can:~$ can@can:~$ ls
setup-usb-gadget.sh
can@can:~$ cd ..
can@can:/home$ cd ..
can@can:/$ ls
bin boot dev etc home lib lost+found media mnt opt proc root run sbin srv sys tmp usr var