1c2c66affSColin Finck /*
2c2c66affSColin Finck * ReactOS Win32 Applications
3c2c66affSColin Finck * Copyright (C) 2005 ReactOS Team
4c2c66affSColin Finck *
5c2c66affSColin Finck * This program is free software; you can redistribute it and/or modify
6c2c66affSColin Finck * it under the terms of the GNU General Public License as published by
7c2c66affSColin Finck * the Free Software Foundation; either version 2 of the License, or
8c2c66affSColin Finck * (at your option) any later version.
9c2c66affSColin Finck *
10c2c66affSColin Finck * This program is distributed in the hope that it will be useful,
11c2c66affSColin Finck * but WITHOUT ANY WARRANTY; without even the implied warranty of
12c2c66affSColin Finck * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13c2c66affSColin Finck * GNU General Public License for more details.
14c2c66affSColin Finck *
15c2c66affSColin Finck * You should have received a copy of the GNU General Public License along
16c2c66affSColin Finck * with this program; if not, write to the Free Software Foundation, Inc.,
17c2c66affSColin Finck * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18c2c66affSColin Finck */
19c2c66affSColin Finck
20c2c66affSColin Finck /*
21c2c66affSColin Finck * COPYRIGHT: See COPYING in the top level directory
22c2c66affSColin Finck * PROJECT: ReactOS arp utility
23c2c66affSColin Finck * FILE: base/applications/network/arp/arp.c
24c2c66affSColin Finck * PURPOSE: view and manipulate the ARP cache
25c2c66affSColin Finck * PROGRAMMERS: Ged Murphy (gedmurphy@gmail.com)
26c2c66affSColin Finck * REVISIONS:
27c2c66affSColin Finck * GM 27/06/05 Created
28c2c66affSColin Finck *
29c2c66affSColin Finck */
30c2c66affSColin Finck
31c2c66affSColin Finck #define WIN32_NO_STATUS
32c2c66affSColin Finck #include <stdarg.h>
33c2c66affSColin Finck #include <windef.h>
34c2c66affSColin Finck #include <winbase.h>
35c2c66affSColin Finck #include <stdio.h>
36c2c66affSColin Finck #include <stdlib.h>
37c2c66affSColin Finck #include <tchar.h>
38c2c66affSColin Finck #define _INC_WINDOWS
39c2c66affSColin Finck #include <winsock2.h>
40c2c66affSColin Finck #include <iphlpapi.h>
41c2c66affSColin Finck
42*6623b8d1SEric Kohl #include <arp_msg.h>
43*6623b8d1SEric Kohl
44c2c66affSColin Finck /*
45c2c66affSColin Finck * Globals
46c2c66affSColin Finck */
47c2c66affSColin Finck const char SEPARATOR = '-';
48c2c66affSColin Finck int _CRT_glob = 0; // stop * from listing dir files in arp -d *
49c2c66affSColin Finck
50c2c66affSColin Finck /*
51c2c66affSColin Finck * function declarations
52c2c66affSColin Finck */
53c2c66affSColin Finck DWORD DoFormatMessage(VOID);
54e3106973SEric Kohl DWORD PrintEntries(PMIB_IPNETROW pIpAddRow);
55e3106973SEric Kohl DWORD DisplayArpEntries(PTCHAR pszInetAddr, PTCHAR pszIfAddr);
56e3106973SEric Kohl DWORD Addhost(PTCHAR pszInetAddr, PTCHAR pszEthAddr, PTCHAR pszIfAddr);
57e3106973SEric Kohl DWORD Deletehost(PTCHAR pszInetAddr, PTCHAR pszIfAddr);
58c2c66affSColin Finck VOID Usage(VOID);
59c2c66affSColin Finck
60c2c66affSColin Finck /*
61c2c66affSColin Finck * convert error code into meaningful message
62c2c66affSColin Finck */
DoFormatMessage(VOID)63c2c66affSColin Finck DWORD DoFormatMessage(VOID)
64c2c66affSColin Finck {
65ac01e4cdSEric Kohl LPTSTR lpMsgBuf;
66c2c66affSColin Finck DWORD RetVal;
67c2c66affSColin Finck
68c2c66affSColin Finck DWORD ErrorCode = GetLastError();
69c2c66affSColin Finck
70c2c66affSColin Finck if (ErrorCode != ERROR_SUCCESS)
71c2c66affSColin Finck {
72c2c66affSColin Finck RetVal = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
73c2c66affSColin Finck FORMAT_MESSAGE_FROM_SYSTEM |
74c2c66affSColin Finck FORMAT_MESSAGE_IGNORE_INSERTS,
75c2c66affSColin Finck NULL,
76c2c66affSColin Finck ErrorCode,
77c2c66affSColin Finck MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */
78c2c66affSColin Finck (LPTSTR) &lpMsgBuf,
79c2c66affSColin Finck 0,
80c2c66affSColin Finck NULL );
81c2c66affSColin Finck
82c2c66affSColin Finck if (RetVal != 0)
83c2c66affSColin Finck {
84e3106973SEric Kohl _tprintf(_T("%s"), lpMsgBuf);
85c2c66affSColin Finck LocalFree(lpMsgBuf);
86c2c66affSColin Finck /* return number of TCHAR's stored in output buffer
87c2c66affSColin Finck * excluding '\0' - as FormatMessage does*/
88c2c66affSColin Finck return RetVal;
89c2c66affSColin Finck }
90c2c66affSColin Finck }
91c2c66affSColin Finck return 0;
92c2c66affSColin Finck }
93c2c66affSColin Finck
94ac01e4cdSEric Kohl VOID
PrintMessage(DWORD dwMessage)95ac01e4cdSEric Kohl PrintMessage(
96ac01e4cdSEric Kohl DWORD dwMessage)
97ac01e4cdSEric Kohl {
98ac01e4cdSEric Kohl LPTSTR lpMsgBuf;
99ac01e4cdSEric Kohl DWORD RetVal;
100ac01e4cdSEric Kohl
101ac01e4cdSEric Kohl RetVal = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
102ac01e4cdSEric Kohl FORMAT_MESSAGE_FROM_HMODULE |
103ac01e4cdSEric Kohl FORMAT_MESSAGE_IGNORE_INSERTS,
104ac01e4cdSEric Kohl GetModuleHandleW(NULL),
105ac01e4cdSEric Kohl dwMessage,
106ac01e4cdSEric Kohl LANG_USER_DEFAULT,
107ac01e4cdSEric Kohl (LPTSTR)&lpMsgBuf,
108ac01e4cdSEric Kohl 0,
109ac01e4cdSEric Kohl NULL);
110ac01e4cdSEric Kohl if (RetVal != 0)
111ac01e4cdSEric Kohl {
112e3106973SEric Kohl _tprintf(_T("%s"), lpMsgBuf);
113ac01e4cdSEric Kohl LocalFree(lpMsgBuf);
114ac01e4cdSEric Kohl }
115ac01e4cdSEric Kohl }
116ac01e4cdSEric Kohl
117ac01e4cdSEric Kohl VOID
PrintMessageV(DWORD dwMessage,...)118ac01e4cdSEric Kohl PrintMessageV(
119ac01e4cdSEric Kohl DWORD dwMessage,
120ac01e4cdSEric Kohl ...)
121ac01e4cdSEric Kohl {
122ac01e4cdSEric Kohl LPTSTR lpMsgBuf;
123ac01e4cdSEric Kohl va_list args = NULL;
124ac01e4cdSEric Kohl DWORD RetVal;
125ac01e4cdSEric Kohl
126ac01e4cdSEric Kohl va_start(args, dwMessage);
127ac01e4cdSEric Kohl
128ac01e4cdSEric Kohl RetVal = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_HMODULE,
129ac01e4cdSEric Kohl GetModuleHandleW(NULL),
130ac01e4cdSEric Kohl dwMessage,
131ac01e4cdSEric Kohl LANG_USER_DEFAULT,
132ac01e4cdSEric Kohl (LPTSTR)&lpMsgBuf,
133ac01e4cdSEric Kohl 0,
134ac01e4cdSEric Kohl &args);
135ac01e4cdSEric Kohl va_end(args);
136ac01e4cdSEric Kohl
137ac01e4cdSEric Kohl if (RetVal != 0)
138ac01e4cdSEric Kohl {
139e3106973SEric Kohl _tprintf(_T("%s"), lpMsgBuf);
140ac01e4cdSEric Kohl LocalFree(lpMsgBuf);
141ac01e4cdSEric Kohl }
142ac01e4cdSEric Kohl }
143ac01e4cdSEric Kohl
144c2c66affSColin Finck /*
145c2c66affSColin Finck *
146c2c66affSColin Finck * Takes an ARP entry and prints the IP address,
147c2c66affSColin Finck * the MAC address and the entry type to screen
148c2c66affSColin Finck *
149c2c66affSColin Finck */
PrintEntries(PMIB_IPNETROW pIpAddRow)150e3106973SEric Kohl DWORD PrintEntries(PMIB_IPNETROW pIpAddRow)
151c2c66affSColin Finck {
152c2c66affSColin Finck IN_ADDR inaddr;
153c2c66affSColin Finck TCHAR cMacAddr[20];
154c2c66affSColin Finck
155c2c66affSColin Finck /* print IP addresses */
156c2c66affSColin Finck inaddr.S_un.S_addr = pIpAddRow->dwAddr;
157c2c66affSColin Finck _tprintf(_T(" %-22s"), inet_ntoa(inaddr));
158c2c66affSColin Finck
159c2c66affSColin Finck /* print MAC address */
160c2c66affSColin Finck _stprintf(cMacAddr, _T("%02x-%02x-%02x-%02x-%02x-%02x"),
161c2c66affSColin Finck pIpAddRow->bPhysAddr[0],
162c2c66affSColin Finck pIpAddRow->bPhysAddr[1],
163c2c66affSColin Finck pIpAddRow->bPhysAddr[2],
164c2c66affSColin Finck pIpAddRow->bPhysAddr[3],
165c2c66affSColin Finck pIpAddRow->bPhysAddr[4],
166c2c66affSColin Finck pIpAddRow->bPhysAddr[5]);
167c2c66affSColin Finck _tprintf(_T("%-22s"), cMacAddr);
168c2c66affSColin Finck
169c2c66affSColin Finck /* print cache type */
170c2c66affSColin Finck switch (pIpAddRow->dwType)
171c2c66affSColin Finck {
172ac01e4cdSEric Kohl case MIB_IPNET_TYPE_DYNAMIC:
173*6623b8d1SEric Kohl PrintMessage(MSG_ARP_DYNAMIC);
174c2c66affSColin Finck break;
175ac01e4cdSEric Kohl
176ac01e4cdSEric Kohl case MIB_IPNET_TYPE_STATIC:
177*6623b8d1SEric Kohl PrintMessage(MSG_ARP_STATIC);
178c2c66affSColin Finck break;
179ac01e4cdSEric Kohl
180ac01e4cdSEric Kohl case MIB_IPNET_TYPE_INVALID:
181*6623b8d1SEric Kohl PrintMessage(MSG_ARP_INVALID);
182c2c66affSColin Finck break;
183ac01e4cdSEric Kohl
184ac01e4cdSEric Kohl case MIB_IPNET_TYPE_OTHER:
185*6623b8d1SEric Kohl PrintMessage(MSG_ARP_OTHER);
186c2c66affSColin Finck break;
187c2c66affSColin Finck }
188e3106973SEric Kohl _putts(_T(""));
189e3106973SEric Kohl return NO_ERROR;
190c2c66affSColin Finck }
191c2c66affSColin Finck
192c2c66affSColin Finck /*
193c2c66affSColin Finck *
194c2c66affSColin Finck * Takes optional parameters of an internet address and interface address.
195c2c66affSColin Finck * Retrieve all entries in the ARP cache. If an internet address is
196c2c66affSColin Finck * specified, display the ARP entry relating to that address. If an
197c2c66affSColin Finck * interface address is specified, display all entries relating to
198c2c66affSColin Finck * that interface.
199c2c66affSColin Finck *
200c2c66affSColin Finck */
201c2c66affSColin Finck /* FIXME: allow user to specify an interface address, via pszIfAddr */
DisplayArpEntries(PTCHAR pszInetAddr,PTCHAR pszIfAddr)202e3106973SEric Kohl DWORD DisplayArpEntries(PTCHAR pszInetAddr, PTCHAR pszIfAddr)
203c2c66affSColin Finck {
204592bafd6SEric Kohl DWORD i, k, dwCount;
205c2c66affSColin Finck PMIB_IPNETTABLE pIpNetTable = NULL;
206c2c66affSColin Finck PMIB_IPADDRTABLE pIpAddrTable = NULL;
207c2c66affSColin Finck ULONG Size = 0;
208c2c66affSColin Finck struct in_addr inaddr, inaddr2;
209c2c66affSColin Finck PTCHAR pszIpAddr;
210c2c66affSColin Finck TCHAR szIntIpAddr[20];
211e3106973SEric Kohl DWORD dwError = NO_ERROR;
212c2c66affSColin Finck
213c2c66affSColin Finck /* retrieve the IP-to-physical address mapping table */
214c2c66affSColin Finck
215c2c66affSColin Finck /* get table size */
216c2c66affSColin Finck GetIpNetTable(pIpNetTable, &Size, 0);
217c2c66affSColin Finck
218c2c66affSColin Finck /* allocate memory for ARP address table */
219c2c66affSColin Finck pIpNetTable = (PMIB_IPNETTABLE)HeapAlloc(GetProcessHeap(), 0, Size);
220c2c66affSColin Finck if (pIpNetTable == NULL)
221e3106973SEric Kohl {
222*6623b8d1SEric Kohl PrintMessage(MSG_ARP_NO_MEMORY);
223e3106973SEric Kohl dwError = ERROR_NOT_ENOUGH_MEMORY;
224c2c66affSColin Finck goto cleanup;
225e3106973SEric Kohl }
226c2c66affSColin Finck
227c2c66affSColin Finck ZeroMemory(pIpNetTable, sizeof(*pIpNetTable));
228c2c66affSColin Finck
229e3106973SEric Kohl dwError = GetIpNetTable(pIpNetTable, &Size, TRUE);
230e3106973SEric Kohl if (dwError != NO_ERROR)
231c2c66affSColin Finck {
232592bafd6SEric Kohl _tprintf(_T("GetIpNetTable failed: %lu\n"), dwError);
233c2c66affSColin Finck DoFormatMessage();
234c2c66affSColin Finck goto cleanup;
235c2c66affSColin Finck }
236c2c66affSColin Finck
237c2c66affSColin Finck /* check there are entries in the table */
238c2c66affSColin Finck if (pIpNetTable->dwNumEntries == 0)
239c2c66affSColin Finck {
240*6623b8d1SEric Kohl PrintMessage(MSG_ARP_NO_ENTRIES);
241c2c66affSColin Finck goto cleanup;
242c2c66affSColin Finck }
243c2c66affSColin Finck
244c2c66affSColin Finck /* Retrieve the interface-to-ip address mapping
245c2c66affSColin Finck * table to get the IP address for adapter */
246c2c66affSColin Finck
247c2c66affSColin Finck /* get table size */
248c2c66affSColin Finck Size = 0;
249c2c66affSColin Finck GetIpAddrTable(pIpAddrTable, &Size, 0);
250c2c66affSColin Finck
251592bafd6SEric Kohl pIpAddrTable = (PMIB_IPADDRTABLE)HeapAlloc(GetProcessHeap(), 0, Size);
252c2c66affSColin Finck if (pIpAddrTable == NULL)
253e3106973SEric Kohl {
254*6623b8d1SEric Kohl PrintMessage(MSG_ARP_NO_MEMORY);
255e3106973SEric Kohl dwError = ERROR_NOT_ENOUGH_MEMORY;
256c2c66affSColin Finck goto cleanup;
257e3106973SEric Kohl }
258c2c66affSColin Finck
259c2c66affSColin Finck ZeroMemory(pIpAddrTable, sizeof(*pIpAddrTable));
260c2c66affSColin Finck
261e3106973SEric Kohl dwError = GetIpAddrTable(pIpAddrTable, &Size, TRUE);
262e3106973SEric Kohl if (dwError != NO_ERROR)
263c2c66affSColin Finck {
264e3106973SEric Kohl _tprintf(_T("GetIpAddrTable failed: %lu\n"), dwError);
265c2c66affSColin Finck DoFormatMessage();
266c2c66affSColin Finck goto cleanup;
267c2c66affSColin Finck }
268c2c66affSColin Finck
269c2c66affSColin Finck for (k = 0; k < pIpAddrTable->dwNumEntries; k++)
270c2c66affSColin Finck {
271c2c66affSColin Finck if (pIpNetTable->table[0].dwIndex == pIpAddrTable->table[k].dwIndex)
272c2c66affSColin Finck {
273c2c66affSColin Finck //printf("debug print: pIpAddrTable->table[?].dwIndex = %lx\n", pIpNetTable->table[k].dwIndex);
274c2c66affSColin Finck inaddr2.s_addr = pIpAddrTable->table[k].dwAddr;
275c2c66affSColin Finck pszIpAddr = inet_ntoa(inaddr2);
276c2c66affSColin Finck strcpy(szIntIpAddr, pszIpAddr);
277c2c66affSColin Finck }
278c2c66affSColin Finck }
279c2c66affSColin Finck
280592bafd6SEric Kohl /* Count relevant ARP entries */
281592bafd6SEric Kohl dwCount = 0;
282592bafd6SEric Kohl for (i = 0; i < pIpNetTable->dwNumEntries; i++)
283592bafd6SEric Kohl {
284592bafd6SEric Kohl /* if the user has supplied their own internet address *
285592bafd6SEric Kohl * only count the arp entry which matches that */
286592bafd6SEric Kohl if (pszInetAddr)
287592bafd6SEric Kohl {
288592bafd6SEric Kohl inaddr.S_un.S_addr = pIpNetTable->table[i].dwAddr;
289592bafd6SEric Kohl pszIpAddr = inet_ntoa(inaddr);
290592bafd6SEric Kohl
291592bafd6SEric Kohl /* check if it matches, count it */
292592bafd6SEric Kohl if (strcmp(pszIpAddr, pszInetAddr) == 0)
293592bafd6SEric Kohl dwCount++;
294592bafd6SEric Kohl }
295592bafd6SEric Kohl else
296592bafd6SEric Kohl {
297592bafd6SEric Kohl /* if an address is not supplied, count all entries */
298592bafd6SEric Kohl dwCount++;
299592bafd6SEric Kohl }
300592bafd6SEric Kohl }
301592bafd6SEric Kohl
302592bafd6SEric Kohl /* Print message and leave if there are no relevant ARP entries */
303592bafd6SEric Kohl if (dwCount == 0)
304592bafd6SEric Kohl {
305*6623b8d1SEric Kohl PrintMessage(MSG_ARP_NO_ENTRIES);
306592bafd6SEric Kohl goto cleanup;
307592bafd6SEric Kohl }
308c2c66affSColin Finck
309c2c66affSColin Finck /* print header, including interface IP address and index number */
310*6623b8d1SEric Kohl PrintMessageV(MSG_ARP_INTERFACE, szIntIpAddr, pIpNetTable->table[0].dwIndex);
311c2c66affSColin Finck
312c2c66affSColin Finck /* go through all ARP entries */
313c2c66affSColin Finck for (i = 0; i < pIpNetTable->dwNumEntries; i++)
314c2c66affSColin Finck {
315c2c66affSColin Finck
316c2c66affSColin Finck /* if the user has supplied their own internet address *
317c2c66affSColin Finck * only print the arp entry which matches that */
318c2c66affSColin Finck if (pszInetAddr)
319c2c66affSColin Finck {
320c2c66affSColin Finck inaddr.S_un.S_addr = pIpNetTable->table[i].dwAddr;
321c2c66affSColin Finck pszIpAddr = inet_ntoa(inaddr);
322c2c66affSColin Finck
323c2c66affSColin Finck /* check if it matches, print it */
324c2c66affSColin Finck if (strcmp(pszIpAddr, pszInetAddr) == 0)
325c2c66affSColin Finck PrintEntries(&pIpNetTable->table[i]);
326c2c66affSColin Finck }
327c2c66affSColin Finck else
328c2c66affSColin Finck /* if an address is not supplied, print all entries */
329c2c66affSColin Finck PrintEntries(&pIpNetTable->table[i]);
330c2c66affSColin Finck }
331c2c66affSColin Finck
332c2c66affSColin Finck cleanup:
333c2c66affSColin Finck if (pIpNetTable != NULL)
334c2c66affSColin Finck HeapFree(GetProcessHeap(), 0, pIpNetTable);
335c2c66affSColin Finck if (pIpAddrTable != NULL)
336c2c66affSColin Finck HeapFree(GetProcessHeap(), 0, pIpAddrTable);
337e3106973SEric Kohl
338e3106973SEric Kohl return dwError;
339c2c66affSColin Finck }
340c2c66affSColin Finck
341c2c66affSColin Finck /*
342c2c66affSColin Finck *
343c2c66affSColin Finck * Takes an internet address, a MAC address and an optional interface
344c2c66affSColin Finck * address as arguments and checks their validity.
345c2c66affSColin Finck * Fill out an MIB_IPNETROW structure and insert the data into the
346c2c66affSColin Finck * ARP cache as a static entry.
347c2c66affSColin Finck *
348c2c66affSColin Finck */
Addhost(PTCHAR pszInetAddr,PTCHAR pszEthAddr,PTCHAR pszIfAddr)349e3106973SEric Kohl DWORD Addhost(PTCHAR pszInetAddr, PTCHAR pszEthAddr, PTCHAR pszIfAddr)
350c2c66affSColin Finck {
351c2c66affSColin Finck PMIB_IPNETROW pAddHost = NULL;
352c2c66affSColin Finck PMIB_IPNETTABLE pIpNetTable = NULL;
353c2c66affSColin Finck DWORD dwIpAddr = 0;
354c2c66affSColin Finck ULONG Size = 0;
355c2c66affSColin Finck INT i, val, c;
356e3106973SEric Kohl DWORD dwError = NO_ERROR;
357c2c66affSColin Finck
358c2c66affSColin Finck /* error checking */
359c2c66affSColin Finck
360c2c66affSColin Finck /* check IP address */
361e3106973SEric Kohl if (pszInetAddr == NULL)
362c2c66affSColin Finck {
363c2c66affSColin Finck Usage();
364e3106973SEric Kohl return ERROR_INVALID_PARAMETER;
365e3106973SEric Kohl }
366e3106973SEric Kohl
367e3106973SEric Kohl dwIpAddr = inet_addr(pszInetAddr);
368e3106973SEric Kohl if (dwIpAddr == INADDR_NONE)
369e3106973SEric Kohl {
370*6623b8d1SEric Kohl PrintMessageV(MSG_ARP_BAD_IP_ADDRESS, pszInetAddr);
371e3106973SEric Kohl return ERROR_INVALID_PARAMETER;
372c2c66affSColin Finck }
373c2c66affSColin Finck
374c2c66affSColin Finck /* check MAC address */
375c2c66affSColin Finck if (strlen(pszEthAddr) != 17)
376c2c66affSColin Finck {
377*6623b8d1SEric Kohl PrintMessageV(MSG_ARP_BAD_ARGUMENT, pszEthAddr);
378e3106973SEric Kohl return ERROR_INVALID_PARAMETER;
379c2c66affSColin Finck }
3805ebde713SEric Kohl
381c2c66affSColin Finck for (i = 0; i < 17; i++)
382c2c66affSColin Finck {
383c2c66affSColin Finck if (pszEthAddr[i] == SEPARATOR)
384c2c66affSColin Finck continue;
385c2c66affSColin Finck
386c2c66affSColin Finck if (!isxdigit(pszEthAddr[i]))
387c2c66affSColin Finck {
388*6623b8d1SEric Kohl PrintMessageV(MSG_ARP_BAD_ARGUMENT, pszEthAddr);
389e3106973SEric Kohl return ERROR_INVALID_PARAMETER;
390c2c66affSColin Finck }
391c2c66affSColin Finck }
392c2c66affSColin Finck
393c2c66affSColin Finck /* We need the IpNetTable to get the adapter index */
394c2c66affSColin Finck /* Return required buffer size */
395c2c66affSColin Finck GetIpNetTable(pIpNetTable, &Size, 0);
396c2c66affSColin Finck
397c2c66affSColin Finck /* allocate memory for ARP address table */
398c2c66affSColin Finck pIpNetTable = (PMIB_IPNETTABLE)HeapAlloc(GetProcessHeap(), 0, Size);
399c2c66affSColin Finck if (pIpNetTable == NULL)
400e3106973SEric Kohl {
401*6623b8d1SEric Kohl PrintMessage(MSG_ARP_NO_MEMORY);
402e3106973SEric Kohl dwError = ERROR_NOT_ENOUGH_MEMORY;
403c2c66affSColin Finck goto cleanup;
404e3106973SEric Kohl }
405c2c66affSColin Finck
406c2c66affSColin Finck ZeroMemory(pIpNetTable, sizeof(*pIpNetTable));
407c2c66affSColin Finck
408e3106973SEric Kohl dwError = GetIpNetTable(pIpNetTable, &Size, TRUE);
409e3106973SEric Kohl if (dwError != NO_ERROR)
410c2c66affSColin Finck {
411592bafd6SEric Kohl _tprintf(_T("GetIpNetTable failed: %lu\n"), dwError);
412c2c66affSColin Finck DoFormatMessage();
413c2c66affSColin Finck goto cleanup;
414c2c66affSColin Finck }
415c2c66affSColin Finck
416c2c66affSColin Finck /* reserve memory on heap and zero */
417592bafd6SEric Kohl pAddHost = (PMIB_IPNETROW)HeapAlloc(GetProcessHeap(), 0, sizeof(MIB_IPNETROW));
418c2c66affSColin Finck if (pAddHost == NULL)
419e3106973SEric Kohl {
420*6623b8d1SEric Kohl PrintMessage(MSG_ARP_NO_MEMORY);
421e3106973SEric Kohl dwError = ERROR_NOT_ENOUGH_MEMORY;
422c2c66affSColin Finck goto cleanup;
423e3106973SEric Kohl }
424c2c66affSColin Finck
425c2c66affSColin Finck ZeroMemory(pAddHost, sizeof(MIB_IPNETROW));
426c2c66affSColin Finck
427c2c66affSColin Finck /* set dwIndex field to the index of a local IP address to
428c2c66affSColin Finck * indicate the network on which the ARP entry applies */
429c2c66affSColin Finck if (pszIfAddr)
430c2c66affSColin Finck {
431c2c66affSColin Finck if (sscanf(pszIfAddr, "%lx", &pAddHost->dwIndex) == EOF)
432c2c66affSColin Finck {
433c2c66affSColin Finck goto cleanup;
434c2c66affSColin Finck }
435c2c66affSColin Finck }
436c2c66affSColin Finck else
437c2c66affSColin Finck {
438c2c66affSColin Finck //printf("debug print: pIpNetTable->table[0].dwIndex = %lx\n", pIpNetTable->table[0].dwIndex);
439c2c66affSColin Finck /* needs testing. I get the correct index on my machine, but need others
440c2c66affSColin Finck * to test their card index. Any problems and we can use GetAdaptersInfo instead */
441c2c66affSColin Finck pAddHost->dwIndex = pIpNetTable->table[0].dwIndex;
442c2c66affSColin Finck }
443c2c66affSColin Finck
444c2c66affSColin Finck /* Set MAC address to 6 bytes (typical) */
445c2c66affSColin Finck pAddHost->dwPhysAddrLen = 6;
446c2c66affSColin Finck
447c2c66affSColin Finck
448c2c66affSColin Finck /* Encode bPhysAddr into correct byte array */
449c2c66affSColin Finck for (i = 0; i < 6; i++)
450c2c66affSColin Finck {
451c2c66affSColin Finck val = 0;
452c2c66affSColin Finck c = toupper(pszEthAddr[i * 3]);
453c2c66affSColin Finck c = c - (isdigit(c) ? '0' : ('A' - 10));
454c2c66affSColin Finck val += c;
455c2c66affSColin Finck val = (val << 4);
456c2c66affSColin Finck c = toupper(pszEthAddr[i * 3 + 1]);
457c2c66affSColin Finck c = c - (isdigit(c) ? '0' : ('A' - 10));
458c2c66affSColin Finck val += c;
459c2c66affSColin Finck pAddHost->bPhysAddr[i] = (BYTE)val;
460c2c66affSColin Finck }
461c2c66affSColin Finck
462c2c66affSColin Finck /* copy converted IP address */
463c2c66affSColin Finck pAddHost->dwAddr = dwIpAddr;
464c2c66affSColin Finck
465c2c66affSColin Finck
466c2c66affSColin Finck /* set type to static */
467c2c66affSColin Finck pAddHost->dwType = MIB_IPNET_TYPE_STATIC;
468c2c66affSColin Finck
469c2c66affSColin Finck
470c2c66affSColin Finck /* Add the ARP entry */
471592bafd6SEric Kohl dwError = SetIpNetEntry(pAddHost);
472592bafd6SEric Kohl if (dwError != NO_ERROR)
473c2c66affSColin Finck {
474c2c66affSColin Finck DoFormatMessage();
475c2c66affSColin Finck goto cleanup;
476c2c66affSColin Finck }
477c2c66affSColin Finck
478c2c66affSColin Finck cleanup:
479c2c66affSColin Finck if (pIpNetTable != NULL)
480c2c66affSColin Finck HeapFree(GetProcessHeap(), 0, pIpNetTable);
481c2c66affSColin Finck if (pAddHost != NULL)
482c2c66affSColin Finck HeapFree(GetProcessHeap(), 0, pAddHost);
483e3106973SEric Kohl
484e3106973SEric Kohl return dwError;
485c2c66affSColin Finck }
486c2c66affSColin Finck
487c2c66affSColin Finck /*
488c2c66affSColin Finck *
489c2c66affSColin Finck * Takes an internet address and an optional interface address as
490c2c66affSColin Finck * arguments and checks their validity.
491c2c66affSColin Finck * Add the interface number and IP to an MIB_IPNETROW structure
492c2c66affSColin Finck * and remove the entry from the ARP cache.
493c2c66affSColin Finck *
494c2c66affSColin Finck */
Deletehost(PTCHAR pszInetAddr,PTCHAR pszIfAddr)495e3106973SEric Kohl DWORD Deletehost(PTCHAR pszInetAddr, PTCHAR pszIfAddr)
496c2c66affSColin Finck {
497c2c66affSColin Finck PMIB_IPNETROW pDelHost = NULL;
498c2c66affSColin Finck PMIB_IPNETTABLE pIpNetTable = NULL;
499c2c66affSColin Finck ULONG Size = 0;
500c2c66affSColin Finck DWORD dwIpAddr = 0;
501c2c66affSColin Finck BOOL bFlushTable = FALSE;
502e3106973SEric Kohl DWORD dwError = NO_ERROR;
503c2c66affSColin Finck
504c2c66affSColin Finck /* error checking */
505c2c66affSColin Finck
506c2c66affSColin Finck /* check IP address */
507e3106973SEric Kohl if (pszInetAddr == NULL)
508c2c66affSColin Finck {
509e3106973SEric Kohl Usage();
510e3106973SEric Kohl return ERROR_INVALID_PARAMETER;
511e3106973SEric Kohl }
512e3106973SEric Kohl
513c2c66affSColin Finck /* if wildcard is given, set flag to delete all hosts */
514c2c66affSColin Finck if (strncmp(pszInetAddr, "*", 1) == 0)
515c2c66affSColin Finck {
516e3106973SEric Kohl bFlushTable = TRUE;
517c2c66affSColin Finck }
518c2c66affSColin Finck else
519c2c66affSColin Finck {
520e3106973SEric Kohl dwIpAddr = inet_addr(pszInetAddr);
521e3106973SEric Kohl if (dwIpAddr == INADDR_NONE)
522e3106973SEric Kohl {
523*6623b8d1SEric Kohl PrintMessageV(MSG_ARP_BAD_IP_ADDRESS, pszInetAddr);
524e3106973SEric Kohl return ERROR_INVALID_PARAMETER;
525e3106973SEric Kohl }
526c2c66affSColin Finck }
527c2c66affSColin Finck
528c2c66affSColin Finck /* We need the IpNetTable to get the adapter index */
529c2c66affSColin Finck /* Return required buffer size */
530c2c66affSColin Finck GetIpNetTable(NULL, &Size, 0);
531c2c66affSColin Finck
532c2c66affSColin Finck /* allocate memory for ARP address table */
533c2c66affSColin Finck pIpNetTable = (PMIB_IPNETTABLE) HeapAlloc(GetProcessHeap(), 0, Size);
534c2c66affSColin Finck if (pIpNetTable == NULL)
535e3106973SEric Kohl {
536*6623b8d1SEric Kohl PrintMessage(MSG_ARP_NO_MEMORY);
537e3106973SEric Kohl dwError = ERROR_NOT_ENOUGH_MEMORY;
538c2c66affSColin Finck goto cleanup;
539e3106973SEric Kohl }
540c2c66affSColin Finck
541c2c66affSColin Finck ZeroMemory(pIpNetTable, sizeof(*pIpNetTable));
542c2c66affSColin Finck
543e3106973SEric Kohl dwError = GetIpNetTable(pIpNetTable, &Size, TRUE);
544e3106973SEric Kohl if (dwError != NO_ERROR)
545c2c66affSColin Finck {
546592bafd6SEric Kohl _tprintf(_T("GetIpNetTable failed: %lu\n"), dwError);
547c2c66affSColin Finck DoFormatMessage();
548c2c66affSColin Finck goto cleanup;
549c2c66affSColin Finck }
550c2c66affSColin Finck
551c2c66affSColin Finck /* reserve memory on heap and zero */
552c2c66affSColin Finck pDelHost = (MIB_IPNETROW *)HeapAlloc(GetProcessHeap(), 0, sizeof(MIB_IPNETROW));
553c2c66affSColin Finck if (pDelHost == NULL)
554e3106973SEric Kohl {
555*6623b8d1SEric Kohl PrintMessage(MSG_ARP_NO_MEMORY);
556e3106973SEric Kohl dwError = ERROR_NOT_ENOUGH_MEMORY;
557c2c66affSColin Finck goto cleanup;
558e3106973SEric Kohl }
559c2c66affSColin Finck
560c2c66affSColin Finck ZeroMemory(pDelHost, sizeof(MIB_IPNETROW));
561c2c66affSColin Finck
562c2c66affSColin Finck /* set dwIndex field to the index of a local IP address to
563c2c66affSColin Finck * indicate the network on which the ARP entry applies */
564c2c66affSColin Finck if (pszIfAddr)
565c2c66affSColin Finck {
566c2c66affSColin Finck if (sscanf(pszIfAddr, "%lx", &pDelHost->dwIndex) == EOF)
567c2c66affSColin Finck {
568c2c66affSColin Finck goto cleanup;
569c2c66affSColin Finck }
570c2c66affSColin Finck }
571c2c66affSColin Finck else
572c2c66affSColin Finck {
573c2c66affSColin Finck /* needs testing. I get the correct index on my machine, but need others
574c2c66affSColin Finck * to test their card index. Any problems and we can use GetAdaptersInfo instead */
575c2c66affSColin Finck pDelHost->dwIndex = pIpNetTable->table[0].dwIndex;
576c2c66affSColin Finck }
577c2c66affSColin Finck
578c2c66affSColin Finck if (bFlushTable != FALSE)
579c2c66affSColin Finck {
580c2c66affSColin Finck /* delete arp cache */
581e3106973SEric Kohl dwError = FlushIpNetTable(pDelHost->dwIndex);
582e3106973SEric Kohl if (dwError != NO_ERROR)
583c2c66affSColin Finck {
584c2c66affSColin Finck DoFormatMessage();
585c2c66affSColin Finck goto cleanup;
586c2c66affSColin Finck }
587e3106973SEric Kohl }
588c2c66affSColin Finck else
589c2c66affSColin Finck {
590c2c66affSColin Finck /* copy converted IP address */
591c2c66affSColin Finck pDelHost->dwAddr = dwIpAddr;
592c2c66affSColin Finck
593e3106973SEric Kohl /* Delete the ARP entry */
594e3106973SEric Kohl dwError = DeleteIpNetEntry(pDelHost);
595e3106973SEric Kohl if (dwError != NO_ERROR)
596c2c66affSColin Finck {
597c2c66affSColin Finck DoFormatMessage();
598c2c66affSColin Finck goto cleanup;
599c2c66affSColin Finck }
600e3106973SEric Kohl }
601c2c66affSColin Finck
602c2c66affSColin Finck cleanup:
603c2c66affSColin Finck if (pIpNetTable != NULL)
604c2c66affSColin Finck HeapFree(GetProcessHeap(), 0, pIpNetTable);
605c2c66affSColin Finck if (pDelHost != NULL)
606c2c66affSColin Finck HeapFree(GetProcessHeap(), 0, pDelHost);
607e3106973SEric Kohl
608e3106973SEric Kohl return dwError;
609c2c66affSColin Finck }
610c2c66affSColin Finck
611c2c66affSColin Finck /*
612c2c66affSColin Finck *
613c2c66affSColin Finck * print program usage to screen
614c2c66affSColin Finck *
615c2c66affSColin Finck */
Usage(VOID)616c2c66affSColin Finck VOID Usage(VOID)
617c2c66affSColin Finck {
618*6623b8d1SEric Kohl PrintMessage(MSG_ARP_SYNTAX);
619c2c66affSColin Finck }
620c2c66affSColin Finck
621c2c66affSColin Finck /*
622c2c66affSColin Finck *
623c2c66affSColin Finck * Program entry.
624c2c66affSColin Finck * Parse command line and call the required function
625c2c66affSColin Finck *
626c2c66affSColin Finck */
main(int argc,char * argv[])627c2c66affSColin Finck INT main(int argc, char* argv[])
628c2c66affSColin Finck {
629e3106973SEric Kohl DWORD dwError = NO_ERROR;
630e3106973SEric Kohl
631c2c66affSColin Finck if ((argc < 2) || (argc > 5))
632c2c66affSColin Finck {
633c2c66affSColin Finck Usage();
634c2c66affSColin Finck return EXIT_FAILURE;
635c2c66affSColin Finck }
636c2c66affSColin Finck
637e3106973SEric Kohl if (argv[1][0] != '-')
638c2c66affSColin Finck {
639e3106973SEric Kohl Usage();
640e3106973SEric Kohl return EXIT_SUCCESS;
641e3106973SEric Kohl }
642e3106973SEric Kohl
643c2c66affSColin Finck switch (argv[1][1])
644c2c66affSColin Finck {
645c2c66affSColin Finck case 'a': /* fall through */
646c2c66affSColin Finck case 'g':
647c2c66affSColin Finck if (argc == 2)
648e3106973SEric Kohl dwError = DisplayArpEntries(NULL, NULL);
649c2c66affSColin Finck else if (argc == 3)
650e3106973SEric Kohl dwError = DisplayArpEntries(argv[2], NULL);
651c2c66affSColin Finck else if ((argc == 4) && ((strcmp(argv[2], "-N")) == 0))
652e3106973SEric Kohl dwError = DisplayArpEntries(NULL, argv[3]);
653c2c66affSColin Finck else if ((argc == 5) && ((strcmp(argv[3], "-N")) == 0))
654e3106973SEric Kohl dwError = DisplayArpEntries(argv[2], argv[4]);
655c2c66affSColin Finck else
656c2c66affSColin Finck {
657c2c66affSColin Finck Usage();
658e3106973SEric Kohl dwError = ERROR_INVALID_PARAMETER;
659c2c66affSColin Finck }
660c2c66affSColin Finck break;
661e3106973SEric Kohl
662e3106973SEric Kohl case 'd':
663e3106973SEric Kohl if (argc == 3)
664e3106973SEric Kohl dwError = Deletehost(argv[2], NULL);
665c2c66affSColin Finck else if (argc == 4)
666e3106973SEric Kohl dwError = Deletehost(argv[2], argv[3]);
667c2c66affSColin Finck else
668c2c66affSColin Finck {
669c2c66affSColin Finck Usage();
670e3106973SEric Kohl dwError = ERROR_INVALID_PARAMETER;
671c2c66affSColin Finck }
672c2c66affSColin Finck break;
673e3106973SEric Kohl
674e3106973SEric Kohl case 's':
675e3106973SEric Kohl if (argc == 4)
676e3106973SEric Kohl dwError = Addhost(argv[2], argv[3], NULL);
677c2c66affSColin Finck else if (argc == 5)
678e3106973SEric Kohl dwError = Addhost(argv[2], argv[3], argv[4]);
679c2c66affSColin Finck else
680c2c66affSColin Finck {
681c2c66affSColin Finck Usage();
682e3106973SEric Kohl dwError = ERROR_INVALID_PARAMETER;
683c2c66affSColin Finck }
684c2c66affSColin Finck break;
685e3106973SEric Kohl
686c2c66affSColin Finck default:
687c2c66affSColin Finck Usage();
688e3106973SEric Kohl dwError = ERROR_INVALID_PARAMETER;
689e3106973SEric Kohl break;
690c2c66affSColin Finck }
691c2c66affSColin Finck
692e3106973SEric Kohl return (dwError == NO_ERROR) ? EXIT_SUCCESS : EXIT_FAILURE;
693c2c66affSColin Finck }
694