How create a virtual io device in Linux that proxies data to real device? - linux

I have an interesting problem. I am working on an embedded box with multiple instances of Linux running each on an ARM processor. They are connected over internal 1GBps network. I have a serial port device node attached to processor A (Lets say Linux-A running on it). I have a program running on processor B (Lets say on Linux-B) access the serial port device as if it is attached to Linux-B locally.
My program invokes term i/o type api calls on device node to control tty echo, character mode input. What I am wondering is if there is a way to create a virtual serial device that is available on Linux-B somehow talking to real serial device on Linux-A over internal network.
I am thinking something along the lines of:
Linux-B has /dev/ttyvirtual. Anything that gets written to it gets transported over network socket to Linux-A serialserver. The serial server exrcises the api calls on real device lets say /dev/ttys0.
Any data waiting on ttys0 gets transported back to /dev/ttyvirtual.
What are all the things involved to get this done fast?
Thanks
Videoguy
Update:
I found a discussion at
http://fixunix.com/bsd/261068-network-socket-serial-port-question.html with great pointers.
Another useful link is http://blog.philippklaus.de/2011/08/make-rs232-serial-devices-accessible-via-ethernet/

Take a look at openpty(3). This lets you create a pseudo-TTY (like /dev/pts/0, the sort that ssh connections use), which will respond as a normal TTY would, but give you direct programmatic control over the connections.
This way you can host a serial device (eg. /dev/pts/5) that you forward data between a network connection, and then other apps can perform serial operations on it without knowing about the underlying network bridge.

I ended up using socat
Examples can be found here: socat examples
You socat back to back on both the machines. One listens on a tcp port and forwards data to local virtual port or pty. The socat on other box uses real device as input and forwards any data to tcp port.

Related

linux usb gadgets traffic monitoring

I am using a BeagleBone Black board (kernel 4.14.108-ti-r104) to create USB gadget using configfs/functionfs. I compose my gadget (using gadgettool) providing details about device configuration (function, vendor id, product id and ton of other params), run my userspace program that writes descriptors and strings to ep0 and connect the device to host. All works fine, I get BIND (when binding device to UDC) and ENABLE (when actually host is connected) events and my device can read from ep2 and write to ep1. Using wireshark I see the communication looks good, device and configuration descriptors as well as strings are exchanged.
The problem starts when I connect the device to another host. Unfortunately I have almost no control over that host, in particular I cannot run wireshark there, I don't even know the OS. The only thing I can do is to plug/unplug device, optionally see a message that device was detected and optionally a restart. What I see on the gadget side is that following BIND and ENABLE events I immediately get SUSPEND event and read on ep2 fails with 108 (ESHUTDOWN). Now the question is how to track the problem down.
I tried usbmon, but it seems it does not listen to traffic when device is in gadget mode. I have also seen https://github.com/torvalds/linux/blob/master/drivers/usb/gadget/udc/trace.h file which seems to define some udc trace points, but I am not really sure how they can be used.
So the final question is simple: how do I get any information about traffic on USB bus having access only to gadget side? I don't need full trace, but al least some information which packets were exchanged would be super useful. Did it fail while exchanging device descriptors, configuration/interface/endpoint descriptors or strings or something totally different?
Small update:
The whole thing is about Android Open Accessory Protocol and I am trying to write a gadget that would connect to this accessory.
I have changed my gadget composition somewhat and now I know the gadget is being identified by host (it displays manufacturer/model) so I suppose the issue is not in device descriptor and strings. I have used two additional flags in descriptors (FUNCTIONFS_ALL_CTRL_RECIP | FUNCTIONFS_CONFIG0_SETUP) and when connecting to my computer I get setup event (request 51 as expected), but when connecting to my accessory I still get SUSPEND/ESHUTDOWN. This time though it looks like the time between ENABLE and SUSPEND is much greater (over 10 seconds) which looks to me as if the host send some message, but this message was not processed by my gadget and then the host timeout out and disabled usb device. Still don't know how to find out if the accessory sent anything to gadget and what it was...

Internet socket behavior when communicating within the same host

I am recently writing some tool for testing some network processes that run across different hosts.
I am tempted to the idea that when testing, instead of running the client and server in different hosts, I can run them within one host.
Since the client and server are using TCP to communicate, so I think this should be fine, except one point below:
Is the TCP socket behavior the same when communicating data within the same host as the case of across hosts?
Will the data be physically present to the NIC interface and then routed to the target socket? Or the kernel will bypass the NIC interface under such scenarios? (Let's limit the OS as only Linux here for discussion)
There seems little specification regarding to such case.
==== EDIT ====
I actually notice some difference between intra-host and inter-host communications.
When doing inter-host communications, my program can successfully get hardware timestamp. But with the exact same code to run within the same host, the hardware timestamp disappears. When supported and enabled, hardware timestamp of TCP packet is available, and is returned as the ancillary data of recvmsg along with the received TCP data. Linux kernel timestamp doc has all the related info.
I checked the source code, the only difference is that whether the sender is within the same host of the receiver, no other difference.
So I am wondering whether Linux kernel will bypass the NIC and present the data directly to the receiver when doing intra-host communication, thus cause the issue.
Will the data be physically present to the NIC interface and then routed to the target socket?
No. There is typically no device that provides this capability, nor is there any need for one.
Or the kernel will bypass the NIC interface under such scenarios?
The kernel will not use the NIC unless it needs to send or receive a packet on a network. Typically, NICs can only return local packets if put in a test or loopback mode, which would require them to stop listening to the network.

IP tunnel over Linux serial default shell

This is a more constrained version of this question:
I have an embedded ARM device running a custom image with a Linux 3.10.0 kernel.
The only physical interface (no, USB, no Ethernet) is the default Linux shell which is connected one of the serial interfaces.
My question is: Is there any built-in or external tool that opens an IP tunnel over this connection?
I see some general issues:
The device is already use by Linux, so it must use stdin/out to communicate instead of accessing the device directly.
After starting the tunneling application, the application must wait for a tunnel client to connect because I need to close the serial connection on my computer and then start the tunnel client.
There should be a way to close the connection and go back to the normal shell
The actual requirement is, that I can access a REST interface that is running on the embedded device from a computer connected to the embedded device via serial cable.
This already works on devices with a physical Ethernet or Ethernet-over-USB but this device does not offer that.
[UPDATE]
As explained, socat is currently not available on our embedded device so as a first attempt, I used the following:
A Linux (Ubuntu) laptop with a physical serial interface
A Windows Laptop with a physical serial interface and cygwin+socat installed
Both connected via Null-modem cable
Note: I'm using a Windows laptop on one side because we will have the socat client running on Linux (unfortunately).
Direct STDIO Connection
Server
socat stdio file:/dev/ttyS0,b115200
Client
socat file:/dev/ttyS4,b115200 stdio
In cygwin, ttyS0 is COM1, ttyS4 in this case is COM5.
Using these, socat works like a little chat program. Why I type on one side is output on the other and vice-versa.
TCP Connection
The next step is to use a TCP connection.
Server
socat /dev/ttyS0,b115200,crtscts=1,raw,echo=0 tcp-connect:localhost:80
Client
socat -T2 file:/dev/ttyS4,b115200,crtscts=1,raw,echo=0 tcp-l:7777,reuseaddr
I specified the baud rate (115200), used raw transmission, no echo (The HTTP request would otherwise be sent back to the requester) using hardware flow control. Pus I had to use a timeout -T2 wich terminates the connection after 2s. Otherwise, curl does not terminate either and waits for more data.
When I use curl on the windows computer, it successfully transmits the request over serial connection and returns the complete HTTP response of the HTTP server on the Linux computer:
curl localhost:7777/index.html
However, it works only once. After the request is completed, both socatclient and server terminates.
Moreover, when I use a browser (Chorme), it uses g-zip encoding which most probably sends binary characters. And one of these characters will be a EOF character which again terminates socat before completing the request/response.
Then I tried to add fork to the server:
socat /dev/ttyS0,b115200,crtscts=1,raw,echo=0 tcp-connect:localhost:80,fork
This keeps the server alive, but curl returns a 400 Bad Request. So it seems as if the socat server initiated a request for each line or chunk since it does not understand HTTP.
IP Connection
Then I thought about going a layer below and using a TUN connection. However, this is not implemented on the Windows version of socat.
HTTP connection
Correct me if I'm wrong, but as far as I understand, socatdoes not provide a connection type that actually understands HTTP and is able to serialize it properly over a serial connection.
So, I couldn't find any stable way to start both client and server and run multiple HTTP requests over the serial connection.
On a normal linux, you could use socat.
This program allows you to connect several stream types (file, socket, tcp, udp, ...). In your case it would be tcp to file or more precisely a tcp socket at port xx to /dev/ttyUSB1. You should launch socat on both sides to build a tunnel.
Edit 1:
Sorry I got also disappointed by socat. I can't find a solution that keeps my TCP listener active for multiple successive connections, but handles only one connection at a time.
My solution is a simple C# program that uses 4 threads:
1. wait for input on stdin e.g. exit command
2. the TCP listener
3. the TCP worker thread for a active connection
4. if TCP is open, it opens another thread for COM
Thread 3 reads from TCP and writes to COM and Tread 4 reads from COM and writes to TCP. If thread gets a TCP close event, it stops thread 4, which closes COMx, and exits it self. Now thread 2 can accept a new connection. If thread 1 reads exit on stdin, it passes a message to all threads to stop and shutdown.
Maybe you can implement such a short program in C with pthreads on your embedded system, which has no socat.
The EOF problem:
I tried to google for a program that escapes a special character or reencodes a data stream from ASCII to ANSI or base64 or whatever.... If you can find such a program or write it also in C you can pipe it in between
Server <=> reencode <=> socat <--serial--> socat <=> reencode <=> client
We've now solved the problem halfway using pppd. As it turns out, even Windows supports ppp. In contrast to socat, pppd actually uses a protocol that will have error detection included and it automatically creates network devices on the Linux and Windows system.
The only problem is, that pppd requires to have access to the serial device. There is no direct mode like the ppp tool provides.
We are now disabling the shell on demand, rebooting into IP-over-serial mode. When we are done, we reboot the system which automatically switch back to getty using the serial line.
The is not the prettiest solution but right now, it seems to work.

When using socket locally where the data go through?

Say the system is linux, I use TPC/IP protocol. When I send data to 127.0.0.1:1024 from A process, then B process get all the data.
How does the system handle these local data traffics?
Does the data go through the network interface card from A to B?
Or they are only manipulated in the memory (much faster than network interface card)?
It'll not be processed by your network card as 127.0.0.1 address is not set on any (it's on loopback device) but it'll go through whole ip stack. Benefits are that you can manipulate this traffic with iptables or iproute tools and whatever you made that way will be ready to work between remote hosts.
If you care more about performance and use only local communiaction consider AF_UNIX socket. You can find more in man socket and man unix.
Check man ipc as well.

Linux user space L2 control protocols

I have a network device where a port of an Ethernet switch chip is connected to a CPU's network controller. The switch chip forwards packets from other ports to the CPU port with special header added (before MAC header) containing such information as ingress port etc.
I can strip the header when receiving the packets in the network controller driver, so the Linux network stack can communicate with the switch in a normal way. My goal, however, is to pass some information in the special headers to a user space Layer 2 control protocol suite.
In my case, a Layer 2 control protocol would normally use a raw socket to receive its control frames. For example, the Spanning Tree Protocol must be able to tell from which switch port did the packet come from.
Also, services such as http, telnet server etc should be able to use the same network interface.
Are there any Linux built-in means for delivering such information from a driver to the user space network server / client?
If not, any suggestions on implementing this?
I could implement a simple ioctl call to query the driver about the header information of the last packet that was read. However, there is no guarantee that the device was not used by other processes between recv() and ioctl().
I think the best way to implement this would be to add a field in sk_buff to store your special L2 header. If I understand correctly, headers should be preserved when passing sk_buffs from one layer to another, albeit, you might need to add some code to skb_clone.
If you reach this point, sending this value to user-space is only limited by your imagination. For example, you could
store the value in the socket structure sock and return it later using an ioctl;
return the value in recvfrom's src_addr directly
Hope this help.

Resources