ModTashtalk: lt0 driver for Linux

twelvetone12

Well-known member
While working on my "portable" version of AirTalk I had my Powerbook 100 hooked via USB to my PC using a makeshift adapter, so I could use tashtalkd and test stuff. "How cool would it be for the PC to be a node in the LocalTalk network" I thought, so I decided I would try my hand to write a Linux network driver.

Here it is in all it's alpha-bad-code glory:

What is it?
It is a Linux Line Discipline driver which ties a TashTalk on any serial port to the networking stack, using the built-in LocalTalk support. It will show up as lt0, which is compatible with the old ISA cards managed by the COPS driver. It is based (very heavily) on the SLIP driver, with parts from COPS and tashtalkd. Once you have your lt0 interface you can use it as a normal network interface on the system.

Does it work?
Sorta, but it still needs testing. It seems to properly receive packets and I can send them: I can send an AEP ping and have a response back.

Does it work with netatalk?
It should but for the moment I could not make it work, this would be the end goal through, but I'm not super expert in netatalk and it is quite a mess to figure out what is going on in the code (I can specify lt0 as an interface but packets get always routed to loopback).

How bad is the code?
Quite a bit :) I hacked it together so I could publish something presentable, there is quite a bit of work to clean up stuff.

I tested it on Linux 5.19 and 6.2. It should compile on Linux 5.15 if I did not do any inline declarations :) My TashTalk is connected via a FTDI usb adapter, so I did not yet test a "real" serial port.

How can I try it?
You adventurous I see ;)
git clone https://bitbucket.org/twelvetone12/modtashtalk/src/master/
cd modtashtalk make ./setup_and_run # This loads the module and lauches the line discipline, it blocks in fg

Then in another terminal:
sudo ifconfig lt0 up # if you specify an IP address, routing will implode sudo tcpdump -i lt0 -vvvX

In even another terminal
cd modtashtalk gcc -o raw raw.c sudo ./raw lt0

You should see the packet in TCP dump. If there is other stuff on the network, you should see that too. In raw.c I hardcoded "27" as the destination node for AEP, so if you have other nodes you could try pinging them and you should see a response!

And that's all for now, comments are welcome!
 

cheesestraws

Well-known member
Very nice stuff!

I've been tempted to try to come up with a Linux driver for LToUDP encapsulation, might start from your work if I can work up the executive function to start it :-|
 

NJRoadfan

Well-known member
I'm going to have to give this a try with netatalk's atalkd. I suspect one reason why it may be failing is with raw.c. It appears to be hard coding the network number as 0, which could pose a problem in some situations. Normally the Localtalk adapter's driver handles setting the node number as the interface's address is self configuring (you wouldn't need to do an 'ifconfig' on any AppleTalk network). The messy details on how the adapter finds a free node address is detailed in "Inside AppleTalk".
 

twelvetone12

Well-known member
yes the node arbitration for the moment is on the TODO list :) The COPS driver works like this:
1) It gets the preferred node id (from netatalk)
2) it tries to arbitrate it
3) sets either the preferred one or the new one if finds
4) netatalk then asks the kernel for the _real_ node id

with my driver, the node id (for the moment) is always the one set in s_node in the socket. Since I only have one mac connected, I just make sure I don't hit the same node id :)
 

NJRoadfan

Well-known member
I may be missing something, but I don't see anywhere in the driver that is actually setting the node ID for the TashTalk hardware when requested by
SIOCSIFADDR (sending command 0x02 followed by the node ID "bitmap"). Might be why netatalk is getting confused. I see it in tashtalk_open(), but no where else.
 

dougg3

Well-known member
Very very cool! I went down this same rabbit hole with creating a native lt0 device and getting it working with netatalk several years ago when I was making my LocalTalk adapter, which used a Cortex-M0 and a real SCC, so not nearly as compact and affordable as TashTalk, but the same concept of communicating the data through a UART and using a TTY line discipline on the Linux side.

The code ended up disappearing from the internet. I had it working to the point where netatalk was acting as a router and bridging between eth0 and lt0. I eventually ended up submitting a patch upstream to the kernel in 2021 because there was a bug with LocalTalk devices that caused a panic. The patch came out sometime around kernel 5.12 or so, so you certainly already have the patch in the kernels you've tested on. It also got backported to older stable kernels.

I saw your post in the other netatalk thread about running it with only a LocalTalk interface, and I don't think I can directly answer that question, but I can say that this is what the bottom of my atalkd.conf file looked like for creating a router between Ethernet and LocalTalk:

Code:
lt0 -seed -phase 2 -net 2 -addr 2.129 -zone "LocalTalk"
eth0 -seed -phase 2 -net 1 -addr 1.205 -zone "Ethernet"

I believe I completely made up network and node numbers for everything. In this case LocalTalk is network 2 and Ethernet is network 1. It caused zones to show up in the Chooser, by the way. I also had a userspace simple LocalTalk-Ethernet bridge implemented that tried to replicate the approach used by the Farallon EtherWave Printer Adapter which basically pretended to be a mini router on the LocalTalk side but just acted as a normal Ethernet node on the Ethernet side.

I ran out of time and interest with my project and it kind of fizzled out. If you're interested I can share the code for my similar module just so you'll have it as a known working reference. I think it's pretty much the same basic concept you have here, although I started from a different driver so it's probably architected quite a bit different. I also made up my own line discipline instead of reusing the one for PPP, although that also required a kernel change. I never got to the point of implementing the node arbitration :)

I feel I should mention that the kernel developers are considering stripping out LocalTalk support due to lack of use and the age of the code. No idea what the timeline looks like though. See this mailing list thread from last year where it was discussed. I was CCed on it and chimed in and said that I thought most development was heading in the userspace direction, although your project might change things!

Nice work!
 

twelvetone12

Well-known member
I may be missing something, but I don't see anywhere in the driver that is actually setting the node ID for the TashTalk hardware when requested by
SIOCSIFADDR (sending command 0x02 followed by the node ID "bitmap"). Might be why netatalk is getting confused. I see it in tashtalk_open(), but no where else.
Well let's say that I was just a bit lazy and I hardcoded node 2 😃 Then I set that up in netatalk.
But I don't think it is actually that, as setting the node number only makes tashtalk reply to ENQs and CTSs for the selected nodes, but for the others it should still be passed over to the serial port (@tashtari please correct me as I very well could be wrong). The problem is that the packets don't make it at all to the lt0 device, or at least they do not if I set -phase 1, with -phase 2 I see some NBP stuff going on the netatalk seems just to write to eth0 (even if I don't configure it).
But at this point I'm not 100% sure I can recvfrom() in linux, when netatalk does it NBP thing I see responses from my powerbook but select() always timeouts, so it seems stuff gets stuck before hitting userspace? It could be very well a fault in my driver.
Unfortunately I'm a bit stuck right now, because I would need to see the localtalk packets arriving on my mac, but it does not work with the modem port, and my rpi hat with the transceivers is stuck in German customs :( so I cannot use the "real" localtalk printer port and sniff out of it.
But if you have any way of testing this, or if you find any obvious faults in the code please let me know! Tomorrow if I have a moment I will try to get setting the address bitmap in tashtalk actually working, and also node id arbitration, so there is something less to think about.
 

mactjaap

Well-known member
How cool is this. You will understand that this is BIG for a LocalTalk nerd as I am! Will try to test soon!
 

twelvetone12

Well-known member
I feel I should mention that the kernel developers are considering stripping out LocalTalk support due to lack of use and the age of the code. No idea what the timeline looks like though. See this mailing list thread from last year where it was discussed. I was CCed on it and chimed in and said that I thought most development was heading in the userspace direction, although your project might change things!

Nice work!
Ooh I did not see your code, I'm going to have a look there too!

Yes I saw the messages about removing appletalk, at least in 6.2 it is still there! I can see both the value of an userspace only solution and having a "real" network driver in the kernel. Personally I found the mixture and weird dependence between the linux kernel and libatalk (in netatalk) extremely difficult to follow, not really well documented, and it took me lots of guesswork and trial and error to get some communication going. But I find it still cool that there is kernel support for DDP and AARP, even if I find it a bit difficult to use. There is even MacIP still with ipddp (which took me a day to not get working). Personally, it could be worth cleaning up and maybe documenting what is there, and use it as a basis for a new appletalk lib, which could derive from some building blocks in netatalk (like the ATP and NBP stuff). But for the moment, I need to get the driver to at least communicate properly :)
 

twelvetone12

Well-known member
How cool is this. You will understand that this is BIG for a LocalTalk nerd as I am! Will try to test soon!
Please do! I suspect I'm still doing something wrong, but if you have any means to transmit and test data I would absolutely love to know your results!
 

NJRoadfan

Well-known member
In discipline.c there is:

#define DEFAULT_IF "eth0"

Perhaps that is the problem?

When I'm back at my dev Pi with the TashTalk, I'll dig into it. The whole "TTY Line Discipline" thing is slowly being superseded by "Serial Device Bus" drivers. For this application, the newer stuff isn't needed.
 

twelvetone12

Well-known member
I don't think it is that, because I switched from my hacked together discipline driver to using ldattach. BTW we should have our own discipline, I used PPP because ldattach seemed upset if I used a non existing one, like 29.
The whole "TTY Line Discipline" thing is slowly being superseded by "Serial Device Bus" drivers. For this application, the newer stuff isn't needed.
I love Linux, there is always something newer you learn about 😃 I guess we could port it if needed,I think the hard part is more in the netif side.
 

Tashtari

PIC Whisperer
setting the node number only makes tashtalk reply to ENQs and CTSs for the selected nodes, but for the others it should still be passed over to the serial port
Correct. TashTalk copies every frame on the LocalTalk bus to its UART regardless of destination (except for frames it generates and sends itself), its "Set Node IDs" command only determines for which node IDs it replies to received RTS and ENQ frames.

I'm excited to see progress here! I wish I could add more to it, but my knowledge of networking above the level of LLAP is limited - but I'm happy to help with that and with the mechanics of TashTalk if I can.
 

slipperygrey

Well-known member
The code ended up disappearing from the internet. I had it working to the point where netatalk was acting as a router and bridging between eth0 and lt0. I eventually ended up submitting a patch upstream to the kernel in 2021 because there was a bug with LocalTalk devices that caused a panic. The patch came out sometime around kernel 5.12 or so, so you certainly already have the patch in the kernels you've tested on. It also got backported to older stable kernels.
I just wanted to lean in and say thanks (again) Doug for rescuing the atalk kernel module from certain doom back in 2020. I definitely wouldn't have spent all that effort to revive netatalk 2.x in the first place if the kernel module was dead! Our community is better of for it.

I feel I should mention that the kernel developers are considering stripping out LocalTalk support due to lack of use and the age of the code. No idea what the timeline looks like though. See this mailing list thread from last year where it was discussed. I was CCed on it and chimed in and said that I thought most development was heading in the userspace direction, although your project might change things!
Reading this discussion thread is both chilling and encouraging at the same time. This inner circle of devs has such a huge influence on the direction of the Linux kernel, and one or two more opinions in one or the other direction may sway the room at any time. It's good that you made them aware that netatalk 2.x is seeing active use.
 

twelvetone12

Well-known member
Hopefully we can keep it alive for more time! I wanted to wrap up address negotiation and actually set the correct bits in tashtalk but life got in a way and I think for a couple weeks I will not be able to touch it. But if anybody can test it with a real net and sniff what the mac is receiving that would be great, as I'm not 100% sure the driver is outputting valid data, but for the moment I can't really test that.
 

dougg3

Well-known member
I just wanted to lean in and say thanks (again) Doug for rescuing the atalk kernel module from certain doom back in 2020. I definitely wouldn't have spent all that effort to revive netatalk 2.x in the first place if the kernel module was dead! Our community is better of for it.

Aww, well thanks! I'm happy I was able to help in any small way! I'm not sure I deserve that much credit on it, but it has definitely been interesting ride over the past few years between being broken for over a year (my blog post seemed to kickstart that fix, luckily) and the recent proposals to strip LocalTalk stuff out.

Hopefully we can keep it alive for more time!

Getting to the point that you could upstream this driver to the mainline kernel would be a big win for keeping the LocalTalk stuff alive if you are interested in going down that path. I agree with NJRoadfan that serdev seems to be the modern way of doing it, although I'm not sure if they've solved issues with serdev as far as how to hook stuff to it at runtime if it's on a USB serial port for example.

I have a fair bit of experience with submitting changes to mainline recently due to another project I've been blogging about, and would be happy to help you out with that process if you get to the point that you would like to give it a shot. Just let me know if/when you're interested!
 
Top