• Updated 2023-07-12: Hello, Guest! Welcome back, and be sure to check out this follow-up post about our outage a week or so ago.

Developing a portable user-land AppleTalk stack

cheesestraws

Well-known member
Rather than posting randomly in the "what did you do to your mac today" thread, I thought I'd make a separate thread for this project in here.  Hope it's in the right place and people find it interesting and want to throw ideas at me.

The plan/project is to write a userland AppleTalk stack aimed at UNIX-like OSes that prioritises talking to vintage macs, especially from the 68k era.  Netatalk no longer bothers with DDP, and AppleTalk in-kernel support in operating systems will, at some point, go away, probably rather sooner than later.  It is being written in Go, partly because it's the main programming language currently in my short-term memory and partly because channels are useful.

The other important theme here is that I want to write this prioritising code clarity and readability rather than performance.  I've often been trying to work out how to interact with a device and looked at the sample code, and then I have two problems rather than one, the second being to understand the sample code.  I'd prefer that not to be the case for this.

Due to the terms of my employment, I can't release any code until I get the project signed off (sigh), but code *will* be coming.  At the moment, you're not missing much anyway, honestly.  Also, updates to this will be very sporadic for various life and health reasons.

State of affairs as of mid-December 2019:

  • I've implemented a slightly hacky Localtalk over UDP multi/broadcast thing for minivmac, using most of the same code as the existing LToE code.  I think this is more flexible for reasons I am happy to go into if anyone wants me to, but is mostly for my own dev convenience.   There is actually a bug in minivmac, even using LToE, that prevents duplicate address detection working.  The chances of anyone hitting this in the wild are fairly remote, but I think I've fixed it and I'll submit a patch when I can.
  • I have the ability to send and receive LLAP packets over an LToUDP network and parse them.  The "physical" layer and the LLAP layer are separate, so in theory it ought to be possible to swap out LToUDP for LToE or "real" localtalk later.
  • I have the ability to acquire a network address on this network and participate in the duplicate address detection protocol with a virtual network of minivmac instances.
  • I can parse short-header DDP packets, but if I want to send any I have to craft them by hand.




 

saybur

Well-known member
First off, thanks for a great writeup, I enjoyed reading through your blog post.  This is an *excellent* idea for long term maintainability - the moldering AppleTalk code in the kernel and/or old versions of netatalk are causing headaches for people, and this seems like a solid way to solve that problem.

I did have a question about how addressing is working: as far as I can grasp, you're just passing the LLAP packets, and letting the Macs fight it out for LLAP address resolution?  Or is there something going on on that front that I'm missing?  I know you mentioned this would hopefully be the start of a full userland AppleTalk stack, so was the routing side of things something further down the pipeline? (and if I'm off base, feel free to correct my ignorance, I probably need to crack Inside AppleTalk again sometime...)

As for your comment about proper LocalTalk networks: it's been a while since I've messed around with it, but at one point I came up with a pretty simple piece of hardware to take raw SDLC data off the LocalTalk network and send it into a standard UART.  The idea at the time was to offload the real-time Manchester decoding onto a small microcontroller, so a piece of userland software could participate in the LocalTalk network.  I got far enough with it to be able to decode packets and read them with an Arduino, but I got distracted with other projects, and I was not looking forward to the looming problem of how to get the LLAP data into a format that could be useful.  It looks like you may have solved my problem!  ;-D

Anyway, awesome job with this, and best of luck getting the code release signoff soon.

 

cheesestraws

Well-known member
Thanks for the feedback and the kind words!

I did have a question about how addressing is working: as far as I can grasp, you're just passing the LLAP packets, and letting the Macs fight it out for LLAP address resolution?
As far as address allocation goes, yes, I'm just passing the LLAP packets and letting the macs and whatever else are listening sort out address allocation using the normal ENQ/ACK code.  This seems to be working quite well so far: I have a reimplementation of address acquisition in Go which seem to play nicely with several hacked mini vmac instances.  One thing I am worried about is latency; the LLAP spec is very ... tight about timings.  IP is a comparatively leisurely protocol in many ways, and I need to intentionally introduce some latency and then induce some address collisions to see how well they're handled.  This may require revisiting, but I hope MacOS is a little more permissive than the spec says it ought to be.

Once I've got this working reliably, the next step is to try to implement EtherTalk, then implementing the router protocols and trying to get routing working between the two.  In fact, my plan, inasmuchas I have one, boils down to working through Inside Appletalk in order...  I'm concentrating on LToUDP at the moment because I'm stuck in a hotel room an ocean and a continent from home and it's something I can run on a single laptop.  And also my home network is in a state of profound disarray...

it's been a while since I've messed around with it, but at one point I came up with a pretty simple piece of hardware to take raw SDLC data off the LocalTalk network and send it into a standard UART.  The idea at the time was to offload the real-time Manchester decoding onto a small microcontroller, so a piece of userland software could participate in the LocalTalk network.
Oh, very nice.  My dream was to take something like an ESP8266 and make a little "wireless dongle" that would wrap LLAP packets in LToUDP and fire them out on the local wireless network, which sounds like something doable with your hardware perhaps?  The IP side is where I live most of the time, I'm woefully inadequate at electronics.

 

saybur

Well-known member
I do vaguely remember the timing on LLAP being oddly tight for hardware of that vintage.  I'm not familiar with the Zilog chips they used for serial, but maybe the low-level handshaking was done completely in hardware, so they figured they could get away with very low timeouts to improve performance?  I'd be interested in hearing how that part of the project goes.

I don't know much about the ESP8266.  To do the line decoding, you do need some decent control over timing, or at least have a pretty good idea of how long your code will get interrupted by the WiFi handling.  At minimum, it should be possible to strap a micro to the ESP module and do things that way to get more control.  It's a pretty cool idea though: LocalTalk over WiFi, what a world!

And safe travels as well!

 

sfiera

Well-known member
This is neat and I’m interested in trying it out (after Christmas, maybe…). I’m reminded of two other pieces of software that do AppleTalk over IP, both by bbraun:

  • abridge (source), which bridges AppleTalk between two networks with pcap. It seems like this approach might be usable to bridge LToU and EtherTalk networks, similarly to LocalTalk Bridge.
  • avpn, which is a System 7-9 extension that tunnels AppleTalk over IP. Unfortunately, the source doesn’t seem available. It would be great to get genuine hardware speaking LToU!
 

cheesestraws

Well-known member
Don't get your hopes up too much!  At the moment this is literally just an LLAP packet parsing/construction and address acquisition library.  I haven't got any further than that yet, along with mini vmac support.  I think I've got all the stuff I need to do done for the paperwork to release code at my end, so the first thing I'm going to do is to get the patches to Mini vMac to the point where they're not embarrassingly bad and submit those, then I'll try to write a couple of demo applications and release that for comments.  But yeah, this isn't yet at the stage where you'll be able to write an AFP server on top of it or anything.

  • avpn, which is a System 7-9 extension that tunnels AppleTalk over IP. Unfortunately, the source doesn’t seem available. It would be great to get genuine hardware speaking LToU! 
I do actually have the source code to avpn - it is around on his website somewhere, because I got it then had to ask on his forums what license it was under. :) I did hack it to speak (an earlier version of) the LToUDP protocol, but it's very unstable and I don't really know why.  It's below the level I usually hack at on the classic MacOS, I'm afraid.  I also vaguely remember that MacTCP doesn't speak multicast (very well? at all?) and multicast is actually quite useful (the loopback interface on OS X doesn't support broadcasts, so if you want to run multiple emulators on an OS X box, it's multicast all the way!).

edit: the source code to avpn is in the archive with the binary that can be downloaded from here: http://www.synack.net/~bbraun/macapps.html.  It requires to be built with a specific version of CodeWarrior, I can't remember which one off the top of my head.

The real problem here is that any computer that could talk LToUDP through an atlk/adev probably already has Ethernet, and so EtherTalk is a better option.  EtherTalk will be supported in this library/implementation, it's just I haven't got to it yet.  The only other option would be running LToUDP over MacIP over LocalTalk through a bridge, which frankly seems like a recipe for total disaster.

The other thing is that all the documentation on how to write atlk/adevs seems to have disappeared completely, unfortunately: there was, at one point, a developer document telling you how to do it, but I have never found a copy, and when I asked on his forum, bbraun hadn't found a copy either.  So this makes writing one/hacking on one a frustrating and intricate experience.

So, with all that in mind, I much prefer the idea of giving real macs LToUDP using a hardware dongle, as discussed a bit upthread.  That way, you just get something you can plug in and it goes, even on Macs without the wherewithal to run their own IP stack.  I've got this idea in my head that you could configure it by sending DDP packets to a "magic" address that would actually do things like select the wireless network.  But that's ... definitely further down the line.

 
Last edited by a moderator:

cheesestraws

Well-known member
I do vaguely remember the timing on LLAP being oddly tight for hardware of that vintage.  I'm not familiar with the Zilog chips they used for serial, but maybe the low-level handshaking was done completely in hardware, so they figured they could get away with very low timeouts to improve performance?  I'd be interested in hearing how that part of the project goes.
If the "algorithms" section at the back of Inside AppleTalk is accurate, the RTS/CTS stuff at least is done in software, but wired off interrupts from the SCC.  I'm not sure if this accurately reflects the actual code in use, but the timings seem achievable if you are able to immediately drop everything and service RTS/CTS state or ENQ/ACKs.

Also according to that section, duplicate address detection should work outside those timings, but what it doesn't seem to specify is what the LocalTalk stack does with the knowledge that there is a duplicate address.  If it just reruns address acquisition, then that's great - if it does something less predictable, then that might be a problem.

I have a suspicion that the very low timeouts especially on ENQ/ACK and address acquisition and so forth are to improve the interactive latency of the system - LocalTalk always feels to me far snappier than it has any right to given its age and actual available bandwidth - and I suspect that's because the latency of the system is kept intentionally as low as it can be.

I don't know much about the ESP8266.  To do the line decoding, you do need some decent control over timing, or at least have a pretty good idea of how long your code will get interrupted by the WiFi handling.  At minimum, it should be possible to strap a micro to the ESP module and do things that way to get more control.  It's a pretty cool idea though: LocalTalk over WiFi, what a world!


Yup, I was assuming I'd have to have one of the more modern SCCs wired up to the ESP.  An auxiliary microcontroller squirting data over a high-speed UART to the ESP, or something along those lines, would be even more sensible, and probably pretty easy, since many of the uses of the smaller ESP stuff seems to be "various serial stuff to IP" bridges.   Did you ever manage to get sending working?

 

sfiera

Well-known member
The real problem here is that any computer that could talk LToUDP through an atlk/adev probably already has Ethernet, and so EtherTalk is a better option.  EtherTalk will be supported in this library/implementation, it's just I haven't got to it yet.  The only other option would be running LToUDP over MacIP over LocalTalk through a bridge, which frankly seems like a recipe for total disaster.
The main reason would be to bridge the physical hardware with emulators. I’m assuming this is difficult or impossible with Mini vMac. I tried and gave up with SheepShaver. If the multicast situation isn’t a dealbreaker, it might even work over Wifi. I assume wireless EtherTalk is impossible, and wired EtherTalk might be impossible in userspace—do you have an idea yet?

LToU avpn doesn’t really sound feasible (in the near future? ever?), though an LToU abridge sounds like something I might like to try hacking on. I don’t expect to be able to write an AFP server, but if I could bridge my Quadra to an AFP server running in Mini vMac, that would still be something I’d have a use for.

 

cheesestraws

Well-known member
The main reason would be to bridge the physical hardware with emulators. I’m assuming this is difficult or impossible with Mini vMac. I tried and gave up with SheepShaver
I think the way to go about this is at first a bridge, and then a full router, between LToUDP and EtherTalk, running on the UNIX side of things.  This is pretty much my first "major" project planned with this stack once I have EtherTalk support in it.

assume wireless EtherTalk is impossible
EtherTalk is just standard Ethernet frames with a SNAP header.  So in theory there's no reason it wouldn't work over wireless - that said, a lot of home-targetted wireless equipment is inadequately-tested rubbish, so whether it will actually pass anything other than IP is a little questionable.  That said, IIRC, IP on wireless is also transmitted with a SNAP header so it will probably work in more situations than people expect.

wired EtherTalk might be impossible in userspace—do you have an idea yet? 
You just posted a link to abridge, which already does EtherTalk in user-space :) .  It's just ethernet.  The software will either need to be run as root or use an unprivileged tap device bridged to the real ethernet device, or something, but that's pretty much par for the course with software doing weird stuff with Ethernet.  There's nothing at all magical about EtherTalk that it needs to be implemented in the kernel.

This isn't particularly relevant to the dongle discussion though, as that will not be doing any EtherTalk at all: it will be just talking bog-standard IP multi/broadcast, which should be coped with by even fairly rubbishy home infrastructure.

if I could bridge my Quadra to an AFP server running in Mini vMac, that would still be something I’d have a use for. 
When I've got half-reasonable EtherTalk support this will basically be the first project I'll be doing with it.  If you would like to hack on it with me your input would be very welcome :).

 

Dog Cow

Well-known member
cheesestraws, There was some AppleTalk networking code written for Unix systems back in 1984-85 at Stanford and other universities. Look up the SUMMacC, EFS, and SEAGATE projects. Towards the bottom of this AppleTalk article in the section "AppleTalk Overview" are some links to get you started.

There are other projects as well, so look around and I think you'll find that a lot of the groundwork is already done for you.

 

cheesestraws

Well-known member
There are other projects as well, so look around and I think you'll find that a lot of the groundwork is already done for you.


I have looked at quite a lot of AppleTalk code and often learned from it.  But the goals of those projects are not the same as this one: they often will not build properly with recent tooling, they were built for people who already knew what they were doing, and a non-trivial number of them seem to require kernel support.  Also, 1980s C code has not aged well in terms of security and the network conditions it is likely to find itself under.

This makes them unsuitable for use in the situations where I intend this to be used (see the first post in this thread for my rationale for doing this).  So far, at least for the link-layer stuff, the appendix to Inside Appletalk has been much more useful, as it is designed to be read and to be explanatory.

 

LaPorta

Well-known member
As far as I'm concerned, if you can create something that will let my modern mac see/talk with my old ones via AppleTalk, I'd be ecstatic.

 

sfiera

Well-known member
You just posted a link to abridge, which already does EtherTalk in user-space :) .  It's just ethernet.  The software will either need to be run as root or use an unprivileged tap device bridged to the real ethernet device, or something, but that's pretty much par for the course with software doing weird stuff with Ethernet.  There's nothing at all magical about EtherTalk that it needs to be implemented in the kernel.
Ah, right, I’m mixing up my terminology. I said “userspace” (non-kernel) but I was thinking “unprivileged” (non-root). Needing root was where I gave up with SheepShaver. Running network infrastructure as root on a Pi sounds totally fine to me, but running a crashy emulator as root on my laptop, not so much…

 

cheesestraws

Well-known member
Ah, right, I’m mixing up my terminology. I said “userspace” (non-kernel) but I was thinking “unprivileged” (non-root). Needing root was where I gave up with SheepShaver. Running network infrastructure as root on a Pi sounds totally fine to me, but running a crashy emulator as root on my laptop, not so much… 
Ah, yes.  No, I'm quite in agreement with you here.  The way I have done it under personally is to have a script that as root creates a tap device, chmods its corresponding file in /dev and adds it to the bridge, then drops privileges to run the emulator with its ethernet port aimed out the tap interface.  This is ... not trivial to set up but works rather well.

One of my "nice-to-haves" would be a "port" for this bridge that could talk the BII AppleTalk-over-UDP hack.  The way that works is that the IP address in the "real" network is encoded in the MAC address for the "virtual" network, so DDP packets can be sent directly wrapped in IP just knowing the MAC address of the destination.  I can't remember if this is in SheepShaver too, but if it *is*, this would be a sensible way to bridge "virtual" networks together without needing any special privileges on the emulators at all.

 
Last edited by a moderator:

cheesestraws

Well-known member
That's actually easier than receiving, it turns out.  I'll get my old notes together and post the work thus far in a separate thread to keep from derailing this discussion.
Yes, please!  I'm intrigued.

Today's progress: I have an LLAP ping utility working, analogously to ARP pings on Ethernet.  It can both scan an attached LToUDP network and ping an individual node on the network:

Code:
prydwen:llapping cheesey$ ./llapping 
usage: ./llapping -a
       Scan the LToUDP network and report on all up nodes

       ./llapping [node]
       Pings the given node with LLAP ENQs

prydwen:llapping cheesey$ ./llapping -a
Node 44 responded in 7.003581ms
Node 118 responded in 14.570215ms
Node 235 responded in 10.000884ms

prydwen:llapping cheesey$ ./llapping 118
lapACK from 118 in 12.545842ms
lapACK from 118 in 12.169505ms
lapACK from 118 in 13.506241ms
lapACK from 118 in 17.27405ms
lapACK from 118 in 5.377009ms
^C

prydwen:llapping cheesey$
I think I've done all the paperwork now to make the git repo public.  If people would like to have a go, I'll publish it tomorrow and post links and an experimental minivmac build...

 
Top