Upgrade to OpenVPN 2.1.0
[tomato.git] / release / src / router / openvpn / tap-win32 / dhcp.c
blob8ef3917bc631be1441e441706d0cdd36dfb41495
1 /*
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 //=========================
29 VOID
30 SetDHCPOpt (DHCPMsg *m, void *data, unsigned int len)
32 if (!m->overflow)
34 if (m->optlen + len <= DHCP_OPTIONS_BUFFER_SIZE)
36 if (len)
38 NdisMoveMemory (m->msg.options + m->optlen, data, len);
39 m->optlen += len;
42 else
44 m->overflow = TRUE;
49 VOID
50 SetDHCPOpt0 (DHCPMsg *msg, int type)
52 DHCPOPT0 opt;
53 opt.type = (UCHAR) type;
54 SetDHCPOpt (msg, &opt, sizeof (opt));
57 VOID
58 SetDHCPOpt8 (DHCPMsg *msg, int type, ULONG data)
60 DHCPOPT8 opt;
61 opt.type = (UCHAR) type;
62 opt.len = sizeof (opt.data);
63 opt.data = (UCHAR) data;
64 SetDHCPOpt (msg, &opt, sizeof (opt));
67 VOID
68 SetDHCPOpt32 (DHCPMsg *msg, int type, ULONG data)
70 DHCPOPT32 opt;
71 opt.type = (UCHAR) type;
72 opt.len = sizeof (opt.data);
73 opt.data = data;
74 SetDHCPOpt (msg, &opt, sizeof (opt));
77 //==============
78 // Checksum code
79 //==============
81 USHORT
82 ip_checksum (const UCHAR *buf, const int len_ip_header)
84 USHORT word16;
85 ULONG sum = 0;
86 int i;
88 // make 16 bit words out of every two adjacent 8 bit words in the packet
89 // and add them up
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
96 while (sum >> 16)
97 sum = (sum & 0xFFFF) + (sum >> 16);
99 // one's complement the result
100 return ((USHORT) ~sum);
103 USHORT
104 udp_checksum (const UCHAR *buf,
105 const int len_udp,
106 const UCHAR *src_addr,
107 const UCHAR *dest_addr)
109 USHORT word16;
110 ULONG sum = 0;
111 int i;
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);
117 sum += word16;
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);
123 sum += word16;
125 for (i = 0; i < 4; i += 2){
126 word16 =((dest_addr[i] << 8) & 0xFF00) + (dest_addr[i+1] & 0xFF);
127 sum += word16;
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
134 while (sum >> 16)
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 //================================
145 VOID
146 SetChecksumDHCPMsg (DHCPMsg *m)
148 // Set IP checksum
149 m->msg.pre.ip.check = htons (ip_checksum ((UCHAR *) &m->msg.pre.ip, sizeof (IPHDR)));
151 // Set UDP Checksum
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);
166 int i;
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
173 return -1;
174 else if (type == DHCP_PAD) // no-operation
176 else if (type == DHCP_MSG_TYPE) // what we are looking for
178 if (room >= 2)
180 if (p[i+1] == 1) // message length should be 1
181 return p[i+2]; // return message type
183 return -1;
185 else // some other message
187 if (room >= 1)
189 const int len = p[i+1]; // get message length
190 i += (len + 1); // advance to next message
194 return -1;
197 BOOLEAN
198 DHCPMessageOurs (const TapAdapterPointer p_Adapter,
199 const ETH_HEADER *eth,
200 const IPHDR *ip,
201 const UDPHDR *udp,
202 const DHCP *dhcp)
204 // Must be UDPv4 protocol
205 if (!(eth->proto == htons (ETH_P_IP) && ip->protocol == IPPROTO_UDP))
206 return FALSE;
208 // Source MAC must be our adapter
209 if (!MAC_EQUAL (eth->src, p_Adapter->m_MAC))
210 return FALSE;
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)))
215 return FALSE;
217 // Port numbers must be correct
218 if (!(udp->dest == htons (BOOTPS_PORT)
219 && udp->source == htons (BOOTPC_PORT)))
220 return FALSE;
222 // Hardware address must be MAC addr sized
223 if (!(dhcp->hlen == sizeof (MACADDR)))
224 return FALSE;
226 // Hardware address must match our adapter
227 if (!MAC_EQUAL (eth->src, dhcp->chaddr))
228 return FALSE;
230 return TRUE;
234 //=====================================================
235 // Build all of DHCP packet except for DHCP options.
236 // Assume that *p has been zeroed before we are called.
237 //=====================================================
239 VOID
240 BuildDHCPPre (const TapAdapterPointer a,
241 DHCPPre *p,
242 const ETH_HEADER *eth,
243 const IPHDR *ip,
244 const UDPHDR *udp,
245 const DHCP *dhcp,
246 const int optlen,
247 const int type)
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);
256 if (broadcast)
257 COPY_MAC (p->eth.dest, a->m_MAC_Broadcast);
258 else
259 COPY_MAC (p->eth.dest, eth->src);
261 p->eth.proto = htons (ETH_P_IP);
263 // Build IP header
265 p->ip.version_len = (4 << 4) | (sizeof (IPHDR) >> 2);
266 p->ip.tos = 0;
267 p->ip.tot_len = htons (sizeof (IPHDR) + sizeof (UDPHDR) + sizeof (DHCP) + optlen);
268 p->ip.id = 0;
269 p->ip.frag_off = 0;
270 p->ip.ttl = 16;
271 p->ip.protocol = IPPROTO_UDP;
272 p->ip.check = 0;
273 p->ip.saddr = a->m_dhcp_server_ip;
275 if (broadcast)
276 p->ip.daddr = ~0;
277 else
278 p->ip.daddr = a->m_dhcp_addr;
280 // Build UDP header
282 p->udp.source = htons (BOOTPS_PORT);
283 p->udp.dest = htons (BOOTPC_PORT);
284 p->udp.len = htons (sizeof (UDPHDR) + sizeof (DHCP) + optlen);
285 p->udp.check = 0;
287 // Build DHCP response
289 p->dhcp.op = BOOTREPLY;
290 p->dhcp.htype = 1;
291 p->dhcp.hlen = sizeof (MACADDR);
292 p->dhcp.hops = 0;
293 p->dhcp.xid = dhcp->xid;
294 p->dhcp.secs = 0;
295 p->dhcp.flags = 0;
296 p->dhcp.ciaddr = 0;
298 if (type == DHCPNAK)
299 p->dhcp.yiaddr = 0;
300 else
301 p->dhcp.yiaddr = a->m_dhcp_addr;
303 p->dhcp.siaddr = a->m_dhcp_server_ip;
304 p->dhcp.giaddr = 0;
305 COPY_MAC (p->dhcp.chaddr, eth->src);
306 p->dhcp.magic = htonl (0x63825363);
308 //=============================
309 // Build specific DHCP messages
310 //=============================
312 VOID
313 SendDHCPMsg (const TapAdapterPointer a,
314 const int type,
315 const ETH_HEADER *eth,
316 const IPHDR *ip,
317 const UDPHDR *udp,
318 const DHCP *dhcp)
320 DHCPMsg *pkt;
322 if (!(type == DHCPOFFER || type == DHCPACK || type == DHCPNAK))
324 DEBUGP (("[TAP] SendDHCPMsg: Bad DHCP type: %d\n", type));
325 return;
328 pkt = (DHCPMsg *) MemAlloc (sizeof (DHCPMsg), TRUE);
330 if (pkt)
332 //-----------------------
333 // Build DHCP options
334 //-----------------------
336 // Message Type
337 SetDHCPOpt8 (pkt, DHCP_MSG_TYPE, type);
339 // Server ID
340 SetDHCPOpt32 (pkt, DHCP_SERVER_ID, a->m_dhcp_server_ip);
342 if (type == DHCPOFFER || type == DHCPACK)
344 // Lease Time
345 SetDHCPOpt32 (pkt, DHCP_LEASE_TIME, htonl (a->m_dhcp_lease_time));
347 // Netmask
348 SetDHCPOpt32 (pkt, DHCP_NETMASK, a->m_dhcp_netmask);
350 // Other user-defined options
351 SetDHCPOpt (pkt,
352 a->m_dhcp_user_supplied_options_buffer,
353 a->m_dhcp_user_supplied_options_buffer_len);
356 // End
357 SetDHCPOpt0 (pkt, DHCP_END);
359 if (!DHCPMSG_OVERFLOW (pkt))
361 // The initial part of the DHCP message (not including options) gets built here
362 BuildDHCPPre (a,
363 &pkt->msg.pre,
364 eth,
366 udp,
367 dhcp,
368 DHCPMSG_LEN_OPT (pkt),
369 type);
371 SetChecksumDHCPMsg (pkt);
373 DUMP_PACKET ("DHCPMsg",
374 DHCPMSG_BUF (pkt),
375 DHCPMSG_LEN_FULL (pkt));
377 // Return DHCP response to kernel
378 InjectPacketDeferred (a,
379 DHCPMSG_BUF (pkt),
380 DHCPMSG_LEN_FULL (pkt));
382 else
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 //===================================================================
399 BOOLEAN
400 ProcessDHCP (TapAdapterPointer p_Adapter,
401 const ETH_HEADER *eth,
402 const IPHDR *ip,
403 const UDPHDR *udp,
404 const DHCP *dhcp,
405 int optlen)
407 int msg_type;
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))
412 return TRUE;
414 // Does this message belong to us?
415 if (!DHCPMessageOurs (p_Adapter, eth, ip, udp, dhcp))
416 return FALSE;
418 msg_type = GetDHCPMessageType (dhcp, optlen);
420 // Drop non-BOOTREQUEST messages
421 if (dhcp->op != BOOTREQUEST)
422 return TRUE;
424 // Drop any messages except DHCPDISCOVER or DHCPREQUEST
425 if (!(msg_type == DHCPDISCOVER || msg_type == DHCPREQUEST))
426 return TRUE;
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,
434 DHCPNAK,
435 eth, ip, udp, dhcp);
436 else
437 SendDHCPMsg (p_Adapter,
438 (msg_type == DHCPDISCOVER ? DHCPOFFER : DHCPACK),
439 eth, ip, udp, dhcp);
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;
449 return TRUE;
452 #if DBG
454 const char *
455 message_op_text (int op)
457 switch (op)
459 case BOOTREQUEST:
460 return "BOOTREQUEST";
461 case BOOTREPLY:
462 return "BOOTREPLY";
463 default:
464 return "???";
468 const char *
469 message_type_text (int type)
471 switch (type)
473 case DHCPDISCOVER:
474 return "DHCPDISCOVER";
475 case DHCPOFFER:
476 return "DHCPOFFER";
477 case DHCPREQUEST:
478 return "DHCPREQUEST";
479 case DHCPDECLINE:
480 return "DHCPDECLINE";
481 case DHCPACK:
482 return "DHCPACK";
483 case DHCPNAK:
484 return "DHCPNAK";
485 case DHCPRELEASE:
486 return "DHCPRELEASE";
487 case DHCPINFORM:
488 return "DHCPINFORM";
489 default:
490 return "???";
494 const char *
495 port_name (int port)
497 switch (port)
499 case BOOTPS_PORT:
500 return "BOOTPS";
501 case BOOTPC_PORT:
502 return "BOOTPC";
503 default:
504 return "unknown";
508 VOID
509 DumpDHCP (const ETH_HEADER *eth,
510 const IPHDR *ip,
511 const UDPHDR *udp,
512 const DHCP *dhcp,
513 const int optlen)
515 DEBUGP ((" %s", message_op_text (dhcp->op)));
516 DEBUGP ((" %s ", message_type_text (GetDHCPMessageType (dhcp, optlen))));
517 PrIP (ip->saddr);
518 DEBUGP ((":%s[", port_name (ntohs (udp->source))));
519 PrMac (eth->src);
520 DEBUGP (("] -> "));
521 PrIP (ip->daddr);
522 DEBUGP ((":%s[", port_name (ntohs (udp->dest))));
523 PrMac (eth->dest);
524 DEBUGP (("]"));
525 if (dhcp->ciaddr)
527 DEBUGP ((" ci="));
528 PrIP (dhcp->ciaddr);
530 if (dhcp->yiaddr)
532 DEBUGP ((" yi="));
533 PrIP (dhcp->yiaddr);
535 if (dhcp->siaddr)
537 DEBUGP ((" si="));
538 PrIP (dhcp->siaddr);
540 if (dhcp->hlen == sizeof (MACADDR))
542 DEBUGP ((" ch="));
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));
552 if (dhcp->hops)
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)));
559 // extra stuff
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)));
568 if (ip->tos)
569 DEBUGP ((" tos=0x%02x", ip->tos));
570 if (ntohs (ip->id))
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),
583 optlen));
585 // Options
587 const UCHAR *opt = (UCHAR *) (dhcp + 1);
588 int i;
590 DEBUGP ((" OPT"));
591 for (i = 0; i < optlen; ++i)
593 const UCHAR data = opt[i];
594 DEBUGP ((".%d", data));
599 #endif /* DBG */