2008-11-17 18:29:00 -05:00
|
|
|
// ----------------------------------------------------------------------------
|
2008-03-05 09:52:00 -05:00
|
|
|
//
|
|
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
|
|
//
|
2008-11-17 18:29:00 -05:00
|
|
|
// ----------------------------------------------------------------------------
|
2008-03-05 09:52:00 -05:00
|
|
|
|
2008-11-17 18:29:00 -05:00
|
|
|
///
|
|
|
|
// Microsoft Research, Cambridge
|
|
|
|
//
|
2008-03-05 09:52:00 -05:00
|
|
|
|
|
|
|
using NetStack.Common;
|
|
|
|
using System;
|
|
|
|
using System.Diagnostics;
|
|
|
|
|
|
|
|
using System.Net.IP;
|
|
|
|
using Drivers.Net;
|
|
|
|
|
|
|
|
namespace NetStack.Protocols
|
|
|
|
{
|
2008-11-17 18:29:00 -05:00
|
|
|
///
|
|
|
|
// declarations of an ARP message, RFC 826
|
|
|
|
//
|
2008-03-05 09:52:00 -05:00
|
|
|
public class ArpFormat
|
|
|
|
{
|
|
|
|
// arp operations:
|
|
|
|
public enum Type
|
|
|
|
{
|
|
|
|
ARP_REQUEST = 1,
|
|
|
|
ARP_REPLY = 2
|
|
|
|
}
|
|
|
|
|
|
|
|
// ARP message size (for ethernet and IP only)
|
|
|
|
public const int Size = 28;
|
|
|
|
|
|
|
|
// methods:
|
|
|
|
public static int Write(byte []! pkt,
|
|
|
|
int offset,
|
|
|
|
EthernetAddress srchw,
|
|
|
|
IPv4 srcip,
|
|
|
|
Type operation,
|
|
|
|
EthernetAddress targethw,
|
|
|
|
IPv4 targetip)
|
|
|
|
{
|
|
|
|
int o = offset;
|
|
|
|
|
|
|
|
pkt[o++] = 0x00; pkt[o++] = 0x01; // hardware type = 0x0001
|
|
|
|
pkt[o++] = 0x08; pkt[o++] = 0x00; // protocol type = 0x0800
|
|
|
|
pkt[o++] = 0x06; // hardware addr len (bytes)
|
|
|
|
pkt[o++] = 0x04; // protocol address len (bytes)
|
|
|
|
pkt[o++] = (byte) (((ushort)operation) >> 8);
|
|
|
|
pkt[o++] = (byte) (((ushort)operation) & 0xff);
|
|
|
|
|
|
|
|
srchw.CopyOut(pkt, o);
|
|
|
|
o += EthernetAddress.Length;
|
|
|
|
|
|
|
|
srcip.CopyOut(pkt, o);
|
|
|
|
o += IPv4.Length;
|
|
|
|
|
|
|
|
targethw.CopyOut(pkt, o);
|
|
|
|
o += EthernetAddress.Length;
|
|
|
|
|
|
|
|
targetip.CopyOut(pkt, o);
|
|
|
|
o += IPv4.Length;
|
|
|
|
|
|
|
|
return o;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Parse "pkt" from "start" bytes in,
|
|
|
|
// and return the sender and target Ethernet addresses, and the
|
|
|
|
// sender and target IP addresses, along with the "opcode".
|
|
|
|
// These may be null if the packet wasn't an ARP for 6-byte Ethernet addresses.
|
|
|
|
// Returns the byte offset of the next layer's header.
|
|
|
|
public static bool Read(IBuffer! buf,
|
|
|
|
out Type opcode,
|
|
|
|
out EthernetAddress senderhw,
|
|
|
|
out IPv4 senderip,
|
|
|
|
out EthernetAddress targethw,
|
|
|
|
out IPv4 targetip)
|
|
|
|
{
|
|
|
|
opcode = Type.ARP_REQUEST;
|
|
|
|
senderhw = targethw = EthernetAddress.Zero;
|
|
|
|
senderip = targetip = IPv4.Zero;
|
|
|
|
|
|
|
|
// check hardware type == 0x0001 (Ethernet)
|
|
|
|
ushort hwtype;
|
2008-11-17 18:29:00 -05:00
|
|
|
if (buf.ReadNet16(out hwtype) == false || hwtype != 0x1) {
|
2008-03-05 09:52:00 -05:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// check protocol type == 0x0800 (IP)
|
|
|
|
ushort proto;
|
2008-11-17 18:29:00 -05:00
|
|
|
if (buf.ReadNet16(out proto) == false || proto != 0x0800) {
|
2008-03-05 09:52:00 -05:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// check hardware address len is 6 bytes
|
|
|
|
|
|
|
|
byte hwlen;
|
2008-11-17 18:29:00 -05:00
|
|
|
if (buf.Read8(out hwlen) == false || hwlen != 6) {
|
2008-03-05 09:52:00 -05:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// check IP address len is 4 bytes
|
|
|
|
byte prlen;
|
2008-11-17 18:29:00 -05:00
|
|
|
if (buf.Read8(out prlen) == false || prlen != 4) {
|
2008-03-05 09:52:00 -05:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Read stuff
|
|
|
|
// operation code
|
|
|
|
ushort temp;
|
2008-11-17 18:29:00 -05:00
|
|
|
if (buf.ReadNet16(out temp) == false) {
|
2008-03-05 09:52:00 -05:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
opcode = (Type)temp;
|
|
|
|
|
2008-11-17 18:29:00 -05:00
|
|
|
if (buf.ReadEthernetAddress(out senderhw) == false) {
|
2008-03-05 09:52:00 -05:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint addr;
|
2008-11-17 18:29:00 -05:00
|
|
|
if (buf.ReadNet32(out addr) == false) {
|
2008-03-05 09:52:00 -05:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
senderip = new IPv4(addr);
|
|
|
|
|
|
|
|
// target HW & IP
|
2008-11-17 18:29:00 -05:00
|
|
|
if (buf.ReadEthernetAddress(out targethw) == false) {
|
2008-03-05 09:52:00 -05:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2008-11-17 18:29:00 -05:00
|
|
|
if (buf.ReadNet32(out addr) == false) {
|
2008-03-05 09:52:00 -05:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
targetip = new IPv4(addr);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// creates an arp reply using the received packet
|
|
|
|
// the packet must be an arp request
|
|
|
|
// the responder should pass its own IP and MAC address
|
|
|
|
// we assume that we have the same hw type
|
|
|
|
// (return offset_arp size)
|
|
|
|
public static int CreateArpReply(ref byte[]! pkt,
|
|
|
|
IPv4 selfIP,
|
|
|
|
EthernetAddress selfMACAddr)
|
|
|
|
{
|
|
|
|
int offset = 14; // arp message starts here.
|
|
|
|
int o = offset;
|
|
|
|
|
|
|
|
// check we have enough packet
|
|
|
|
if (pkt.Length - offset < Size)
|
|
|
|
return offset;
|
|
|
|
|
|
|
|
// check hardware type == 0x0001 (Ethernet)
|
|
|
|
if (pkt[o++] != 0x00 || pkt[o++] != 0x01)
|
|
|
|
return offset;
|
|
|
|
|
|
|
|
// check protocol type == 0x0800 (IP)
|
|
|
|
if (pkt[o++] != 0x08 || pkt[o++] != 0x00)
|
|
|
|
return offset; // error
|
|
|
|
|
|
|
|
// check addresses len
|
|
|
|
if (pkt[o++] != 0x06)
|
|
|
|
return offset;
|
|
|
|
|
|
|
|
if (pkt[o++] != 0x04)
|
|
|
|
return offset;
|
|
|
|
|
|
|
|
// operation code
|
|
|
|
Type opcode = (Type)(((int)pkt[o++] << 8) | (int)pkt[o++]);
|
|
|
|
|
|
|
|
// we need a request message.
|
|
|
|
if (opcode != Type.ARP_REQUEST)
|
|
|
|
return offset;
|
|
|
|
|
|
|
|
// sender HW & IP
|
|
|
|
EthernetAddress senderhw = EthernetAddress.ParseBytes(pkt, o);
|
|
|
|
o += EthernetAddress.Length;
|
|
|
|
|
|
|
|
IPv4 senderIP = IPv4.ParseBytes(pkt, o);
|
|
|
|
o += IPv4.Length;
|
|
|
|
|
|
|
|
// target HW & IP
|
|
|
|
// EthernetAddress targethw = EthernetAddress.ParseBytes(pkt, o);
|
|
|
|
o += EthernetAddress.Length;
|
|
|
|
|
|
|
|
// IPv4 targetIP = IPv4.ParseBytes(pkt, o);
|
|
|
|
o += IPv4.Length;
|
|
|
|
|
|
|
|
// all is well, do our stuff...
|
|
|
|
// 1. set local hw address to arp's source ether address + fix dest addresses
|
|
|
|
// 2. set arp type = ARP_REPLY
|
|
|
|
// 3. set the destination's ethernet address to self
|
|
|
|
// and target is the source of the request.
|
|
|
|
|
|
|
|
o = offset+6; // opcode entry
|
|
|
|
pkt[o++] = (byte)(((ushort)Type.ARP_REPLY) >> 8);
|
|
|
|
pkt[o++] = (byte)Type.ARP_REPLY;
|
|
|
|
|
|
|
|
// set hw and IP address
|
|
|
|
selfMACAddr.CopyOut(pkt, o);
|
|
|
|
o += EthernetAddress.Length;
|
|
|
|
|
|
|
|
selfIP.CopyOut(pkt, o);
|
|
|
|
o += IPv4.Length;
|
|
|
|
|
|
|
|
// setup dest address to the requesting host address
|
|
|
|
senderhw.CopyOut(pkt, o);
|
|
|
|
o += EthernetAddress.Length;
|
|
|
|
|
|
|
|
senderIP.CopyOut(pkt, o);
|
|
|
|
o += IPv4.Length;
|
|
|
|
|
|
|
|
// set ethernet level addresses
|
|
|
|
Array.Copy(pkt, 6, pkt, 0, 6); // src -> dest
|
|
|
|
selfMACAddr.CopyOut(pkt, 6); // self -> src
|
|
|
|
|
|
|
|
return offset + Size;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|