Writing the RNDIS Control Application

The RNDIS Control Application needs to handle notifications to start and stop the uplink. It also needs to configure the NAPT protocol.

The RNDIS Control Application needs to do the following:

  • Handle notifications to start and stop the uplink

    The RNDIS Agent uses Publish & Subscribe (P&S) to provide the RNDIS Control Application with RNDIS connection events and the Uplink Requirement Notification.

  • Configure the Network Address and Port Translation (NAPT) protocol

    The NAPT component has been implemented as IP hooks that modify the IP headers of traffic that is being transferred between a private and public network. IP hooks are implemented as protocols and therefore to attach the NAPT IP hooks the NAPT protocol has to be loaded.

Device creators can start the RNDIS Control Application at either of the following times:

  • When the USB Control Application detects USB cable attaching

  • At system start up.

Note: To ensure the RNDIS Control Application does not miss the uplink notifications from RNDIS Service, it must start before the RNDIS Service starts.

The USB Control Application stops the RNDIS Control Application by killing the RNDIS Control Application process. Then it stops the RNDIS Service. The Kernel helps to close the handle of the P&S Key and to stop the AO.

The header file rndis.h provides the PID. The header file rndisuiinterfaces.h provides the typedef for TRndisConnectionEvent and TRndisUplinkRequirementValue.
// Keys to be defined in C32 process (Using C32 process SID as the 
//Category 0x101F7989)
static const TUint KKeyRndisConnectionEvent = 0x10286a96;
static const TUint KKeyRndisUplinkRequirement = 0x10286a97;

enum TRndisConnectionEvent
{
ERndisConnectionEstablished,    // RNDIS connection    established
ERndisConnectionDestroyed,      // RNDIS connection    destroyed
};

enum TRndisUplinkRequirementValue
{
ERndisUplinkRequired,
ERndisUplinkNotRequired
Note: A process to write these keys must have NetworkControl capability.

  1. The RNDIS Control Application must start an AO and subscribe to the P&S key: KKeyRndisUplinkRequirement. Then the RNDIS Control Application must interpret the Connection Event buffer. The following code shows how to interpret the buffer of the P&S key:KKeyRndisConnectionEvent:
    const TUid KC32ExeSid = {0x101F7989};
    rndisConnectionEventProp.Attach(KC32ExeSid, KKeyRndisConnectionEvent)
    Tint32 rndisState; 
    TRndisConnectionEventPckg pckg;
    TInt err = rndisConnectionEventProp.Get(pckg);
    rndisState = pckg().iEvent;
    switch (rndisState)
        {
        case ERndisConnectionEstablished:
            {
            TRndisConnectionEventPayloadEstablished &payload =        
               reinterpret_cast< TRndisConnectionEventPayloadEstablished&>
               (pckg ().iPayload[0]);
            // Access every field in TRndisConnectionEventPayloadEstablished 
            // through reference payload.
            }
            break;
        case ERndisConnectionDestroyed:
            {
            TRndisConnectionEventPayloadDestroyed &payload =        
               reinterpret_cast< TRndisConnectionEventPayloadDestroyed&>
               (pckg ().iPayload[0]);
            // Access every field in TRndisConnectionEventPayloadDestroyed 
            through reference payload.
            }
            break;
    }
    

  2. When the control application receives the notification ERndisUplinkRequired, it must do the following:

    1. Get the RNDIS IAP ID from the notification. Then interpret the Uplink Requirement Buffer. The following code shows how to interpret the buffer of P&S key KKeyRndisUplinkRequirement:
      const TUid KC32ExeSid = {0x101F7989};
      rndisUplinkProp.Attach(KC32ExeSid, KKeyRndisUplinkRequirement)
      TInt err = rndisUplinkProp.Get(uplinkReq);
      switch(uplinkReq().iValue)
          {
          case ERndisUplinkRequired:
              {
              TRndisUplinkRequirementPayloadRequired &payload = 
                 reinterpret_cast<TRndisUplinkRequirementPayloadRequired&>
                 (uplinkReq().iPayload[0]);
              // Access every field in TRndisUplinkRequirementPayloadRequired 
              // through reference payload.
              }        
              break;
          case ERndisUplinkNotRequired:
              // There is no field in payload for ERndisUplinkNotRequired.
              break;
          }
      

    2. Then the RNDIS Control Application must retrieve the Uplink IAP ID from the Central Repository. (For retrieving the Uplink IAP ID, the device creator can use other methods, such as retrieving from an INI file.)

    3. Configure the NAPT protocol. If the RNDIS IAP ID and Uplink IAP ID are retrieved successfully, the RNDIS Control Application tries to start uplink connection specified by the Uplink IAP ID and to load NAPT. IP hooks are implemented as protocols and therefore to attach the NAPT IP hooks the NAPT protocol has to be loaded, this can be done as follows:
      if (iNaptSocket.Open(iSockServ, _L("napt")) == KErrNone)
          {
          // NAPT successfully loaded, can now be configured
          }
      
      If the NAPT protocol is loaded successfully, it must then be configured before any traffic will be successfully forwarded with translated addresses. To configure NAPT, a packaged TInterfaceLockInfo structure has to be passed to a SetOpt call as follows for example:
      iNaptInfo().iPublicIap = iUplinkIapId;;
      iNaptInfo().iPublicIp.SetAddress(iPublicAddr);
      
      iNaptInfo().iPrivateIap = iRndisIapId;
      iNaptInfo().iPrivateIp.SetAddress(iPrivateAddr);
                      
      iNaptInfo().iNetmaskLength = 24;
                      
      if (iNaptSocket.SetOpt(KSoNaptSetup, KSolNapt, iNaptInfo) == KErrNone)
          {
          // NAPT successfully configured
          }
      
      To ensure that NAPT is configured correctly both the Uplink and the RNDIS IAP must be started and the corresponding interfaces have the IP addresses assigned that are used in the NAPT configuration. After configuring NAPT, you must enable IP forwarding in NAPT:
      //This macro introduced by networking to support IP forwarding.
      #if defined(SYMBIAN_NETWORKING_ADDRESS_PROVISION)
      TPckgBuf<TIpForwardingInfo> ipforwardInfo;
      //Set iUplinkAccess to TRUE to enable IP forwarding in NAPT
      ipforwardInfo().iUplinkAccess = ETrue;
      User::LeaveIfError(iNaptSocket.SetOpt(KSoNaptProvision, KSolNapt, 
      ipforwardInfo));
      #endif
      

  3. When the control application receives the notification ERndisUplinkNotRequired, the control application must stop the uplink used by the PC connected using RNDIS network connection and it must close the NAPT socket.

Related information