{ Driver->Net->L3->ARP - Address Resolution Protocol Driver. @author(Kieron Morris ) } unit arp; interface uses tracer, lmemorymanager, util, lists, console, terminal, net, nettypes, netutils, netlog, eth2, ipv4; type PARPCacheRecord = ^TARPCacheRecord; TARPCacheRecord = record MAC : TMACAddress; IP : TIPv4Address; end; procedure register; function IPv4ToMAC(ip : puint8) : puint8; function MACToIIPv4(mac : puint8) : puint8; procedure sendGratuitous; procedure sendRequest(ip : puint8); procedure send(hType : uint16; pType : uint16; op : uint16; p_context : PPacketContext); function resolveIP(ip : puint8) : puint8; implementation var Registered : Boolean = false; Cache : PLinkedListBase; function findCacheRecordByMAC(mac : puint8) : PARPCacheRecord; var i : uint32; r : PARPCacheRecord; begin push_trace('arp.findCacheRecordByMAC'); findCacheRecordByMAC:= nil; if LL_Size(Cache) > 0 then begin for i:=0 to LL_Size(Cache)-1 do begin r:= PARPCacheRecord(LL_Get(Cache, i)); if MACEqual(mac, @r^.MAC[0]) then begin findCacheRecordByMAC:= r; break; end; end; end; end; function findCacheRecordByIP(ip : puint8) : PARPCacheRecord; var i : uint32; r : PARPCacheRecord; begin push_trace('arp.findCacheRecordByIP'); findCacheRecordByIP:= nil; if LL_Size(Cache) > 0 then begin for i:=0 to LL_Size(Cache)-1 do begin r:= PARPCacheRecord(LL_Get(Cache, i)); if IPEqual(ip, @r^.IP[0]) then begin findCacheRecordByIP:= r; break; end; end; end; end; procedure send(hType : uint16; pType : uint16; op : uint16; p_context : PPacketContext); var buf : void; hdr : PARPHeader; hSize, pSize : uint8; begin push_trace('arp.send'); writeToLogLn(' L3: arp.send'); if p_context <> nil then begin buf:= kalloc(sizeof(TARPHeader)); hdr:= PARPHeader(buf); case hType of $1 : hSize:= 6; else hSize:= 0; end; case pType of $0800 : pSize:= 4; else pSize:= 0; end; if (hSize > 0) and (pSize > 0) then begin hdr^.Hardware_Type_Hi:= hType SHR 8; hdr^.Hardware_Type_Lo:= hType AND $FF; hdr^.Protocol_Type_Hi:= pType SHR 8; hdr^.Protocol_Type_Lo:= pType AND $FF; hdr^.Hardware_Address_Length:= hSize; hdr^.Protocol_Address_Length:= pSize; hdr^.Operation_Hi:= op SHR 8; hdr^.Operation_Lo:= op AND $FF; copyMAC(@p_context^.MAC.Source[0], @hdr^.Source_Hardware[0]); //copyMAC(@FORCE_MAC[0], @hdr^.Source_Hardware[0]); copyIPv4(@p_context^.IP.Source[0], @hdr^.Source_Protocol[0]); copyMAC(@p_context^.MAC.Destination[0], @hdr^.Destination_Hardware[0]); copyIPv4(@p_context^.IP.Destination[0], @hdr^.Destination_Protocol[0]); if MACEqual(@p_context^.MAC.Destination[0], @NULL_MAC[0]) then begin CopyMAC(@BROADCAST_MAC[0], @p_context^.MAC.Destination[0]); end; eth2.send(buf, sizeof(TARPHeader), $0806, p_context); end; kfree(buf); end; end; procedure sendGratuitous; var context : PPacketContext; begin context:= newPacketContext; CopyIPv4(@getIPv4Config^.Address[0], @context^.IP.Destination[0]); CopyIPv4(@getIPv4Config^.Address[0], @context^.IP.Source[0]); CopyMAC(GetMAC, @context^.MAC.Source[0]); CopyMAC(@NULL_MAC[0], @context^.MAC.Destination[0]); arp.send($1, $0800, $1, context); freePacketContext(context); end; procedure sendRequestGateway(ip : puint8); var context : PPacketContext; CacheRecord : PARPCacheRecord; begin context:= newPacketContext; CacheRecord:= findCacheRecordByIP(@getIPv4Config^.Gateway[0]); if CacheRecord <> nil then begin CopyMAC(@CacheRecord^.MAC[0], @context^.MAC.Destination[0]); CopyIPv4(ip, @context^.IP.Destination[0]); CopyIPv4(@getIPv4Config^.Address[0], @context^.IP.Source[0]); CopyMAC(GetMAC, @context^.MAC.Source[0]); arp.send($1, $0800, $1, context); end; freePacketContext(context); end; procedure sendRequest(ip : puint8); var context : PPacketContext; CacheRecord : PARPCacheRecord; begin context:= newPacketContext; CopyIPv4(ip, @context^.IP.Destination[0]); CopyIPv4(@getIPv4Config^.Address[0], @context^.IP.Source[0]); CopyMAC(GetMAC, @context^.MAC.Source[0]); CacheRecord:= findCacheRecordByIP(@getIPv4Config^.Gateway[0]); CopyMAC(@NULL_MAC[0], @context^.MAC.Destination[0]); arp.send($1, $0800, $1, context); freePacketContext(context); sendRequestGateway(ip); end; function resolveIP(ip : puint8) : puint8; var CacheRecord : PARPCacheRecord; begin CacheRecord:= findCacheRecordByIP(ip); resolveIP:= nil; if CacheRecord = nil then begin sendRequest(ip); sendRequestGateway(ip); end else begin resolveIP:= @CacheRecord^.MAC[0]; end; end; procedure recv(p_data : void; p_len : uint16; p_context : PPacketContext); var Header : PARPHeader; AHeader : TARPAbstractHeader; CacheElement : PARPCacheRecord; Merge : boolean; context : PPacketContext; begin push_trace('arp.recv'); writeToLogLn(' L3: arp.recv'); console.redrawWindows; { Get our converted Header } Header:= PARPHeader(p_data); AHeader.Hardware_Type:= (Header^.Hardware_Type_Hi SHL 8) + Header^.Hardware_Type_Lo; AHeader.Protocol_Type:= (Header^.Protocol_Type_Hi SHL 8) + Header^.Protocol_Type_Lo; AHeader.Hardware_Address_Length:= Header^.Hardware_Address_Length; AHeader.Protocol_Address_Length:= Header^.Protocol_Address_Length; AHeader.Operation:= (Header^.Operation_Hi SHL 8) + Header^.Operation_Lo; copyMAC(@Header^.Source_Hardware[0], @AHeader.Source_Hardware[0]); copyIPv4(@Header^.Source_Protocol[0], @AHeader.Source_Protocol[0]); copyMAC(@Header^.Destination_Hardware[0], @AHeader.Destination_Hardware[0]); copyIPv4(@Header^.Destination_Protocol[0], @AHeader.Destination_Protocol[0]); { Process ARP Packet } CacheElement:= findCacheRecordByIP(@AHeader.Source_Protocol[0]); if CacheElement = nil then CacheElement:= findCacheRecordByMAC(@AHeader.Source_Hardware[0]); if CacheElement <> nil then begin copyMAC(@AHeader.Source_Hardware[0], @CacheElement^.MAC[0]); copyIPv4(@AHeader.Source_Protocol[0], @CacheElement^.IP[0]); end else begin CacheElement:= PARPCacheRecord(LL_Add(Cache)); CopyMAC(@AHeader.Source_Hardware[0], @CacheElement^.MAC[0]); copyIPv4(@AHeader.Source_Protocol[0], @CacheElement^.IP[0]); end; if IPEqual(@AHeader.Destination_Protocol[0], @getIPv4Config^.Address[0]) then begin case AHeader.Operation of $1:begin { ARP Request } writeToLogLn(' arp.recv.arp.req'); context:= newPacketContext; copyMAC(@AHeader.Source_Hardware[0], @context^.MAC.Destination[0]); copyIPv4(@AHeader.Source_Protocol[0], @context^.IP.Destination[0]); copyMAC(getMAC, @context^.MAC.Source[0]); copyIPv4(@getIPv4Config^.Address[0], @context^.IP.Source[0]); send($1, $0800, $2, context); freePacketContext(context); end; $2:begin { ARP Reply } writeToLogLn(' arp.recv.arp.rep'); end; $3:begin { RARP Request } writeToLogLn(' arp.recv.rarp.req'); end; $4:begin { RARP Reply } writeToLogLn(' arp.recv.rarp.rep'); end; $5:begin { DRARP Request } writeToLogLn(' arp.recv.drarp.req'); end; $6:begin { DRARP Reply } writeToLogLn(' arp.recv.drarp.rep'); end; $7:begin { DRARP Error } writeToLogLn(' arp.recv.drarp.err'); end; $8:begin { InARP Request } writeToLogLn(' arp.recv.inarp.req'); end; $9:begin { InARP Reply } writeToLogLn(' arp.recv.inarp.rep'); end; end; end; end; procedure terminal_command_arp(Params : PParamList); var i : uint32; elm : PARPCacheRecord; sIP : pchar; _IP : puint8; begin if ParamCount(Params) > 0 then begin sIP:= getParam(0, Params); _IP:= stringToIPv4(sIP); sendRequest(_IP); writestringlnWND('ARP Request Sent.', getTerminalHWND); end else begin if LL_Size(Cache) > 0 then begin writestringlnWND('MAC IPv4', getTerminalHWND); For i:=0 to LL_Size(Cache)-1 do begin elm:= PARPCacheRecord(LL_Get(Cache, i)); writeMACAddressEx(@elm^.MAC[0], getTerminalHWND); writestringWND(' ', getTerminalHWND); writeIPv4AddressEx(@elm^.IP[0], getTerminalHWND); writestringlnWND(' ', getTerminalHWND); end; end else begin writestringlnWND('No entries in ARP table.', getTerminalHWND); end; end; end; procedure register; begin push_trace('arp.register'); if not Registered then begin Cache:= LL_New(sizeof(TARPCacheRecord)); eth2.registerTypePromisc($0806, @recv); terminal.registerCommand('ARP', @terminal_command_arp, 'Get ARP Table.'); Registered:= true; end; pop_trace; end; function IPv4ToMAC(ip : puint8) : puint8; var r : PARPCacheRecord; begin push_trace('arp.IPv4ToMAC'); register; IPv4ToMAC:= nil; r:= findCacheRecordByIP(ip); if r <> nil then begin IPv4ToMAC:= @r^.MAC[0]; end; pop_trace; end; function MACToIIPv4(mac : puint8) : puint8; var r : PARPCacheRecord; begin push_trace('arp.MACToIPv4'); register; MACToIIPv4:= nil; r:= findCacheRecordByMAC(mac); if r <> nil then begin MACToIIPv4:= @r^.IP[0]; end; pop_trace; end; end.