private byte[] CreateOptionStruct(DHCPMsgType msgType, DHCPReplyOptions replyOptions, Dictionary <DHCPOption, byte[]> otherForceOptions, IEnumerable <DHCPOption> forceOptions)
        {
            Dictionary <DHCPOption, byte[]> options = new Dictionary <DHCPOption, byte[]>();

            byte[] resultOptions = null;
            // Requested options
            var reqList = GetRequestedOptionsList();
            // Option82?
            var relayInfo = this.GetOptionData(DHCPOption.RelayInfo);

            CreateOptionElement(ref resultOptions, DHCPOption.DHCPMessageTYPE, new byte[] { (byte)msgType });
            // Server identifier - our IP address
            if ((replyOptions != null) && (replyOptions.ServerIdentifier != null))
            {
                options[DHCPOption.ServerIdentifier] = replyOptions.ServerIdentifier.GetAddressBytes();
            }

            if (reqList == null && forceOptions != null)
            {
                reqList = new DHCPOption[0];
            }

            // Requested options
            if ((reqList != null) && (replyOptions != null))
            {
                if (forceOptions == null)
                {
                    forceOptions = new List <DHCPOption>();
                }
            }

            foreach (DHCPOption i in reqList.Union(forceOptions).Distinct().OrderBy(x => (int)x))
            {
                byte[] optionData = null;
                // If it's force option - ignore it. We'll send it later.
                if ((otherForceOptions != null) && (otherForceOptions.TryGetValue(i, out optionData)))
                {
                    continue;
                }
                switch (i)
                {
                case DHCPOption.SubnetMask:
                    if (replyOptions.SubnetMask != null)
                    {
                        optionData = replyOptions.SubnetMask.GetAddressBytes();
                    }
                    break;

                case DHCPOption.Router:
                    if (replyOptions.RouterIP != null)
                    {
                        optionData = replyOptions.RouterIP.GetAddressBytes();
                    }
                    break;

                case DHCPOption.DomainNameServers:
                    if (replyOptions.DomainNameServers != null)
                    {
                        optionData = new byte[] { };
                        foreach (var dns in replyOptions.DomainNameServers)
                        {
                            var dnsserv = dns.GetAddressBytes();
                            Array.Resize(ref optionData, optionData.Length + 4);
                            Array.Copy(dnsserv, 0, optionData, optionData.Length - 4, 4);
                        }
                    }
                    break;

                case DHCPOption.DomainName:
                    if (!string.IsNullOrEmpty(replyOptions.DomainName))
                    {
                        optionData = System.Text.Encoding.ASCII.GetBytes(replyOptions.DomainName);
                    }
                    break;

                case DHCPOption.ServerIdentifier:
                    if (replyOptions.ServerIdentifier != null)
                    {
                        optionData = replyOptions.ServerIdentifier.GetAddressBytes();
                    }
                    break;

                case DHCPOption.LogServer:
                    if (replyOptions.LogServerIP != null)
                    {
                        optionData = replyOptions.LogServerIP.GetAddressBytes();
                    }
                    break;

                case DHCPOption.StaticRoutes:
                case DHCPOption.StaticRoutesWin:
                    if (replyOptions.StaticRoutes != null)
                    {
                        optionData = new byte[] { };
                        foreach (var route in replyOptions.StaticRoutes)
                        {
                            var routeData = route.BuildRouteData();
                            Array.Resize(ref optionData, optionData.Length + routeData.Length);
                            Array.Copy(routeData, 0, optionData, optionData.Length - routeData.Length, routeData.Length);
                        }
                    }
                    break;

                default:
                    replyOptions.OtherRequestedOptions.TryGetValue(i, out optionData);
                    break;
                }
                if (optionData != null)
                {
                    options[i] = optionData;
                }
            }

            if (GetMsgType() != DHCPMsgType.DHCPINFORM)
            {
                // Lease time
                if (replyOptions != null)
                {
                    var leaseTime = new byte[4];
                    leaseTime[3] = (byte)(replyOptions.IPAddressLeaseTime);
                    leaseTime[2] = (byte)(replyOptions.IPAddressLeaseTime >> 8);
                    leaseTime[1] = (byte)(replyOptions.IPAddressLeaseTime >> 16);
                    leaseTime[0] = (byte)(replyOptions.IPAddressLeaseTime >> 24);
                    options[DHCPOption.IPAddressLeaseTime] = leaseTime;
                    if (replyOptions.RenewalTimeValue_T1.HasValue)
                    {
                        leaseTime[3] = (byte)(replyOptions.RenewalTimeValue_T1);
                        leaseTime[2] = (byte)(replyOptions.RenewalTimeValue_T1 >> 8);
                        leaseTime[1] = (byte)(replyOptions.RenewalTimeValue_T1 >> 16);
                        leaseTime[0] = (byte)(replyOptions.RenewalTimeValue_T1 >> 24);
                        options[DHCPOption.RenewalTimeValue_T1] = leaseTime;
                    }
                    if (replyOptions.RebindingTimeValue_T2.HasValue)
                    {
                        leaseTime[3] = (byte)(replyOptions.RebindingTimeValue_T2);
                        leaseTime[2] = (byte)(replyOptions.RebindingTimeValue_T2 >> 8);
                        leaseTime[1] = (byte)(replyOptions.RebindingTimeValue_T2 >> 16);
                        leaseTime[0] = (byte)(replyOptions.RebindingTimeValue_T2 >> 24);
                        options[DHCPOption.RebindingTimeValue_T2] = leaseTime;
                    }
                }
            }
            // Other requested options
            if (otherForceOptions != null)
            {
                foreach (var option in otherForceOptions.Keys)
                {
                    options[option] = otherForceOptions[option];
                    if (option == DHCPOption.RelayInfo)
                    {
                        relayInfo = null;
                    }
                }
            }

            // Option 82? Send it back!
            if (relayInfo != null)
            {
                options[DHCPOption.RelayInfo] = relayInfo;
            }

            foreach (var option in options.OrderBy(x => (int)x.Key))
            {
                CreateOptionElement(ref resultOptions, option.Key, option.Value);
            }

            // Create the end option
            Array.Resize(ref resultOptions, resultOptions.Length + 1);
            Array.Copy(new byte[] { 255 }, 0, resultOptions, resultOptions.Length - 1, 1);
            return(resultOptions);
        }
        /// <summary>
        /// Sends DHCP reply
        /// </summary>
        /// <param name="msgType">Type of DHCP message to send</param>
        /// <param name="ip">IP for client</param>
        /// <param name="replyData">Reply options (will be sent if requested)</param>
        /// <param name="otherForceOptions">Force reply options (will be sent anyway)</param>
        private async void SendDHCPReply(DHCPMsgType msgType, IPAddress ip, DHCPReplyOptions replyData, Dictionary <DHCPOption, byte[]> otherForceOptions, IEnumerable <DHCPOption> forceOptions)
        {
            var replyBuffer = requestData;

            replyBuffer.op     = 2;                    // Reply
            replyBuffer.yiaddr = ip.GetAddressBytes(); // Client's IP
            if (replyData.ServerIpAddress != null)
            {
                replyBuffer.siaddr = replyData.ServerIpAddress.GetAddressBytes();
            }
            replyBuffer.options = CreateOptionStruct(msgType, replyData, otherForceOptions, forceOptions); // Options
            if (!string.IsNullOrEmpty(dhcpServer.ServerName))
            {
                var serverNameBytes = Encoding.ASCII.GetBytes(dhcpServer.ServerName);
                int len             = (serverNameBytes.Length > 63) ? 63 : serverNameBytes.Length;
                Array.Copy(serverNameBytes, replyBuffer.sname, len);
                replyBuffer.sname[len] = 0;
            }
            //lock (requestSocket)
            {
                var DataToSend = BuildDataStructure(replyBuffer);
                if (DataToSend.Length < 300)
                {
                    var sendArray = new byte[300];
                    Array.Copy(DataToSend, 0, sendArray, 0, DataToSend.Length);
                    DataToSend = sendArray;
                }

                if ((replyBuffer.giaddr[0] == 0) && (replyBuffer.giaddr[1] == 0) &&
                    (replyBuffer.giaddr[2] == 0) && (replyBuffer.giaddr[3] == 0))
                {
                    //requestSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, true);
                    //endPoint = new IPEndPoint(dhcpServer.BroadcastAddress, PORT_TO_SEND_TO_CLIENT);

                    //var udp = new UdpClient();
                    //udp.EnableBroadcast = true;
                    //udp.Send(DataToSend, DataToSend.Length, new IPEndPoint(dhcpServer.BroadcastAddress, 68));
                    //udp.Close();

                    var datagramsocket = new Windows.Networking.Sockets.DatagramSocket();

                    using (var stream = await datagramsocket.GetOutputStreamAsync(new Windows.Networking.HostName(dhcpServer.BroadcastAddress), PORT_TO_SEND_TO_CLIENT.ToString()))
                    {
                        using (var datawriter = new Windows.Storage.Streams.DataWriter(stream))
                        {
                            datawriter.WriteBytes(DataToSend);
                            await datawriter.StoreAsync();
                        }
                    }
                }
                else
                {
                    //requestSocket .SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, false);
                    //endPoint = new IPEndPoint(new IPAddress(replyBuffer.giaddr), PORT_TO_SEND_TO_RELAY);
                    //requestSocket.SendTo(DataToSend, endPoint);

                    using (var stream = await requestSocket.GetOutputStreamAsync(new Windows.Networking.HostName(new IPAddress(replyBuffer.giaddr).ToString()), PORT_TO_SEND_TO_RELAY.ToString()))
                    {
                        using (var datawriter = new Windows.Storage.Streams.DataWriter(stream))
                        {
                            datawriter.WriteBytes(DataToSend);
                            await datawriter.StoreAsync();
                        }
                    }
                }
            }
        }
 /// <summary>
 /// Sends DHCP reply
 /// </summary>
 /// <param name="msgType">Type of DHCP message to send</param>
 /// <param name="ip">IP for client</param>
 /// <param name="replyData">Reply options (will be sent if requested)</param>
 /// <param name="otherForceOptions">Force reply options (will be sent anyway)</param>
 internal void SendDHCPReply(DHCPMsgType msgType, IPAddress ip, DHCPReplyOptions replyData,
                             Dictionary <DHCPOption, byte[]> otherForceOptions)
 {
     SendDHCPReply(msgType, ip, replyData, otherForceOptions, null);
 }
 /// <summary>
 /// Sends DHCP reply
 /// </summary>
 /// <param name="msgType">Type of DHCP message to send</param>
 /// <param name="ip">IP for client</param>
 /// <param name="replyData">Reply options (will be sent if requested)</param>
 /// <param name="forceOptions">Force reply options (will be sent anyway)</param>
 internal void SendDHCPReply(DHCPMsgType msgType, IPAddress ip, DHCPReplyOptions replyData,
                             IEnumerable <DHCPOption> forceOptions)
 {
     SendDHCPReply(msgType, ip, replyData, null, forceOptions);
 }
 /// <summary>
 /// Sends DHCP reply
 /// </summary>
 /// <param name="msgType">Type of DHCP message to send</param>
 /// <param name="ip">IP for client</param>
 /// <param name="replyData">Reply options (will be sent if requested)</param>
 internal void SendDHCPReply(DHCPMsgType msgType, IPAddress ip, DHCPReplyOptions replyData)
 {
     SendDHCPReply(msgType, ip, replyData, null, null);
 }