This week I tested uIP communication using a GPRS modem. There is not a PPP stack to uIP but Instituto Atlantico developed this stack I am using now. All headers files have a license text saying it is open source (a BSD like), but I couldn’t find it at any place on the internet.
Well, it was hard to got working. I read the RFC1661 in order to understand more about the PPP, LCP and other procotols.
I found a very nice text describing about the PPP low level using examples to illustrate it:
http://www.geocities.com/SiliconValley/2072/bit60.txt
Happily yesterday I salved it on my computer because today geocities (Yahoo) tell me it is not available. Here goes it:
Establishing A PPP Link:
PPP begins with LCP (Link Control Protocol). The first step, after a
communications channel becomes active, is for each side to send a
Configure-Request packet. This is a standard type of LCP packet that means
the sender is requesting configuration information. Assuming all goes well,
each side should respond in turn with a Configure-ACK packet. As soon as both
sides have sent a Configure-ACK packet, the link is considered established,
and the exchange moves on to the authentication phase. (If one side does not
accept the other side's Configure-Request packet, it will respond with a
Configure-Reject or a Configure-NAK packet.)
Authentication is actually optional; However, virtually all PPP servers will
implement it, since otherwise anybody could log in and start using the system
without authorization to do so. If authentication is used, the type of
authentication required will actually have already been specified; It is part
of the Configure-Request packets that were exchanged earlier. The
Configure-Request packet must explicitly describe if (for example) PAP or
CHAP authentication is desired. Thus, both systems already know what kind of
authentication to use once the authentication phase is reached.
Once the authentication phase is complete, LCP has done its job, and the NCPs
(Network Control Protocols) which the client wishes to use may begin. For
most dial-up Internet access situations, the main NCP used would be IPCP (IP
Control Protocol).
So what exactly goes into an LCP packet? A very basic LCP Configure-Request
packet is this:
01 01 00 04
This is the shortest possible Configure-Request packet. The first byte of an
LCP packet indicates what type of message it contains. The code for
Configure-Request is 1, so the first byte of a Configure-Request packet must
always be 1. The next byte is an identifier. This must be unique for each
separate LCP packet sent over the connection, and can be arbitrarily set to
anything. In this case, we're using 1 (a logical choice for the first
packet). The next two bytes indicate the size of the entire LCP packet, in
bytes. In this case, the whole packet is 4 bytes (the smallest possible LCP
packet). Thus, 0004 is used, and we are left with a complete LCP packet.
Unfortunately, you cannot just dial in to your ISP and send a raw LCP packet,
because they must be encapsulated in PPP format, which is considerably more
complicated. The standard for dial-up ISPs is to use "PPP in HDLC-like
framing", defined in RFC 1662. Under this system, each byte of actual data to
be sent is to be preceded by a 7Dh character (called a "control escape"
character), and the actual bytes are to be XORed with 20h before sending. (I
know, who's the genius who came up with THAT arrangement? It seems ludicrous,
but that's how PPP works.) So, our original LCP byte pattern, under this
system, becomes this:
7D 21 7D 21 7D 20 7D 24
This is almost a complete PPP frame, except for two additions: The beginning
and the end. A PPP LCP frame is supposed to begin with the following six
bytes: 7E FF 7D 23 C0 21. Also, each frame is to be ended with a 7E
character. Adding these to the previous byte string, we now have:
7E FF 7D 23 C0 21 7D 21 7D 21 7D 20 7D 24 7E
This is a complete PPP frame, which you can transmit to a dial-up ISP as soon
as the modem has connected, which will be a valid Configure-Request LCP
packet to it. Sending this to the ISP will probably make it begin
transmitting Configure-Request packets back to you (if it doesn't
automatically do so upon modem connect), and assuming you send it a
Configure-ACK, and it sends you a Configure-ACK as well, an LCP link has been
established.
Now, of course, you've got to understand what the ISP sends you back. To
demonstrate, here's a fairly typical Configure-Request packet that you'll see
from a typical ISP. Slight variations are common, but this shows most of the
configuration options you'll see out there:
7E FF 7D 23 C0 21 7D 21 0F 7D xx xx 7D 22 7D 26 7D xx 7D xx 7D xx 7D xx
7D 23 7D 24 C0 23 7D 25 7D 26 xx xx xx xx 7D 27 7D 22 7D 28 7D 22
(If PPP Multilink Protocol (MP) is used): 7D 31 7D 24 7D xx xx
(If endpoint discriminator option is used): 7D 33 7D xx 7D 21 blah
(Final 3 bytes, consisting of FCS and closing 7E): xx xx 7E
The first six bytes are, again, a signal of the beginning of a PPP LCP frame.
Next, we have 7D 21, which is an LCP byte 1, meaning this is a
Configure-Request message. Immediately after the 21 is a byte 0F, which is
used for the identifier. (Different ISPs may choose different identifier
numbers, but it doesn't matter, it's just an arbitrary number for reference.)
Although technically, according to the RFC, the identifier number *should* be
preceded by another 7D character and XORed with 20, it seems to be in fashion
for ISPs to do neither. Thus, the identifier comes right after the 21, and is
transmitted in its true form, not XORed with 20.
After that comes two more LCP bytes; These are for the size of the entire LCP
packet, in bytes. The actual numbers are simply shown as xx here, since they
will vary. Although technically, you're supposed to use a 7D character for
each new character, it seems to be common practice among ISPs to transmit
both size bytes at once, so instead of 7D xx 7D xx, you might just see it
without the second 7D, to wit: 7D xx xx.
The first three standard LCP fields (packet code, packet identifier, and
packet length) have now been transmitted, and everything following are the
configuration options. You can tell which configuration option is being
configured by the first byte of it. In this case, the next byte after the
size bytes is an LCP byte 2, which is the code for an Async Control Character
Map (ACCM). Next is a 6, indicating that this whole option is 6 bytes long.
The 2 for the code and the 6 for the length count as part of that, meaning
the rest of the code is 4 bytes long. Following that are 4 LCP bytes, which
collectively form the actual ACCM. (Don't worry too much about what the ACCM
itself means right now.)
Next we have an LCP byte 3, which is the code for indicating authentication
protocol. After that is a 4, indicating this field is 4 bytes. The final 2
bytes come immediately without being 7D'd, and they are C0 23, which is the
code for PAP (Password Authentication Protocol). If CHAP were desired, C2 23
would have been used instead. (PAP and CHAP were originally documented in RFC
1334, "PPP Authentication Protocols". The CHAP specification was later
updated in RFC 1994.)
Next is an LCP byte 5, which is the code for a magic number. After that is a
6, meaning this field is 6 bytes long (including these actual code and length
bytes). Right after the 6 come four bytes which together make up the actual
magic number itself. (Does it seem odd that the ACCM had each byte preceded
by a 7D, while the magic number is transmitted directly and without
modification? It's rather silly, but that's how this stuff is implemented.)
Next comes LCP 7 and 2. These two bytes, together, are an indication that the
ISP is letting you know it wants to use Protocol Field Compression (PFC).
After that is an 8 and a 2, which lets you know it also wants to use Address
and Control Field Compression (ACFC).
There are other things which most ISPs nowadays include in the frame as well,
most of which are documented in RFC 1990, "The PPP Multilink Protocol (MP)".
Most common among these are the MRRU (Maximum Received Reconstructed Unit)
option and the endpoint discriminator option. The MRRU begins with an LCP
byte 11, which indicates the MRRU LCP option. (RFC 1990 states that it's a
17, but it's talking decimal, and we're talking hexadecimal here. 17 decimal
equals 11 hexadecimal.) After that is an LCP byte indicating the size of this
option, which is always 4. After that, two bytes in succession (which are not
separated by a 7D, although the first one is preceded by a 7D) which indicate
the actual MRRU size. If the system actually sends the MRRU option, this
indicates that the system sending it implements the PPP Multilink Protocol.
If not rejected, the system will continue to use the PPP MP.
The other PPP MP option commonly configured at this stage is the endpoint
discriminator option. This starts with an LCP byte 13. (Again, RFC 1990 says
this should be a 19, but it's talking decimal. 19 decimal equals 13
hexadecimal.) After that is an LCP byte stating the size of this option,
which is always 3 plus the length of the actual address specified in this
option (we'll get to the address in a moment). The next LCP byte is usually a
1, indicating a locally-assigned address. Immediately following the 1 is a
succession of bytes which are the actual address of the system specified in
this option. (These bytes are represented as "blah" in the sample PPP frame
above.)
The PPP frame closes with two bytes which you can safely ignore for now
(they're the FCS (Frame Check Sequence)). The final byte is 7E, which always
closes the PPP frame, just as it opens a new one. So, now you have seen a
fairly realistic PPP frame from an ISP, and you know what to expect in the
real world (pretty much). So how do we acknowledge this to the ISP? With a
Configure-ACK packet. Making a Configure-ACK packet is actually quite simple,
because all we need to do is mirror the options that were sent to us. In
fact, the complete packet would look almost exactly the same as the
Configure-Request packet it is acknowledging, except that instead of
beginning with an LCP byte 1, it begins with an LCP byte 2. The identifier
byte must be the same, the length will be the same, and all the options must
be transmitted back the same way, so the other side of the connection
understands that we are acknowledging all of them. Our complete PPP frame
that we transmit back, then, would look like this:
7E FF 7D 23 C0 21 7D 22 0F 7D xx xx 7D 22 7D 26 7D xx 7D xx 7D xx 7D xx
7D 23 7D 24 C0 23 7D 25 7D 26 xx xx xx xx 7D 27 7D 22 7D 28 7D 22
(If PPP Multilink Protocol (MP) is used): 7D 31 7D 24 7D xx xx
(If endpoint discriminator option is used): 7D 33 7D xx 7D 21 blah
xx xx 7E
Note that the only difference is, the eighth byte has been made 22 instead of
21, making it an LCP byte 2 instead of a 1. As soon as Configure-ACK packets
like this have been sent by each side, the LCP link is open and can continue
to authentication with PAP or CHAP, or to networking with an NCP if no
authentication was specified in the Configure packets.
I was getting an error during the Configurating Phase (when client and server exchange Configuration Options), the server was returning a NACK. After my tests I discovered the problem happened because the PPP server at the point couldn’t accept changing the MRU length.