2 * TAP-Win32/TAP-Win64 -- A kernel driver to provide virtual tap
3 * device functionality on Windows.
5 * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson.
7 * This source code is Copyright (C) 2002-2009 OpenVPN Technologies, Inc.,
8 * and is released under the GPL version 2 (see below).
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2
12 * as published by the Free Software Foundation.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program (see the file COPYING included with this
21 * distribution); if not, write to the Free Software Foundation, Inc.,
22 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 //=========================
26 // Code to set DHCP options
27 //=========================
30 SetDHCPOpt (DHCPMsg
*m
, void *data
, unsigned int len
)
34 if (m
->optlen
+ len
<= DHCP_OPTIONS_BUFFER_SIZE
)
38 NdisMoveMemory (m
->msg
.options
+ m
->optlen
, data
, len
);
50 SetDHCPOpt0 (DHCPMsg
*msg
, int type
)
53 opt
.type
= (UCHAR
) type
;
54 SetDHCPOpt (msg
, &opt
, sizeof (opt
));
58 SetDHCPOpt8 (DHCPMsg
*msg
, int type
, ULONG data
)
61 opt
.type
= (UCHAR
) type
;
62 opt
.len
= sizeof (opt
.data
);
63 opt
.data
= (UCHAR
) data
;
64 SetDHCPOpt (msg
, &opt
, sizeof (opt
));
68 SetDHCPOpt32 (DHCPMsg
*msg
, int type
, ULONG data
)
71 opt
.type
= (UCHAR
) type
;
72 opt
.len
= sizeof (opt
.data
);
74 SetDHCPOpt (msg
, &opt
, sizeof (opt
));
82 ip_checksum (const UCHAR
*buf
, const int len_ip_header
)
88 // make 16 bit words out of every two adjacent 8 bit words in the packet
90 for (i
= 0; i
< len_ip_header
- 1; i
+= 2) {
91 word16
= ((buf
[i
] << 8) & 0xFF00) + (buf
[i
+1] & 0xFF);
92 sum
+= (ULONG
) word16
;
95 // take only 16 bits out of the 32 bit sum and add up the carries
97 sum
= (sum
& 0xFFFF) + (sum
>> 16);
99 // one's complement the result
100 return ((USHORT
) ~sum
);
104 udp_checksum (const UCHAR
*buf
,
106 const UCHAR
*src_addr
,
107 const UCHAR
*dest_addr
)
113 // make 16 bit words out of every two adjacent 8 bit words and
114 // calculate the sum of all 16 bit words
115 for (i
= 0; i
< len_udp
; i
+= 2){
116 word16
= ((buf
[i
] << 8) & 0xFF00) + ((i
+ 1 < len_udp
) ? (buf
[i
+1] & 0xFF) : 0);
120 // add the UDP pseudo header which contains the IP source and destination addresses
121 for (i
= 0; i
< 4; i
+= 2){
122 word16
=((src_addr
[i
] << 8) & 0xFF00) + (src_addr
[i
+1] & 0xFF);
125 for (i
= 0; i
< 4; i
+= 2){
126 word16
=((dest_addr
[i
] << 8) & 0xFF00) + (dest_addr
[i
+1] & 0xFF);
130 // the protocol number and the length of the UDP packet
131 sum
+= (USHORT
) IPPROTO_UDP
+ (USHORT
) len_udp
;
133 // keep only the last 16 bits of the 32 bit calculated sum and add the carries
135 sum
= (sum
& 0xFFFF) + (sum
>> 16);
137 // Take the one's complement of sum
138 return ((USHORT
) ~sum
);
141 //================================
142 // Set IP and UDP packet checksums
143 //================================
146 SetChecksumDHCPMsg (DHCPMsg
*m
)
149 m
->msg
.pre
.ip
.check
= htons (ip_checksum ((UCHAR
*) &m
->msg
.pre
.ip
, sizeof (IPHDR
)));
152 m
->msg
.pre
.udp
.check
= htons (udp_checksum ((UCHAR
*) &m
->msg
.pre
.udp
,
153 sizeof (UDPHDR
) + sizeof (DHCP
) + m
->optlen
,
154 (UCHAR
*)&m
->msg
.pre
.ip
.saddr
,
155 (UCHAR
*)&m
->msg
.pre
.ip
.daddr
));
158 //===================
159 // DHCP message tests
160 //===================
163 GetDHCPMessageType (const DHCP
*dhcp
, const int optlen
)
165 const UCHAR
*p
= (UCHAR
*) (dhcp
+ 1);
168 for (i
= 0; i
< optlen
; ++i
)
170 const UCHAR type
= p
[i
];
171 const int room
= optlen
- i
- 1;
172 if (type
== DHCP_END
) // didn't find what we were looking for
174 else if (type
== DHCP_PAD
) // no-operation
176 else if (type
== DHCP_MSG_TYPE
) // what we are looking for
180 if (p
[i
+1] == 1) // message length should be 1
181 return p
[i
+2]; // return message type
185 else // some other message
189 const int len
= p
[i
+1]; // get message length
190 i
+= (len
+ 1); // advance to next message
198 DHCPMessageOurs (const TapAdapterPointer p_Adapter
,
199 const ETH_HEADER
*eth
,
204 // Must be UDPv4 protocol
205 if (!(eth
->proto
== htons (ETH_P_IP
) && ip
->protocol
== IPPROTO_UDP
))
208 // Source MAC must be our adapter
209 if (!MAC_EQUAL (eth
->src
, p_Adapter
->m_MAC
))
212 // Dest MAC must be either broadcast or our virtual DHCP server
213 if (!(MAC_EQUAL (eth
->dest
, p_Adapter
->m_MAC_Broadcast
)
214 || MAC_EQUAL (eth
->dest
, p_Adapter
->m_dhcp_server_mac
)))
217 // Port numbers must be correct
218 if (!(udp
->dest
== htons (BOOTPS_PORT
)
219 && udp
->source
== htons (BOOTPC_PORT
)))
222 // Hardware address must be MAC addr sized
223 if (!(dhcp
->hlen
== sizeof (MACADDR
)))
226 // Hardware address must match our adapter
227 if (!MAC_EQUAL (eth
->src
, dhcp
->chaddr
))
234 //=====================================================
235 // Build all of DHCP packet except for DHCP options.
236 // Assume that *p has been zeroed before we are called.
237 //=====================================================
240 BuildDHCPPre (const TapAdapterPointer a
,
242 const ETH_HEADER
*eth
,
249 // Should we broadcast or direct to a specific MAC / IP address?
250 const BOOLEAN broadcast
= (type
== DHCPNAK
251 || MAC_EQUAL (eth
->dest
, a
->m_MAC_Broadcast
));
252 // Build ethernet header
254 COPY_MAC (p
->eth
.src
, a
->m_dhcp_server_mac
);
257 COPY_MAC (p
->eth
.dest
, a
->m_MAC_Broadcast
);
259 COPY_MAC (p
->eth
.dest
, eth
->src
);
261 p
->eth
.proto
= htons (ETH_P_IP
);
265 p
->ip
.version_len
= (4 << 4) | (sizeof (IPHDR
) >> 2);
267 p
->ip
.tot_len
= htons (sizeof (IPHDR
) + sizeof (UDPHDR
) + sizeof (DHCP
) + optlen
);
271 p
->ip
.protocol
= IPPROTO_UDP
;
273 p
->ip
.saddr
= a
->m_dhcp_server_ip
;
278 p
->ip
.daddr
= a
->m_dhcp_addr
;
282 p
->udp
.source
= htons (BOOTPS_PORT
);
283 p
->udp
.dest
= htons (BOOTPC_PORT
);
284 p
->udp
.len
= htons (sizeof (UDPHDR
) + sizeof (DHCP
) + optlen
);
287 // Build DHCP response
289 p
->dhcp
.op
= BOOTREPLY
;
291 p
->dhcp
.hlen
= sizeof (MACADDR
);
293 p
->dhcp
.xid
= dhcp
->xid
;
301 p
->dhcp
.yiaddr
= a
->m_dhcp_addr
;
303 p
->dhcp
.siaddr
= a
->m_dhcp_server_ip
;
305 COPY_MAC (p
->dhcp
.chaddr
, eth
->src
);
306 p
->dhcp
.magic
= htonl (0x63825363);
308 //=============================
309 // Build specific DHCP messages
310 //=============================
313 SendDHCPMsg (const TapAdapterPointer a
,
315 const ETH_HEADER
*eth
,
322 if (!(type
== DHCPOFFER
|| type
== DHCPACK
|| type
== DHCPNAK
))
324 DEBUGP (("[TAP] SendDHCPMsg: Bad DHCP type: %d\n", type
));
328 pkt
= (DHCPMsg
*) MemAlloc (sizeof (DHCPMsg
), TRUE
);
332 //-----------------------
333 // Build DHCP options
334 //-----------------------
337 SetDHCPOpt8 (pkt
, DHCP_MSG_TYPE
, type
);
340 SetDHCPOpt32 (pkt
, DHCP_SERVER_ID
, a
->m_dhcp_server_ip
);
342 if (type
== DHCPOFFER
|| type
== DHCPACK
)
345 SetDHCPOpt32 (pkt
, DHCP_LEASE_TIME
, htonl (a
->m_dhcp_lease_time
));
348 SetDHCPOpt32 (pkt
, DHCP_NETMASK
, a
->m_dhcp_netmask
);
350 // Other user-defined options
352 a
->m_dhcp_user_supplied_options_buffer
,
353 a
->m_dhcp_user_supplied_options_buffer_len
);
357 SetDHCPOpt0 (pkt
, DHCP_END
);
359 if (!DHCPMSG_OVERFLOW (pkt
))
361 // The initial part of the DHCP message (not including options) gets built here
368 DHCPMSG_LEN_OPT (pkt
),
371 SetChecksumDHCPMsg (pkt
);
373 DUMP_PACKET ("DHCPMsg",
375 DHCPMSG_LEN_FULL (pkt
));
377 // Return DHCP response to kernel
378 InjectPacketDeferred (a
,
380 DHCPMSG_LEN_FULL (pkt
));
384 DEBUGP (("[TAP] SendDHCPMsg: DHCP buffer overflow\n"));
387 MemFree (pkt
, sizeof (DHCPMsg
));
391 //===================================================================
392 // Handle a BOOTPS packet produced by the local system to
393 // resolve the address/netmask of this adapter.
394 // If we are in TAP_IOCTL_CONFIG_DHCP_MASQ mode, reply
395 // to the message. Return TRUE if we processed the passed
396 // message, so that downstream stages can ignore it.
397 //===================================================================
400 ProcessDHCP (TapAdapterPointer p_Adapter
,
401 const ETH_HEADER
*eth
,
409 // Sanity check IP header
410 if (!(ntohs (ip
->tot_len
) == sizeof (IPHDR
) + sizeof (UDPHDR
) + sizeof (DHCP
) + optlen
411 && (ntohs (ip
->frag_off
) & IP_OFFMASK
) == 0))
414 // Does this message belong to us?
415 if (!DHCPMessageOurs (p_Adapter
, eth
, ip
, udp
, dhcp
))
418 msg_type
= GetDHCPMessageType (dhcp
, optlen
);
420 // Drop non-BOOTREQUEST messages
421 if (dhcp
->op
!= BOOTREQUEST
)
424 // Drop any messages except DHCPDISCOVER or DHCPREQUEST
425 if (!(msg_type
== DHCPDISCOVER
|| msg_type
== DHCPREQUEST
))
428 // Should we reply with DHCPOFFER, DHCPACK, or DHCPNAK?
429 if (msg_type
== DHCPREQUEST
430 && ((dhcp
->ciaddr
&& dhcp
->ciaddr
!= p_Adapter
->m_dhcp_addr
)
431 || !p_Adapter
->m_dhcp_received_discover
432 || p_Adapter
->m_dhcp_bad_requests
>= BAD_DHCPREQUEST_NAK_THRESHOLD
))
433 SendDHCPMsg (p_Adapter
,
437 SendDHCPMsg (p_Adapter
,
438 (msg_type
== DHCPDISCOVER
? DHCPOFFER
: DHCPACK
),
441 // Remember if we received a DHCPDISCOVER
442 if (msg_type
== DHCPDISCOVER
)
443 p_Adapter
->m_dhcp_received_discover
= TRUE
;
445 // Is this a bad DHCPREQUEST?
446 if (msg_type
== DHCPREQUEST
&& dhcp
->ciaddr
!= p_Adapter
->m_dhcp_addr
)
447 ++p_Adapter
->m_dhcp_bad_requests
;
455 message_op_text (int op
)
460 return "BOOTREQUEST";
469 message_type_text (int type
)
474 return "DHCPDISCOVER";
478 return "DHCPREQUEST";
480 return "DHCPDECLINE";
486 return "DHCPRELEASE";
509 DumpDHCP (const ETH_HEADER
*eth
,
515 DEBUGP ((" %s", message_op_text (dhcp
->op
)));
516 DEBUGP ((" %s ", message_type_text (GetDHCPMessageType (dhcp
, optlen
))));
518 DEBUGP ((":%s[", port_name (ntohs (udp
->source
))));
522 DEBUGP ((":%s[", port_name (ntohs (udp
->dest
))));
540 if (dhcp
->hlen
== sizeof (MACADDR
))
543 PrMac (dhcp
->chaddr
);
546 DEBUGP ((" xid=0x%08x", ntohl (dhcp
->xid
)));
548 if (ntohl (dhcp
->magic
) != 0x63825363)
549 DEBUGP ((" ma=0x%08x", ntohl (dhcp
->magic
)));
550 if (dhcp
->htype
!= 1)
551 DEBUGP ((" htype=%d", dhcp
->htype
));
553 DEBUGP ((" hops=%d", dhcp
->hops
));
554 if (ntohs (dhcp
->secs
))
555 DEBUGP ((" secs=%d", ntohs (dhcp
->secs
)));
556 if (ntohs (dhcp
->flags
))
557 DEBUGP ((" flags=0x%04x", ntohs (dhcp
->flags
)));
561 if (ip
->version_len
!= 0x45)
562 DEBUGP ((" vl=0x%02x", ip
->version_len
));
563 if (ntohs (ip
->tot_len
) != sizeof (IPHDR
) + sizeof (UDPHDR
) + sizeof (DHCP
) + optlen
)
564 DEBUGP ((" tl=%d", ntohs (ip
->tot_len
)));
565 if (ntohs (udp
->len
) != sizeof (UDPHDR
) + sizeof (DHCP
) + optlen
)
566 DEBUGP ((" ul=%d", ntohs (udp
->len
)));
569 DEBUGP ((" tos=0x%02x", ip
->tos
));
571 DEBUGP ((" id=0x%04x", ntohs (ip
->id
)));
572 if (ntohs (ip
->frag_off
))
573 DEBUGP ((" frag_off=0x%04x", ntohs (ip
->frag_off
)));
575 DEBUGP ((" ttl=%d", ip
->ttl
));
576 DEBUGP ((" ic=0x%04x [0x%04x]", ntohs (ip
->check
),
577 ip_checksum ((UCHAR
*)ip
, sizeof (IPHDR
))));
578 DEBUGP ((" uc=0x%04x [0x%04x/%d]", ntohs (udp
->check
),
579 udp_checksum ((UCHAR
*) udp
,
580 sizeof (UDPHDR
) + sizeof (DHCP
) + optlen
,
581 (UCHAR
*) &ip
->saddr
,
582 (UCHAR
*) &ip
->daddr
),
587 const UCHAR
*opt
= (UCHAR
*) (dhcp
+ 1);
591 for (i
= 0; i
< optlen
; ++i
)
593 const UCHAR data
= opt
[i
];
594 DEBUGP ((".%d", data
));