8bit TelBBS
Quantumlink protocol not that hard...

Hey, Jim Brain, you have 0 messages, 0 are new.
7/25/05 at 10:03





8bit TelBBS :: General :: Qlink Rebuilding Project :: Quantumlink protocol not that hard...
   [Search This Thread] [Add Bookmark] [Reply] [Send Topic To Friend] [Print]
 Author Topic: Quantumlink protocol not that hard... (Read 82 times)
Keith Henrickson
Guest
 Quantumlink protocol not that hard...
Thread Started on 7/3/05 at 14:38
[Quote]

I've actually got a good deal of the protocol understood. My challenge is finding the time to do anything with it.

One challenge to be overcome is understanding the disk file format. There are only 3 'real' programs on the disk. "*", "CHANGE ACCESS", and "DSK". The remaining programs are all loaded through the three letter filenames, as has been discussed on other threads. These files are simply track/sector pointers to the real files to be loaded. However, you ONLY have to learn about this if you want to write your own BASIC games to run inside people connection. Since each file has a header saying what to do with it, and can be lightly compressed/encrypted, this would need some exploration.

However, most people are probably interested in bringing back the service. It's not THAT hard to get your head around the protocol.

The Tymnet/Telenet login stuff is EASY to fake. Simply send the following string. C format for any programmers out there. "IDENTIFIER\xBA\xBA+" That's it. Just use a phone number like "/555-5555" to use the Tymnet (I beleive) login. Don't worry about what the commands mean. It's useless once you get connected.

Next comes layer 2. The client will send "\x5a\x4*\x*1\x4*\x*1\x7F\x7F\x23\x07\x09\x0D"
The 5A and the 0D are framing characters. They were used by the system to pick each packet apart. The stuff with the '*' is the CRC. It is NOT a custom CRC, it is plain jane CRC-16, padded with the 4's and the 1's. Why they did THAT, I have no clue. The next two bytes are sequence numbers. The first byte is the packet # that is being transmitted. The second byte is the last packet number successfully received by the sender of the packet. It ALWAYS starts at 0x7F, and wraps around to 0x10. For instance, if I am sending packet 0x15, and I have most recently received your packet 0x11, then the bytes would be "\x15\x11". This way every time you receive a packet, you know which of YOUR packets the other guy has received so that you can throw away the copies you kept and free up memory. The "\x23\x07\x09" is saying, "I am a confused client, and my version number is 9.7."

To respond to this, the server sends back "\x5A\x4*\x*1\x4*\x*1\x7F\x7F\x24\x0D". The "\x24" tells the client, "You're OK. I understand you, and we'll start all over."

For those of you who have worked at VERY low levels with ISDN, you will recognize some of this from Q.921. Interesting. Of course, all the numbers have changed and stuff, and the CRCs are added. But the concept is the same. LAPM on modems is actually quite similar too. Again, in ISDN terms, "\x23" is like a SABME, and "\x24" is like a UA.

Once you exchange these two packets, layer 2 is up. YAY. The client will switch from "Waiting for access to Q-Link..." to "Verifying your account details".

It will then send a packet like. "\x5A\x4*\x*1\x4*\x*1\x10\x7F\x20DD1234567890ABCD\x0d"

Ok, now "\x20" says that this is a data packet. Data packets, and ONLY data packets increment our packet number. That's why the "\x7F" changed to a "\x10". Yay. Now, the next two bytes are always two alphanumerics. That is the command the client is sending. "DD" means, "logging in with account number and validation code". The first ten digits are your account number, NOT your screen name. The screen name is NEVER sent to the server. The last four letters are a validation code. Sort of a password.

If your account is valid, the server will respond "D3EFGH". D3 says to write a new validation code, and the new code, which will be used on the NEXT login, is "EFGH".

When the client has done so, it will send "D6", saying it wrote the code without errors.

The server will then send either a "DO", to display the main menu, or it will send the welcome text using "SM/SE". All lines but the last are sent with SM, and the last line is sent with SE. That way the client knows you have the whole thing, and lets you press F5 to go to the main menu.

I know a LOT more, and if there is real interest I will write it up.
IP: Logged
Keith Henrickson
Guest
 Re: Quantumlink protocol not that hard...
Reply #1 on 7/3/05 at 14:44
[Quote]

Oh, and if you want to send me an email, my address is flipper@phin.com
IP: Logged
Jeff Ledger
Administrator
*****
member is offline

[avatar]


[homepage] [send pm]

Joined: Feb 2004
Posts: 182
 Re: Quantumlink protocol not that hard...
Reply #2 on 7/3/05 at 21:43
[Quote]

The only successful login I've been able to use is the
TERMINAL=
@
@
\0d
CONNECTED

using the number +5551212

Once connected it sends about 5 of these and then gives up.

ZqEN#
ZqEN#
ZqEN#
ZqEN#

Am I looking at some type of compressed code?

Jeff
IP: Logged


"My computer boots in 2 seconds!"
--Microsoft Beat That!
Keith Henrickson
Guest
 Re: Quantumlink protocol not that hard...
Reply #3 on 7/4/05 at 0:39
[Quote]

Ok, so you're having better luck with Telenet. Or I have them backwards. Been MANY years, and I never used either service for anything but Q-Link.

ANYWAY, you're seeing the clients hellos. :)

Z is 0x5A in ASCII, of course, and will start EVERY packet.

The next four characters are the encoded CRC. Looking them up in an ASCII table, I get:
0x71, 0x45, 0xF1, 0x4E.
The significant digits are 7, 5, F, E. The others are the static padding I referred to (if incorrectly), in my original post. The CRC is reassembled as FE75. This seems to be a perfectly normal CRC-16 of the remaining bytes in the packet.

The '#' is 0x23 in ASCII, and therefore this is the 'confused client' packet that is always sent on startup.

The remaining bytes 0x7F, 0x7F, 0x07, 0x09 (the last two may differ, they're a version number), are unprintable and therefore won't show in a simple ASCII trace.

You're 90% of the way to your first breakthrough. If you can figure out how to calculate CRCs (test it by confirming the CRC in the 0x23. I SWEAR this is a normal CRC-16.), then you can reply by changing the 0x23 to a 0x24, getting rid of the 0x07 and 0x09 bytes, fixing up the CRC, and sending it to the client.

You will see your first text change when you get it right. The CRC function is based on a very poor understanding of what it was doing. It works, but all the variable names should be considered wrong. The algorithm is poor as well. I have a better function, but haven't had a chance to test it yet. I beleive this function generates CRC-16 with the byte order incorrect, which will of course, propogate through the entire CRC function


/*Compute CRC for a packet. The packet data including sequence numbers and
the packet type must be present. The framing characters and CRC bytes should
not be present at all. */
unsigned short compute_CRC(unsigned char *pszPacketDataBuf, int nPacketLen){

int nByteCounter;
int nBitCounter;
unsigned short nTempCRC;
unsigned char nCRCHigh;
unsigned char nCRCLow;

nCRCHigh = 0;
nCRCLow = 0;

for (nByteCounter = 0; nByteCounter < nPacketLen; nByteCounter++){
/*Set a counter to 8 times*/
nTempCRC = (nCRCLow << 8);
for (nBitCounter = 0; nBitCounter < 8; nBitCounter++) {
/*Move low bit of new byte to C, high bit of new byte becomes 0
Move C into low bit of A, Move high bit of A into C
Mask off all of A except new bit */
nTempCRC = ((nTempCRC & 0xFF00) | ((pszPacketDataBuf[nByteCounter] & (1 << nBitCounter)) >> nBitCounter));
/*Xor CRChigh into A*/
nTempCRC = nTempCRC ^ nCRCHigh;
/*Move low bit of CRClow into C, high bit of CRC low becomes 0
Move C into high bit of A, move low bit of A into C
If C is not set, not ready to xor in CRC polynomial */
if (nTempCRC & 1) {
nTempCRC = nTempCRC >> 1;
/*Get CRClow
Xor in polylow
Store CRClow */
nTempCRC = ((nTempCRC & 0x00FF) | (((nTempCRC >> 8) ^ 0xA0) << 8));
/*Xor in polyhigh
Store CRChigh */
nTempCRC = nTempCRC ^ 0x01;
nCRCHigh = nTempCRC & 0x00FF;
} else {
nTempCRC = nTempCRC >> 1;
nCRCHigh = nTempCRC & 0x00FF;
}
}
nCRCLow = nTempCRC >> 8;
}
return ((nCRCHigh << 8) | nCRCLow);
}

/*Takes some data and sends it through the packet protocol. The
packet type byte must be present, but the sequence numbers and
framing bytes will be generated by this function. */
void transmit_packet(unsigned char *pPacketBuf, int nPacketLen) {
unsigned char szTempBuf[1024];
unsigned short nCRC;

szTempBuf[0] = 0x5A;

memcpy(&szTempBuf[7], pPacketBuf, nPacketLen);
szTempBuf[5] = 0x7f;
szTempBuf[6] = 0x7f;
nCRC = compute_CRC(&szTempBuf[5], nPacketLen+2);
szTempBuf[1] = (nCRC & 0x00F0) | 0x01;
szTempBuf[2] = (nCRC & 0x000F) | 0x40;
szTempBuf[3] = ((nCRC >> 8)& 0x00F0) | 0x01;
szTempBuf[4] = ((nCRC >> 8)& 0x000F) | 0x40;
szTempBuf[nPacketLen + 7] = 0x0D;

write(nWriteFD, szTempBuf, nPacketLen + 8);
}

// Of course, this isn't in a function, but it shows the way to invoke the above code to get what you want
transmit_packet("\x24",1);


IP: Logged
Jim Brain
Full Member
***
member is online




[email] [send pm]

Joined: Mar 2004
Posts: 189
 Re: Quantumlink protocol not that hard...
Reply #4 on 7/23/05 at 2:28
[Quote] [Modify] [Delete]

Yay!

Success, thanks to Keith:

2005-07-23 01:15:42:168113080::RS->|0000|0d 0a |.. |
2005-07-23 01:15:42:168113080::RS->|0000|43 4f 4e 4e 45 43 54 |CONNECT |
2005-07-23 01:15:42:168113080::RS->|0000|0d 0a |.. |
2005-07-23 01:15:43:168113080::RS<-|0000|0d |. |
2005-07-23 01:15:43:168113080::RS<-|0000|0d |. |
2005-07-23 01:15:43:168113464::RS->|0000|54 45 52 4d 49 4e 41 4c 3d 0d |TERMINAL=. |
2005-07-23 01:15:47:168113080::RS<-|0000|44 31 0d |D1. |
2005-07-23 01:15:47:168113464::RS->|0000|40 |@ |
2005-07-23 01:15:47:168113080::RS<-|0000|53 45 54 3f 20 31 30 3a |SET? 10: |
2005-07-23 01:15:48:168113080::RS<-|0000|30 2c 31 35 3a 30 2c 30 |0,15:0,0 |
2005-07-23 01:15:48:168113080::RS<-|0000|3a 33 33 2c 35 37 3a 31 |:33,57:1 |
2005-07-23 01:15:48:168113080::RS<-|0000|2c 36 33 3a 30 0d |,63:0. |
2005-07-23 01:15:48:168113464::RS->|0000|40 |@ |
2005-07-23 01:15:49:168113080::RS<-|0000|43 4f 4e 4e 45 43 54 20 |CONNECT |
2005-07-23 01:15:49:168113080::RS<-|0000|37 30 33 33 39 2e 38 37 |70339.87 |
2005-07-23 01:15:50:168113080::RS<-|0000|0d |. |
2005-07-23 01:15:51:168113464::RS->|0000|0d 0d 43 4f 4e 4e 45 43 54 45 44 0d |..CONNECTED. |
2005-07-23 01:15:54:168113080::RS<-|0000|5a 81 42 31 4e 7f 7f 23 |Z.B1N..# |
2005-07-23 01:15:54:168113080::RS<-|0000|05 09 0d |... |
2005-07-23 01:15:54:168113464::RS->|0000|5a f1 43 11 41 7f 7f 24 0d |Z.C.A..$. |
2005-07-23 01:15:55:168113080::RS<-|0000|5a 71 4b 41 4f 10 7f 20 |ZqKAO.. |
2005-07-23 01:15:55:168113080::RS<-|0000|44 44 35 38 38 39 33 34 |DD588934 |
2005-07-23 01:15:55:168113080::RS<-|0000|39 35 36 37 31 20 20 20 |95671 |
2005-07-23 01:15:56:168113080::RS<-|0000|0d |. |
2005-07-23 01:15:56:168113464::RS->|0000|5a 61 40 f1 41 10 10 20 44 33 31 20 20 20 0d |Za@.A.. D31 . |
2005-07-23 01:15:56:168113080::RS<-|0000|5a c1 44 81 45 11 10 20 |Z.D.E.. |
2005-07-23 01:15:57:168113080::RS<-|0000|53 53 0d |SS. |
2005-07-23 01:15:57:168113464::RS->|0000|5a 31 48 81 44 11 11 20 53 53 0d |Z1H.D.. SS. |
2005-07-23 01:15:59:168113080::RS<-|0000|5a 31 47 c1 40 12 11 20 |Z1G.@.. |
2005-07-23 01:15:59:168113080::RS<-|0000|53 47 0d 5a 21 43 31 42 |SG.Z!C1B |
2005-07-23 01:16:00:168113080::RS<-|0000|13 11 20 44 36 0d |.. D6. |
2005-07-23 01:16:00:168113464::RS->|0000|5a b1 49 c1 4f 12 13 20 44 4f 0d |Z.I.O.. DO. |


I'm at the 9 colored blocks... I never used Q-Link, so I am driving in the blind.

Notice in the above that I got a SS after the D3, to which I sent an SS back. I then got a SG and a D6 piggybacked on it, to which I sent the DO.

In any event, many thanks. If I had not taken such a wrong turn trying to step through the code (spent days trying to get through it), I'd be much further. Oh well, time to make up for lost time.

Keith, you sure I can;t interest you in a Java codebase? It has the FSM already installed (though it will no doubt need serious work).

Jim
IP: Logged

--
Jim Brain
Jim Brain
Full Member
***
member is online




[email] [send pm]

Joined: Mar 2004
Posts: 189
 Re: Quantumlink protocol not that hard...
Reply #5 on 7/23/05 at 2:31
[Quote] [Modify] [Delete]

By the way, here's a much simpler CRC to use:
Code:
int poly=0xa001;
int crc=0;
int data;
boolean carry;

for(int i=0;i<stream.length;i++) {
data=stream[i];
for(int k=0;k<8;k++) {
carry
crc=crc^(data&1);
data=data>>1;

if((crc&1)!=0) {
crc=crc>>1;
crc=crc^poly;
} else {
crc=crc>>1;
}
}
}

Last Edit: 7/23/05 at 2:36 by Jim Brain IP: Logged

--
Jim Brain
Jim Brain
Full Member
***
member is online




[email] [send pm]

Joined: Mar 2004
Posts: 189
 Re: Quantumlink protocol not that hard...
Reply #6 on 7/23/05 at 2:55
[Quote] [Modify] [Delete]

OK, two questions:

When I select All but Commodore Showcase and PeopleConnection, I get ML, but what do I need to send back?

Also, how does the server determine which of them the user selected, since they all send ML?

IP: Logged

--
Jim Brain
Keith Henrickson
Guest
 Re: Quantumlink protocol not that hard...
Reply #7 on 7/23/05 at 12:21
[Quote]

People connection sends MR, and of course does it's own thing. To bring up the simplest of people connection screens, send back 'CMLobby' and 'CE\x01JBrain'. It's not much, but you will have access to the menu on F7 and everything.

The other 8 areas should all function identically. You should receive 'ML', and send back 'MC'. You will then see the first line of a menu pop up at the top of the screen. It is waiting for the menu in the form of 'KA' and 'KB' commands. To see how to draw a menu, look at qlinkold/qmenus.c

The function qmens_rendermenu() outputs a standard menu.
There are basically two fields to each line. One is the item number. It simply says which item will be requested from the server.
The other field is a 24 bit value, of which two bytes have a significance that I understand. The first byte is the type of resource being requested. Some of them are simple like, "Change Area Menu", or "Post Office", or "Text Document". Some of them are complicated, like "Gateway service", and "Message Board", or "Mall Item". I have a list of what I know of each item in qlinkold/qlinkfuncs.txt
The second byte is a bitfield, with the second bit indicating plus time or not. IIRC. There is a buffer overflow here that lets you create 'minus time'. Of course, that was just a cosmetic indicator on the client side. Setting it didn't do anything to the server.

One correction to qlinkfuncs.txt is:
Item 0x85 is the 'gateway service', and basically a simple line by line terminal program that communicates over the Y* series of commands in that file.
IP: Logged
Keith Henrickson
Guest
 Re: Quantumlink protocol not that hard...
Reply #8 on 7/23/05 at 14:02
[Quote]


7/23/05 at 12:21, Keith Henrickson wrote:

The other 8 areas should all function identically. You should receive 'ML', and send back 'MC'. You will then see the first line of a menu pop up at the top of the screen. It is waiting for the menu in the form of 'KA' and 'KB' commands. To see how to draw a menu, look at qlinkold/qmenus.c

Also, the client will send 'K1@@@a' or somesuch. There is a hard coded list of these in the client, one for each of the 8 root menus. After that, you're pretty much free to pick your own menu names. THere are some rules, but I haven't figured out what they are. The menu names are a 4 ASCII char encoding of a 24 bit number. But message boards will pick their own 24 bit numbers in some cases. I never did figure them out.
IP: Logged
   [Search This Thread] [Add Bookmark] [Reply] [Send Topic To Friend] [Print]


Quick Reply
Message:

Shortcut to Quick Reply box: Alt+Q. Shortcut to post message: Alt+S.

Click Here To Make This Board Ad-Free

| Vacations | Hotels | T1 | Vacation Packages | Airline Tickets | DSL |

This Board Hosted For FREE By ProBoards
Get Your Own Free Message Board!