NetworkManager/dhcpcd/arp.c
Dan Williams 2ad25b238e 2004-11-15 Dan Williams <dcbw@redhat.com>
Major rework of link detection code.  We now use DHCP
	as part of the link detection which proves to be much more robust,
	and also supports Open System authentication for wireless networks.

	We no longer use external DHCP client programs.  Instead, we use
	our own DHCP client, based on substantially reworked bits of 'dhcpcd'
	which was written by:
		Yoichi Hariguchi <yoichi@fore.com>
		Sergei Viznyuk <sv@phystech.com>
		http://www.phystech.com/download/
	It resides in the "dhcpcd" directory and was refactored into a general
	purpose DHCP client library by me.

	Also misc fixes (CPPFLAGS->AM_CPPFLAGS, move some stuff around),
	move src/backends/NetworkManagerSystem.h -> src/NetworkManagerSystem.h


git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@314 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
2004-11-16 02:41:53 +00:00

229 lines
7.8 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"
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,len=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 = (iface->bTokenRing) ? htons(ARPHRD_IEEE802_TR) : 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 ( iface->bTokenRing )
len = eth2tr (&arp_msg_send.ethhdr, BasicArpLen(ArpMsgSend));
else
len = sizeof (arpMessage);
if ( sendto(iface->sk, &arp_msg_send, len, 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 ( iface->bTokenRing )
{
if ( tr2eth (&arp_msg_recv.ethhdr) )
continue;
}
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;
int len;
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 = (iface->bTokenRing) ? htons(ARPHRD_IEEE802_TR) : 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 ( iface->bTokenRing )
len = eth2tr (&ArpMsgSend.ethhdr, BasicArpLen(ArpMsgSend));
else
len = sizeof (arpMessage);
if ( sendto (iface->sk, &ArpMsgSend, len, 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;
int len;
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 = (iface->bTokenRing) ? htons(ARPHRD_IEEE802_TR) : 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 ( iface->bTokenRing )
len = eth2tr(&ArpMsgSend.ethhdr,BasicArpLen(ArpMsgSend));
else
len = sizeof(arpMessage);
if ( sendto(iface->sk,&ArpMsgSend,len,0, &addr,sizeof(struct sockaddr)) == -1 )
{
syslog(LOG_ERR,"arpInform: sendto: %m\n");
return -1;
}
return 0;
}