void SendArpGeneric(UInt64 destinationEthernetAddress, ArpOperation arpOperation, UInt64 targetPhysicalAddress, UInt32 targetProtocolAddress, Int64 timeoutInMachineTicks)
        {
            if (_isDisposed)
            {
                return;
            }

            lock (_arpFrameBufferLock)
            {
                UInt64 physicalAddress = _ethernetInterface.PhysicalAddressAsUInt64;

                // configure ARP packet
                /* Op: request (1) or reply (2) */
                _arpFrameBuffer[6] = (byte)(((UInt16)arpOperation >> 8) & 0xFF);
                _arpFrameBuffer[7] = (byte)((UInt16)arpOperation & 0xFF);
                /* Sender Harwdare Address */
                _arpFrameBuffer[8]  = (byte)((physicalAddress >> 40) & 0xFF);
                _arpFrameBuffer[9]  = (byte)((physicalAddress >> 32) & 0xFF);
                _arpFrameBuffer[10] = (byte)((physicalAddress >> 24) & 0xFF);
                _arpFrameBuffer[11] = (byte)((physicalAddress >> 16) & 0xFF);
                _arpFrameBuffer[12] = (byte)((physicalAddress >> 8) & 0xFF);
                _arpFrameBuffer[13] = (byte)(physicalAddress & 0xFF);
                /* Sender Protocol Address */
                _arpFrameBuffer[14] = (byte)((_ipv4ProtocolAddress >> 24) & 0xFF);
                _arpFrameBuffer[15] = (byte)((_ipv4ProtocolAddress >> 16) & 0xFF);
                _arpFrameBuffer[16] = (byte)((_ipv4ProtocolAddress >> 8) & 0xFF);
                _arpFrameBuffer[17] = (byte)(_ipv4ProtocolAddress & 0xFF);
                /* Target Harwdare Address (if known) */
                _arpFrameBuffer[18] = (byte)((targetPhysicalAddress >> 40) & 0xFF);
                _arpFrameBuffer[19] = (byte)((targetPhysicalAddress >> 32) & 0xFF);
                _arpFrameBuffer[20] = (byte)((targetPhysicalAddress >> 24) & 0xFF);
                _arpFrameBuffer[21] = (byte)((targetPhysicalAddress >> 16) & 0xFF);
                _arpFrameBuffer[22] = (byte)((targetPhysicalAddress >> 8) & 0xFF);
                _arpFrameBuffer[23] = (byte)(targetPhysicalAddress & 0xFF);
                /* Target Protocol Address */
                _arpFrameBuffer[24] = (byte)((targetProtocolAddress >> 24) & 0xFF);
                _arpFrameBuffer[25] = (byte)((targetProtocolAddress >> 16) & 0xFF);
                _arpFrameBuffer[26] = (byte)((targetProtocolAddress >> 8) & 0xFF);
                _arpFrameBuffer[27] = (byte)(targetProtocolAddress & 0xFF);

                _bufferArray[0] = _arpFrameBuffer;
                _ethernetInterface.Send(destinationEthernetAddress, DATA_TYPE_ARP /* dataType: ARP */, _ipv4ProtocolAddress, targetProtocolAddress, 1 /* one buffer in bufferArray */, _bufferArray, _indexArray, _countArray, timeoutInMachineTicks);
            }
        }
Esempio n. 2
0
        public void Send(byte protocol, UInt32 srcIPAddress, UInt32 dstIPAddress, byte[][] buffer, int[] offset, int[] count, Int64 timeoutInMachineTicks)
        {
            /* if we are receiving more than (MAX_BUFFER_COUNT - 1) buffers, abort; if we need more, we'll have to change our array sizes at top */
            if (buffer.Length > MAX_BUFFER_SEGMENT_COUNT - 1)
            {
                throw new ArgumentException();
            }

            // determine whether dstIPAddress is a local address or a remote address.
            UInt64 dstPhysicalAddress;

            if ((dstIPAddress == _ipv4configIPAddress) || ((dstIPAddress & LOOPBACK_SUBNET_MASK) == (LOOPBACK_IP_ADDRESS & LOOPBACK_SUBNET_MASK)))
            {
                // loopback: the destination is ourselves

                // if the loopback buffer is in use then wait for it to be freed (or until our timeout occurs); if timeout occrs then drop the packet
                bool loopbackBufferInUse = _loopbackBufferInUse;
                if (loopbackBufferInUse)
                {
                    Int32 waitTimeout = (Int32)((timeoutInMachineTicks != Int64.MaxValue) ? System.Math.Max((timeoutInMachineTicks - Microsoft.SPOT.Hardware.Utility.GetMachineTime().Ticks) / System.TimeSpan.TicksPerMillisecond, 0) : System.Threading.Timeout.Infinite);
                    loopbackBufferInUse = !(_loopbackBufferFreedEvent.WaitOne(waitTimeout, false));
                }

                if (!loopbackBufferInUse)
                {
                    lock (_loopbackBufferLockObject)
                    {
                        _loopbackProtocol             = (ProtocolType)protocol;
                        _loopbackSourceIPAddress      = srcIPAddress;
                        _loopbackDestinationIPAddress = dstIPAddress;

                        // if we haven't needed loopback yet, allocate our loopback buffer now.
                        if (_loopbackBuffer == null)
                        {
                            _loopbackBuffer = new byte[LOOPBACK_BUFFER_SIZE];
                        }

                        int loopbackBufferCount = 0;
                        for (int iBuffer = 0; iBuffer < buffer.Length; iBuffer++)
                        {
                            Array.Copy(buffer[iBuffer], offset[iBuffer], _loopbackBuffer, loopbackBufferCount, count[iBuffer]);
                            loopbackBufferCount += count[iBuffer];
                        }
                        _loopbackBufferCount = loopbackBufferCount;
                        _loopbackBufferInUse = true;

                        _loopbackBufferFilledEvent.Set();
                    }
                }
                return;
            }
            else if (dstIPAddress == 0xFFFFFFFF)
            {
                // direct delivery: this destination address is our broadcast address
                /* get destinationPhysicalAddress of dstIPAddress */
                dstPhysicalAddress = _arpResolver.TranslateIPAddressToPhysicalAddress(dstIPAddress, timeoutInMachineTicks);
            }
            else if ((dstIPAddress & _ipv4configSubnetMask) == (_ipv4configIPAddress & _ipv4configSubnetMask))
            {
                // direct delivery: this destination address is on our local subnet
                /* get destinationPhysicalAddress of dstIPAddress */
                dstPhysicalAddress = _arpResolver.TranslateIPAddressToPhysicalAddress(dstIPAddress, timeoutInMachineTicks);
            }
            else
            {
                // indirect delivery; send the frame to our gateway instead
                /* get destinationPhysicalAddress of dstIPAddress */
                dstPhysicalAddress = _arpResolver.TranslateIPAddressToPhysicalAddress(_ipv4configGatewayAddress, timeoutInMachineTicks);
            }
            if (dstPhysicalAddress == 0)
            {
                throw Utility.NewSocketException(SocketError.HostUnreachable);  /* TODO: consider returning a success/fail as bool from this function */
            }
            lock (_ipv4HeaderBufferLockObject)
            {
                int headerLength = IPV4_HEADER_MIN_LENGTH;
                int dataLength   = 0;
                for (int i = 0; i < buffer.Length; i++)
                {
                    dataLength += count[i];
                }

                // we will send the data in fragments if the total data length exceeds 1500 bytes
                Int32 fragmentOffset = 0;
                Int32 fragmentLength;

                /* NOTE: we send the fragment offsets in reverse order so that the destination host has a chance to create the full buffer size before receiving additional fragments */
                if (dataLength > MAX_IPV4_DATA_FRAGMENT_SIZE)
                {
                    fragmentOffset = dataLength - (dataLength % MAX_IPV4_DATA_FRAGMENT_SIZE);
                }
                while (fragmentOffset >= 0)
                {
                    fragmentLength = System.Math.Min(dataLength - fragmentOffset, MAX_IPV4_DATA_FRAGMENT_SIZE);

                    // populate the header fields
                    _ipv4HeaderBuffer[1] = 0; /* leave the DSField/ECN fields blank */
                    UInt16 identification = GetNextDatagramID();
                    _ipv4HeaderBuffer[4] = (byte)((identification >> 8) & 0xFF);
                    _ipv4HeaderBuffer[5] = (byte)(identification & 0xFF);
                    // TODO: populate flags and fragmentation fields, if necessary
                    _ipv4HeaderBuffer[6] = (byte)(
                        (/* (flags << 5) + */ ((fragmentOffset >> 11) & 0xFF))
                        | ((fragmentOffset + fragmentLength == dataLength) ? 0 : 0x20) /* set MF (More Fragments) bit if this is not the only/last fragment in a datagram */
                        );
                    _ipv4HeaderBuffer[7] = (byte)((fragmentOffset >> 3) & 0xFF);
                    // populate the TTL (MaxHopCount) and protocol fields
                    _ipv4HeaderBuffer[8] = DEFAULT_TIME_TO_LIVE;
                    _ipv4HeaderBuffer[9] = protocol;
                    // fill in source and destination addresses
                    _ipv4HeaderBuffer[12] = (byte)((srcIPAddress >> 24) & 0xFF);
                    _ipv4HeaderBuffer[13] = (byte)((srcIPAddress >> 16) & 0xFF);
                    _ipv4HeaderBuffer[14] = (byte)((srcIPAddress >> 8) & 0xFF);
                    _ipv4HeaderBuffer[15] = (byte)(srcIPAddress & 0xFF);
                    _ipv4HeaderBuffer[16] = (byte)((dstIPAddress >> 24) & 0xFF);
                    _ipv4HeaderBuffer[17] = (byte)((dstIPAddress >> 16) & 0xFF);
                    _ipv4HeaderBuffer[18] = (byte)((dstIPAddress >> 8) & 0xFF);
                    _ipv4HeaderBuffer[19] = (byte)(dstIPAddress & 0xFF);

                    /* TODO: populate any datagram options */
                    // pseudocode: while (options) { AddOptionAt(_upV4HeaderBuffer[20 + offset]); headerLength += 4 };

                    // insert the length (and header length)
                    _ipv4HeaderBuffer[0] = (byte)((0x04 << 4) /* version: IPv4 */ + (headerLength / 4)) /* Internet Header Length: # of 32-bit words */;
                    _ipv4HeaderBuffer[2] = (byte)(((headerLength + fragmentLength) >> 8) & 0xFF); /* MSB of total datagram length */
                    _ipv4HeaderBuffer[3] = (byte)((headerLength + fragmentLength) & 0xFF);        /* LSB of total datagram length */

                    // finally calculate the header checksum
                    // for checksum calculation purposes, the checksum field must be empty.
                    _ipv4HeaderBuffer[10] = 0;
                    _ipv4HeaderBuffer[11] = 0;
                    UInt16 checksum = Netduino.IP.Utility.CalculateInternetChecksum(_ipv4HeaderBuffer, 0, headerLength);
                    _ipv4HeaderBuffer[10] = (byte)((checksum >> 8) & 0xFF);
                    _ipv4HeaderBuffer[11] = (byte)(checksum & 0xFF);

                    // queue up our buffer arrays
                    _bufferArray[0] = _ipv4HeaderBuffer;
                    _indexArray[0]  = 0;
                    _countArray[0]  = headerLength;

                    Int32 totalBufferOffset = 0;
                    Int32 bufferArrayLength = 1; /* we start with index 1, after our IPv4 header */
                    for (int i = 0; i < buffer.Length; i++)
                    {
                        if (totalBufferOffset + count[i] > fragmentOffset)
                        {
                            // add data from this buffer to our set of downstream buffers
                            _bufferArray[bufferArrayLength] = buffer[i];
                            _indexArray[bufferArrayLength]  = offset[i] + System.Math.Max(0, (fragmentOffset - totalBufferOffset));
                            _countArray[bufferArrayLength]  = System.Math.Min(count[i] - System.Math.Max(0, (fragmentOffset - totalBufferOffset)), fragmentLength - totalBufferOffset);
                            bufferArrayLength++;
                        }
                        else
                        {
                            // we have not yet reached our fragment point; increment our totalBufferOffset and move to the next buffer.
                        }
                        totalBufferOffset += count[i];

                        // if we have filled our fragment buffer set completely, break out now.
                        if (totalBufferOffset >= fragmentOffset + fragmentLength)
                        {
                            break;
                        }
                    }

                    // send the datagram (or datagram fragment)
                    _ethernetInterface.Send(dstPhysicalAddress, 0x0800 /* dataType: IPV4 */, srcIPAddress, dstIPAddress, bufferArrayLength, _bufferArray, _indexArray, _countArray, timeoutInMachineTicks);

                    fragmentOffset -= MAX_IPV4_DATA_FRAGMENT_SIZE;
                }
            }
        }