PPP Interface

Jump to: navigation, search

Table of Contents >> Optional Protocols


Introduction

The Point-to-Point Protocol (usually referred to as PPP) is a low level protocol that performs two basic functions. It establishes a link between two peers, and it maintains that link. This protocol communicates through the hardware layer to the PPP layer on a peer system. Because communication takes place between two machines that have the same authority in the negotiation process, neither system can be considered a client or a server.

Let's examine how PPP creates a link and communicates between two machines. Communication is established in essentially three phases:

  1. Link Control Protocol (LCP)
  2. Authentication
  3. Network Control Protocol (NCP)


Link Control Protocol (LCP)

Negotiates options and establishes the link between two systems.


Authentication

This takes place after LCP option negotiation. It is a request for a peer machine to identify itself with some form of password scheme. We will discuss some of these methods later in this document. While authentication is optional, it is widely used with ISP's and other dial-ins that require secure logins.


Network Control Protocol (NCP)

Configures upper level protocols to operate over PPP. For example, our implementation of PPP uses IPCP (Internet Protocol Control Protocol).


PPP Negotiation

The first phase, LCP, is responsible for negotiating various options that will be enabled, disabled, or given specific values during communication. LCP negotiation makes PPP more effective than SLIP, Kermit, Z-Modem, and many of the other early peer-to-peer protocols. Unlike PPP, these early protocols did not have robust schemes for negotiating options, and they were not extensible. Newer versions of PPP may contain more options than previous versions, but can still effectively communicate with them.

Each system knows how it would like to receive data (the most efficient way, or options required by a system administrator), and tells its peer by sending a Configure-Request (Conf-Req). A Conf-Req specifies options such as authentication, control field compression, address field compression, Maximum Receive Unit (MRU), Magic Number, and many others. If a system receives a Conf-Req and all of the requested options are acceptable it replies with a Configure-Acknowledge (Conf-Ack).

The Configure-Acknowledge tells the sender of the Conf-Req that all the requested options are acceptable, have been enabled, and it is ready to start communicating.

Because some systems may have certain options disabled, or have version of PPP that does not support all the options, they may not be able to comply with a set of options a peer might request. For example, if a machine requests the MRU option set to 3000 bytes, and the peer system could not send data in blocks that large, it would return a Configure-Negative-Acknowledge (Conf-Nak). The Conf-Nak includes the options that the receiver of the Conf-Req found unacceptable, and a suggestion for an appropriate value. When a system receives a Conf-Req that contains options it is unfamiliar with, it responds with a Configure-Reject (Conf-Rej). It is similar to the Conf-Nak, in that it contains only those options that are unacceptable but it does not offer an alternative. If a system receives a Conf-Rej reply to its Conf-Req, it must send a new Conf-Req without the unfamiliar options, and exclude them from any future Conf-Req messages.


PPP Callback

When initiating a PPP session, the calling station may be required to be called back by the answering station before the PPP session is established.

The PPP callback option is an LCP extension described in RFC 1570. Mentioned in that description are a variety of different callback operations can be negotiated between the calling and answering stations:

0 Location is determined by user authentication.
1 Dialing string, the format and contents of which assumes configuration knowledge of the specific device which is making the callback.
2 Location identifier, which may or may not be human readable, to be used together with the authentication information for a database lookup to determine the callback location.
3 E.164 number.
4 Distinguished name.

After successful callback negotiation, the two stations would presumably go through an authentication phase and both would then gracefully disconnect from the network. After a delay, the answering station would return the call using the negotiated callback operation and PPP would go through its normal setup, including authentication (if required).


An enhancement, called the Callback Control Protocol (CBCP), is proposed in IETF draft draft-ietf-pppext-callback-cp-02.txt. This draft adds a new callback operation value: 6. No information is exchanged between calling and answering stations during LCP negotiation other than that they accept or reject the operation.


If CBCP is accepted by both stations, negotiation of the callback type, address and delay occurs after the authentication phase. If negotiation is successful, the two stations will proceed with disconnection and callback, if that is what is agreed upon.


The manner in which the application is physically connected to the network is unknown to the Treck stack. So, some additional help from the application is needed when, for example, Treck PPP must disconnect from the network (hang up), connect to a particular network address (dial a phone number) or answer an incoming call.


The application requirements are:

  1. Enable the PPP callback option in your trsystem.h file,
  2. Call tfPppSetOption() to configure Callback Control Protocol (CBCP),
  3. Call tfPppCallbackIoctl() to notify Treck PPP of external events,
  4. Call tfPppCallbackRegister() to provide Treck with an application function that will receive requests from Treck to hang up or dial a number.


When configuring CBCP, it is essential that the roles of the two stations are well defined. The CBCP request is always sent by the answering station (i.e. the station that received the call). The subsequent response is sent by the calling station (i.e. the station that initiated the call). Since Treck PPP does not actually know who placed the call and who answered the call, it will make the following assumption based on the link layer chosen by the application. If the following assumption is false, you must override the default role.

Caller = Client = tfUseAsyncPpp()

Answerer = Server = tfUseAsyncServerPpp()


To enable support for Treck PPP Callback, both PPP and the PPP Callback functionality must be enabled at compile time with the TM_USE_PPP and TM_USE_PPP_CALLBACK macros.

#define TM_USE_PPP
#define TM_USE_PPP_CALLBACK

The application will likely need to supply a function that Treck PPP can call to request an external action or notify of an internal event. Treck PPP will need assistance from the application, for example, to dial a phone number, answer an incoming call or disconnect from the network (hang up).


Use caution when calling Treck or kernel API calls from your action/notification function, as the function is called from deep within the Treck PPP state machine for the interface. Avoid calls that could block the current thread or calls that could directly affect the interface. Processing of the action/event should be deferred until after you record the event and return from the function-perhaps, in a worker thread.

Sample LCP Negotiation

Here is a sample negotiation between two machines: System X sends a Conf-Req to System Y that asks for several options:

System X System Y
I send a Conf-Req to System Y that asks for several options:

I would like you to send my PPP datagrams in blocks of 3000 bytes (MRU option set to 3000).

I can handle compressed protocol field compression; enable this option.

I would also like you to identify yourself, let's use CHAP.

I don't know what protocol field compression is.

Because I don't understand protocol field compression, I must send a Conf-Rej containing that option.

After receiving the Conf-Rej, I must now send another Conf-Req, but I may not ask for protocol field compression again:

I would like you to send my PPP datagrams in blocks of 3000 bytes (MRU option set to 3000).

I would like you to authenticate using CHAP.

I don't know how to use CHAP, let's use PAP instead.
This last reply was a Conf-Nak. As you can see, this message does not necessarily instruct me to discard these options. It merely tells me that certain attributes are unacceptable and offers values or attributes that are more agreeable. I must send another Conf-Req:

I would like my PPP datagrams in 3000 byte blocks.

I would like you to identify yourself using PAP.

Because System X accepted the hints I offered and included them in this Conf-Req, I will send a Conf-Ack that would look like this:

I am going to send you data in 3000 byte blocks.

I will use PAP to identify myself.

This is only one half of the LCP process. Both systems will send Conf-Reqs nearly simultaneously. In terms of our example negotiation, System Y would also send a Conf-Req to describe how it would like to receive its data as well.


PPP and Authentication

On some systems, a secure login is desirable. These systems could be an ISP, a business network with some form of remote access, or any system that must be mindful of what other systems should or should not have access. LCP negotiates what authentication method if any, will be used. Authentication actually taking place is a different phase. There are a variety of authentication methods, and we will briefly examine the most common three:

  1. Password Authentication Protocol (PAP)
  2. Challenge-Handshake Authentication Protocol (CHAP)
  3. Microsoft-Challenge-Handshake Authentication Protocol (MS-CHAP)
  4. Extensible Authentication Protocol (EAP)


Password Authentication Protocol (PAP)

This is one of the earliest and simplest of the authentication methods available. With this method, both peers know a secret and one will send a user name and password when it is requested. Of course, if authentication is intended to be bi-directional, there should be two sets of secrets. PAP's weakness is that the user name and password are sent across the wire in clear-text and leaves the possibility that these secrets can be intercepted.

Systems that use PAP typically do not use re-authentication, though it is not impossible. If re-authentication is necessary, LCP must renegotiate and utilize PAP again. For more information regarding PAP, please refer to RFC 1334.


Challenge-Handshake Authentication Protocol (CHAP)

This authentication method is more secure than PAP because it does not send a clear-text user name and password. Instead, when a peer wishes to validate another, it sends a name and a randomly generated number. The peer attempting to gain access uses the name given by the authenticator to obtain a plain text secret (it may prompt the user, or look it up in a database). The secret is then hashed with the random number and the result is sent to the authenticator. The original sender then uses the same algorithm and compares the result with the value it received from its peer. Based on the comparison, a success or failure message is sent to the system requesting access. Unlike PAP, CHAP has the ability to send periodic re-authentication requests without renegotiating. More information on CHAP can be found in RFC 1994.


Microsoft-Challenge-Handshake Authentication Protocol (MS-CHAP)

This authentication method is very similar to regular CHAP except for a few details:

Standard CHAP uses 05 for the hashing algorithm while MS-CHAP uses 08. It does not require the authenticator to store a clear-text or reversibly encrypted password. The authenticator has the ability to choose the number of retries as well as the ability to change passwords. Unlike CHAP, MS-CHAP will give a reason for failure (for example: incorrect password). More information on MS-CHAP is available in RFC 2433.


Extensible Authentication Protocol (EAP)

Not an authentication method, per se, EAP is a framework that supports multiple authentication methods. EAP is a request-response protocol with the requesting side controlling the exchange and granting or denying access. More than one method can be requested during an EAP session but each must complete before proceeding to the next. Some methods require more than one request-response message exchange but only one request or response message may be sent at a time (lock-step messaging). The session ends with the requesting side sending an EAP-Success or EAP-Failure message, indicating the EAP authentication result.

EAP RFC 3748 defines the following terms:

authenticator 
The end of the link initiating EAP authentication (aka. the server).
peer 
The end of the link that responds to the authenticator (aka. the client).
Master Session Key (MSK) 
Keying material that is derived between the EAP peer and server and exported by the EAP method.
Extended Master Session Key (EMSK) 
Additional keying material derived between the EAP client and server that is exported by the EAP method.

Authentication methods provided by the Treck EAP implementation are:

Identity 
Used to query the identity of the peer.
MD5-Challenge 
Analogous to the PPP CHAP protocol, with MD5 as the specified algorithm.
EAP-TLS 
The method defined in RFC 5216 that authenticates with a TLS/SSL exchange.

The EAP option is not compiled, by default. To use EAP, uncomment the following compile-time macro in trsystem.h and recompile the Treck library.

#define TM_USE_EAP

Configure PPP to use EAP by calling tfPppSetOption() with protocol TM_PPP_EAP_PROTOCOL as shown in the following client and server examples.

Using tfPppSetOption() to enable EAP.
Client (EAP peer) example Server (authenticator) example
ttUserLinkLayer pppHandle;
ttUserInterface myInterface;
ttUser16Bit pppProto;
int errorCode;
  . . .
pppHandle = tfUseAsyncPpp(...);
assert(pppHandle != (ttUserLinkLayer)0);
 
myInterface = tfAddInterface("PPP.Client",
                             pppHandle,
                             ...);
assert(myInterface != (ttUserInterface)0);
  . . .
pppProto = TM_PPP_EAP_PROTOCOL;
errorCode = tfPppSetOption( myInterface,
                            TM_PPP_LCP_PROTOCOL,
                            TM_PPP_OPT_ALLOW,
                            TM_LCP_AUTH_PROTOCOL,
                            (char *)&pppProto,
                            sizeof(pppProto) );
assert(errorCode == TM_ENOERROR);
  . . .
/* Set your EAP options (see below) */
  . . .
/* Open the interface to begin EAP authentication */
errorCode = tfNgOpenInterface(...);
assert(   errorCode == TM_ENOERROR
       || errorCode == TM_EINPROGRESS );
ttUserLinkLayer pppHandle;
ttUserInterface myInterface;
ttUser16Bit pppProto;
int errorCode;
  . . .
pppHandle = tfUseAsyncServerPpp(...);
assert(pppHandle != (ttUserLinkLayer)0);
 
myInterface = tfAddInterface("PPP.Server",
                             pppHandle,
                             ...);
assert(myInterface != (ttUserInterface)0);
  . . .
pppProto = TM_PPP_EAP_PROTOCOL;
errorCode = tfPppSetOption( myInterface,
                            TM_PPP_LCP_PROTOCOL,
                            TM_PPP_OPT_WANT,
                            TM_LCP_AUTH_PROTOCOL,
                            (char *)&pppProto,
                            sizeof(pppProto) );
assert(errorCode == TM_ENOERROR);
  . . .
/* Set your EAP options (see below) */
  . . .
/* Open the interface to begin EAP authentication */
errorCode = tfNgOpenInterface(...);
assert(   errorCode == TM_ENOERROR
       || errorCode == TM_EINPROGRESS );

Configure EAP by calling tfEapSetOption(). See the examples in the following EAP sections. If your application is a server (EAP authenticator) that accepts incoming connections, use option TM_EAP_USE_PROTO to request a particular authentication method. If your application is a client (EAP peer) that connects to a server, you only need to set the parameters for the methods you intend to support. A client may use option TM_EAP_REQ_PROTO to require a particular authentication method, which causes the client to fail if the server does not request the method.

Note Note: Options set via tfEapSetOption() will remain set after closing and reopening the interface (tfCloseInterface() and tfNgOpenInterface() or tfNgConfigInterface()).

EAP Timeout options

Treck sets default time limits on message exchanges for each EAP method and for the entire session, as recommended by the specification. You may change the following limits by calling tfEapSetOption().

Session timeout 
(Default: 120s) The maximum time to complete all methods.
Message retransmission 
Failing to receive a response within a time interval (default: 3s), each method will retransmit the last message a maximum number of times (default: 10). Message timeout is typically the responsibility of the authenticator (if a message is lost in either direction, the lock-step exchange stops for both ends).

EAP Identity method

As the name suggests, the Identity method is used by the authenticator to establish the peer's identity. The authenticator can then choose the authentication method and parameters that are suitable for the peer. Since EAP Identity is not useful for authentication, it is usually configured in conjunction with one of the authentication methods described in the following sections.

Configuring EAP Identity.
Client example Server example
ttUserInterface myInterface;
static char eapIdentity[] = "user@example.com";
int errorCode;
 
/* Set the EAP identity */
errorCode = tfEapSetOption( myInterface,
                            TM_EAP_IDENT_STR,
                            eapIdentity,
                            strlen(eapIdentity) );
assert(errorCode == TM_ENOERROR);
ttUserInterface myInterface;
ttUser8Bit eapOpt;
int errorCode;
 
/* Request the peer's identity */
eapOpt = TM_EAP_IDENTITY;
errorCode = tfEapSetOption( myInterface,
                            TM_EAP_USE_PROTO,
                            (char *)&eapOpt,
                            sizeof(eapOpt) );
assert(errorCode == TM_ENOERROR);

EAP MD5-Challenge Authentication method

A challenge-handshake exchange that uses the MD5 algorithm and a shared secret to authenticate the peer.

EAP MD5-Challenge specific function:

tfEapMd5RegisterAuthenticate() 
(Authenticator only) Register a function that will return the MD5-Challenge secret for a username.

Code examples to configure EAP MD5-Challenge:

Configuring EAP MD5-Challenge.
Client example Server example
ttUserInterface myInterface;
static char eapUsername[] = "user@example.com";
static char eapPassword[] = "password";
int errorCode;
 
/* Username and password for MD5-Challenge */
errorCode = tfEapSetOption( myInterface,
                            TM_EAP_MD5_USERNAME,
                            eapUsername,
                            strlen(eapUsername) );
assert(errorCode == TM_ENOERROR);
 
errorCode = tfEapSetOption( myInterface,
                            TM_EAP_MD5_PASSWORD,
                            eapPassword,
                            strlen(eapPassword) );
assert(errorCode == TM_ENOERROR);
ttUserInterface myInterface;
ttUser8Bit eapOpt;
static char eapName[] = "authenticator";
int errorCode;
 
/* Request MD5-Challenge exchange */
eapOpt = TM_EAP_MD5_CHALLENGE;
errorCode = tfEapSetOption( myInterface,
                            TM_EAP_USE_PROTO,
                            (char *)&eapOpt,
                            sizeof(eapOpt) );
assert(errorCode == TM_ENOERROR);
 
/* Authenticator's name for MD5-Challenge */
errorCode = tfEapSetOption( myInterface,
                            TM_EAP_MD5_AUTHNAME,
                            eapName,
                            strlen(eapName) );
assert(errorCode == TM_ENOERROR);
 
/* Register a function to provide MD5-Challenge secrets */
errorCode = tfEapMd5RegisterAuthenticate( myInterface,
                                          myMd5AuthFn );
assert(errorCode == TM_ENOERROR);
 
  . . .
 
static char * myMd5AuthFn(char * md5Name, int * errPtr)
{
    char * secretStr;  /* an ASCII NUL terminated string */
/*
 * Lookup the secret for md5Name.
 * If successful, set *errPtr = TM_ENOERROR and return the secret.
 * If unsuccessful, set *errPtr = TM_EACCES and return "".
 */
    return secretStr;
}

EAP-TLS Authentication method

The EAP-TLS method uses Treck TLS/SSL for authentication (using public key certificates). Note the following distinctions versus traditional TLS/SSL (RFC 5246):

TLS/SSL EAP-TLS
  • TLS/SSL offers authentication and data channel protection (encryption and integrity).
  • The client often remains anonymous to the server (client-side certificates are rare). The server application will often authenticate the client with other means, after the channel is secure (e.g. sign-on with username and password).
  • The session begins when client sends a TLS Client Hello after the transport layer connection is made (e.g. TCP handshake).
  • EAP Peer == TLS Client.
  • EAP Authenticator == TLS Server.
  • EAP-TLS offers authentication only. Once authentication is complete, the TLS session is destroyed.
  • The EAP peer will often need a signing certificate to prove it's identity to the authenticator.
  • The session begins with a method request from the EAP authenticator. The EAP peer responds with a TLS Client Hello.
  • Cryptographic key material can be exported, e.g. for data channel protection by some other means.
  • The minimum requirement is TLS v1.0. SSL v3.0 is not supported.

The EAP-TLS option is not compiled, by default. To use EAP-TLS, uncomment the following compile-time macros in trsystem.h and recompile the Treck library.

#define TM_USE_EAPTLS
#define TM_USE_SSL_CLIENT  /* if you need to connect as a client (peer) */
#define TM_USE_SSL_SERVER  /* if you need to connect as a server (authenticator) */

You will also need to initialize TLS/SSL, PKI and provide public key certificates (see SSL Programmer's Reference and Cryptography). The sample below shows the TLS client (EAP peer) providing a signing certificate. If the authenticator allows the EAP peer to remain anonymous, this step may be omitted.

The EAP-TLS option has the following additional code options in trsystem.h. By default, the options are compiled and available at runtime. If you have no need for the option, it can be disabled to reduce the Treck code size and, in the case of key export, execution time. The options are related to information that can be found in the EAP-TLS specification (RFC 5216). Additional runtime configuration may be required to enable the feature (see below and tfEapSetOption()).

#define TM_DISABLE_EAPTLS_AUTHENTICATOR   /* Authenticator (EAP-TLS server) support */
#define TM_DISABLE_EAPTLS_PEER            /* Peer (EAP-TLS client) support */
#define TM_DISABLE_EAPTLS_KEY_GEN         /* Export of EAP key material (MSK, EMSK, etc.) */
#define TM_DISABLE_EAPTLS_ID_PRIVACY      /* Identity privacy (2 successive TLS handshakes) */

EAP-TLS specific options you can set (see tfEapSetOption() for details):

TLS session id index 
(Required) This is the value returned by tfSslNewSession(). It defines the TLS parameters to be used (cipher suites, certificates and other TLS options).
TLS session id bytes 
From 0 to 32 random bytes supplied by the server during the TLS handshake and saved. The value may be used to shorten a subsequent TLS handshake with the same server if the server caches the session parameters. Set a zero-length value to disable the TLS resume feature, e.g. if you changed a session parameter since the last time you connected to the server.
User handshake process 
Defer processing of the TLS receive queue (see Deferring EAP-TLS processing of received TLS records below).
Identity privacy 
This feature allows client certificates to be sent encrypted (see Identity privacy in EAP-TLS below).
Key lengths 
The amount of EAP key material exported by the EAP-TLS can be overridden with these options. For example, your application may only require the Master Session Key (MSK) and, hence, set EMSK and IV lengths to zero.

EAP-TLS specific values you can retrieve (see tfEapGetOption() for details):

TLS session id index 
This is the value returned by tfSslNewSession() and set via tfEapSetOption().
TLS session id bytes 
From 0 to 32 random bytes supplied by the server during the TLS handshake and saved. You do not need to reload this value prior to the next connection attempt—the value saved from the previous TLS handshake will be used automatically.
Key values 
The EAP key material produced by the EAP-TLS method: MSK, EMSK, IV (see RFC 5216, section 2.3 and RFC 5247).
TLS identities 
The RFC 5216 specification discusses several values produced by the EAP-TLS method: peer and server identities (extracted from the peer and server certificates used in the TLS handshake) and session id (derived from the client and server nonces used in the TLS handshake, not the session id values mentioned above).
Timeout values 
(Authenticator only) The remaining retransmission downcount and interval can be read.

EAP-TLS specific functions:

tfEapTlsRegisterNotify() 
Register a function to receive EAP-TLS event notifications (see Deferring EAP-TLS processing of received TLS records below).
tfEapTlsProcessHandshake() 
Process TLS messages that are in the receive queue (see Deferring EAP-TLS processing of received TLS records below).

Deferring EAP-TLS processing of received TLS records

If you have a receive task that concurrently handles packet traffic unrelated to EAP-TLS, that traffic could be affected by the cryptographic processing that occurs when EAP-TLS packets are received. Normally, this isn't a problem but if it is you can defer this processing by doing the following after adding the interface:

  1. Register a callback function by calling tfEapTlsRegisterNotify().
  2. Enable option TM_EAPTLS_USER_PROCESS by calling tfEapSetOption().
  3. Open the interface.
  4. Your callback function will receive one or more TM_CB_SSL_HANDSHK_PROCESS events (signaled in the context of the receive task). Pass this signal on to a lower priority application task, however you do this for your operating system.
  5. When your application task receives the signal, call tfEapTlsProcessHandshake().

Key material exported by EAP-TLS

Besides authentication, the Treck EAP-TLS method can export key material for cryptographic protection. The specification for method-independent EAP cryptographic key material can be found in RFC 5247. How the key material is derived from the TLS master secret is specified in RFC 5216. Upon successful completion, the EAP-TLS method destroys all TLS cryptographic material but leaves all exported EAP key material available for the application to use.

If you have no need for this feature, you can reduce code size and execution time by defining the following compile time macro in trsystem.h:

#define TM_DISABLE_EAPTLS_KEY_GEN

The following material is exported, by default. You can retrieve the data via tfEapGetOption(). You can control the process via tfEapSetOption().

  • Master Session Key (MSK), which is split into:
    • Enc-RECV-Key (also known as MS-MPPE-Recv-Key or PMK)
    • Enc-SEND-Key (also known as MS-MPPE-Send-Key)
  • Extended Master Session Key (EMSK)
  • Initialization Vector (IV), which is split into:
    • RECV-IV
    • SEND-IV
  • Session-Id (derived from the TLS handshake nonces)
  • Peer-Id (extracted from the EAP Peer's certificate)
  • Server-Id (extracted from the EAP Authenticator's certificate)

Identity privacy in EAP-TLS

Peer identity privacy, described in the EAP-TLS specification (RFC 5216), is supported but disabled by default (for EAP Peer and Authenticator). The feature requires two consecutive TLS handshakes in which the client sends an empty certificate chain in the first (unencrypted) handshake. This relies on the server to initially accept the anonymous client then immediately send a Hello Request to start a second handshake (encrypted). The client must send it's credentials in the second round.

Note: Using this feature may cause the authentication to fail if the client cannot, or is not permitted to, send an empty certificate chain.

If you have no need for this feature, you can reduce code size by defining the following compile time macro in trsystem.h:

#define TM_DISABLE_EAPTLS_ID_PRIVACY

To enable this feature, you must set option TM_EAPTLS_PEER_PRIVACY via tfEapSetOption():

ttUserInterface myInterface;
int eaptlsOpt;
int errorCode;
  . . .
eaptlsOpt = 1;
errorCode = tfEapSetOption( myInterface,
                            TM_EAPTLS_PEER_PRIVACY,
                            (char *)&eaptlsOpt,
                            sizeof(eaptlsOpt) );
assert(errorCode == TM_ENOERROR);

Code examples to configure EAP-TLS

Configuring EAP-TLS.
Client example Server example
ttUserInterface myInterface;
int tlsSessionId;
int errorCode;
  . . .
/* Load PKI certificates (see PKI page) */
errorCode = tfUsePki();
assert(errorCode == TM_ENOERROR);
 
/* Trusted root CA certificates */
errorCode = tfPkiCertificateAdd(...);
assert(errorCode == TM_ENOERROR);
 
/* Client's public/private keys */
errorCode = tfPkiOwnKeyPairAdd(...);
assert(errorCode == TM_ENOERROR);
 
/* Client's signing certificate */
errorCode = tfPkiCertificateAdd(...);
assert(errorCode == TM_ENOERROR);
 
/* Create a TLS session (see SSL page) */
errorCode = tfUseSsl(...);
assert(errorCode == TM_ENOERROR);
 
tlsSessionId = tfSslNewSession(...);
assert(tlsSessionId >= 0);
 
/* TLS session id */
errorCode = tfEapSetOption( myInterface,
                            TM_EAPTLS_SESSION_INDEX,
                            (char *)&tlsSessionId,
                            sizeof(tlsSessionId) );
assert(errorCode == TM_ENOERROR);
 
/* Set any additional EAP-TLS options */
ttUserInterface myInterface;
int tlsSessionId;
ttUser8Bit eapOpt;
int errorCode;
  . . .
/* Load PKI certificates (see PKI page) */
errorCode = tfUsePki();
assert(errorCode == TM_ENOERROR);
 
/* Trusted root CA certificates */
errorCode = tfPkiCertificateAdd(...);
assert(errorCode == TM_ENOERROR);
 
/* Server's public/private keys */
errorCode = tfPkiOwnKeyPairAdd(...);
assert(errorCode == TM_ENOERROR);
 
/* Server's signing certificate */
errorCode = tfPkiCertificateAdd(...);
assert(errorCode == TM_ENOERROR);
 
/* Create a TLS session (see SSL page) */
errorCode = tfUseSsl(...);
assert(errorCode == TM_ENOERROR);
 
tlsSessionId = tfSslNewSession(...);
assert(tlsSessionId >= 0);
 
/* TLS session id */
errorCode = tfEapSetOption( myInterface,
                            TM_EAPTLS_SESSION_INDEX,
                            (char *)&tlsSessionId,
                            sizeof(tlsSessionId) );
assert(errorCode == TM_ENOERROR);
 
/* Request EAP-TLS exchange */
eapOpt = TM_EAP_TLS;
errorCode = tfEapSetOption( myInterface,
                            TM_EAP_USE_PROTO,
                            (char *)&eapOpt,
                            sizeof(eapOpt) );
assert(errorCode == TM_ENOERROR);
 
/* Set any additional EAP-TLS options */


Internet Protocol Control Protocol (IPCP)

The Internet Protocol Control Protocol enables, disables, and configures various IP modules on each end of the peer-to-peer link. This protocol has its own list of options such as various types of compression, MTU discovery, specifying IP addresses, and several more. It is important to remember no IP packets can be sent before PPP is in the NCP phase. In terms of the current Treck stack, the NCP phase consists solely of IPCP. This means a PPP link is first negotiated with LCP, authentication takes place (if it has been requested in LCP), and then IPCP establishes communication with the IP layer on the peer machine. For detailed information about the options within IPCP, please refer to RFC 1332.

IPCP in the Treck stack also includes options to obtain the addresses of Domain Name Servers (DNS servers). Domain name servers are remote servers that match domain names (such as treck.com) to an appropriate IP address. Detailed information on the DNS options within IPCP and implementation can be found in RFC 1877.


PPP Link Quality Monitoring (LQM)

PPP LQM enables the application to determine when PPP link quality has degraded to the point where recovery is necessary. PPP LQM does this via the exchange of Link-Quality-Report protocol messages at a negotiated interval (referred to as the Reporting-Period of the LQR timer). A Link-Quality-Report message contains the sender's state information w/ regards to how many packets and bytes have been successfully sent and received on the link. When the peer receives the Link-Quality-Report message, it can compare these counts against it's own similar state information to determine link quality, and then if it judges link quality bad, can recover the link (i.e. by bringing the link down and then up again, or some other application-specific recovery algorithm). The link can have a transient failure, in which case some amount of hysteresis is needed to average link quality over some multiple of the Reporting-Period so that transient link failures do not cause the link to go up and down too frequently.

PPP LQM does not specify the specific policy to be used to judge link quality, nor does it specify how to recover the link when link quality is judged bad. Since we believe that any user planning to use PPP LQM is sophisticated enough to implement their own link quality determination policy and recovery algorithm, also since the specific implementation will likely vary significantly depending on the application, we have decided not to implement any default link quality determination policy or recovery algorithm, but instead we provide a flexible API which enables the user to implement their own.


Description

First, before doing anything else, if link quality monitoring is desired, the user must #define TM_PPP_LQM in <trsystem.h>, and then rebuild all of the Treck TCP/IP code. tfUsePppLqm() is called to allocate the LQM state vector. Before the link is opened, the user calls tfPppSetOption() to set the TM_LCP_QUALITY_PROTOCOL configuration option, and if the user wants to register a link quality monitoring function, then they also negotiate a non-zero value for the LQR timer. After PPP opens the link, PPP starts the LQR timer. Either before or after PPP opens the link, but after the call to tfUsePppLqm(), the user calls tfLqmRegisterMonitor() to register their link quality monitoring function. Whenever a LQR is received, the user's link quality monitoring function is called, and is it passed incoming and outgoing packet and byte counts (derived from information contained in this LQR and also from the previously received LQR) and the elapsed time since the this function was last called. The user's link quality monitoring function then determines the link quality based on these counts and the delta time, and returns 0 if link quality is good, and 1 if it is bad (or greater than one to short-circuit the hysteresis and cause link recovery to occur sooner). These link quality counts are accumulated over multiple calls to the user's link quality monitoring function, and if they surpass a specified max failure count within a specified number of times that this function was called, then the user is notified that the link is bad via a PPP callback flag, after which they should attempt recovery of the link.

Example

#include <trsocket.h>
 
/* Parameters controlling determination of link quality */
#define LQM_HYSTERESIS_MAX_FAILURES   3
#define LQM_HYSTERESIS_SAMPLES        4
 
/* Function prototype for link quality monitoring function */
ttUser8Bit myLinkQualityMonitor(
    ttUserInterface interfaceHandle,
    int reasonCode,
    unsigned long timeElapsedMsec,
    ttLqrCountDeltasPtr countDeltasPtr,
    ttConstLqrCountsPtr countsPtr,
    ttUser32Bit outLqrs,
    ttUser32Bit outPackets,
    ttUser32Bit outOctets);
 
/* Function prototype for PPP link notification function */
void myPppLinkNotify(ttUserInterface interfaceHandle, int flag);
 
ttUserInterface interfaceHandle;
char errorMsgBuf[256];
 
/* Status flags */
int lqmEnabledStatus;
int linkBadStatus;
int linkQualityMonitorRegisteredStatus;
 
int main(void)
{
    int errorCode;
 
/* initialization */
    lqmEnabledStatus = 0;
    linkBadStatus = 0;
    linkQualityMonitorRegisteredStatus = 0;
 
/* start Treck */
    errorCode = tfStartTreck();
    ...
 
/* initialize PPP */
    linkLayerHandle = tfUseAsyncPpp((ttUserLnkNotifyFuncPtr)myPppLinkNotify);
 
/* add the PPP interface */
    interfaceHandle = tfAddInterface(
/* name of the device */
        "MYDEVICE.001",
/* Link Layer to use */
        linkLayerHandle,
        ...);
 
/* initialize LQM with a 3 second retransmission timer */
    errorCode = tfUsePppLqm(interfaceHandle, (ttUser32Bit)3000);
 
/* set PPP options for negotiation */
    errorCode = tfPppSetOption(interfaceHandle, ...);
 
/* open the PPP interface */
    errorCode=tfOpenInterface(interfaceHandle, ...);
 
/* main polling loop */
    while(1)
    {
        if (lqmEnabledStatus == 1)
        {
            if (linkQualityMonitorRegisteredStatus == 0)
            {
                linkQualityMonitorRegisteredStatus = 1;
 
/* after LQM is enabled, register the link quality monitor */
                errorCode = tfLqmRegisterMonitor(
                    interfaceHandle,
                    (ttLqmMonitorFuncPtr)myLinkQualityMonitor,
                    LQM_HYSTERESIS_MAX_FAILURES,
                    LQM_HYSTERESIS_SAMPLES);
                if (errorCode != TM_ENOERROR)
                {
                    tfSPrintF(errorMsgBuf,
                              "tfLqmRegisterMonitor failed '%s'\n",
                              tfStrError(errorCode));
                    tfKernelWarning("main", errorMsgBuf);
                }
            }
        }
 
        if (linkBadStatus == 1)
        {
            linkBadStatus = 0;
 
/* perform custom link recovery processing */
            ...
        }
 
/* other stuff */
        ...
    }
}
 
void myPppLinkNotify(ttUserInterface interfaceHandle, int flag)
{
    switch (flag)
    {
    case TM_LL_LQM_LINK_BAD:
        linkBadStatus = 1;
        break;
 
    case TM_LL_LQM_UP:
        lqmEnabledStatus = 1;
        break;
 
    case TM_LL_LQM_DISABLED:
        lqmEnabledStatus = 0;
        break;
 
/* other stuff */
    ...
    }
}
 
ttUser8Bit myLinkQualityMonitor(
    ttUserInterface interfaceHandle,
    int reasonCode,
    unsigned long timeElapsedMsec,
    ttLqrCountDeltasPtr countDeltasPtr,
    ttConstLqrCountsPtr countsPtr,
    ttUser32Bit outLqrs,
    ttUser32Bit outPackets,
    ttUser32Bit outOctets)
{
    int linkQuality;
    int outboundLqrsInPipeline;
 
    linkQuality = 0;
    switch(reasonCode)
    {
    case TM_LQM_MONITOR_LQR:
/* calculate link quality of the outgoing link */
        if (countDeltasPtr->deltaLastOutPackets
            >(countDeltasPtr->deltaPeerInPackets
              + countDeltasPtr->deltaPeerInDiscards))
        {
           linkQuality += countDeltasPtr->deltaLastOutPackets
                            - (countDeltasPtr->deltaPeerInPackets
                            + countDeltasPtr->deltaPeerInDiscards);
        }
 
/* calculate link quality of the incoming link */
        if (countDeltasPtr->deltaPeerOutPackets
            > countDeltasPtr->deltaSaveInPackets)
        {
           linkQuality += countDeltasPtr->deltaPeerOutPackets
                            - countDeltasPtr->deltaSaveInPackets;
        }
 
/* calculate number of outbound LQRs still in the pipeline */
        outboundLqrsInPipeline = (int)
            ((ttUser32Bit)0xffffffff & (outLqrs - countsPtr->lastOutLqrs));
        if (outboundLqrsInPipeline > 1)
        {
            linkQuality += outboundLqrsInPipeline - 1;
        }
        break;
 
    case TM_LQM_MONITOR_TIMEOUT:
        linkQuality = 1;
        break;
 
    default:
/* this should not happen */
        tfKernelWarning("myLinkQualityMonitor",
                        "unrecognized value for reasonCode");
        break;
    }
 
/* require at least 2 sample periods to declare a link bad */
    if (linkQuality > LQM_HYSTERESIS_MAX_FAILURES)
    {
        linkQuality = LQM_HYSTERESIS_MAX_FAILURES;
    }
 
    return (ttUser8Bit) linkQuality;
}

Limitations

We do not implement a default policy for judging the quality of the link, and we do not attempt any recovery when the link quality is judged bad. Instead, the user must register a link quality monitoring function if they want to implement a link quality monitoring policy, and we will give them a PPP callback (after a user-specified amount of hysteresis has been applied) when the link quality is judged bad so that they can attempt recovery.


IP Header Compression Over PPP

IP Header Compression (IPHC) allows various network headers, such as IPv4, IPv6, TCP and UDP, to be compressed over point to point links. This compression is especially advantageous over low speed serial links. The full IPHC protocol and implementation is described in RFC 2507. This document describes the interface and interaction between IPHC and the PPP link layer, including negotiation of IPHC options and muxing/demuxing of compressed packets.


Function Calls


Table of Contents >> Optional Protocols