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:
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.