NetworkManager/dhcpcd/arp.c
Dan Williams d0c93d3c69 2004-12-05 Dan Williams <dcbw@redhat.com>
* Major rework of the DHCP code, taking some cues from pump.  We don't
		write raw Ethernet packets anymore, which simplifies the code quite
		a bit.  The new code should be more robust, not hang in recvfrom()
		as much, and generally work better.  This also means that we need
		to force HAL/dbus to use a created GMainContext rather than the
		default context, since having the DHCP renew/rebind thread using
		its own GMainContext seemed to give dbus a fit.  There is also more
		debugging information printed from the DHCP loop to help with future
		problems.

	* Also, if the DHCP server doesn't give us the "routersOnSubnet" option,
		assume that the default gateway should be the DHCP server.

	Patch from Matthew Schick <matt oss-institute org>
	* src/backends/NetworkManagerGentoo.c
		- Fix compilation error due to missing "ip4_broadcast"


git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@336 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
2004-12-05 21:28:42 +00:00

217 lines
7.5 KiB
C

/*
* dhcpcd - DHCP client daemon -
* Copyright (C) 1996 - 1997 Yoichi Hariguchi <yoichi@fore.com>
* Copyright (C) January, 1998 Sergei Viznyuk <sv@phystech.com>
*
* dhcpcd is an RFC2131 and RFC1541 compliant DHCP client daemon.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <sys/socket.h>
#include <netinet/in.h>
#include <net/if_arp.h>
#include <string.h>
#include <syslog.h>
#include "client.h"
#include "arp.h"
struct packed_ether_header
{
u_int8_t ether_dhost[ETH_ALEN]; /* destination eth addr */
u_int8_t ether_shost[ETH_ALEN]; /* source ether addr */
u_int16_t ether_type; /* packet type ID field */
} __attribute__((packed));
typedef struct arpMessage
{
struct packed_ether_header ethhdr;
u_short htype; /* hardware type (must be ARPHRD_ETHER) */
u_short ptype; /* protocol type (must be ETHERTYPE_IP) */
u_char hlen; /* hardware address length (must be 6) */
u_char plen; /* protocol address length (must be 4) */
u_short operation; /* ARP opcode */
u_char sHaddr[ETH_ALEN]; /* sender's hardware address */
u_char sInaddr[4]; /* sender's IP address */
u_char tHaddr[ETH_ALEN]; /* target's hardware address */
u_char tInaddr[4]; /* target's IP address */
u_char pad[18]; /* pad for min. Ethernet payload (60 bytes) */
} __attribute__((packed)) arpMessage;
#define BasicArpLen(A) (sizeof(A) - (sizeof(A.ethhdr) + sizeof(A.pad)))
extern int DebugFlag;
int eth2tr(struct packed_ether_header *frame, int datalen);
int tr2eth(struct packed_ether_header *frame);
/*****************************************************************************/
#ifdef ARPCHECK
int arpCheck(const dhcp_interface *iface)
{
arpMessage arp_msg_send;
arpMessage arp_msg_recv;
struct sockaddr addr;
int j,i=0;
memset (&arp_msg_send, 0, sizeof(arpMessage));
memcpy (arp_msg_send.ethhdr.ether_dhost, MAC_BCAST_ADDR, ETH_ALEN);
memcpy (arp_msg_send.ethhdr.ether_shost, iface->chaddr, ETH_ALEN);
arp_msg_send.ethhdr.ether_type = htons(ETHERTYPE_ARP);
arp_msg_send.htype = htons(ARPHRD_ETHER);
arp_msg_send.ptype = htons(ETHERTYPE_IP);
arp_msg_send.hlen = ETH_ALEN;
arp_msg_send.plen = 4;
arp_msg_send.operation = htons(ARPOP_REQUEST);
memcpy (arp_msg_send.sHaddr, iface->chaddr, ETH_ALEN);
memcpy (&arp_msg_send.tInaddr, &(iface->ciaddr), 4);
if ( DebugFlag )
{
syslog(LOG_DEBUG, "broadcasting ARPOP_REQUEST for %u.%u.%u.%u\n",
arp_msg_send.tInaddr[0],arp_msg_send.tInaddr[1],
arp_msg_send.tInaddr[2],arp_msg_send.tInaddr[3]);
}
do
{
do
{
if ( i++ > 4 )
return 0; /* 5 probes */
memset (&addr, 0, sizeof(struct sockaddr));
memcpy (addr.sa_data, iface->iface, strlen (iface->iface));
if ( sendto(iface->sk, &arp_msg_send, sizeof (arpMessage), 0, &addr, sizeof(struct sockaddr)) == -1 )
{
syslog(LOG_ERR,"arpCheck: sendto: %m\n");
return -1;
}
} while ( peekfd(iface->sk,50000) ); /* 50 msec timeout */
do
{
memset (&arp_msg_recv, 0, sizeof(arpMessage));
j = sizeof(struct sockaddr);
if ( recvfrom(iface->sk, &arp_msg_recv, sizeof(arpMessage), 0, (struct sockaddr *)&addr, &j) == -1 )
{
syslog(LOG_ERR,"arpCheck: recvfrom: %m\n");
return -1;
}
if ( arp_msg_recv.ethhdr.ether_type != htons(ETHERTYPE_ARP) )
continue;
if ( arp_msg_recv.operation == htons(ARPOP_REPLY) )
{
if ( DebugFlag )
syslog(LOG_DEBUG, "ARPOP_REPLY received from %u.%u.%u.%u for %u.%u.%u.%u\n",
arp_msg_recv.sInaddr[0],arp_msg_recv.sInaddr[1],
arp_msg_recv.sInaddr[2],arp_msg_recv.sInaddr[3],
arp_msg_recv.tInaddr[0],arp_msg_recv.tInaddr[1],
arp_msg_recv.tInaddr[2],arp_msg_recv.tInaddr[3]);
}
else
continue;
if ( memcmp (arp_msg_recv.tHaddr, iface->chaddr, ETH_ALEN) )
{
if ( DebugFlag )
syslog(LOG_DEBUG,
"target hardware address mismatch: %02X.%02X.%02X.%02X.%02X.%02X received, %02X.%02X.%02X.%02X.%02X.%02X expected\n",
arp_msg_recv.tHaddr[0],arp_msg_recv.tHaddr[1],arp_msg_recv.tHaddr[2],
arp_msg_recv.tHaddr[3],arp_msg_recv.tHaddr[4],arp_msg_recv.tHaddr[5],
iface->chaddr[0],iface->chaddr[1],
iface->chaddr[2],iface->chaddr[3],
iface->chaddr[4],iface->chaddr[5]);
continue;
}
if (memcmp (&arp_msg_recv.sInaddr, &(iface->ciaddr), 4))
{
if ( DebugFlag )
syslog(LOG_DEBUG, "sender IP address mismatch: %u.%u.%u.%u received, %u.%u.%u.%u expected\n",
arp_msg_recv.sInaddr[0],arp_msg_recv.sInaddr[1],arp_msg_recv.sInaddr[2],arp_msg_recv.sInaddr[3],
((unsigned char *)&(iface->ciaddr))[0],
((unsigned char *)&(iface->ciaddr))[1],
((unsigned char *)&(iface->ciaddr))[2],
((unsigned char *)&(iface->ciaddr))[3]);
continue;
}
return 1;
} while ( peekfd(iface->sk,50000) == 0 );
} while ( 1 );
return 0;
}
#endif
/*****************************************************************************/
int arpRelease(const dhcp_interface *iface) /* sends UNARP message, cf. RFC1868 */
{
arpMessage ArpMsgSend;
struct sockaddr addr;
const int inaddr_broadcast = INADDR_BROADCAST;
/* build Ethernet header */
memset (&ArpMsgSend,0,sizeof(arpMessage));
memcpy (ArpMsgSend.ethhdr.ether_dhost, MAC_BCAST_ADDR, ETH_ALEN);
memcpy (ArpMsgSend.ethhdr.ether_shost, iface->chaddr, ETH_ALEN);
ArpMsgSend.ethhdr.ether_type = htons(ETHERTYPE_ARP);
/* build UNARP message */
ArpMsgSend.htype = htons(ARPHRD_ETHER);
ArpMsgSend.ptype = htons(ETHERTYPE_IP);
ArpMsgSend.plen = 4;
ArpMsgSend.operation= htons(ARPOP_REPLY);
memcpy (&ArpMsgSend.sInaddr, &(iface->ciaddr), 4);
memcpy (&ArpMsgSend.tInaddr, &inaddr_broadcast, 4);
memset(&addr,0,sizeof(struct sockaddr));
memcpy(addr.sa_data,iface->iface,strlen (iface->iface));
if ( sendto (iface->sk, &ArpMsgSend, sizeof (arpMessage), 0, &addr, sizeof(struct sockaddr)) == -1 )
{
syslog (LOG_ERR,"arpRelease: sendto: %m\n");
return -1;
}
return 0;
}
/*****************************************************************************/
int arpInform(const dhcp_interface *iface)
{
arpMessage ArpMsgSend;
struct sockaddr addr;
const int inaddr_broadcast = INADDR_BROADCAST;
memset (&ArpMsgSend, 0, sizeof(arpMessage));
memcpy (ArpMsgSend.ethhdr.ether_dhost, MAC_BCAST_ADDR, ETH_ALEN);
memcpy (ArpMsgSend.ethhdr.ether_shost, iface->chaddr, ETH_ALEN);
ArpMsgSend.ethhdr.ether_type = htons(ETHERTYPE_ARP);
ArpMsgSend.htype = htons(ARPHRD_ETHER);
ArpMsgSend.ptype = htons(ETHERTYPE_IP);
ArpMsgSend.hlen = ETH_ALEN;
ArpMsgSend.plen = 4;
ArpMsgSend.operation= htons(ARPOP_REPLY);
memcpy (ArpMsgSend.sHaddr, iface->chaddr, ETH_ALEN);
memcpy (ArpMsgSend.tHaddr, iface->shaddr, ETH_ALEN);
memcpy (ArpMsgSend.sInaddr, &(iface->ciaddr), 4);
memcpy (ArpMsgSend.tInaddr, &inaddr_broadcast, 4);
memset (&addr, 0, sizeof(struct sockaddr));
memcpy (addr.sa_data, iface->iface, strlen (iface->iface));
if ( sendto (iface->sk, &ArpMsgSend, sizeof (arpMessage), 0, &addr, sizeof(struct sockaddr)) == -1 )
{
syslog(LOG_ERR,"arpInform: sendto: %m\n");
return -1;
}
return 0;
}