/********************************************************************/ /** Copyright(c) 1989 Microsoft Corporation. **/ /********************************************************************/ //*** // // Filename: lcp.c // // Description: Contains entry points to configure LCP. // // History: // Nov 11,1993. NarenG Created original version. // // #include #include #include // needed for winbase.h #include // Win32 base API's #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // // Default values // const static LCP_OPTIONS LcpDefault = { 0, // Negotiation flags LCP_DEFAULT_MRU, // Default value for MRU 0xFFFFFFFF, // Default ACCM value. 0, // no authentication ( for client ) 0, // no authentication data. ( for client ) NULL, // no authentication data. ( for client ) 0, // Magic Number. FALSE, // Protocol field compression. FALSE, // Address and Contorl-Field Compression. 0, // Callback Operation message field LCP_DEFAULT_MRU, // Default value for MRRU == MRU according to RFC1717 0, // No short sequencing 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // No endpoint discriminator 0, // Length of Endpoint Discriminator 0 // Link Discriminator (for BAP/BACP) }; // // Accept anything we understand in the NAK and in a REQ from a remote host // static DWORD LcpNegotiate = LCP_N_MRU | LCP_N_ACCM | LCP_N_MAGIC | LCP_N_PFC | LCP_N_ACFC; static DWORD SizeOfOption[] = { 0, // unused PPP_OPTION_HDR_LEN + 2, // MRU PPP_OPTION_HDR_LEN + 4, // ACCM PPP_OPTION_HDR_LEN + 2, // authentication 0, // Unused. PPP_OPTION_HDR_LEN + 4, // magic number 0, // Reserved, unused PPP_OPTION_HDR_LEN + 0, // Protocol compression PPP_OPTION_HDR_LEN + 0, // Address/Control compression 0, // Unused 0, // Unused 0, // Unused 0, // Unused PPP_OPTION_HDR_LEN + 1, // Callback 0, // Unused 0, // Unused 0, // Unused PPP_OPTION_HDR_LEN + 2, // MRRU PPP_OPTION_HDR_LEN + 0, // Short Sequence Header Format PPP_OPTION_HDR_LEN, // Endpoint Discriminator 0, // Unused 0, // Unused 0, // Unused PPP_OPTION_HDR_LEN + 2 // Link Discriminator (for BAP/BACP) }; WORD WLinkDiscriminator = 0; // Next Link Discriminator to use BYTE BCount = 0; // To make EndpointDiscriminator different //** // // Call: MakeAuthProtocolOption // // Returns: NO_ERROR - Success // Non-zero returns - Failure // // Description: Given a certain authentication protocol, will construct the // configuration option for it. // DWORD MakeAuthProtocolOption( IN LCP_SIDE * pLcpSide ) { switch( pLcpSide->fLastAPTried ) { case LCP_AP_EAP: pLcpSide->Work.AP = PPP_EAP_PROTOCOL; if ( pLcpSide->Work.APDataSize != 0 ) { pLcpSide->Work.APDataSize = 0; if ( pLcpSide->Work.pAPData != NULL ) { LOCAL_FREE( pLcpSide->Work.pAPData ); pLcpSide->Work.pAPData = NULL; } } break; case LCP_AP_CHAP_MS: case LCP_AP_CHAP_MS_NEW: default: pLcpSide->Work.AP = PPP_CHAP_PROTOCOL; if ( pLcpSide->Work.APDataSize != 1 ) { pLcpSide->Work.APDataSize = 1; if ( NULL != pLcpSide->Work.pAPData ) { LOCAL_FREE( pLcpSide->Work.pAPData ); pLcpSide->Work.pAPData = NULL; } pLcpSide->Work.pAPData = (PBYTE)LOCAL_ALLOC( LPTR, pLcpSide->Work.APDataSize ); if ( pLcpSide->Work.pAPData == NULL ) { pLcpSide->Work.APDataSize = 0; return( GetLastError() ); } } if ( pLcpSide->fLastAPTried == LCP_AP_CHAP_MS_NEW ) { *(pLcpSide->Work.pAPData) = PPP_CHAP_DIGEST_MSEXT_NEW; } else { *(pLcpSide->Work.pAPData) = PPP_CHAP_DIGEST_MSEXT; } break; case LCP_AP_CHAP_MD5: pLcpSide->Work.AP = PPP_CHAP_PROTOCOL; if ( pLcpSide->Work.APDataSize != 1 ) { pLcpSide->Work.APDataSize = 1; if ( NULL != pLcpSide->Work.pAPData ) { LOCAL_FREE( pLcpSide->Work.pAPData ); pLcpSide->Work.pAPData = NULL; } pLcpSide->Work.pAPData = (PBYTE)LOCAL_ALLOC( LPTR, pLcpSide->Work.APDataSize ); if ( pLcpSide->Work.pAPData == NULL ) { pLcpSide->Work.APDataSize = 0; return( GetLastError() ); } } *(pLcpSide->Work.pAPData) = PPP_CHAP_DIGEST_MD5; break; case LCP_AP_SPAP_NEW: pLcpSide->Work.AP = PPP_SPAP_NEW_PROTOCOL; if ( pLcpSide->Work.APDataSize != 4 ) { pLcpSide->Work.APDataSize = 4; if ( NULL != pLcpSide->Work.pAPData ) { LOCAL_FREE( pLcpSide->Work.pAPData ); pLcpSide->Work.pAPData = NULL; } pLcpSide->Work.pAPData = (PBYTE)LOCAL_ALLOC( LPTR, pLcpSide->Work.APDataSize ); if ( pLcpSide->Work.pAPData == NULL ) { pLcpSide->Work.APDataSize = 0; return( GetLastError() ); } } HostToWireFormat32( LCP_SPAP_VERSION, pLcpSide->Work.pAPData ); break; case LCP_AP_PAP: pLcpSide->Work.AP = PPP_PAP_PROTOCOL; if ( pLcpSide->Work.APDataSize != 0 ) { pLcpSide->Work.APDataSize = 0; if ( pLcpSide->Work.pAPData != NULL ) { LOCAL_FREE( pLcpSide->Work.pAPData ); pLcpSide->Work.pAPData = NULL; } } break; } return( NO_ERROR ); } //** // // Call: LcpBegin // // Returns: NO_ERROR - Success // non-zero error - Failure // // // Description: Called once before any other call to LCP is made. Allocate // a work buffer and initialize it. // DWORD LcpBegin( IN OUT VOID** ppWorkBuf, IN VOID* pInfo ) { LCPCB * pLcpCb; RAS_FRAMING_CAPABILITIES RasFramingCapabilities; DWORD dwRetCode; DWORD dwIndex; PPPCP_INIT * pPppCpInit; *ppWorkBuf = LOCAL_ALLOC( LPTR, sizeof( LCPCB ) ); if ( *ppWorkBuf == NULL ) { return( GetLastError() ); } pLcpCb = (LCPCB *)*ppWorkBuf; pPppCpInit = (PPPCP_INIT *)pInfo; pLcpCb->fServer = pPppCpInit->fServer; pLcpCb->hPort = pPppCpInit->hPort; pLcpCb->PppConfigInfo = pPppCpInit->PppConfigInfo;; pLcpCb->fRouter = ( pPppCpInit->IfType == ROUTER_IF_TYPE_FULL_ROUTER ); pLcpCb->dwMagicNumberFailureCount = 0; pLcpCb->dwMRUFailureCount = 2; // // Check to see if we need to override the Negotiate Multi Link // send by the caller // BugID: WINSE 17061 Windows Bugs: 347562 if ( PppConfigInfo.dwDontNegotiateMultiLinkOnSingleLink ) { //remove NegotiateMultiLink from config info PppLog( 2, "Removing NegotiateMultilink due to registry override" ); pLcpCb->PppConfigInfo.dwConfigMask &= ~PPPCFG_NegotiateMultilink; } // // Set up defaults // CopyMemory( &(pLcpCb->Local.Want), &LcpDefault, sizeof( LCP_OPTIONS ) ); CopyMemory( &(pLcpCb->Remote.Want), &LcpDefault, sizeof( LCP_OPTIONS ) ); // // Get Framing information from the driver. // dwRetCode = RasGetFramingCapabilities( pLcpCb->hPort, &RasFramingCapabilities ); if ( dwRetCode != NO_ERROR ) { LOCAL_FREE( *ppWorkBuf ); return( dwRetCode ); } pLcpCb->Local.WillNegotiate = LcpNegotiate; pLcpCb->Remote.WillNegotiate = LcpNegotiate; pLcpCb->Local.Want.MRU = RasFramingCapabilities.RFC_MaxFrameSize; pLcpCb->Remote.Want.MRU = RasFramingCapabilities.RFC_MaxFrameSize; pLcpCb->Local.Want.Negotiate = LCP_N_MAGIC; pLcpCb->Remote.Want.Negotiate = LCP_N_MAGIC; if (RasFramingCapabilities.RFC_MaxFrameSize != LCP_DEFAULT_MRU) { pLcpCb->Local.Want.Negotiate |= LCP_N_MRU; pLcpCb->Remote.Want.Negotiate |= LCP_N_MRU; } if ( RasFramingCapabilities.RFC_FramingBits & PPP_COMPRESS_ADDRESS_CONTROL ) { pLcpCb->Local.Want.ACFC = TRUE; pLcpCb->Local.Want.Negotiate |= LCP_N_ACFC; pLcpCb->Remote.Want.ACFC = TRUE; pLcpCb->Remote.Want.Negotiate |= LCP_N_ACFC; } if ( RasFramingCapabilities.RFC_FramingBits & PPP_COMPRESS_PROTOCOL_FIELD ) { pLcpCb->Local.Want.PFC = TRUE; pLcpCb->Local.Want.Negotiate |= LCP_N_PFC; pLcpCb->Remote.Want.PFC = TRUE; pLcpCb->Remote.Want.Negotiate |= LCP_N_PFC; } if ( RasFramingCapabilities.RFC_FramingBits & PPP_ACCM_SUPPORTED ) { pLcpCb->Local.Want.ACCM = RasFramingCapabilities.RFC_DesiredACCM; pLcpCb->Local.Want.Negotiate |= LCP_N_ACCM; } if ( pLcpCb->PppConfigInfo.dwConfigMask & PPPCFG_NegotiateMultilink ) { pLcpCb->Local.Want.dwEDLength = ( PppConfigInfo.EndPointDiscriminator[0] == 1 ) ? 21 : 7; CopyMemory( pLcpCb->Local.Want.EndpointDiscr, PppConfigInfo.EndPointDiscriminator, pLcpCb->Local.Want.dwEDLength ); if ( ( pPppCpInit->dwDeviceType & RDT_Tunnel ) && ( !pPppCpInit->fServer ) ) { // // If a VPN connection goes down unexpectedly, the server doesn't // realize this for upto 2 min. When the client redials, we don't // want the server to bundle the old link and the new one. Hence, // we change the EndpointDiscriminator. // BCount++; pLcpCb->Local.Want.EndpointDiscr[pLcpCb->Local.Want.dwEDLength-1] += BCount; } pLcpCb->Local.Want.Negotiate |= LCP_N_ENDPOINT; pLcpCb->Remote.Want.Negotiate |= LCP_N_ENDPOINT; pLcpCb->Local.Want.MRRU = RasFramingCapabilities.RFC_MaxReconstructedFrameSize; pLcpCb->Remote.Want.MRRU = 1500; // Can always handle sending 1500 pLcpCb->Local.Want.Negotiate |= LCP_N_MRRU; pLcpCb->Remote.Want.Negotiate |= LCP_N_MRRU; if ( RasFramingCapabilities.RFC_FramingBits & PPP_SHORT_SEQUENCE_HDR_FORMAT ) { pLcpCb->Local.Want.ShortSequence = TRUE; pLcpCb->Local.Want.Negotiate |= LCP_N_SHORT_SEQ; pLcpCb->Remote.Want.ShortSequence = TRUE; pLcpCb->Remote.Want.Negotiate |= LCP_N_SHORT_SEQ; } pLcpCb->Local.WillNegotiate |= ( LCP_N_SHORT_SEQ | LCP_N_ENDPOINT | LCP_N_MRRU ); pLcpCb->Remote.WillNegotiate |= ( LCP_N_SHORT_SEQ | LCP_N_ENDPOINT | LCP_N_MRRU ); if ( pLcpCb->PppConfigInfo.dwConfigMask & PPPCFG_NegotiateBacp ) { pLcpCb->Local.Want.dwLinkDiscriminator = WLinkDiscriminator++; pLcpCb->Remote.Want.dwLinkDiscriminator = 0; pLcpCb->Local.Want.Negotiate |= LCP_N_LINK_DISCRIM; pLcpCb->Remote.Want.Negotiate |= LCP_N_LINK_DISCRIM; pLcpCb->Local.WillNegotiate |= LCP_N_LINK_DISCRIM; pLcpCb->Remote.WillNegotiate |= LCP_N_LINK_DISCRIM; } } // // We always negotiate callback if this is not a callback // if ( !pPppCpInit->fThisIsACallback ) { // // If the CBCP dll is loaded // if ( GetCpIndexFromProtocol( PPP_CBCP_PROTOCOL ) != (DWORD)-1 ) { if ( pLcpCb->PppConfigInfo.dwConfigMask & PPPCFG_UseLcpExtensions ) { pLcpCb->Local.Want.Negotiate |= LCP_N_CALLBACK; pLcpCb->Local.Want.Callback = PPP_NEGOTIATE_CALLBACK; } pLcpCb->Local.WillNegotiate |= LCP_N_CALLBACK; pLcpCb->Remote.WillNegotiate |= LCP_N_CALLBACK; } } // // Figure out what authentication protocols we may use for this connection. // if ( pLcpCb->PppConfigInfo.dwConfigMask & PPPCFG_NegotiatePAP ) { pLcpCb->Local.fAPsAvailable |= LCP_AP_PAP; pLcpCb->Remote.fAPsAvailable |= LCP_AP_PAP; } if ( pLcpCb->PppConfigInfo.dwConfigMask & PPPCFG_NegotiateMD5CHAP ) { pLcpCb->Remote.fAPsAvailable |= LCP_AP_CHAP_MD5; pLcpCb->Local.fAPsAvailable |= LCP_AP_CHAP_MD5; } if ( pLcpCb->PppConfigInfo.dwConfigMask & PPPCFG_NegotiateMSCHAP ) { pLcpCb->Local.fAPsAvailable |= LCP_AP_CHAP_MS; pLcpCb->Remote.fAPsAvailable |= LCP_AP_CHAP_MS; } if ( pLcpCb->PppConfigInfo.dwConfigMask & PPPCFG_NegotiateEAP ) { pLcpCb->Remote.fAPsAvailable |= LCP_AP_EAP; pLcpCb->Local.fAPsAvailable |= LCP_AP_EAP; } if ( pLcpCb->PppConfigInfo.dwConfigMask & PPPCFG_NegotiateSPAP ) { pLcpCb->Local.fAPsAvailable |= LCP_AP_SPAP_NEW; pLcpCb->Remote.fAPsAvailable |= LCP_AP_SPAP_NEW; } if ( pLcpCb->PppConfigInfo.dwConfigMask & PPPCFG_NegotiateStrongMSCHAP ) { pLcpCb->Local.fAPsAvailable |= LCP_AP_CHAP_MS_NEW; pLcpCb->Remote.fAPsAvailable |= LCP_AP_CHAP_MS_NEW; } if ( pLcpCb->PppConfigInfo.dwConfigMask & PPPCFG_AllowNoAuthOnDCPorts ) { pLcpCb->Local.fAPsAvailable = 0; pLcpCb->Remote.fAPsAvailable = 0; } // // Make sure we have at least one authentication protocol if we are a // server or a router dialing out. Fail if we are not allow no // authentication. // if ( ( pLcpCb->Local.fAPsAvailable == 0 ) && ( !( pLcpCb->PppConfigInfo.dwConfigMask & PPPCFG_AllowNoAuthentication ) ) && ( ( pLcpCb->fServer ) || ( pLcpCb->fRouter ) ) ) { LOCAL_FREE( *ppWorkBuf ); return( ERROR_NO_AUTH_PROTOCOL_AVAILABLE ); } PppLog( 2, "ConfigInfo = %x", pLcpCb->PppConfigInfo.dwConfigMask ); PppLog( 2, "APs available = %x", pLcpCb->Local.fAPsAvailable ); // // If this is the server side or we are a router dialing out, // we need to request an authentication protocol. // if ( ( pLcpCb->Local.fAPsAvailable > 0 ) && (( pLcpCb->fServer ) || ( ( pLcpCb->fRouter ) && ( pLcpCb->PppConfigInfo.dwConfigMask & PPPCFG_AuthenticatePeer )))) { pLcpCb->Local.Want.Negotiate |= LCP_N_AUTHENT; pLcpCb->Local.WillNegotiate |= LCP_N_AUTHENT; pLcpCb->Local.Work.APDataSize = 0; pLcpCb->Local.Work.pAPData = NULL; } // // If this is the client side and no protocol other than MSCHAP v2 and EAP // is allowed, then we insist on being authenticated. // if (!( pLcpCb->fServer )) { if ( ( pLcpCb->Remote.fAPsAvailable & ~( LCP_AP_CHAP_MS_NEW | LCP_AP_EAP ) ) == 0 ) { pLcpCb->Remote.Work.APDataSize = 0; pLcpCb->Remote.Work.pAPData = NULL; pLcpCb->Remote.WillNegotiate |= LCP_N_AUTHENT; pLcpCb->Remote.Want.Negotiate |= LCP_N_AUTHENT; } } // // Accept authentication if there are authentication protocols available // If it turns out that it is a client dialing in then authentication // will fail and we will renegotiate and this time we will reject // authentication option. See auth.c. // if ( pLcpCb->Remote.fAPsAvailable > 0 ) { pLcpCb->Remote.Work.APDataSize = 0; pLcpCb->Remote.Work.pAPData = NULL; pLcpCb->Remote.WillNegotiate |= LCP_N_AUTHENT; } return( NO_ERROR ); } //** // // Call: LcpEnd // // Returns: NO_ERROR - Success // // Description: Frees the LCP work buffer. // DWORD LcpEnd( IN VOID * pWorkBuf ) { LCPCB * pLcpCb = (LCPCB *)pWorkBuf; PppLog( 2, "LcpEnd"); if ( pLcpCb->Local.Work.pAPData != (PBYTE)NULL ) { LOCAL_FREE( pLcpCb->Local.Work.pAPData ); } if ( pLcpCb->Remote.Work.pAPData != (PBYTE)NULL ) { LOCAL_FREE( pLcpCb->Remote.Work.pAPData ); } if ( pWorkBuf != NULL ) { LOCAL_FREE( pWorkBuf ); } return( NO_ERROR ); } //** // // Call: LcpReset // // Returns: NO_ERROR - Success // // Description: Called to reset the state of LCP. Will re-initialize the work // buffer. // DWORD LcpReset( IN VOID * pWorkBuf ) { LCPCB * pLcpCb = (LCPCB *)pWorkBuf; PVOID pAPData; DWORD APDataSize; DWORD dwIndex; DWORD dwRetCode; // // Make sure we have at least one authentication protocol if we are a // server or a router dialing out. Fail if we are not allow no // authentication. // if ( ( pLcpCb->Local.fAPsAvailable == 0 ) && ( !( pLcpCb->PppConfigInfo.dwConfigMask & PPPCFG_AllowNoAuthentication ) ) && ( ( pLcpCb->fServer ) || ( pLcpCb->fRouter ) ) ) { return( ERROR_NO_AUTH_PROTOCOL_AVAILABLE ); } pLcpCb->dwMagicNumberFailureCount = 0; if ( pLcpCb->Local.Want.Negotiate & LCP_N_MAGIC ) { srand( GetCurrentTime() ); // // Shift left since rand returns a max of 0x7FFF // pLcpCb->Local.Want.MagicNumber = ( rand() << 16 ); pLcpCb->Local.Want.MagicNumber += rand(); // // Make sure that this is not 0 // if ( pLcpCb->Local.Want.MagicNumber == 0 ) { pLcpCb->Local.Want.MagicNumber = 23; } pLcpCb->Remote.Want.MagicNumber = pLcpCb->Local.Want.MagicNumber + 1; } pAPData = pLcpCb->Local.Work.pAPData; APDataSize = pLcpCb->Local.Work.APDataSize; CopyMemory( &(pLcpCb->Local.Work), &(pLcpCb->Local.Want), sizeof(LCP_OPTIONS) ); pLcpCb->Local.Work.pAPData = pAPData; pLcpCb->Local.Work.APDataSize = APDataSize; pAPData = pLcpCb->Remote.Work.pAPData; APDataSize = pLcpCb->Remote.Work.APDataSize; CopyMemory( &(pLcpCb->Remote.Work), &(pLcpCb->Remote.Want), sizeof(LCP_OPTIONS)); pLcpCb->Remote.Work.pAPData = pAPData; pLcpCb->Remote.Work.APDataSize = APDataSize; if ( ( pLcpCb->Local.fAPsAvailable > 0 ) && (( pLcpCb->fServer ) || ( ( pLcpCb->fRouter ) && ( pLcpCb->PppConfigInfo.dwConfigMask & PPPCFG_AuthenticatePeer )))) { // // Start with the highest order bit which is the strongest protocol. // for( dwIndex = 0, pLcpCb->Local.fLastAPTried = 1; !(( pLcpCb->Local.fLastAPTried << dwIndex ) & LCP_AP_MAX ); dwIndex++ ) { if ( ( pLcpCb->Local.fLastAPTried << dwIndex ) & ( pLcpCb->Local.fAPsAvailable )) { pLcpCb->Local.fLastAPTried = (pLcpCb->Local.fLastAPTried << dwIndex); break; } } pLcpCb->Local.fOldLastAPTried = pLcpCb->Local.fLastAPTried; dwRetCode = MakeAuthProtocolOption( &(pLcpCb->Local) ); if ( dwRetCode != NO_ERROR ) { return( dwRetCode ); } } // // Do the same for remote. // if ( pLcpCb->Remote.fAPsAvailable > 0 ) { for( dwIndex = 0, pLcpCb->Remote.fLastAPTried = LCP_AP_FIRST; !(( pLcpCb->Remote.fLastAPTried << dwIndex ) & LCP_AP_MAX); dwIndex++ ) { if ( ( pLcpCb->Remote.fLastAPTried << dwIndex ) & ( pLcpCb->Remote.fAPsAvailable ) ) { pLcpCb->Remote.fLastAPTried = (pLcpCb->Remote.fLastAPTried << dwIndex); // // We need to back up one since we are the client and we haven't // sent this yet. // if ( pLcpCb->Remote.fLastAPTried == LCP_AP_FIRST ) { pLcpCb->Remote.fLastAPTried = 0; } else { pLcpCb->Remote.fLastAPTried >>= 1; } pLcpCb->Remote.fOldLastAPTried = pLcpCb->Remote.fLastAPTried; break; } } } return( NO_ERROR ); } //** // // Call: MakeOption // // Returns: NO_ERROR - Success // ERROR_BUFFER_TOO_SMALL - Buffer passed in is not large enough. // ERROR_INVALID_PARAMETER - Option type not recognized. // // Description: This is not an entry point, it is an internal procedure called // to build a particular option. // DWORD MakeOption( IN LCP_OPTIONS * pOptionValues, IN DWORD dwOptionType, IN PPP_OPTION * pSendOption, IN DWORD cbSendOption ) { if ( cbSendOption < SizeOfOption[ dwOptionType ] ) return( ERROR_BUFFER_TOO_SMALL ); pSendOption->Type = (BYTE)dwOptionType; pSendOption->Length = (BYTE)(SizeOfOption[ dwOptionType ]); switch( dwOptionType ) { case LCP_OPTION_MRU: HostToWireFormat16( (WORD)(pOptionValues->MRU), pSendOption->Data ); break; case LCP_OPTION_ACCM: HostToWireFormat32( pOptionValues->ACCM, pSendOption->Data ); break; case LCP_OPTION_AUTHENT: HostToWireFormat16( (WORD)pOptionValues->AP, pSendOption->Data ); // // First check to see if we have enough space to put the // digest algorithm // if (cbSendOption<(SizeOfOption[dwOptionType]+pOptionValues->APDataSize)) { return( ERROR_BUFFER_TOO_SMALL ); } CopyMemory( pSendOption->Data+2, pOptionValues->pAPData, pOptionValues->APDataSize ); pSendOption->Length += (BYTE)(pOptionValues->APDataSize); break; case LCP_OPTION_MAGIC: HostToWireFormat32( pOptionValues->MagicNumber, pSendOption->Data ); break; case LCP_OPTION_PFC: // // This is a boolean option, there is no value. // break; case LCP_OPTION_ACFC: // // This is a boolean option, there is no value. // break; case LCP_OPTION_CALLBACK: *(pSendOption->Data) = (BYTE)(pOptionValues->Callback); break; case LCP_OPTION_MRRU: HostToWireFormat16( (WORD)(pOptionValues->MRRU), pSendOption->Data ); break; case LCP_OPTION_SHORT_SEQ: // // This is a boolean option, there is no value. // break; case LCP_OPTION_ENDPOINT: // // First check to see if we have enough space to put the // discriminator // if ( cbSendOption < ( SizeOfOption[dwOptionType] + pOptionValues->dwEDLength ) ) { return( ERROR_BUFFER_TOO_SMALL ); } CopyMemory( pSendOption->Data, pOptionValues->EndpointDiscr, pOptionValues->dwEDLength ); pSendOption->Length += (BYTE)( pOptionValues->dwEDLength ); break; case LCP_OPTION_LINK_DISCRIM: HostToWireFormat16( (WORD)(pOptionValues->dwLinkDiscriminator), pSendOption->Data ); break; default: // // If we do not recognize the option // return( ERROR_INVALID_PARAMETER ); } return( NO_ERROR ); } //** // // Call: CheckOption // // Returns: CONFIG_ACK // CONFIG_NAK // CONFIG_REJ // // Description: This is not an entry point. Called to check to see if an option // value is valid and if it is the new value is saved in the // work buffer. // DWORD CheckOption( IN LCPCB * pLcpCb, IN LCP_SIDE * pLcpSide, IN PPP_OPTION * pOption, IN BOOL fMakingResult ) { DWORD dwIndex; DWORD dwAPDataSize; DWORD dwRetCode = CONFIG_ACK; if ( pOption->Length < SizeOfOption[ pOption->Type ] ) return( CONFIG_REJ ); // // If we do not want to negotiate the option we CONFIG_REJ it. // if ( !( pLcpSide->WillNegotiate & (1 << pOption->Type)) ) return( CONFIG_REJ ); switch( pOption->Type ) { case LCP_OPTION_MRU: pLcpSide->Work.MRU = WireToHostFormat16( pOption->Data ); // // Check to see if this value is appropriate // if ( !fMakingResult ) { // // We cannot receive bigger packets. // if ( pLcpSide->Work.MRU > pLcpSide->Want.MRU ) { // // Check to see if the server nak'd. If so // check to see if peer wants <= 1500 mru // and if we have already sent the request // 2 times, just ack peers mru. // if(pLcpSide->Work.MRU <= LCP_DEFAULT_MRU) { if(pLcpCb->dwMRUFailureCount > 0) { pLcpCb->dwMRUFailureCount--; } if(pLcpCb->dwMRUFailureCount == 0) { break; } } pLcpSide->Work.MRU = pLcpSide->Want.MRU; dwRetCode = CONFIG_NAK; } } break; case LCP_OPTION_ACCM: pLcpSide->Work.ACCM = WireToHostFormat32( pOption->Data ); // // If we are responding to a request, we accept it blindly, if we are // processing a NAK, then the remote host may ask to escape more // control characters than we require, but must escape at least the // control chars that we require. // if ( !fMakingResult ) { if ( pLcpSide->Work.ACCM != ( pLcpSide->Work.ACCM | pLcpSide->Want.ACCM ) ) { pLcpSide->Work.ACCM |= pLcpSide->Want.ACCM; dwRetCode = CONFIG_NAK; } } break; case LCP_OPTION_AUTHENT: pLcpSide->Work.AP = WireToHostFormat16( pOption->Data ); // // If there was Authentication data. // if ( pOption->Length > PPP_OPTION_HDR_LEN + 2 ) { dwAPDataSize = pOption->Length - PPP_OPTION_HDR_LEN - 2; if ( dwAPDataSize != pLcpSide->Work.APDataSize ) { pLcpSide->Work.APDataSize = dwAPDataSize; if ( NULL != pLcpSide->Work.pAPData ) { LOCAL_FREE( pLcpSide->Work.pAPData ); pLcpSide->Work.pAPData = NULL; } pLcpSide->Work.pAPData = (PBYTE)LOCAL_ALLOC( LPTR, pLcpSide->Work.APDataSize ); if ( NULL == pLcpSide->Work.pAPData ) { pLcpSide->Work.APDataSize = 0; return( CONFIG_REJ ); } } CopyMemory( pLcpSide->Work.pAPData, pOption->Data+2, pLcpSide->Work.APDataSize ); } else { pLcpSide->Work.APDataSize = 0; } pLcpSide->fOldLastAPTried = pLcpSide->fLastAPTried; switch( pLcpSide->Work.AP ) { case PPP_CHAP_PROTOCOL: // // If CHAP is not available // if ( !( pLcpSide->fAPsAvailable & ( LCP_AP_CHAP_MS | LCP_AP_CHAP_MD5 | LCP_AP_CHAP_MS_NEW ))) { dwRetCode = CONFIG_NAK; break; } // // If there was no digest algorithm then we respond with the // digest algorithm the next time. To do this we need to back up // one in the list of APs tried so that we try this AP again. // if ( pOption->Length < (PPP_OPTION_HDR_LEN + 3) ) { pLcpSide->fLastAPTried = 0; dwRetCode = CONFIG_NAK; break; } if ( *(pLcpSide->Work.pAPData) == PPP_CHAP_DIGEST_MSEXT ) { if ( !( pLcpSide->fAPsAvailable & LCP_AP_CHAP_MS ) ) { dwRetCode = CONFIG_NAK; } } else if ( *(pLcpSide->Work.pAPData) == PPP_CHAP_DIGEST_MSEXT_NEW ) { if ( !( pLcpSide->fAPsAvailable & LCP_AP_CHAP_MS_NEW ) ) { dwRetCode = CONFIG_NAK; } } else if ( *(pLcpSide->Work.pAPData) == PPP_CHAP_DIGEST_MD5 ) { if ( !( pLcpSide->fAPsAvailable & LCP_AP_CHAP_MD5 ) ) { dwRetCode = CONFIG_NAK; } } else { dwRetCode = CONFIG_NAK; } break; case PPP_PAP_PROTOCOL: if ( !( pLcpSide->fAPsAvailable & LCP_AP_PAP ) ) { dwRetCode = CONFIG_NAK; } break; case PPP_EAP_PROTOCOL: if ( !( pLcpSide->fAPsAvailable & LCP_AP_EAP ) ) { dwRetCode = CONFIG_NAK; } break; case PPP_SPAP_NEW_PROTOCOL: if ( !( pLcpSide->fAPsAvailable & LCP_AP_SPAP_NEW ) ) { dwRetCode = CONFIG_NAK; break; } if ( pOption->Length < (PPP_OPTION_HDR_LEN+6) ) { dwRetCode = CONFIG_NAK; // // We are a client responding to a remote CONFIG_REQ // if ( fMakingResult ) { pLcpSide->fLastAPTried = ( LCP_AP_SPAP_NEW >> 1 ); } break; } // // If encryption algorithm is not 1. NAK with 1. // if (WireToHostFormat32(pLcpSide->Work.pAPData) != LCP_SPAP_VERSION) { // // We are a client responding to a remote CONFIG_REQ // if ( fMakingResult ) { pLcpSide->fLastAPTried = ( LCP_AP_SPAP_NEW >> 1 ); } dwRetCode = CONFIG_NAK; break; } break; default: dwRetCode = CONFIG_NAK; break; } if ( dwRetCode == CONFIG_NAK ) { // // The fLastAPTried is set to 0, then we set to LCP_AP_FIRST // if ( pLcpSide->fLastAPTried == 0 ) { pLcpSide->fLastAPTried = LCP_AP_FIRST; } // // We look for the next weakest protocol available. // for( dwIndex = 1; !(( pLcpSide->fLastAPTried << dwIndex ) & LCP_AP_MAX); dwIndex++ ) { if ( ( pLcpSide->fLastAPTried << dwIndex ) & pLcpSide->fAPsAvailable ) { pLcpSide->fLastAPTried = (pLcpSide->fLastAPTried<Work.MagicNumber = WireToHostFormat32( pOption->Data ); if ( fMakingResult ) { // // Ensure that magic numbers are different and that the remote // request does not contain a magic number of 0. // if ( (pLcpSide->Work.MagicNumber == pLcpCb->Local.Work.MagicNumber) || ( pLcpSide->Work.MagicNumber == 0 ) ) { if (pLcpSide->Work.MagicNumber==pLcpCb->Local.Work.MagicNumber) { ++(pLcpCb->dwMagicNumberFailureCount); } // // Shift left since rand returns a max of 0x7FFF // pLcpSide->Work.MagicNumber = ( rand() << 16 ); pLcpSide->Work.MagicNumber += rand(); if ( pLcpSide->Work.MagicNumber == 0 ) { pLcpSide->Work.MagicNumber = 48; } dwRetCode = CONFIG_NAK; } } else { // // The remote peer NAK'ed with a magic number, check to see if // the magic number in the NAK is the same as what we NAK'ed last // if ( pLcpSide->Work.MagicNumber == pLcpCb->Remote.Work.MagicNumber ) { ++(pLcpCb->dwMagicNumberFailureCount); // // Shift left since rand returns a max of 0x7FFF // pLcpSide->Work.MagicNumber = ( rand() << 16 ); pLcpSide->Work.MagicNumber += rand(); if ( pLcpSide->Work.MagicNumber == 0 ) { pLcpSide->Work.MagicNumber = 93; } dwRetCode = CONFIG_NAK; } } break; case LCP_OPTION_PFC: pLcpSide->Work.PFC = TRUE; if ( pLcpSide->Want.PFC == FALSE ) dwRetCode = CONFIG_REJ; break; case LCP_OPTION_ACFC: pLcpSide->Work.ACFC = TRUE; if ( pLcpSide->Want.ACFC == FALSE ) dwRetCode = CONFIG_REJ; break; case LCP_OPTION_CALLBACK: pLcpSide->Work.Callback = *(pOption->Data); // // If the Callback control protocol is not loaded. // if ( GetCpIndexFromProtocol(PPP_CBCP_PROTOCOL) == (DWORD)-1 ) { dwRetCode = CONFIG_REJ; } else if ( pLcpSide->Work.Callback != PPP_NEGOTIATE_CALLBACK ) { if ( fMakingResult ) { // // We only understand this option. // pLcpSide->Work.Callback = PPP_NEGOTIATE_CALLBACK; dwRetCode = CONFIG_NAK; } else { // // If we are processing a NAK from the remote peer, then we // simply do not negotiate this option again. // dwRetCode = CONFIG_REJ; } } break; case LCP_OPTION_MRRU: pLcpSide->Work.MRRU = WireToHostFormat16( pOption->Data ); // // Check to see if this value is appropriate // if ( fMakingResult ) { // // We cannot send smaller reconstructed packets. // if ( pLcpSide->Work.MRRU < pLcpSide->Want.MRRU ) { pLcpSide->Work.MRRU = pLcpSide->Want.MRRU; dwRetCode = CONFIG_NAK; } } else { // // We cannot receive bigger reconstructed packets. // if ( pLcpSide->Work.MRRU > pLcpSide->Want.MRRU ) { pLcpSide->Work.MRRU = pLcpSide->Want.MRRU; dwRetCode = CONFIG_NAK; } } break; case LCP_OPTION_SHORT_SEQ: pLcpSide->Work.ShortSequence = TRUE; if ( pLcpSide->Want.ShortSequence == FALSE ) dwRetCode = CONFIG_REJ; break; case LCP_OPTION_ENDPOINT: // // If this option was NAKed then we do not change this value and // simply resend the config request // if ( !fMakingResult ) { break; } ZeroMemory( pLcpSide->Work.EndpointDiscr, sizeof( pLcpSide->Work.EndpointDiscr ) ); // // Make sure that the discriminator can fit into our storage allocated // for it, otherwise simply truncate and hope that it is unique. We do // not want to reject it since we want bundling to work. // if ( ( pOption->Length - PPP_OPTION_HDR_LEN ) > sizeof(pLcpSide->Work.EndpointDiscr) ) { pLcpSide->Work.dwEDLength = sizeof( pLcpSide->Work.EndpointDiscr ); } else { pLcpSide->Work.dwEDLength = pOption->Length - PPP_OPTION_HDR_LEN; } CopyMemory( pLcpSide->Work.EndpointDiscr, pOption->Data, pLcpSide->Work.dwEDLength ); break; case LCP_OPTION_LINK_DISCRIM: pLcpSide->Work.dwLinkDiscriminator = WireToHostFormat16( pOption->Data ); break; default: // // If we do not recognize the option we CONFIG_REJ it. // dwRetCode = CONFIG_REJ; break; } return( dwRetCode ); } //** // // Call: BuildOptionList // // Returns: NO_ERROR - Success // Non-zero returns from MakeOption // // Description: This is not an entry point. Will build a list of options // either for a configure request or a configure result. // DWORD BuildOptionList( IN OUT BYTE * pOptions, IN OUT DWORD * pcbOptions, IN LCP_OPTIONS * LcpOptions, IN DWORD Negotiate ) { DWORD OptionType; DWORD dwRetCode; DWORD cbOptionLength = *pcbOptions; for ( OptionType = 1; OptionType <= LCP_OPTION_LIMIT; OptionType++ ) { if ( Negotiate & ( 1 << OptionType )) { if ( ( dwRetCode = MakeOption( LcpOptions, OptionType, (PPP_OPTION *)pOptions, cbOptionLength ) ) != NO_ERROR ) return( dwRetCode ); cbOptionLength -= ((PPP_OPTION*)pOptions)->Length; pOptions += ((PPP_OPTION*)pOptions)->Length; } } *pcbOptions -= cbOptionLength; return( NO_ERROR ); } //** // // Call: LcpMakeConfigRequest // // Returns: NO_ERROR - Success // Non-zero returns from BuildOptionList // // Description: This is a entry point that is called to make a configure // request packet. // DWORD LcpMakeConfigRequest( IN VOID * pWorkBuffer, IN PPP_CONFIG * pSendConfig, IN DWORD cbSendConfig ) { LCPCB * pLcpCb = (LCPCB*)pWorkBuffer; DWORD dwRetCode; cbSendConfig -= PPP_CONFIG_HDR_LEN; dwRetCode = BuildOptionList( pSendConfig->Data, &cbSendConfig, &(pLcpCb->Local.Work), pLcpCb->Local.Work.Negotiate ); if ( dwRetCode != NO_ERROR ) return( dwRetCode ); pSendConfig->Code = CONFIG_REQ; HostToWireFormat16( (WORD)(cbSendConfig + PPP_CONFIG_HDR_LEN), pSendConfig->Length ); return( NO_ERROR ); } //** // // Call: LcpMakeConfigResult // // Returns: // // Description: // DWORD LcpMakeConfigResult( IN VOID * pWorkBuffer, IN PPP_CONFIG * pRecvConfig, OUT PPP_CONFIG * pSendConfig, IN DWORD cbSendConfig, IN BOOL fRejectNaks ) { DWORD dwDesired; DWORD dwRetCode; LCPCB * pLcpCb = (LCPCB*)pWorkBuffer; DWORD ResultType = CONFIG_ACK; PPP_OPTION * pRecvOption = (PPP_OPTION *)(pRecvConfig->Data); PPP_OPTION * pSendOption = (PPP_OPTION *)(pSendConfig->Data); LONG lSendLength = cbSendConfig - PPP_CONFIG_HDR_LEN; LONG lRecvLength = WireToHostFormat16( pRecvConfig->Length ) - PPP_CONFIG_HDR_LEN; // // Clear negotiate mask // pLcpCb->Remote.Work.Negotiate = 0; // // Process options requested by remote host // while( lRecvLength > 0 ) { if ( pRecvOption->Length == 0 ) return( ERROR_PPP_INVALID_PACKET ); if ( ( lRecvLength -= pRecvOption->Length ) < 0 ) return( ERROR_PPP_INVALID_PACKET ); dwRetCode = CheckOption( pLcpCb, &(pLcpCb->Remote), pRecvOption, TRUE ); // // If we were building an ACK and we got a NAK or reject OR // we were building a NAK and we got a reject. // if ( (( ResultType == CONFIG_ACK ) && ( dwRetCode != CONFIG_ACK )) || (( ResultType == CONFIG_NAK ) && ( dwRetCode == CONFIG_REJ )) ) { ResultType = dwRetCode; pSendOption = (PPP_OPTION *)(pSendConfig->Data); lSendLength = cbSendConfig - PPP_CONFIG_HDR_LEN; } // // Remember that we processed this option // if ( ( dwRetCode != CONFIG_REJ ) && ( pRecvOption->Type <= LCP_OPTION_LIMIT ) ) { pLcpCb->Remote.Work.Negotiate |= ( 1 << pRecvOption->Type ); } // // Add the option to the list. // if ( dwRetCode == ResultType ) { // // If this option is to be rejected, simply copy the // rejected option to the send buffer // if ( ( dwRetCode == CONFIG_REJ ) || ( ( dwRetCode == CONFIG_NAK ) && ( fRejectNaks ) ) ) { CopyMemory( pSendOption, pRecvOption, pRecvOption->Length ); } else { if ( ( dwRetCode = MakeOption( &(pLcpCb->Remote.Work), pRecvOption->Type, pSendOption, lSendLength ) ) != NO_ERROR ) return( dwRetCode ); } lSendLength -= pSendOption->Length; pSendOption = (PPP_OPTION *) ( (BYTE *)pSendOption + pSendOption->Length ); } pRecvOption = (PPP_OPTION *)((BYTE*)pRecvOption + pRecvOption->Length); } // // If this was an NAK and we have cannot send any more NAKS then we // make this a REJECT packet // if ( ( ResultType == CONFIG_NAK ) && fRejectNaks ) pSendConfig->Code = CONFIG_REJ; else pSendConfig->Code = (BYTE)ResultType; HostToWireFormat16( (WORD)(cbSendConfig - lSendLength), pSendConfig->Length ); // // If we want to be authenticated, but the other side doesn't try to // authenticate us, NAK with LCP_N_AUTHENT. // if ( ( pLcpCb->Remote.Want.Negotiate & LCP_N_AUTHENT ) & ~( pLcpCb->Remote.Work.Negotiate ) ) { DWORD cbOptions; // // We cannot send a NAK if we are sending a REJECT // if ( ResultType != CONFIG_REJ ) { if ( pLcpCb->Remote.fAPsAvailable & LCP_AP_EAP ) { pLcpCb->Remote.fLastAPTried = LCP_AP_EAP; } else { pLcpCb->Remote.fLastAPTried = LCP_AP_CHAP_MS_NEW; } MakeAuthProtocolOption( &(pLcpCb->Remote) ); if ( ResultType == CONFIG_ACK ) { ResultType = CONFIG_NAK; pSendOption = (PPP_OPTION *)(pSendConfig->Data); lSendLength = cbSendConfig - PPP_CONFIG_HDR_LEN; } cbOptions = lSendLength; dwRetCode = BuildOptionList( (BYTE*)pSendOption, &cbOptions, &(pLcpCb->Remote.Work), LCP_N_AUTHENT ); if ( dwRetCode != NO_ERROR ) { return( dwRetCode ); } pSendConfig->Code = CONFIG_NAK; HostToWireFormat16( (WORD)(cbSendConfig - lSendLength + cbOptions), pSendConfig->Length ); } } // // If we are rejecting this packet then we restore the LastAPTried value // if ( pSendConfig->Code == CONFIG_REJ ) { pLcpCb->Remote.fLastAPTried = pLcpCb->Remote.fOldLastAPTried; } else { pLcpCb->Remote.fOldLastAPTried = pLcpCb->Remote.fLastAPTried; } // // If we have more than 3 conflicts with the magic number then we assume // that we are talking with ourself. // if ((ResultType == CONFIG_NAK) && (pLcpCb->dwMagicNumberFailureCount > 3)) { return( ERROR_PPP_LOOPBACK_DETECTED ); } return( NO_ERROR ); } //** // // Call: LcpConfigAckReceived // // Returns: // // Description: // DWORD LcpConfigAckReceived( IN VOID * pWorkBuffer, IN PPP_CONFIG * pRecvConfig ) { DWORD dwRetCode; BYTE ConfigReqSent[LCP_DEFAULT_MRU]; LCPCB * pLcpCb = (LCPCB *)pWorkBuffer; PPP_OPTION * pRecvOption = (PPP_OPTION *)(pRecvConfig->Data); DWORD cbConfigReqSent = sizeof( ConfigReqSent ); DWORD dwLength = WireToHostFormat16( pRecvConfig->Length ) - PPP_CONFIG_HDR_LEN; // // Get a copy of last request we sent // dwRetCode = BuildOptionList( ConfigReqSent, &cbConfigReqSent, &(pLcpCb->Local.Work), pLcpCb->Local.Work.Negotiate ); if ( dwRetCode != NO_ERROR ) return( dwRetCode ); // // Overall buffer length should match // if ( dwLength != cbConfigReqSent ) { // // Hack to work around WinCE bug on the server side only. // If we request EAP, WinCE ACKs without auth option. // Bug#333332 // LCP_OPTIONS * pOptionValues = &(pLcpCb->Local.Work); // // If we are a client then we simply return // if ( !pLcpCb->fServer ) return( ERROR_PPP_INVALID_PACKET ); // // If we requested EAP // if ( pOptionValues->AP == PPP_EAP_PROTOCOL ) { DWORD dwIndex; // // Check to see if ACK did not contain the auth option // while ( dwLength > 0 ) { if ( pRecvOption->Length == 0 ) return( ERROR_PPP_INVALID_PACKET ); if ( (long)(dwLength -= pRecvOption->Length) < 0 ) return( ERROR_PPP_INVALID_PACKET ); if ( pRecvOption->Length < SizeOfOption[ pRecvOption->Type ] ) return( ERROR_PPP_INVALID_PACKET ); if ( pRecvOption->Type == LCP_OPTION_AUTHENT ) return( ERROR_PPP_INVALID_PACKET ); pRecvOption = (PPP_OPTION *)((BYTE*)pRecvOption + pRecvOption->Length); } // // If we get here then no authentication option was sent in the ACK // so we need to treat this as a NAK. Go to the next auth protocol. // pLcpCb->Local.fLastAPTried = LCP_AP_EAP; // // We look for the next weakest protocol available. // for( dwIndex = 1; !(( pLcpCb->Local.fLastAPTried << dwIndex ) & LCP_AP_MAX); dwIndex++ ) { if ( ( pLcpCb->Local.fLastAPTried << dwIndex ) & pLcpCb->Local.fAPsAvailable ) { pLcpCb->Local.fLastAPTried = (pLcpCb->Local.fLastAPTried << dwIndex ); break; } } MakeAuthProtocolOption( &(pLcpCb->Local) ); } return( ERROR_PPP_INVALID_PACKET ); } // // Each byte should match // if ( memcmp( ConfigReqSent, pRecvConfig->Data, dwLength ) != 0 ) return( ERROR_PPP_INVALID_PACKET ); return( NO_ERROR ); } //** // // Call: LcpConfigNakReceived // // Returns: // // Description: // DWORD LcpConfigNakReceived( IN VOID * pWorkBuffer, IN PPP_CONFIG * pRecvConfig ) { DWORD dwResult; LCPCB * pLcpCb = (LCPCB *)pWorkBuffer; PPP_OPTION * pOption = (PPP_OPTION*)(pRecvConfig->Data); DWORD dwLastOption = 0; LONG lcbRecvConfig = WireToHostFormat16( pRecvConfig->Length ) - PPP_CONFIG_HDR_LEN; // // First, process in order. Then, process extra "important" options // while ( lcbRecvConfig > 0 ) { if ( pOption->Length == 0 ) return( ERROR_PPP_INVALID_PACKET ); if ( ( lcbRecvConfig -= pOption->Length ) < 0 ) return( ERROR_PPP_INVALID_PACKET ); // // If this option was not requested, we mark it as negotiable // if ( ( pOption->Type <= LCP_OPTION_LIMIT ) && ( pLcpCb->Local.WillNegotiate & (1 << pOption->Type) ) && !( pLcpCb->Local.Work.Negotiate & (1 << pOption->Type) ) ) { pLcpCb->Local.Work.Negotiate |= (1 << pOption->Type ); } dwLastOption = pOption->Type; dwResult = CheckOption( pLcpCb, &(pLcpCb->Local), pOption, FALSE ); // // Update the negotiation status. If we cannot accept this option, // then we will not send it again. // if (( dwResult == CONFIG_REJ ) && ( pOption->Type <= LCP_OPTION_LIMIT )) pLcpCb->Local.Work.Negotiate &= ~(1 << pOption->Type); pOption = (PPP_OPTION *)( (BYTE *)pOption + pOption->Length ); } return( NO_ERROR ); } //** // // Call: LcpConfigRejReceived // // Returns: // // Description: // DWORD LcpConfigRejReceived( IN VOID * pWorkBuffer, IN PPP_CONFIG * pRecvConfig ) { DWORD dwRetCode; LCPCB * pLcpCb = (LCPCB *)pWorkBuffer; PPP_OPTION * pOption = (PPP_OPTION*)(pRecvConfig->Data); DWORD dwLastOption = 0; BYTE ReqOption[LCP_DEFAULT_MRU]; LONG lcbRecvConfig = WireToHostFormat16( pRecvConfig->Length ) - PPP_CONFIG_HDR_LEN; // // Process in order, checking for errors // while ( lcbRecvConfig > 0 ) { if ( pOption->Length == 0 ) return( ERROR_PPP_INVALID_PACKET ); if ( ( lcbRecvConfig -= pOption->Length ) < 0 ) return( ERROR_PPP_INVALID_PACKET ); // // Cannot receive an option out of order or an option that was // not requested. // if ( ( pOption->Type <= LCP_OPTION_LIMIT ) && (( pOption->Type < dwLastOption ) || ( !( pLcpCb->Local.Work.Negotiate & (1 << pOption->Type)))) ) return( ERROR_PPP_INVALID_PACKET ); // // If we are a server and the client rejects the authentication // protocol then we fail to converge, if we are not set to allow no // authentication. // if ( ( pLcpCb->Local.Want.Negotiate & LCP_N_AUTHENT ) && ( pOption->Type == LCP_OPTION_AUTHENT ) && ( !( pLcpCb->PppConfigInfo.dwConfigMask & PPPCFG_AllowNoAuthentication ) ) ) { return( ERROR_PEER_REFUSED_AUTH ); } // // The option should not have been modified in any way // if ( ( dwRetCode = MakeOption( &(pLcpCb->Local.Work), pOption->Type, (PPP_OPTION *)ReqOption, sizeof( ReqOption ) ) ) != NO_ERROR ) return( dwRetCode ); if ( memcmp( ReqOption, pOption, pOption->Length ) != 0 ) return( ERROR_PPP_INVALID_PACKET ); dwLastOption = pOption->Type; // // The next configure request should not contain this option // if ( pOption->Type <= LCP_OPTION_LIMIT ) pLcpCb->Local.Work.Negotiate &= ~(1 << pOption->Type); pOption = (PPP_OPTION *)( (BYTE *)pOption + pOption->Length ); } return( NO_ERROR ); } //** // // Call: LcpThisLayerStarted // // Returns: // // Description: // DWORD LcpThisLayerStarted( IN VOID * pWorkBuffer ) { return( NO_ERROR ); } //** // // Call: LcpThisLayerFinished // // Returns: // // Description: // DWORD LcpThisLayerFinished( IN VOID * pWorkBuffer ) { return( NO_ERROR ); } //** // // Call: LcpThisLayerUp // // Returns: None // // Description: Sets the framing parameters to what was negotiated. // DWORD LcpThisLayerUp( IN VOID * pWorkBuffer ) { DWORD dwRetCode = NO_ERROR; RAS_FRAMING_INFO RasFramingInfo; DWORD LocalMagicNumber; DWORD RemoteMagicNumber; DWORD LocalAuthProtocol; DWORD RemoteAuthProtocol; LCPCB * pLcpCb = (LCPCB *)pWorkBuffer; PCB * pPcb; pPcb = GetPCBPointerFromhPort( pLcpCb->hPort ); if ( pPcb == (PCB *)NULL ) { return( NO_ERROR ); } ZeroMemory( &RasFramingInfo, sizeof( RasFramingInfo ) ); if ( pLcpCb->Local.Work.Negotiate & LCP_N_MRU ) { RasFramingInfo.RFI_MaxRecvFrameSize = pLcpCb->Local.Work.MRU; } else { RasFramingInfo.RFI_MaxRecvFrameSize = LcpDefault.MRU; } if ( pLcpCb->Local.Work.Negotiate & LCP_N_ACCM ) { RasFramingInfo.RFI_RecvACCM = pLcpCb->Local.Work.ACCM; } else { RasFramingInfo.RFI_RecvACCM = LcpDefault.ACCM; } if ( pLcpCb->Local.Work.Negotiate & LCP_N_PFC ) { RasFramingInfo.RFI_RecvFramingBits |= PPP_COMPRESS_PROTOCOL_FIELD; } if ( pLcpCb->Local.Work.Negotiate & LCP_N_ACFC ) { RasFramingInfo.RFI_RecvFramingBits |= PPP_COMPRESS_ADDRESS_CONTROL; } if ( pLcpCb->Local.Work.Negotiate & LCP_N_SHORT_SEQ ) { RasFramingInfo.RFI_RecvFramingBits |= PPP_SHORT_SEQUENCE_HDR_FORMAT; } if ( pLcpCb->Local.Work.Negotiate & LCP_N_AUTHENT ) { LocalAuthProtocol = pLcpCb->Local.Work.AP; } else { LocalAuthProtocol = LcpDefault.AP; pLcpCb->Local.Work.AP = LcpDefault.AP; } if ( pLcpCb->Local.Work.Negotiate & LCP_N_MAGIC ) { LocalMagicNumber = pLcpCb->Local.Work.MagicNumber; } else { LocalMagicNumber = LcpDefault.MagicNumber; } if ( pLcpCb->Local.Work.Negotiate & LCP_N_MRRU ) { RasFramingInfo.RFI_RecvFramingBits |= PPP_MULTILINK_FRAMING; RasFramingInfo.RFI_MaxRRecvFrameSize = pLcpCb->Local.Work.MRRU; } else { RasFramingInfo.RFI_MaxRRecvFrameSize = LcpDefault.MRRU; } if ( ( pLcpCb->Local.Work.Negotiate & LCP_N_LINK_DISCRIM ) && ( pLcpCb->Remote.Work.Negotiate & LCP_N_LINK_DISCRIM ) ) { pPcb->pBcb->fFlags |= BCBFLAG_CAN_DO_BAP; } RasFramingInfo.RFI_RecvFramingBits |= PPP_FRAMING; PppLog( 1, "LCP Local Options-------------"); PppLog( 1, "\tMRU=%d,ACCM=%d,Auth=%x,MagicNumber=%d,PFC=%s,ACFC=%s", RasFramingInfo.RFI_MaxRecvFrameSize, RasFramingInfo.RFI_RecvACCM, LocalAuthProtocol, LocalMagicNumber, (RasFramingInfo.RFI_RecvFramingBits & PPP_COMPRESS_PROTOCOL_FIELD) ? "ON" : "OFF", ( RasFramingInfo.RFI_RecvFramingBits & PPP_COMPRESS_ADDRESS_CONTROL ) ? "ON" : "OFF" ); PppLog( 1, "\tRecv Framing = %s,SSHF=%s,MRRU=%d,LinkDiscrim=%x,BAP=%s", ( RasFramingInfo.RFI_RecvFramingBits & PPP_MULTILINK_FRAMING ) ? "PPP Multilink" : "PPP", ( RasFramingInfo.RFI_RecvFramingBits & PPP_SHORT_SEQUENCE_HDR_FORMAT) ? "ON" : "OFF", RasFramingInfo.RFI_MaxRRecvFrameSize, pLcpCb->Local.Work.dwLinkDiscriminator, pPcb->pBcb->fFlags & BCBFLAG_CAN_DO_BAP ? "ON" : "OFF"); if ( pLcpCb->Local.Work.Negotiate & LCP_N_ENDPOINT ) { PppLog( 1, "\tED Class = %d, ED Value = %0*x%0*x%0*x%0*x%0*x", *(pLcpCb->Local.Work.EndpointDiscr), 8,WireToHostFormat32(pLcpCb->Local.Work.EndpointDiscr+1), 8,WireToHostFormat32(pLcpCb->Local.Work.EndpointDiscr+5), 8,WireToHostFormat32(pLcpCb->Local.Work.EndpointDiscr+9), 8,WireToHostFormat32(pLcpCb->Local.Work.EndpointDiscr+13), 8,WireToHostFormat32(pLcpCb->Local.Work.EndpointDiscr+17) ); } if ( pLcpCb->Remote.Work.Negotiate & LCP_N_MRU ) { RasFramingInfo.RFI_MaxSendFrameSize = pLcpCb->Remote.Work.MRU; } else { RasFramingInfo.RFI_MaxSendFrameSize = LcpDefault.MRU; pLcpCb->Remote.Work.MRU = LcpDefault.MRU; } if ( pLcpCb->Remote.Work.Negotiate & LCP_N_ACCM ) { RasFramingInfo.RFI_SendACCM = pLcpCb->Remote.Work.ACCM; } else { RasFramingInfo.RFI_SendACCM = LcpDefault.ACCM; } if ( pLcpCb->Remote.Work.Negotiate & LCP_N_PFC ) { RasFramingInfo.RFI_SendFramingBits |= PPP_COMPRESS_PROTOCOL_FIELD; } if ( pLcpCb->Remote.Work.Negotiate & LCP_N_ACFC ) { RasFramingInfo.RFI_SendFramingBits |= PPP_COMPRESS_ADDRESS_CONTROL; } if ( pLcpCb->Remote.Work.Negotiate & LCP_N_SHORT_SEQ ) { RasFramingInfo.RFI_SendFramingBits |= PPP_SHORT_SEQUENCE_HDR_FORMAT; } if ( pLcpCb->Remote.Work.Negotiate & LCP_N_AUTHENT ) { RemoteAuthProtocol = pLcpCb->Remote.Work.AP; } else { RemoteAuthProtocol = LcpDefault.AP; pLcpCb->Remote.Work.AP = LcpDefault.AP; } if ( pLcpCb->Remote.Work.Negotiate & LCP_N_MAGIC ) { RemoteMagicNumber = pLcpCb->Remote.Work.MagicNumber; } else { RemoteMagicNumber = LcpDefault.MagicNumber; } if ( pLcpCb->Remote.Work.Negotiate & LCP_N_MRRU ) { RasFramingInfo.RFI_SendFramingBits |= PPP_MULTILINK_FRAMING; RasFramingInfo.RFI_MaxRSendFrameSize = pLcpCb->Remote.Work.MRRU; } else { RasFramingInfo.RFI_MaxRSendFrameSize = LcpDefault.MRRU; } RasFramingInfo.RFI_SendFramingBits |= PPP_FRAMING; PppLog( 1, "LCP Remote Options-------------"); PppLog( 1, "\tMRU=%d,ACCM=%d,Auth=%x,MagicNumber=%d,PFC=%s,ACFC=%s", RasFramingInfo.RFI_MaxSendFrameSize, RasFramingInfo.RFI_SendACCM, RemoteAuthProtocol, RemoteMagicNumber, (RasFramingInfo.RFI_SendFramingBits & PPP_COMPRESS_PROTOCOL_FIELD) ? "ON" : "OFF", (RasFramingInfo.RFI_SendFramingBits & PPP_COMPRESS_ADDRESS_CONTROL) ? "ON" : "OFF" ); PppLog( 1, "\tSend Framing = %s,SSHF=%s,MRRU=%d,LinkDiscrim=%x", ( RasFramingInfo.RFI_SendFramingBits & PPP_MULTILINK_FRAMING ) ? "PPP Multilink" : "PPP", ( RasFramingInfo.RFI_SendFramingBits & PPP_SHORT_SEQUENCE_HDR_FORMAT) ? "ON" : "OFF", RasFramingInfo.RFI_MaxRSendFrameSize, pLcpCb->Remote.Work.dwLinkDiscriminator ); if ( pLcpCb->Remote.Work.Negotiate & LCP_N_ENDPOINT ) { PppLog( 1, "\tED Class = %d, ED Value = %0*x%0*x%0*x%0*x%0*x", *(pLcpCb->Remote.Work.EndpointDiscr), 8,WireToHostFormat32(pLcpCb->Remote.Work.EndpointDiscr+1), 8,WireToHostFormat32(pLcpCb->Remote.Work.EndpointDiscr+5), 8,WireToHostFormat32(pLcpCb->Remote.Work.EndpointDiscr+9), 8,WireToHostFormat32(pLcpCb->Remote.Work.EndpointDiscr+13), 8,WireToHostFormat32(pLcpCb->Remote.Work.EndpointDiscr+17)); } if ( pLcpCb->Local.Work.Negotiate & LCP_N_MRRU ) { pPcb->fFlags |= PCBFLAG_CAN_BE_BUNDLED; } else { pPcb->fFlags &= ~PCBFLAG_CAN_BE_BUNDLED; } if ( ( pLcpCb->Local.Work.Negotiate & LCP_N_CALLBACK ) || ( pLcpCb->Remote.Work.Negotiate & LCP_N_CALLBACK ) ) { pPcb->fFlags |= PCBFLAG_NEGOTIATE_CALLBACK; } else { pPcb->fFlags &= ~PCBFLAG_NEGOTIATE_CALLBACK; } dwRetCode = RasPortSetFramingEx( pLcpCb->hPort, &RasFramingInfo ); // // This is a benign error and should not be logged. // if ( dwRetCode == ERROR_NOT_CONNECTED ) { return( NO_ERROR ); } else { return( dwRetCode ); } } //** // // Call: LcpThisLayerDown // // Returns: NO_ERROR - Success // Non-zero return from RasPortSetFraming - Failure // // Description: Simply sets the framing parameters to the default values, // ie. ACCM = 0xFFFFFFFF, everything else is zeros. // DWORD LcpThisLayerDown( IN VOID * pWorkBuffer ) { DWORD dwRetCode; RAS_FRAMING_INFO RasFramingInfo; LCPCB * pLcpCb = (LCPCB *)pWorkBuffer; ZeroMemory( &RasFramingInfo, sizeof( RasFramingInfo ) ); RasFramingInfo.RFI_RecvACCM = LcpDefault.ACCM; RasFramingInfo.RFI_SendACCM = LcpDefault.ACCM; RasFramingInfo.RFI_SendFramingBits = PPP_FRAMING; RasFramingInfo.RFI_RecvFramingBits = PPP_FRAMING; dwRetCode = RasPortSetFramingEx( pLcpCb->hPort, &RasFramingInfo ); if ( dwRetCode == ERROR_NOT_CONNECTED ) { return( NO_ERROR ); } else { return( dwRetCode ); } } //** // // Call: LcpGetNegotiatedInfo // // Returns: NO_ERROR - Success // Non-zero returns - Failure // // Description: // DWORD LcpGetNegotiatedInfo( IN VOID* pWorkBuffer, OUT PPP_LCP_RESULT * pLcpResult ) { LCPCB * pLcpCb = (LCPCB *)pWorkBuffer; if ( pLcpCb->Local.Work.Negotiate & LCP_N_MRRU ) { pLcpResult->dwLocalFramingType |= PPP_MULTILINK_FRAMING; } else { pLcpResult->dwLocalFramingType |= PPP_FRAMING; } if ( pLcpCb->Local.Work.Negotiate & LCP_N_AUTHENT ) { pLcpResult->dwLocalAuthProtocol = pLcpCb->Local.Work.AP; } else { pLcpResult->dwLocalAuthProtocol = LcpDefault.AP; } pLcpResult->dwLocalOptions = 0; if ( pLcpCb->Local.Work.Negotiate & LCP_N_PFC ) { pLcpResult->dwLocalOptions |= PPPLCPO_PFC; } if ( pLcpCb->Local.Work.Negotiate & LCP_N_ACFC ) { pLcpResult->dwLocalOptions |= PPPLCPO_ACFC; } if ( pLcpCb->Local.Work.Negotiate & LCP_N_SHORT_SEQ ) { pLcpResult->dwLocalOptions |= PPPLCPO_SSHF; } if ( ( pLcpCb->Local.Work.APDataSize > 0 ) && ( pLcpCb->Local.Work.APDataSize < 5 ) ) { if ( pLcpCb->Local.Work.APDataSize == 1 ) { pLcpResult->dwLocalAuthProtocolData = (DWORD)*(pLcpCb->Local.Work.pAPData); } else if ( pLcpCb->Local.Work.APDataSize == 2 ) { pLcpResult->dwLocalAuthProtocolData = WireToHostFormat16( pLcpCb->Local.Work.pAPData ); } else { pLcpResult->dwLocalAuthProtocolData = WireToHostFormat32( pLcpCb->Local.Work.pAPData ); } } else { pLcpResult->dwLocalAuthProtocolData = 0; } if ( pLcpCb->Remote.Work.Negotiate & LCP_N_AUTHENT ) { pLcpResult->dwRemoteAuthProtocol = pLcpCb->Remote.Work.AP; } else { pLcpResult->dwRemoteAuthProtocol = LcpDefault.AP; } if ( pLcpCb->Remote.Work.Negotiate & LCP_N_MRRU ) { pLcpResult->dwRemoteFramingType |= PPP_MULTILINK_FRAMING; } else { pLcpResult->dwRemoteFramingType |= PPP_FRAMING; } pLcpResult->dwRemoteOptions = 0; if ( pLcpCb->Remote.Work.Negotiate & LCP_N_PFC ) { pLcpResult->dwRemoteOptions |= PPPLCPO_PFC; } if ( pLcpCb->Remote.Work.Negotiate & LCP_N_ACFC ) { pLcpResult->dwRemoteOptions |= PPPLCPO_ACFC; } if ( pLcpCb->Remote.Work.Negotiate & LCP_N_SHORT_SEQ ) { pLcpResult->dwRemoteOptions |= PPPLCPO_SSHF; } if ( ( pLcpCb->Remote.Work.APDataSize > 0 ) && ( pLcpCb->Remote.Work.APDataSize < 5 ) ) { if ( pLcpCb->Remote.Work.APDataSize == 1 ) { pLcpResult->dwRemoteAuthProtocolData = (DWORD)*(pLcpCb->Remote.Work.pAPData); } else if ( pLcpCb->Remote.Work.APDataSize == 2 ) { pLcpResult->dwRemoteAuthProtocolData = WireToHostFormat16( pLcpCb->Remote.Work.pAPData ); } else { pLcpResult->dwRemoteAuthProtocolData = WireToHostFormat32( pLcpCb->Remote.Work.pAPData ); } } else { pLcpResult->dwRemoteAuthProtocolData = 0; } return( NO_ERROR ); } //** // // Call: LcpGetInfo // // Returns: NO_ERROR - Success // ERROR_INVALID_PARAMETER - Protocol id is unrecogized // // Description: This entry point is called for get all information for the // control protocol in this module. // DWORD LcpGetInfo( IN DWORD dwProtocolId, OUT PPPCP_INFO* pCpInfo ) { if ( dwProtocolId != PPP_LCP_PROTOCOL ) return( ERROR_INVALID_PARAMETER ); ZeroMemory( pCpInfo, sizeof( PPPCP_INFO ) ); pCpInfo->Protocol = PPP_LCP_PROTOCOL; pCpInfo->Recognize = TIME_REMAINING + 1; pCpInfo->RasCpBegin = LcpBegin; pCpInfo->RasCpEnd = LcpEnd; pCpInfo->RasCpReset = LcpReset; pCpInfo->RasCpThisLayerStarted = LcpThisLayerStarted; pCpInfo->RasCpThisLayerFinished = LcpThisLayerFinished; pCpInfo->RasCpThisLayerUp = LcpThisLayerUp; pCpInfo->RasCpThisLayerDown = LcpThisLayerDown; pCpInfo->RasCpMakeConfigRequest = LcpMakeConfigRequest; pCpInfo->RasCpMakeConfigResult = LcpMakeConfigResult; pCpInfo->RasCpConfigAckReceived = LcpConfigAckReceived; pCpInfo->RasCpConfigNakReceived = LcpConfigNakReceived; pCpInfo->RasCpConfigRejReceived = LcpConfigRejReceived; pCpInfo->RasCpGetNegotiatedInfo = LcpGetNegotiatedInfo; return( NO_ERROR ); }