📄 ipv6intf.c
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// This source code is licensed under Microsoft Shared Source License
// Version 1.0 for Windows CE.
// For a copy of the license visit http://go.microsoft.com/fwlink/?LinkId=3223.
//
//
// This file contains the functions to interface into the lower layer of IPV6
// as implemented in tcpip6.dll
//
#include "windows.h"
#include "cxport.h"
#include "types.h"
#include "ndis.h"
#include "util.h"
// PPP Include Files
#include "protocol.h"
#include "ppp.h"
#include "pppserver.h"
#include "lcp.h"
#include "ncp.h"
#include "ip_intf.h"
#include "ipv6intf.h"
#include "ipv6cp.h"
#include "tcpip.h"
#include "ipexport.h"
typedef PVOID IPv6Packet; // kludge to allow inclusion of llip6if.h, IPv6Packet is opaque to us
#include "llip6if.h"
#include "llipv6.h"
#include <ntddip6.h>
#include <cenet.h>
// Function pointers into the upper layer IP stack
IPV6AddInterfaceRtn g_pfnIPv6AddInterface;
IPV6DelInterfaceRtn g_pfnIPv6DeleteInterface;
IPV6SendCompleteRtn g_pfnIPv6SendComplete;
IPV6ReceiveRtn g_pfnIPv6Receive;
HINSTANCE g_hIPV6Module;
#ifdef DEBUG
//
// Debug display routine for TCP/IPv6 packet headers
//
typedef struct IPv6Header {
BYTE VersClassFlow[4]; // 4 bits Version, 8 Traffic Class, 20 Flow Label.
BYTE PayloadLength[2]; // Zero indicates Jumbo Payload hop-by-hop option.
BYTE NextHeader; // Values are superset of IPv4's Protocol field.
BYTE HopLimit;
BYTE Source[16];
BYTE Dest[16];
} IPv6Header;
#define PROTOCOL_TCP 6 // from tcpipw\h\tcp.h
#define IP_VER_FLAG 0xF0 // from tcpipw\ip\ipdef.h
void
IPV6AddrToSz(
IN PBYTE pAddr,
OUT PSTR szAddr)
{
int iWord;
USHORT word;
for (iWord = 0; iWord < 8; iWord++, pAddr += 2)
{
word = (pAddr[0] << 8) | pAddr[1];
szAddr += sprintf(szAddr, "%X%s", word, iWord == 7 ? "" : ":");
}
}
BOOL
DumpIPv6 (BOOL Direction, PBYTE Buffer, DWORD Len)
{
IPv6Header IPHdr;
TCPHeader TCPHdr;
char szSrcIP[64],
szDstIP[64];
DWORD payloadLength;
if (Len < sizeof(IPv6Header)) {
return FALSE;
}
memcpy ((char *)&IPHdr, Buffer, sizeof(IPHdr));
IPV6AddrToSz(&IPHdr.Source[0], &szSrcIP[0]);
IPV6AddrToSz(&IPHdr.Dest[0], &szDstIP[0]);
payloadLength = (IPHdr.PayloadLength[0] << 8) | IPHdr.PayloadLength[1];
if (IPHdr.NextHeader == PROTOCOL_TCP)
{
memcpy ((char *)&TCPHdr, Buffer + sizeof(IPv6Header), sizeof(TCPHeader));
NKDbgPrintfW (TEXT("%hs TCP %hs%hs%hs%hs%hs%hs, %hs(%d) => %hs(%d) Seq=%d-%d Ack=%d Win=%d\r\n"),
Direction ? "XMIT" : "RECV",
TCPHdr.tcp_flags & TCP_FLAG_URG ? "U" : ".",
TCPHdr.tcp_flags & TCP_FLAG_ACK ? "A" : ".",
TCPHdr.tcp_flags & TCP_FLAG_PUSH ? "P" : ".",
TCPHdr.tcp_flags & TCP_FLAG_RST ? "R" : ".",
TCPHdr.tcp_flags & TCP_FLAG_SYN ? "S" : ".",
TCPHdr.tcp_flags & TCP_FLAG_FIN ? "F" : ".",
&szSrcIP[0],
net_short(TCPHdr.tcp_src),
&szDstIP[0],
net_short(TCPHdr.tcp_dest),
net_long(TCPHdr.tcp_seq),
net_long(TCPHdr.tcp_seq) + payloadLength -
(net_short(TCPHdr.tcp_flags) >> 12)*4,
net_long(TCPHdr.tcp_ack),
net_short(TCPHdr.tcp_window));
return FALSE;
}
else
{
NKDbgPrintfW (TEXT("%hs IPv6 ver=%d Len=%d Next=%d HopL=%d Src=%hs Dest=%hs\r\n"),
Direction ? "XMIT" : "RECV",
(IPHdr.VersClassFlow[0] & 0xF0) >> 4,
payloadLength,
IPHdr.NextHeader,
IPHdr.HopLimit,
&szSrcIP[0],
&szDstIP[0]);
}
return FALSE;
}
#endif // DEBUG
// Receive
//
// Function: Send data up to IPV6
//
void
PppIPV6Receive(
void *context,
pppMsg_t *pMsg)
{
PPP_CONTEXT *pContext = (PPP_CONTEXT *)context;
pppUnLock( pContext->Session );
//
// IPCP may be OPEN but the interface not registered if
// RequireDataEncryption is set and CCP is not OPEN yet. In
// this case IPContext will be NULL until CCP enters the OPEN
// state and registers the interface with IP. Until the
// interface is registered IP packets are discarded.
//
if (pContext->IPV6Context && g_pfnIPv6Receive)
{
#ifdef DEBUG
if (dpCurSettings.ulZoneMask & 0x80000000)
DumpIPv6(FALSE, pMsg->data, pMsg->len);
#endif
g_pfnIPv6Receive( pContext->IPV6Context, // IP's Context
pMsg->data, // The Packet
pMsg->len); // Data Size
}
pppLock( pContext->Session );
}
//* IPV6PppCreateToken
//
// Initializes the interface identifer in the address.
//
void
PppIPv6CreateToken(
void *Context,
IPv6Addr *Address)
{
PPP_CONTEXT *pContext = Context;
PBYTE pIFID;
pIFID = &((PIPV6Context)( ((ncpCntxt_t *)(pContext->Session->ncpCntxt)) ->protocol[NCP_IPV6CP].context)) ->LocalInterfaceIdentifier[0];
memcpy(&Address->s6_bytes[8], pIFID, IPV6_IFID_LENGTH);
}
//* PppIPV6ConvertAddr
//
// PppIPV6ConvertAddr does not use Neighbor Discovery or link-layer addresses.
//
ushort
PppIPV6ConvertAddr(
void *Context,
const IPv6Addr *Address,
void *LinkAddress)
{
return ND_STATE_PERMANENT;
}
// PppIPV6Transmit
//
// Called by TCP/IPV6 stack to transmit a packet
//
void
PppIPV6Transmit(
PVOID Context, // Pointer to ppp context.
PNDIS_PACKET Packet, // Pointer to packet to be transmitted.
uint Offset, // Offset from start of packet to IPv6 header.
const void *LinkAddress) // Link-level address.
{
PPP_CONTEXT *pContext = (PPP_CONTEXT *)Context;
pppSession_t *s_p = (pppSession_t *)(pContext->Session);
NDIS_STATUS Status;
PVOID IPV6Context = pContext->IPV6Context;
DEBUGMSG( ZONE_IPV6, (TEXT("PPP: +PppIPV6Transmit\n")));
ASSERT(Offset == 0);
Status = PppSendIPvX(Context, Packet, 6);
if (IPV6Context)
g_pfnIPv6SendComplete(IPV6Context, Packet, Status == NDIS_STATUS_SUCCESS ? IP_SUCCESS : IP_PARAM_PROBLEM);
DEBUGMSG( ZONE_IPV6, (TEXT("PPP: -PppIPV6Transmit Status = %u\n"), Status));
}
DWORD
PppIPV6AddRoute(
IN PPP_CONTEXT *pContext,
IN PBYTE pPrefix,
IN DWORD PrefixBitLength,
IN DWORD InterfaceIndex)
//
// When the server creates a new interface, it needs to add a route
// for that interface to specify the network prefix to be sent to
// the client in the routing advertisement. Otherwise, the client
// will only have a link local (FE80::) address.
//
{
IPV6_INFO_ROUTE_TABLE Route;
DWORD BytesReturned;
HANDLE Handle;
DWORD dwResult = NO_ERROR;
ASSERT(PrefixBitLength <= 128);
memset(&Route, 0, sizeof(Route));
Route.SitePrefixLength = 0;
Route.ValidLifetime = INFINITE_LIFETIME;
Route.PreferredLifetime = INFINITE_LIFETIME;
Route.Preference = ROUTE_PREF_HIGHEST;
Route.Type = RTE_TYPE_MANUAL;
Route.Publish = TRUE;
Route.Immortal = Route.Publish;
Route.This.Neighbor.IF.Index = InterfaceIndex;
//Route.This.Neighbor.Address = { 0 };
memcpy(&Route.This.Prefix, pPrefix, (PrefixBitLength + 7) / 8);
Route.This.PrefixLength = PrefixBitLength;
Handle = CreateFileW(L"IP60:", GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
if (Handle == INVALID_HANDLE_VALUE)
{
DEBUGMSG(ZONE_ERROR, (L"PPP: Unable to open IP60: device\n"));
dwResult = GetLastError();
}
else
{
if (!DeviceIoControl(Handle, IOCTL_IPV6_UPDATE_ROUTE_TABLE,
&Route, sizeof Route,
NULL, 0, &BytesReturned, NULL))
{
DEBUGMSG(ZONE_ERROR, (L"PPP: Unable to update IPV6 route table\n"));
dwResult = GetLastError();
}
CloseHandle(Handle);
}
return dwResult;
}
//
// Register an interface with the IP6 stack.
//
BOOL
PPPAddIPV6Interface(
PPP_CONTEXT *pContext)
{
LLIPBindInfo BindInfo;
IP_STATUS Status = -1;
DWORD IFIndex;
DEBUGMSG(ZONE_FUNCTION, (TEXT("+PPPAddIPV6Interface: %s\n"), &pContext->AdapterName[0]));
ASSERT(pContext->IPV6Context == NULL);
if (pContext->IPV6Context == NULL && g_pfnIPv6AddInterface)
{
memset(&BindInfo, 0, sizeof(BindInfo));
//
// A NULL lip_context indicates that we want to use
// the IPv6 Interface structure instead.
//
BindInfo.lip_context = pContext;
if (pContext->Session->Mode == PPPMODE_PPP)
{
// Set the IP MaxSegmentSize (MSS) to the maximum frame size that the PPP peer can
// receive. This usually is 1500, but the adapter (e.g. AsyncMac) may restrict
// the max send size and/or it may be changed during LCP negotiation by the peer sending
// a Maximum-Receive-Unit option.
BindInfo.lip_maxmtu = ((PLCPContext)(pContext->Session->lcpCntxt))->peer.MRU;
BindInfo.lip_defmtu = BindInfo.lip_maxmtu;
}
else // SLIP
{
BindInfo.lip_maxmtu = SLIP_DEFAULT_MTU;
BindInfo.lip_defmtu = SLIP_DEFAULT_MTU;
}
BindInfo.lip_flags = IF_FLAG_MULTICAST | IF_FLAG_P2P | IF_FLAG_NEIGHBOR_DISCOVERS | IF_FLAG_ROUTER_DISCOVERS;
//
// If we are a server, send Router Advertisements to clients
//
if (pContext->Session->bIsServer)
BindInfo.lip_flags |= IF_FLAG_ADVERTISES | IF_FLAG_FORWARDS;
BindInfo.lip_type = IF_TYPE_IPV6_PPP;
BindInfo.lip_hdrsize = 0;
BindInfo.lip_addrlen = IPV6_IFID_LENGTH;
BindInfo.lip_dadxmit = 0;
BindInfo.lip_pref = 0;
BindInfo.lip_addr = &((PIPV6Context)( ((ncpCntxt_t *)(pContext->Session->ncpCntxt)) ->protocol[NCP_IPV6CP].context)) ->LocalInterfaceIdentifier[0];
BindInfo.lip_token = PppIPv6CreateToken;
BindInfo.lip_rdllopt = NULL;
BindInfo.lip_wrllopt = NULL;
BindInfo.lip_cvaddr = PppIPV6ConvertAddr;
BindInfo.lip_transmit = PppIPV6Transmit;
BindInfo.lip_mclist = NULL;
BindInfo.lip_close = NULL;
BindInfo.lip_cleanup = NULL;
Status = g_pfnIPv6AddInterface(&pContext->AdapterName[0], &BindInfo, &pContext->IPV6Context, &IFIndex);
if (Status != IP_SUCCESS)
{
DEBUGMSG(ZONE_ERROR, (TEXT("PPP: ERROR - IPV6AddInterface failed, status=%u\n"), Status));
}
else
{
PIPV6Context pIPV6Context = (PIPV6Context)( ((ncpCntxt_t *)(pContext->Session->ncpCntxt))->protocol[NCP_IPV6CP].context);
//
// If we are a server, configure the network prefix if available.
//
if (pContext->Session->bIsServer)
{
PPPServerGetSessionIPV6NetPrefix(pContext->Session, &pIPV6Context->NetPrefix[0], &pIPV6Context->NetPrefixBitLength);
if (pIPV6Context->NetPrefixBitLength)
{
DWORD dwResult;
dwResult = PppIPV6AddRoute(pContext, &pIPV6Context->NetPrefix[0], pIPV6Context->NetPrefixBitLength, IFIndex);
}
}
}
}
return Status == IP_SUCCESS;
}
void
PPPDeleteIPV6Interface(
PPP_CONTEXT *pContext)
{
if (pContext->IPV6Context && g_pfnIPv6DeleteInterface)
{
g_pfnIPv6DeleteInterface(pContext->IPV6Context);
pContext->IPV6Context = NULL;
}
}
DWORD
PPPIPV6InterfaceInitialize()
//
// Initialize function pointers into tcpip6.dll for adding
// and removing interfaces.
//
{
DWORD dwResult = NO_ERROR;
if (g_hIPV6Module == NULL)
{
dwResult = CXUtilGetProcAddresses(TEXT("tcpip6.dll"), &g_hIPV6Module,
TEXT("CEIPv6AddInterface"), &g_pfnIPv6AddInterface,
TEXT("CEIPv6DeleteInterface"), &g_pfnIPv6DeleteInterface,
TEXT("CEIPv6Receive"), &g_pfnIPv6Receive,
TEXT("CEIPv6SendComplete"), &g_pfnIPv6SendComplete,
NULL);
if (dwResult != NO_ERROR)
{
DEBUGMSG(ZONE_INIT, (TEXT("PPP: LoadLibrary of tcpip6.dll failed, IPV6 over PPP will not be supported\n")));
}
}
return dwResult;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -