Browse code

Merge branch 'feat_ipv6_wintap' into beta2.2

David Sommerseth authored on 2010/07/23 05:35:46
Showing 3 changed files
... ...
@@ -29,9 +29,11 @@
29 29
 #pragma pack(1)
30 30
 
31 31
 #define IP_HEADER_SIZE 20
32
+#define IPV6_HEADER_SIZE 40
32 33
 
33 34
 typedef unsigned char MACADDR [6];
34 35
 typedef unsigned long IPADDR;
36
+typedef unsigned char IPV6ADDR [16];
35 37
 
36 38
 //-----------------
37 39
 // Ethernet address
... ...
@@ -55,6 +57,7 @@ typedef struct
55 55
   MACADDR src;                /* source ether addr	*/
56 56
 
57 57
 # define ETH_P_IP   0x0800    /* IPv4 protocol */
58
+# define ETH_P_IPV6 0x86DD    /* IPv6 protocol */
58 59
 # define ETH_P_ARP  0x0806    /* ARP protocol */
59 60
   USHORT proto;               /* packet type ID field	*/
60 61
 } ETH_HEADER, *PETH_HEADER;
... ...
@@ -161,4 +164,61 @@ typedef struct {
161 161
 #define	TCPOPT_MAXSEG  2
162 162
 #define TCPOLEN_MAXSEG 4
163 163
 
164
+//------------
165
+// IPv6 Header
166
+//------------
167
+
168
+typedef struct {
169
+  UCHAR    version_prio;
170
+  UCHAR    flow_lbl[3];
171
+  USHORT   payload_len;
172
+# define IPPROTO_ICMPV6  0x3a  /* ICMP protocol v6 */
173
+  UCHAR    nexthdr;
174
+  UCHAR    hop_limit;
175
+  IPV6ADDR saddr;
176
+  IPV6ADDR daddr;
177
+} IPV6HDR;
178
+
179
+//--------------------------------------------
180
+// IPCMPv6 NS/NA Packets (RFC4443 and RFC4861)
181
+//--------------------------------------------
182
+
183
+// Neighbor Solictiation - RFC 4861, 4.3
184
+// (this is just the ICMPv6 part of the packet)
185
+typedef struct {
186
+  UCHAR    type;
187
+# define ICMPV6_TYPE_NS	135		// neighbour solicitation
188
+  UCHAR    code;
189
+# define ICMPV6_CODE_0	0		// no specific sub-code for NS/NA
190
+  USHORT   checksum;
191
+  ULONG    reserved;
192
+  IPV6ADDR target_addr;
193
+} ICMPV6_NS;
194
+
195
+// Neighbor Advertisement - RFC 4861, 4.4 + 4.6/4.6.1
196
+// (this is just the ICMPv6 payload)
197
+typedef struct {
198
+  UCHAR    type;
199
+# define ICMPV6_TYPE_NA	136		// neighbour advertisement
200
+  UCHAR    code;
201
+# define ICMPV6_CODE_0	0		// no specific sub-code for NS/NA
202
+  USHORT   checksum;
203
+  UCHAR    rso_bits;			// Router(0), Solicited(2), Ovrrd(4)
204
+  UCHAR	   reserved[3];
205
+  IPV6ADDR target_addr;
206
+// always include "Target Link-layer Address" option (RFC 4861 4.6.1)
207
+  UCHAR    opt_type;
208
+#define ICMPV6_OPTION_TLLA 2
209
+  UCHAR    opt_length;
210
+#define ICMPV6_LENGTH_TLLA 1		// multiplied by 8 -> 1 = 8 bytes
211
+  MACADDR  target_macaddr;
212
+} ICMPV6_NA;
213
+
214
+// this is the complete packet with Ethernet and IPv6 headers
215
+typedef struct {
216
+  ETH_HEADER eth;
217
+  IPV6HDR    ipv6;
218
+  ICMPV6_NA  icmpv6;
219
+} ICMPV6_NA_PKT;
220
+
164 221
 #pragma pack()
... ...
@@ -1430,6 +1430,158 @@ NDIS_STATUS AdapterModify
1430 1430
   return l_Status;
1431 1431
 }
1432 1432
 
1433
+// checksum code for ICMPv6 packet, taken from dhcp.c / udp_checksum
1434
+// see RFC 4443, 2.3, and RFC 2460, 8.1
1435
+USHORT
1436
+icmpv6_checksum (const UCHAR *buf,
1437
+	         const int len_icmpv6,
1438
+	         const UCHAR *saddr6,
1439
+	         const UCHAR *daddr6)
1440
+{
1441
+  USHORT word16;
1442
+  ULONG sum = 0;
1443
+  int i;
1444
+
1445
+  // make 16 bit words out of every two adjacent 8 bit words and
1446
+  // calculate the sum of all 16 bit words
1447
+  for (i = 0; i < len_icmpv6; i += 2){
1448
+    word16 = ((buf[i] << 8) & 0xFF00) + ((i + 1 < len_icmpv6) ? (buf[i+1] & 0xFF) : 0);
1449
+    sum += word16;
1450
+  }
1451
+
1452
+  // add the IPv6 pseudo header which contains the IP source and destination addresses
1453
+  for (i = 0; i < 16; i += 2){
1454
+    word16 =((saddr6[i] << 8) & 0xFF00) + (saddr6[i+1] & 0xFF);
1455
+    sum += word16;
1456
+  }
1457
+  for (i = 0; i < 16; i += 2){
1458
+    word16 =((daddr6[i] << 8) & 0xFF00) + (daddr6[i+1] & 0xFF);
1459
+    sum += word16;
1460
+  }
1461
+
1462
+  // the next-header number and the length of the ICMPv6 packet
1463
+  sum += (USHORT) IPPROTO_ICMPV6 + (USHORT) len_icmpv6;
1464
+
1465
+  // keep only the last 16 bits of the 32 bit calculated sum and add the carries
1466
+  while (sum >> 16)
1467
+    sum = (sum & 0xFFFF) + (sum >> 16);
1468
+
1469
+  // Take the one's complement of sum
1470
+  return ((USHORT) ~sum);
1471
+}
1472
+
1473
+// check IPv6 packet for "is this an IPv6 Neighbor Solicitation that
1474
+// the tap driver needs to answer?"
1475
+// see RFC 4861 4.3 for the different cases
1476
+static IPV6ADDR IPV6_NS_TARGET_MCAST =
1477
+	{ 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1478
+          0x00, 0x00, 0x00, 0x01, 0xff, 0x00, 0x00, 0x08 };
1479
+static IPV6ADDR IPV6_NS_TARGET_UNICAST =
1480
+	{ 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1481
+          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08 };
1482
+
1483
+BOOLEAN
1484
+HandleIPv6NeighborDiscovery( TapAdapterPointer p_Adapter, UCHAR * m_Data )
1485
+{
1486
+    const ETH_HEADER * e = (ETH_HEADER *) m_Data;
1487
+    const IPV6HDR *ipv6 = (IPV6HDR *) (m_Data + sizeof (ETH_HEADER));
1488
+    const ICMPV6_NS * icmpv6_ns = (ICMPV6_NS *) (m_Data + sizeof (ETH_HEADER) + sizeof (IPV6HDR));
1489
+    ICMPV6_NA_PKT *na;
1490
+    USHORT icmpv6_len, icmpv6_csum;
1491
+
1492
+    // we don't really care about the destination MAC address here
1493
+    // - it's either a multicast MAC, or the userland destination MAC
1494
+    // but since the TAP driver is point-to-point, all packets are "for us"
1495
+
1496
+    // IPv6 target address must be ff02::1::ff00:8 (multicast for
1497
+    // initial NS) or fe80::1 (unicast for recurrent NUD)
1498
+    if ( memcmp( ipv6->daddr, IPV6_NS_TARGET_MCAST,
1499
+		 sizeof(IPV6ADDR) ) != 0 &&
1500
+         memcmp( ipv6->daddr, IPV6_NS_TARGET_UNICAST,
1501
+		 sizeof(IPV6ADDR) ) != 0 )
1502
+    {
1503
+	return FALSE;				// wrong target address
1504
+    }
1505
+
1506
+    // IPv6 Next-Header must be ICMPv6
1507
+    if ( ipv6->nexthdr != IPPROTO_ICMPV6 )
1508
+    {
1509
+	return FALSE;				// wrong next-header
1510
+    }
1511
+
1512
+    // ICMPv6 type+code must be 135/0 for NS
1513
+    if ( icmpv6_ns->type != ICMPV6_TYPE_NS ||
1514
+	 icmpv6_ns->code != ICMPV6_CODE_0 )
1515
+    {
1516
+	return FALSE;				// wrong ICMPv6 type
1517
+    }
1518
+
1519
+    // ICMPv6 target address must be fe80::8 (magic)
1520
+    if ( memcmp( icmpv6_ns->target_addr, IPV6_NS_TARGET_UNICAST,
1521
+	         sizeof(IPV6ADDR) ) != 0 )
1522
+    {
1523
+	return FALSE;				// not for us
1524
+    }
1525
+
1526
+    // packet identified, build magic response packet
1527
+
1528
+    na = (ICMPV6_NA_PKT *) MemAlloc (sizeof (ICMPV6_NA_PKT), TRUE);
1529
+    if ( !na ) return FALSE;
1530
+
1531
+    //------------------------------------------------
1532
+    // Initialize Neighbour Advertisement reply packet
1533
+    //------------------------------------------------
1534
+
1535
+    // ethernet header
1536
+    na->eth.proto = htons(ETH_P_IPV6);
1537
+    COPY_MAC(na->eth.dest, p_Adapter->m_MAC);
1538
+    COPY_MAC(na->eth.src, p_Adapter->m_TapToUser.dest);
1539
+
1540
+    // IPv6 header
1541
+    na->ipv6.version_prio = ipv6->version_prio;
1542
+    NdisMoveMemory( na->ipv6.flow_lbl, ipv6->flow_lbl,
1543
+		    sizeof(na->ipv6.flow_lbl) );
1544
+    icmpv6_len = sizeof(ICMPV6_NA_PKT) - sizeof(ETH_HEADER) - sizeof(IPV6HDR);
1545
+    na->ipv6.payload_len = htons(icmpv6_len);
1546
+    na->ipv6.nexthdr = IPPROTO_ICMPV6;
1547
+    na->ipv6.hop_limit = 255;
1548
+    NdisMoveMemory( na->ipv6.saddr, IPV6_NS_TARGET_UNICAST,
1549
+		    sizeof(IPV6ADDR) );
1550
+    NdisMoveMemory( na->ipv6.daddr, ipv6->saddr,
1551
+		    sizeof(IPV6ADDR) );
1552
+
1553
+    // ICMPv6
1554
+    na->icmpv6.type = ICMPV6_TYPE_NA;
1555
+    na->icmpv6.code = ICMPV6_CODE_0;
1556
+    na->icmpv6.checksum = 0;
1557
+    na->icmpv6.rso_bits = 0x60;		// Solicited + Override
1558
+    NdisZeroMemory( na->icmpv6.reserved, sizeof(na->icmpv6.reserved) );
1559
+    NdisMoveMemory( na->icmpv6.target_addr, IPV6_NS_TARGET_UNICAST,
1560
+		    sizeof(IPV6ADDR) );
1561
+
1562
+    // ICMPv6 option "Target Link Layer Address"
1563
+    na->icmpv6.opt_type = ICMPV6_OPTION_TLLA;
1564
+    na->icmpv6.opt_length = ICMPV6_LENGTH_TLLA;
1565
+    COPY_MAC( na->icmpv6.target_macaddr, p_Adapter->m_TapToUser.dest );
1566
+
1567
+    // calculate and set checksum
1568
+    icmpv6_csum = icmpv6_checksum ( (UCHAR*) &(na->icmpv6),
1569
+				    icmpv6_len,
1570
+				    na->ipv6.saddr,
1571
+				    na->ipv6.daddr );
1572
+    na->icmpv6.checksum = htons( icmpv6_csum );
1573
+
1574
+    DUMP_PACKET ("HandleIPv6NeighborDiscovery",
1575
+		 (unsigned char *) na,
1576
+		 sizeof (ICMPV6_NA_PKT));
1577
+
1578
+    InjectPacketDeferred (p_Adapter, (UCHAR *) na, sizeof (ICMPV6_NA_PKT));
1579
+
1580
+    MemFree (na, sizeof (ICMPV6_NA_PKT));
1581
+
1582
+    return TRUE;				// all fine
1583
+}
1584
+
1433 1585
 //====================================================================
1434 1586
 //                               Adapter Transmission
1435 1587
 //====================================================================
... ...
@@ -1566,7 +1718,10 @@ AdapterTransmit (IN NDIS_HANDLE p_AdapterContext,
1566 1566
 
1567 1567
     //===============================================
1568 1568
     // In Point-To-Point mode, check to see whether
1569
-    // packet is ARP or IPv4 (if neither, then drop).
1569
+    // packet is ARP (handled) or IPv4 (sent to app).
1570
+    // IPv6 packets are inspected for neighbour discovery
1571
+    // (to be handled locally), and the rest is forwarded
1572
+    // all other protocols are dropped
1570 1573
     //===============================================
1571 1574
     if (l_Adapter->m_tun)
1572 1575
       {
... ...
@@ -1611,6 +1766,27 @@ AdapterTransmit (IN NDIS_HANDLE p_AdapterContext,
1611 1611
 
1612 1612
 	    // Packet looks like IPv4, queue it.
1613 1613
 	    l_PacketBuffer->m_SizeFlags |= TP_TUN;
1614
+
1615
+	  case ETH_P_IPV6:
1616
+	    // make sure that packet is large
1617
+	    // enough to be IPv6
1618
+	    if (l_PacketLength
1619
+		< ETHERNET_HEADER_SIZE + IPV6_HEADER_SIZE)
1620
+	      goto no_queue;
1621
+
1622
+	    // broadcasts and multicasts are handled specially
1623
+	    // (to be implemented)
1624
+
1625
+	    // neighbor discovery packets to fe80::8 are special
1626
+	    // OpenVPN sets this next-hop to signal "handled by tapdrv"
1627
+	    if ( HandleIPv6NeighborDiscovery( l_Adapter,
1628
+					      l_PacketBuffer->m_Data ))
1629
+	      {
1630
+		goto no_queue;
1631
+	      }
1632
+
1633
+	    // Packet looks like IPv6, queue it :-)
1634
+	    l_PacketBuffer->m_SizeFlags |= TP_TUN;
1614 1635
 	  }
1615 1636
       }
1616 1637
 
... ...
@@ -1902,6 +2078,8 @@ TapDeviceHook (IN PDEVICE_OBJECT p_DeviceObject, IN PIRP p_IRP)
1902 1902
 		  COPY_MAC (l_Adapter->m_UserToTap.dest, l_Adapter->m_MAC);
1903 1903
 
1904 1904
 		  l_Adapter->m_TapToUser.proto = l_Adapter->m_UserToTap.proto = htons (ETH_P_IP);
1905
+		  l_Adapter->m_UserToTap_IPv6 = l_Adapter->m_UserToTap;
1906
+		  l_Adapter->m_UserToTap_IPv6.proto = htons(ETH_P_IPV6);
1905 1907
 
1906 1908
 		  l_Adapter->m_tun = TRUE;
1907 1909
 
... ...
@@ -1939,6 +2117,8 @@ TapDeviceHook (IN PDEVICE_OBJECT p_DeviceObject, IN PIRP p_IRP)
1939 1939
 		  COPY_MAC (l_Adapter->m_UserToTap.dest, l_Adapter->m_MAC);
1940 1940
 
1941 1941
 		  l_Adapter->m_TapToUser.proto = l_Adapter->m_UserToTap.proto = htons (ETH_P_IP);
1942
+		  l_Adapter->m_UserToTap_IPv6 = l_Adapter->m_UserToTap;
1943
+		  l_Adapter->m_UserToTap_IPv6.proto = htons(ETH_P_IPV6);
1942 1944
 
1943 1945
 		  l_Adapter->m_tun = TRUE;
1944 1946
 
... ...
@@ -2236,10 +2416,18 @@ TapDeviceHook (IN PDEVICE_OBJECT p_DeviceObject, IN PIRP p_IRP)
2236 2236
 	  {
2237 2237
 	    __try
2238 2238
 	      {
2239
+		ETH_HEADER * p_UserToTap = &l_Adapter->m_UserToTap;
2240
+
2241
+		// for IPv6, need to use ethernet header with IPv6 proto
2242
+		if ( IPH_GET_VER( ((IPHDR*) p_IRP->AssociatedIrp.SystemBuffer)->version_len) == 6 )
2243
+		  {
2244
+		    p_UserToTap = &l_Adapter->m_UserToTap_IPv6;
2245
+		  }
2246
+
2239 2247
 		p_IRP->IoStatus.Information = l_IrpSp->Parameters.Write.Length;
2240 2248
 
2241 2249
 		DUMP_PACKET2 ("IRP_MJ_WRITE P2P",
2242
-			      &l_Adapter->m_UserToTap,
2250
+			      p_UserToTap,
2243 2251
 			      (unsigned char *) p_IRP->AssociatedIrp.SystemBuffer,
2244 2252
 			      l_IrpSp->Parameters.Write.Length);
2245 2253
 
... ...
@@ -2258,8 +2446,8 @@ TapDeviceHook (IN PDEVICE_OBJECT p_DeviceObject, IN PIRP p_IRP)
2258 2258
 		NdisMEthIndicateReceive
2259 2259
 		  (l_Adapter->m_MiniportAdapterHandle,
2260 2260
 		   (NDIS_HANDLE) l_Adapter,
2261
-		   (unsigned char *) &l_Adapter->m_UserToTap,
2262
-		   sizeof (l_Adapter->m_UserToTap),
2261
+		   (unsigned char *) p_UserToTap,
2262
+		   sizeof (ETH_HEADER),
2263 2263
 		   (unsigned char *) p_IRP->AssociatedIrp.SystemBuffer,
2264 2264
 		   l_IrpSp->Parameters.Write.Length,
2265 2265
 		   l_IrpSp->Parameters.Write.Length);
... ...
@@ -2820,6 +3008,7 @@ VOID ResetTapAdapterState (TapAdapterPointer p_Adapter)
2820 2820
   p_Adapter->m_remoteNetmask = 0;
2821 2821
   NdisZeroMemory (&p_Adapter->m_TapToUser, sizeof (p_Adapter->m_TapToUser));
2822 2822
   NdisZeroMemory (&p_Adapter->m_UserToTap, sizeof (p_Adapter->m_UserToTap));
2823
+  NdisZeroMemory (&p_Adapter->m_UserToTap_IPv6, sizeof (p_Adapter->m_UserToTap_IPv6));
2823 2824
 
2824 2825
   // DHCP Masq
2825 2826
   p_Adapter->m_dhcp_enabled = FALSE;
... ...
@@ -143,6 +143,7 @@ typedef struct _TapAdapter
143 143
   IPADDR m_remoteNetmask;
144 144
   ETH_HEADER m_TapToUser;
145 145
   ETH_HEADER m_UserToTap;
146
+  ETH_HEADER m_UserToTap_IPv6;		// same as UserToTap but proto=ipv6
146 147
   MACADDR m_MAC_Broadcast;
147 148
 
148 149
   // Used for DHCP server masquerade