How to I detect whether a tty belonging to a gsm/3g-modem is a data or control port? - linux

I'm currently writing a small tool for a linux router that sets up a wwan (gsm/3g) connection when I plug an appropriate modem into its USB port. When the device is plugged in several ttys are registered and I currently maintain a list of manufacturers and devices and which of their registered ttys is the control / data port.
If possible I want to get rid of this list and find a way to somehow probe the registered ttys directly to check if they are a control port or a data port.
I examined the sourcecode of wvdial and modem-manager to see how these tools detect the right port but was unable to find suitable information. I also tried to look for information in sysfs to distinguish the ports but this wasn't successful either.

You cannot detect this via external means. The common practise is either to setup udev rules for specific modem manufacturer and model. Or you can sequentially connect to each tty and verify via AT command what type of port it is.
In the case of udev rules you can follow this process:
1) Detect modem vid and pid
2) Based on vid/pid create symlinks in /dev/serial/by-id
For example a Sierra Wireless MC8795V modem with vid = 1199 and pid 683c. I know that port 3 is always the AT command channel. Therefore you could create a symlink post-fixed with -AT at the end.
In the case of detecting via AT commands the best and more common approach is to execute the AT command to see if the tty responds at all. You should get an echo back or an OK if your configured your modem not to echo.
For example:
AT
AT
OK
If you get a response this means you found either an AT control port or a PPP port. To check this simply execute a ATI command. If the response contains APP1, APP2, APP3 then you hit a PPP port. Otherwise you found your AT control port.
For example a AT control port:
ATI
Manufacturer: Sierra Wireless, Incorporated
Model: MC8795V
Revision: K2_0_7_46AP C:/WS/FW/K2_0_7_46AP/MSM6290/SRC 2010/10/27 22:15:30
IMEI: XXXXXXXXXXXXXXX
IMEI SV: 20
FSN: D9A2160146410
3GPP Release 6
+GCAP: +CGSM,+DS,+ES
OK
For example a PPP port:
ATI
Sierra Wireless, Incorporated
MC8795V
APP1
OK
A word of warning though. In the case of Sierra Wireless modules they clearly show which port is which. In the case of other manufacturers you'll need to check the USB interface guide to see if it is possible via ATI to take this approach.

I use this script to get Data and Control ports for 3g usb dongle.
#!/bin/sh
. /usr/share/libubox/jshn.sh
for a in `ls /sys/bus/usb/devices`; do
local vendor product
[ -z "$usb" -a -f /sys/bus/usb/devices/$a/idVendor -a -f /sys/bus/usb/devices/$a/idProduct ] || continue
vendor=$(cat /sys/bus/usb/devices/$a/idVendor)
product=$(cat /sys/bus/usb/devices/$a/idProduct)
echo Vendor $vendor, Product $product
[ -f /lib/network/wwan/$vendor:$product ] && {
usb=/lib/network/wwan/$vendor:$product
devicename=$a
echo usb: $usb devicename: $devicename
}
done
[ -n "$usb" ] && {
local old_cb control data
json_set_namespace wwan old_cb
json_init
json_load "$(cat $usb)"
echo "$(cat $usb)"
json_select
json_get_vars desc control data
json_set_namespace $old_cb
[ -n "$control" -a -n "$data" ] && {
ttys=$(ls -d /sys/bus/usb/devices/$devicename/${devicename}*/tty* | sed "s/.*\///g" | tr "\n" " ")
ctl_device=$(echo $ttys | cut -d" " -f $((control + 1)))
[ -n "$ctl_device" ] && ctl_device=/dev/$ctl_device
dat_device=$(echo $ttys | cut -d" " -f $((data + 1)))
[ -n "$dat_device" ] && dat_device=/dev/$dat_device
echo control_device: $ctl_device, data_device: $dat_device
}
}
Sample outputs:
Connected ZTE MF667
Vendor 1a40, Product 0101 #this is usb hub
Vendor 19d2, Product 0016
usb: /lib/network/wwan/19d2:0016 devicename: 1-1.2
{
"desc": "ONDA MF110/ZTE",
"control": 1,
"data": 2
}}
control_device: /dev/ttyUSB1, data_device: /dev/ttyUSB2
Connected Huawei E3131
Vendor 1a40, Product 0101 #this is usb hub
Vendor 12d1, Product 1506
usb: /lib/network/wwan/12d1:1506 devicename: 1-1.2
{
"desc": "Huawei E367/E398",
"control": 2,
"data": 0
}}
control_device: /dev/ttyUSB2, data_device: /dev/ttyUSB0

This works for me:
for device in $(mmcli -L | grep ModemManager | awk '{print $1}'); do
cport=$(mmcli -m $device | awk '/primary port:/{ print $NF }' | tr -d \')
ldevices=($(mmcli -m $device | grep "ports:" | pcregrep -o1 "(\w+) \(at\)"))
dport=$(echo "/dev/${ldevices[#]##$cport}")
[ -c $dport ] && echo $dport
done

Related

How can I tail dmesg

I am using Ubuntu 20.04.3 LTS. I am trying to monitor the serial port connect with my Arduino.
I have seen my friend using the following command (he performed it in my laptop):
tail -f {dmesg,syslog} | grep -i tty
And whenever I plugin and unplug the arduino, the terminal always keep up showing serial port name, its condition. But when I try it myself, it says that there is not such file or directory. I have search and tried following command:
tail -f var/log/dmesg
tail -f var/log/{dmesg,syslog}
But it seems like it does not show up the serial port or keep up with condition. Would you help me with any ideas?
You can use
dmesg -W | grep -i tty
-w, --follow
Wait for new messages. This feature is supported only on systems with a readable /dev/kmsg (since kernel 3.5.0).
So Output will be something like this
rexter#rexter:/media/rexter/REXDRIVE$ dmesg -w | grep -i tty
[ 0.112876] printk: console [tty0] enabled
[ 332.500320] Bluetooth: RFCOMM TTY layer initialized
If you want to get only new message and want to hide the old ones then use -W
-W, --follow-new
Wait and print only new messages.
Bonus:
Use -T to get the time stamp so that you can get the time when you receive the log.
Thank you :)

Controlling IKEA Tradfri lights from Raspberry Pi

I have a home automation system set up using a few Raspberry pi zeros all connected through sockets to a pi b+ that i use to host a web server with PHP running the whole system.
I bought the IKEA Tradfri lights and gateway after seeing that it was possible to control them through the raspberry pi.
I followed the instructions on Pimoroni
I follow the instructions for
Installing libcoap with support for DTLS
Following the instructions under
API endpoints
I copy and paste the code:
coap-client -m put -u "Client_identity" -k "1a2b3c4d5e6f7g8h" -e '{ "3311": [{ "5850": 0 }] }' "coaps://192.168.0.10:5684/15001/65537"
Changing the IP address to the IP address of my IKEA tradfri gateway and the security key to the one on the gateway.
I get the following:
pi#raspberrypi:~/libcoap $ coap-client -m put -u "Client_identity" -k
"My security key" -e '{ "3311": [{ "5850": 0 }] }'
"coaps://192.168.0.105:5684/15001/65537"
v:1 t:CON c:PUT i:442d {} [ ]
decrypt_verify(): found 24 bytes cleartext
decrypt_verify(): found 4 bytes cleartext
4.01
But nothing seems to happen .....
I expect the first light that I connected to the system to turn off
if I try
coap-client -m get -u "Client_identity" -k "1a2b3c4d5e6f7g8h" "coaps://192.168.0.10:5684/15001/65537"
To try get information about the lights i get the same response.
I don't see any errors so i don't even know where to start with figuring this out.
Any suggestions on what I could do ?
IKEA Trådfri's firmware update changed in such a way that you must create a new identity for your integration: https://github.com/ggravlingen/pytradfri/issues/90
I had the same problem, but it works if you leave the user name empty:
coap-client -m put -k "SECURITY_CODE" -e '{ "3311": [{ "5850": 0 }] }' "coaps://192.168.0.10:5684/15001/65537"
Tested using coap-client v4.1.2 and Trådfri Gateway firmware v1.4.15

Read raw USB data for port being used by VirtualBox

I have software for communicating with a serial device that only runs on Windows 7. My host machine is running Ubuntu 16.04, with Windows 7 in virtual box.
I've managed to set it up using USB device filters in VirtualBox settings so that Windows sees and can communicate with the device.
However I'd like to capture what's being sent to and from the device. I thought something as simple as cat /dev/ttyUSB0 would work but unfortunately when I start VirtualBox I get this in dmesg:
[31199.465270] vboxdrv: ffffffffc0df4020 VMMR0.r0
[31199.653494] vboxdrv: ffffffffc0ef7020 VBoxDDR0.r0
[31199.710573] VBoxNetFlt: attached to 'wlp1s0' / 98:54:1b:04:13:48
[31199.863579] ftdi_sio ttyUSB0: FTDI USB Serial Device converter now disconnected from ttyUSB0
[31199.863674] ftdi_sio 1-3:1.0: device disconnected
So I don't know which file to monitor in /dev anymore. I suppose I might be able to try listen for the communication from Windows, but if I can I'd like to know if it's possible to monitor it from my host machine.
Edit:
This answer helped me for a start. I now get some cool looking stream on the terminal, next step is deciphering it, or if anyone has a better way I'm interested - it looks like the person who answered that question still has deciphering it as a TODO :-)
The fact that it was communicating with software in VirtualBox didn't really matter. This answer got me most of the way just by (as root):
modprobe usbmon
cat /sys/kernel/debug/usb/devices|less and search for device
cat /sys/kernel/debug/usb/usbmon/7u where 7 is the number from "Bus=" in the device table from step 2
From there is was just filtering the output.
A basic way could be just
cat /sys/kernel/debug/usb/usbmon/1u |cut -d\ -f9- | grep ^\n
But the device I was working with was constantly sending lines with just 4 characters, to filter out those I got the address word from the output line, and grepped for that. In my case I only wanted to capture "C" or callback output. I was also filtering for lines that contained more than just the default "0160" that the device was constantly outputting. To try understand the hex output I put a xxd -r -p at the end which gave me:
cat /sys/kernel/debug/usb/usbmon/1u | grep -e 'C Bi:1:005:1\s0\s\w*\s=\s0160\w' | cut -d\ -f8- | xxd -r
Where the grep is
grep -e 'C <address> <someotherstuff> = <always-output-string><anycharacter>
This still gave me this indecipherable junk below, but I don't know the format so I'm stuck here. Maybe the steps to read and filter will be useful for someone
>
O�UDQN��RG_JAMS142E DEFAULT0XXXXXXX�lSTz:�RSDU�vy��������������������������z�fff=�����{6zC"z�u6zC�z�H
;�����C��Af[���RSC�b ISD�EGIN
�CG_IEW0321:0407JUN12S��Z-�$''$'''C'''

Communication protocol using netcat

I need to create a way to communicate commands and transfer files from a host server to a development board.
The only access to the board is via the host server (wired Ethernet connection).
Both the host server and the board are running Linux.
I have the ability to change the Linux environment on the board.
I DO NOT have the ability to change the host server environment.
I DO NOT know which users need to connect to the board.
The connection between the host server and the board does not need to be secure.
Right now, I'm using netcat for my needs but have run into reliability issues - Could someone point me to some tools that are better suited to my needs and perhaps higher performance, please?
My current solution:
A script is constantly running on the board:
while [ 1 ] ; do
# Start a netcat server, awaiting a file.
nc -l -p 1357 > file.bin
# Acknowledge receipt of file.
status=fail
while [ ${status} -ne 0 ] ; do
status=$(echo 0 | nc <host_ip> 2468 2>&1)
done
# Wait for a command.
nc -l -p 1357 -e /bin/sh
# Acknowledge receipt of command.
status=fail
while [ ${status} -ne 0 ] ; do
status=$(echo 0 | nc <host ip> 2468 2>&1)
done
done
The only way users have access to the board is through a script on the server:
# Send over a file.
cat some_file.bin | /bin/nc -w 10
# Wait for acknowledge.
if [ $( nc -l 2468 ) -ne 0 ] ; then
exit # Fail
fi
# Send a command.
echo "<some_command>" | nc -w 10 <board ip> 1357
# Wait for acknowledge.
if [ $( nc -l 2468 ) -ne 0 ] ; then
exit # Fail
fi
The reason I'm using netcat right now is that I don't know of any way to use SSH or SCP without a password given that:
I can't generate an SSH key for everyone that needs access to the board, especially since I don't know who will be using it.
I can't install sshpass or expect since I don't have control of the server.
Please help,
Thanks.
You could use SSH with host-based authentication. Then you would not need those script and simply use SSH and SCP normally, without the need for passwords nor user keys.
With host-based authentication, any user connecting from a predefined set of machines (here it would be the host) is automatically authenticated on the target machine (here the board).
You need to modify the SSH server configuration on the board, and the SSH client configuration on the host (which you can do without the need for a root access).
Here is a tutorial that should get you started.
Note that if encryption is not mandatory and performance is of issue, you can use the same host-based authentication scheme for RSH access.

Programmatically removing all bluetooth devices on the Linux command line

I am able to scan for all available bluetooth devices with hcitool or with my C program.
I can pair the device using it's address with a simple-agent python script.
I would like to know if I can also remove the paired device using either hcitool, hciconfig or some kind of bluetooth command.
I know the information of detected devices for the hci0 controller is stored in /var/lib/bluetooth/XX:XX:XX:XX:XX:XX, where XX:XX:XX:XX:XX is the address of the hci controller.
This would be useful for testing pairing, connecting and disconnecting devices.
For those using Ubuntu 20.04, here is the same command using the bluetoothctl command
#!/bin/bash
for device in $(bluetoothctl devices | grep -o "[[:xdigit:]:]\{8,17\}"); do
echo "removing bluetooth device: $device | $(bluetoothctl remove $device)"
done
bluez-test-device remove XX:XX:XX:XX:XX:XX
If you install the bluez-tools package, run this to unpair a bluetooth device :
bt-device -r xx:xx:xx:xx:xx:xx
where xx:xx:xx:xx:xx:xx is the address of the paired device.
As it is mentioned above on ashish's answer, you can us bluez-test-device to remove the device which that you already know its mac address. So the problem is to parse the mac address of the added devices.
With python or c or whatever you use,
1) list the devices with;
bluez-test-device list
and parse the output and get all the MAC addresses of the devices, add them to a list.
2) disconnect and remove the devices;
bluez-test-device disconnect <MAC ADDRESS>
bluez-test-device remove <MAC ADDRESS>
Command using bluetoothctl binary: for device in $(bluetoothctl devices | grep -vEi '(o que mais vc quer deixar aqui|samsung|jbl|wireless)' | awk '{print $2}'); do bluetoothctl remove $device; done
All these answers don't answer the headline "removing all Bluetooth devices"
I wrote this little bash script to remove all the Bluetooth devices that are listed in the bt-device -l
#!/bin/bash
for device in $(bt-device -l | grep -o "[[:xdigit:]:]\{11,17\}"); do
echo "removing bluetooth device: $device | $(bt-device -r $device)"
done
How to run?
Make a new file like <fileName>.sh and paste the code above.
Run chmod +x <fileName> to make the script executable
Run ./<fileName>.sh
Celebrate! All Bluetooth devices are removed now :)

Resources