diff --git a/ChangeLog b/ChangeLog index 8f7eaed5b..cf72ea171 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,22 @@ +2004-12-05 Dan Williams + + * 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 + * src/backends/NetworkManagerGentoo.c + - Fix compilation error due to missing "ip4_broadcast" + 2004-12-03 Dan Williams * initscript/Makefile.am diff --git a/dhcpcd/Makefile.am b/dhcpcd/Makefile.am index 2bc2a17cc..4d44c8310 100644 --- a/dhcpcd/Makefile.am +++ b/dhcpcd/Makefile.am @@ -8,8 +8,6 @@ AM_CPPFLAGS = \ noinst_LIBRARIES = libdhcpc.a libdhcpc_a_SOURCES= \ - udpipgen.c \ - udpipgen.h \ buildmsg.c \ buildmsg.h \ arp.c \ diff --git a/dhcpcd/arp.c b/dhcpcd/arp.c index f33e0ddc8..d21783c1e 100644 --- a/dhcpcd/arp.c +++ b/dhcpcd/arp.c @@ -28,6 +28,13 @@ #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; @@ -57,14 +64,14 @@ int arpCheck(const dhcp_interface *iface) arpMessage arp_msg_send; arpMessage arp_msg_recv; struct sockaddr addr; - int j,i=0,len=0; + 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 = (iface->bTokenRing) ? htons(ARPHRD_IEEE802_TR) : htons(ARPHRD_ETHER); + 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; @@ -87,11 +94,7 @@ int arpCheck(const dhcp_interface *iface) 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 ) + if ( sendto(iface->sk, &arp_msg_send, sizeof (arpMessage), 0, &addr, sizeof(struct sockaddr)) == -1 ) { syslog(LOG_ERR,"arpCheck: sendto: %m\n"); return -1; @@ -107,11 +110,6 @@ int arpCheck(const dhcp_interface *iface) 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; @@ -161,7 +159,6 @@ 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 */ @@ -171,7 +168,7 @@ int arpRelease(const dhcp_interface *iface) /* sends UNARP message, cf. RFC1868 ArpMsgSend.ethhdr.ether_type = htons(ETHERTYPE_ARP); /* build UNARP message */ - ArpMsgSend.htype = (iface->bTokenRing) ? htons(ARPHRD_IEEE802_TR) : htons(ARPHRD_ETHER); + ArpMsgSend.htype = htons(ARPHRD_ETHER); ArpMsgSend.ptype = htons(ETHERTYPE_IP); ArpMsgSend.plen = 4; ArpMsgSend.operation= htons(ARPOP_REPLY); @@ -180,11 +177,7 @@ int arpRelease(const dhcp_interface *iface) /* sends UNARP message, cf. RFC1868 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 ) + if ( sendto (iface->sk, &ArpMsgSend, sizeof (arpMessage), 0, &addr, sizeof(struct sockaddr)) == -1 ) { syslog (LOG_ERR,"arpRelease: sendto: %m\n"); return -1; @@ -196,7 +189,6 @@ int arpInform(const dhcp_interface *iface) { arpMessage ArpMsgSend; struct sockaddr addr; - int len; const int inaddr_broadcast = INADDR_BROADCAST; memset (&ArpMsgSend, 0, sizeof(arpMessage)); @@ -204,7 +196,7 @@ int arpInform(const dhcp_interface *iface) 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.htype = htons(ARPHRD_ETHER); ArpMsgSend.ptype = htons(ETHERTYPE_IP); ArpMsgSend.hlen = ETH_ALEN; ArpMsgSend.plen = 4; @@ -216,11 +208,7 @@ int arpInform(const dhcp_interface *iface) 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 ) + if ( sendto (iface->sk, &ArpMsgSend, sizeof (arpMessage), 0, &addr, sizeof(struct sockaddr)) == -1 ) { syslog(LOG_ERR,"arpInform: sendto: %m\n"); return -1; diff --git a/dhcpcd/buildmsg.c b/dhcpcd/buildmsg.c index 59001ecf5..7ccaa22e6 100644 --- a/dhcpcd/buildmsg.c +++ b/dhcpcd/buildmsg.c @@ -20,36 +20,28 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include #include #include #include #include #include "client.h" #include "buildmsg.h" -#include "udpipgen.h" - -#include extern int DebugFlag; /*****************************************************************************/ -void fill_common_fields (dhcp_interface *iface, udpipMessage *msg, unsigned char dhost_addr[6], int bcast_rep) +void fill_common_fields (dhcp_interface *iface, dhcpMessage *dhcp_msg, int bcast_resp) { - dhcpMessage *dhcp_msg = (dhcpMessage *)&(msg->udpipmsg[sizeof(udpiphdr)]); - int magic_cookie = htonl (MAGIC_COOKIE); - - /* build Ethernet header */ - memcpy (msg->ethhdr.ether_dhost, dhost_addr, ETH_ALEN); - memcpy (msg->ethhdr.ether_shost, iface->chaddr, ETH_ALEN); - msg->ethhdr.ether_type = htons (ETHERTYPE_IP); + int magic_cookie = htonl (MAGIC_COOKIE); dhcp_msg->op = DHCP_BOOTREQUEST; - dhcp_msg->htype = (iface->bTokenRing) ? ARPHRD_IEEE802_TR : ARPHRD_ETHER; + dhcp_msg->htype = ARPHRD_ETHER; dhcp_msg->hlen = ETH_ALEN; dhcp_msg->xid = iface->xid; - dhcp_msg->secs = htons(10); + dhcp_msg->secs = htons (10); - if ( bcast_rep && iface->client_options->do_broadcast_response ) + if ( bcast_resp && iface->client_options->do_broadcast_response ) dhcp_msg->flags = htons (BROADCAST_FLAG); memcpy (dhcp_msg->chaddr, iface->chaddr, ETH_ALEN); @@ -134,7 +126,7 @@ unsigned char *fill_server_id (unsigned int *server_id, unsigned char *p) /*****************************************************************************/ unsigned char *fill_message_type (unsigned char request, unsigned char *p) { - const unsigned short dhcpMsgSize = htons(sizeof(dhcpMessage)); + const unsigned short dhcpMsgSize = htons (sizeof (dhcpMessage)); *p++ = dhcpMessageType; *p++ = 1; @@ -145,16 +137,27 @@ unsigned char *fill_message_type (unsigned char request, unsigned char *p) p += 2; return p; } - /*****************************************************************************/ -udpipMessage *buildDhcpDiscover(dhcp_interface *iface) +void construct_dest_address (struct sockaddr_in *dest_addr, unsigned int in_addr) { - udpipMessage *udp_msg = calloc (1, sizeof (udpipMessage)); - dhcpMessage *dhcp_msg = (dhcpMessage *)&(udp_msg->udpipmsg[sizeof(udpiphdr)]); + if (!dest_addr) + return; + + memset (dest_addr, 0, sizeof (struct sockaddr_in)); + dest_addr->sin_family = AF_INET; + dest_addr->sin_port = htons (DHCP_SERVER_PORT); + memcpy (&dest_addr->sin_addr, &in_addr, sizeof (dest_addr->sin_addr)); +} +/*****************************************************************************/ +dhcpMessage *build_dhcp_discover (dhcp_interface *iface, int *msg_len, struct sockaddr_in *dest_addr) +{ + dhcpMessage *dhcp_msg = calloc (1, sizeof (dhcpMessage)); register unsigned char *p = dhcp_msg->options + 4; unsigned int lease_time = htonl (iface->default_lease_time); - fill_common_fields (iface, udp_msg, MAC_BCAST_ADDR, 1); + construct_dest_address (dest_addr, IP_BCAST_ADDR); + + fill_common_fields (iface, dhcp_msg, 1); p = fill_message_type (DHCP_DISCOVER, p); if ( iface->ciaddr ) { @@ -168,19 +171,18 @@ udpipMessage *buildDhcpDiscover(dhcp_interface *iface) p = fill_host_and_class_id (iface, p); *p = endOption; - /* build UDP/IP header */ - udpipgen ((udpiphdr *)(udp_msg->udpipmsg), 0, INADDR_BROADCAST, &iface->ip_id); - - return (udp_msg); + *msg_len = (char *)(++p) - (char *)dhcp_msg; + return (dhcp_msg); } /*****************************************************************************/ -udpipMessage *buildDhcpRequest(dhcp_interface *iface) +dhcpMessage *build_dhcp_request (dhcp_interface *iface, int *msg_len, struct sockaddr_in *dest_addr) { - udpipMessage *udp_msg = calloc (1, sizeof (udpipMessage)); - dhcpMessage *dhcp_msg = (dhcpMessage *)&(udp_msg->udpipmsg[sizeof(udpiphdr)]); + dhcpMessage *dhcp_msg = calloc (1, sizeof (dhcpMessage)); register unsigned char *p = dhcp_msg->options + 4; + + construct_dest_address (dest_addr, IP_BCAST_ADDR); - fill_common_fields (iface, udp_msg, MAC_BCAST_ADDR, 1); + fill_common_fields (iface, dhcp_msg, 1); p = fill_message_type (DHCP_REQUEST, p); p = fill_server_id (iface->dhcp_options.val[dhcpServerIdentifier], p); if ( iface->client_options->do_rfc1541 ) @@ -193,19 +195,18 @@ udpipMessage *buildDhcpRequest(dhcp_interface *iface) p = fill_host_and_class_id (iface, p); *p = endOption; - /* build UDP/IP header */ - udpipgen ((udpiphdr *)(udp_msg->udpipmsg), 0, INADDR_BROADCAST, &iface->ip_id); - - return udp_msg; + *msg_len = (char *)(++p) - (char *)dhcp_msg; + return (dhcp_msg); } /*****************************************************************************/ -udpipMessage *buildDhcpRenew(dhcp_interface *iface) +dhcpMessage *build_dhcp_renew (dhcp_interface *iface, int *msg_len, struct sockaddr_in *dest_addr) { - udpipMessage *udp_msg = calloc (1, sizeof (udpipMessage)); - dhcpMessage *dhcp_msg = (dhcpMessage *)&(udp_msg->udpipmsg[sizeof(udpiphdr)]); + dhcpMessage *dhcp_msg = calloc (1, sizeof (dhcpMessage)); register unsigned char *p = dhcp_msg->options + 4; - fill_common_fields (iface, udp_msg, iface->shaddr, 1); + construct_dest_address (dest_addr, iface->siaddr); + + fill_common_fields (iface, dhcp_msg, 1); dhcp_msg->ciaddr = iface->ciaddr; p = fill_message_type (DHCP_REQUEST, p); #if 0 @@ -216,18 +217,18 @@ udpipMessage *buildDhcpRenew(dhcp_interface *iface) p = fill_host_and_class_id (iface, p); *p = endOption; - udpipgen ((udpiphdr *)(udp_msg->udpipmsg), iface->ciaddr, iface->siaddr, &iface->ip_id); - - return (udp_msg); + *msg_len = (char *)(++p) - (char *)dhcp_msg; + return (dhcp_msg); } /*****************************************************************************/ -udpipMessage *buildDhcpRebind(dhcp_interface *iface) +dhcpMessage *build_dhcp_rebind (dhcp_interface *iface, int *msg_len, struct sockaddr_in *dest_addr) { - udpipMessage *udp_msg = calloc (1, sizeof (udpipMessage)); - dhcpMessage *dhcp_msg = (dhcpMessage *)&(udp_msg->udpipmsg[sizeof(udpiphdr)]); + dhcpMessage *dhcp_msg = calloc (1, sizeof (dhcpMessage)); register unsigned char *p = dhcp_msg->options + 4; - fill_common_fields (iface, udp_msg, MAC_BCAST_ADDR, 1); + construct_dest_address (dest_addr, IP_BCAST_ADDR); + + fill_common_fields (iface, dhcp_msg, 1); dhcp_msg->ciaddr = iface->ciaddr; p = fill_message_type (DHCP_REQUEST, p); if ( iface->dhcp_options.val[dhcpIPaddrLeaseTime] ) @@ -236,19 +237,19 @@ udpipMessage *buildDhcpRebind(dhcp_interface *iface) p = fill_host_and_class_id (iface, p); *p = endOption; - udpipgen ((udpiphdr *)(udp_msg->udpipmsg), iface->ciaddr, INADDR_BROADCAST, &iface->ip_id); - - return udp_msg; + *msg_len = (char *)(++p) - (char *)dhcp_msg; + return (dhcp_msg); } /*****************************************************************************/ -udpipMessage *buildDhcpReboot(dhcp_interface *iface) +dhcpMessage *build_dhcp_reboot (dhcp_interface *iface, int *msg_len, struct sockaddr_in *dest_addr) { - udpipMessage *udp_msg = calloc (1, sizeof (udpipMessage)); - dhcpMessage *dhcp_msg = (dhcpMessage *)&(udp_msg->udpipmsg[sizeof(udpiphdr)]); + dhcpMessage *dhcp_msg = calloc (1, sizeof (dhcpMessage)); register unsigned char *p = dhcp_msg->options + 4; unsigned int lease_time = htonl (iface->default_lease_time); - fill_common_fields (iface, udp_msg, MAC_BCAST_ADDR, 1); + construct_dest_address (dest_addr, IP_BCAST_ADDR); + + fill_common_fields (iface, dhcp_msg, 1); p = fill_message_type (DHCP_REQUEST, p); if ( iface->client_options->do_rfc1541 ) dhcp_msg->ciaddr = iface->ciaddr; @@ -259,18 +260,18 @@ udpipMessage *buildDhcpReboot(dhcp_interface *iface) p = fill_host_and_class_id (iface, p); *p = endOption; - udpipgen ((udpiphdr *)(udp_msg->udpipmsg), 0, INADDR_BROADCAST, &iface->ip_id); - - return (udp_msg); + *msg_len = (char *)(++p) - (char *)dhcp_msg; + return (dhcp_msg); } /*****************************************************************************/ -udpipMessage *buildDhcpRelease(dhcp_interface *iface) +dhcpMessage *build_dhcp_release (dhcp_interface *iface, int *msg_len, struct sockaddr_in *dest_addr) { - udpipMessage *udp_msg = calloc (1, sizeof (udpipMessage)); - dhcpMessage *dhcp_msg = (dhcpMessage *)&(udp_msg->udpipmsg[sizeof(udpiphdr)]); + dhcpMessage *dhcp_msg = calloc (1, sizeof (dhcpMessage)); register unsigned char *p = dhcp_msg->options + 4; - fill_common_fields (iface, udp_msg, iface->shaddr, 1); + construct_dest_address (dest_addr, iface->siaddr); + + fill_common_fields (iface, dhcp_msg, 1); dhcp_msg->ciaddr = iface->ciaddr; *p++ = dhcpMessageType; *p++ = 1; @@ -280,19 +281,19 @@ udpipMessage *buildDhcpRelease(dhcp_interface *iface) p += iface->cli_id_len; *p = endOption; - udpipgen ((udpiphdr *)(udp_msg->udpipmsg), iface->ciaddr, iface->siaddr, &iface->ip_id); - - return (udp_msg); + *msg_len = (char *)(++p) - (char *)dhcp_msg; + return (dhcp_msg); } /*****************************************************************************/ #ifdef ARPCHECK -udpipMessage *buildDhcpDecline(dhcp_interface *iface) +dhcpMessage *build_dhcp_decline (dhcp_interface *iface, int *msg_len, struct sockaddr_in *dest_addr) { - udpipMessage *udp_msg = calloc (1, sizeof (udpipMessage)); - dhcpMessage *dhcp_msg = (dhcpMessage *)&(udp_msg->udpipmsg[sizeof(udpiphdr)]); + dhcpMessage *dhcp_msg = calloc (1, sizeof (dhcpMessage)); register unsigned char *p = dhcp_msg->options + 4; - fill_common_fields (iface, udp_msg, iface->shaddr, 1); + construct_dest_address (dest_addr, iface->siaddr); + + fill_common_fields (iface, udp_msg, 1); *p++ = dhcpMessageType; *p++ = 1; *p++ = DHCP_DECLINE; @@ -305,26 +306,25 @@ udpipMessage *buildDhcpDecline(dhcp_interface *iface) p += iface->cli_id_len; *p = endOption; - udpipgen ((udpiphdr *)(udp_msg->udpipmsg), 0, iface->siaddr, &iface->ip_id); - - return (udp_msg); + *msg_len = (char *)(++p) - (char *)dhcp_msg; + return (dhcp_msg); } #endif /*****************************************************************************/ -udpipMessage *buildDhcpInform(dhcp_interface *iface) +dhcpMessage *build_dhcp_inform (dhcp_interface *iface, int *msg_len, struct sockaddr_in *dest_addr) { - udpipMessage *udp_msg = calloc (1, sizeof (udpipMessage)); - dhcpMessage *dhcp_msg = (dhcpMessage *)&(udp_msg->udpipmsg[sizeof(udpiphdr)]); + dhcpMessage *dhcp_msg = calloc (1, sizeof (dhcpMessage)); register unsigned char *p = dhcp_msg->options + 4; - fill_common_fields (iface, udp_msg, iface->shaddr, 1); + construct_dest_address (dest_addr, IP_BCAST_ADDR); + + fill_common_fields (iface, dhcp_msg, 1); dhcp_msg->ciaddr = iface->ciaddr; p = fill_message_type (DHCP_INFORM, p); p = fill_param_request (p); p = fill_host_and_class_id (iface, p); *p = endOption; - udpipgen((udpiphdr *)(udp_msg->udpipmsg), 0, INADDR_BROADCAST, &iface->ip_id); - - return (udp_msg); + *msg_len = (char *)(++p) - (char *)dhcp_msg; + return (dhcp_msg); } diff --git a/dhcpcd/buildmsg.h b/dhcpcd/buildmsg.h index 96c030073..ea314452a 100644 --- a/dhcpcd/buildmsg.h +++ b/dhcpcd/buildmsg.h @@ -23,13 +23,15 @@ #ifndef BUILDMSG_H #define BUILDMSG_H -udpipMessage *buildDhcpDiscover(dhcp_interface *iface); -udpipMessage *buildDhcpRequest(dhcp_interface *iface); -udpipMessage *buildDhcpRenew(dhcp_interface *iface); -udpipMessage *buildDhcpRebind(dhcp_interface *iface); -udpipMessage *buildDhcpReboot(dhcp_interface *iface); -udpipMessage *buildDhcpRelease(dhcp_interface *iface); -udpipMessage *buildDhcpDecline(dhcp_interface *iface); -udpipMessage *buildDhcpInform(dhcp_interface *iface); +dhcpMessage *build_dhcp_discover (dhcp_interface *iface, int *msg_len, struct sockaddr_in *dest_addr); +dhcpMessage *build_dhcp_request (dhcp_interface *iface, int *msg_len, struct sockaddr_in *dest_addr); +dhcpMessage *build_dhcp_renew (dhcp_interface *iface, int *msg_len, struct sockaddr_in *dest_addr); +dhcpMessage *build_dhcp_rebind (dhcp_interface *iface, int *msg_len, struct sockaddr_in *dest_addr); +dhcpMessage *build_dhcp_reboot (dhcp_interface *iface, int *msg_len, struct sockaddr_in *dest_addr); +dhcpMessage *build_dhcp_release (dhcp_interface *iface, int *msg_len, struct sockaddr_in *dest_addr); +#ifdef ARPCHECK +dhcpMessage *build_dhcp_decline (dhcp_interface *iface, int *msg_len, struct sockaddr_in *dest_addr); +#endif +dhcpMessage *build_dhcp_inform (dhcp_interface *iface, int *msg_len, struct sockaddr_in *dest_addr); #endif diff --git a/dhcpcd/client.c b/dhcpcd/client.c index 5f79da98d..6c3552361 100644 --- a/dhcpcd/client.c +++ b/dhcpcd/client.c @@ -30,6 +30,10 @@ #include #include #include +#include +#include +#include +#include #include #include #include @@ -41,21 +45,26 @@ #include #include "client.h" #include "buildmsg.h" -#include "udpipgen.h" #include "arp.h" int DebugFlag = 1; #define DEBUG -void debug_dump_dhcp_options (udpipMessage *udp_msg, dhcpOptions *options); +typedef struct dhcp_response_return +{ + unsigned int server_ip_addr; + char server_hw_addr[ETH_ALEN]; + dhcpMessage dhcp_msg; +} dhcp_response_return; + + +void debug_dump_dhcp_options (struct sockaddr_ll *saddr, dhcpMessage *dhcp_msg, dhcpOptions *options); /*****************************************************************************/ -int parseDhcpMsgRecv(udpipMessage *udp_msg, dhcpOptions *options) /* this routine parses dhcp message received */ +int parse_dhcp_reply (struct iphdr *iphdr, struct sockaddr_ll *saddr, dhcpMessage *dhcp_msg, dhcpOptions *options) { - const struct ip *ip_msg = (struct ip *)((struct udpiphdr *)udp_msg->udpipmsg)->ip; - dhcpMessage *dhcp_msg = (dhcpMessage *)&(udp_msg->udpipmsg[sizeof(udpiphdr)]); register u_char *p = dhcp_msg->options+4; - unsigned char *end = dhcp_msg->options + sizeof(dhcp_msg->options); + unsigned char *end = dhcp_msg->options + sizeof (dhcp_msg->options); /* Force T1 and T2 to 0: either new values will be in message, or they will need to be recalculated from lease time */ @@ -96,47 +105,45 @@ int parseDhcpMsgRecv(udpipMessage *udp_msg, dhcpOptions *options) /* this routin swend: #ifdef DEBUG - debug_dump_dhcp_options (udp_msg, options); + debug_dump_dhcp_options (saddr, dhcp_msg, options); #endif #if 0 - if ( ! dhcp_msg->yiaddr ) + if ( !dhcp_msg->yiaddr ) dhcp_msg->yiaddr = DhcpMsgSend->ciaddr; #endif - if ( ! options->val[dhcpServerIdentifier] ) /* did not get dhcpServerIdentifier */ + if (!options->val[dhcpServerIdentifier]) /* did not get dhcpServerIdentifier */ { /* make it the same as IP address of the sender */ - options->val[dhcpServerIdentifier] = malloc(4); - memcpy (options->val[dhcpServerIdentifier], &ip_msg->ip_src.s_addr, 4); + options->val[dhcpServerIdentifier] = malloc (4); + memcpy (options->val[dhcpServerIdentifier], &(iphdr->saddr), 4); options->len[dhcpServerIdentifier] = 4; options->num++; - if ( DebugFlag ) - syslog(LOG_DEBUG, "dhcpServerIdentifier option is missing in DHCP server response. Assuming %u.%u.%u.%u\n", + if (DebugFlag) + syslog (LOG_DEBUG, "dhcpServerIdentifier option is missing in DHCP server response. Assuming %u.%u.%u.%u\n", ((unsigned char *)options->val[dhcpServerIdentifier])[0], ((unsigned char *)options->val[dhcpServerIdentifier])[1], ((unsigned char *)options->val[dhcpServerIdentifier])[2], ((unsigned char *)options->val[dhcpServerIdentifier])[3]); } - if ( ! options->val[dns] ) /* did not get DNS */ + if (!options->val[dns]) /* did not get DNS */ { /* make it the same as dhcpServerIdentifier */ - options->val[dns] = malloc(4); + options->val[dns] = malloc (4); memcpy (options->val[dns], options->val[dhcpServerIdentifier], 4); options->len[dns] = 4; options->num++; if ( DebugFlag ) - syslog(LOG_DEBUG, "dns option is missing in DHCP server response. Assuming %u.%u.%u.%u\n", - ((unsigned char *)options->val[dns])[0], - ((unsigned char *)options->val[dns])[1], - ((unsigned char *)options->val[dns])[2], - ((unsigned char *)options->val[dns])[3]); + syslog (LOG_DEBUG, "dns option is missing in DHCP server response. Assuming %u.%u.%u.%u\n", + ((unsigned char *)options->val[dns])[0], ((unsigned char *)options->val[dns])[1], + ((unsigned char *)options->val[dns])[2], ((unsigned char *)options->val[dns])[3]); } - if ( ! options->val[subnetMask] ) /* did not get subnetMask */ + if (!options->val[subnetMask]) /* did not get subnetMask */ { - options->val[subnetMask] = malloc(4); + options->val[subnetMask] = malloc (4); ((unsigned char *)options->val[subnetMask])[0] = 255; - if ( IN_CLASSA(ntohl(dhcp_msg->yiaddr)) ) + if (IN_CLASSA (ntohl (dhcp_msg->yiaddr))) { ((unsigned char *)options->val[subnetMask])[1] = 0; /* class A */ ((unsigned char *)options->val[subnetMask])[2] = 0; @@ -145,7 +152,7 @@ swend: else { ((unsigned char *)options->val[subnetMask])[1] = 255; - if ( IN_CLASSB(ntohl(dhcp_msg->yiaddr)) ) + if (IN_CLASSB (ntohl (dhcp_msg->yiaddr))) { ((unsigned char *)(options->val[subnetMask]))[2] = 0;/* class B */ ((unsigned char *)(options->val[subnetMask]))[3] = 0; @@ -153,7 +160,7 @@ swend: else { ((unsigned char *)options->val[subnetMask])[2] = 255; - if ( IN_CLASSC(ntohl(dhcp_msg->yiaddr)) ) + if (IN_CLASSC (ntohl (dhcp_msg->yiaddr))) ((unsigned char *)options->val[subnetMask])[3] = 0; /* class C */ else ((unsigned char *)options->val[subnetMask])[3] = 255; @@ -161,59 +168,51 @@ swend: } options->len[subnetMask] = 4; options->num++; - if ( DebugFlag ) - syslog(LOG_DEBUG, "subnetMask option is missing in DHCP server response. Assuming %u.%u.%u.%u\n", - ((unsigned char *)options->val[subnetMask])[0], - ((unsigned char *)options->val[subnetMask])[1], - ((unsigned char *)options->val[subnetMask])[2], - ((unsigned char *)options->val[subnetMask])[3]); + if (DebugFlag) + syslog (LOG_DEBUG, "subnetMask option is missing in DHCP server response. Assuming %u.%u.%u.%u\n", + ((unsigned char *)options->val[subnetMask])[0], ((unsigned char *)options->val[subnetMask])[1], + ((unsigned char *)options->val[subnetMask])[2], ((unsigned char *)options->val[subnetMask])[3]); } - if ( ! options->val[broadcastAddr] ) /* did not get broadcastAddr */ + if (!options->val[broadcastAddr]) /* did not get broadcastAddr */ { int br = dhcp_msg->yiaddr | ~*((int *)options->val[subnetMask]); - options->val[broadcastAddr] = malloc(4); + options->val[broadcastAddr] = malloc (4); memcpy (options->val[broadcastAddr], &br, 4); options->len[broadcastAddr] = 4; options->num++; - if ( DebugFlag ) + if (DebugFlag) syslog(LOG_DEBUG, "broadcastAddr option is missing in DHCP server response. Assuming %u.%u.%u.%u\n", - ((unsigned char *)options->val[broadcastAddr])[0], - ((unsigned char *)options->val[broadcastAddr])[1], - ((unsigned char *)options->val[broadcastAddr])[2], - ((unsigned char *)options->val[broadcastAddr])[3]); + ((unsigned char *)options->val[broadcastAddr])[0], ((unsigned char *)options->val[broadcastAddr])[1], + ((unsigned char *)options->val[broadcastAddr])[2], ((unsigned char *)options->val[broadcastAddr])[3]); } -#if 0 - if ( ! options->val[routersOnSubnet] ) + if (!options->val[routersOnSubnet]) { - options->val[routersOnSubnet] = malloc(4); - if ( dhcp_msg->giaddr ) - memcpy(options->val[routersOnSubnet],&dhcp_msg->giaddr,4); + options->val[routersOnSubnet] = malloc (4); + if (options->val[dhcpServerIdentifier]) + memcpy (options->val[routersOnSubnet], options->val[dhcpServerIdentifier], 4); else - memcpy(options->val[routersOnSubnet],options->val[dhcpServerIdentifier],4); + memcpy (options->val[routersOnSubnet], &dhcp_msg->giaddr, 4); options->len[routersOnSubnet] = 4; options->num++; - if ( DebugFlag ) - syslog(LOG_DEBUG, "routersOnSubnet option is missing in DHCP server response. Assuming %u.%u.%u.%u\n", - ((unsigned char *)options->val[routersOnSubnet])[0], - ((unsigned char *)options->val[routersOnSubnet])[1], - ((unsigned char *)options->val[routersOnSubnet])[2], - ((unsigned char *)options->val[routersOnSubnet])[3]); + if (DebugFlag) + syslog (LOG_DEBUG, "routersOnSubnet option is missing in DHCP server response. Assuming %u.%u.%u.%u (DHCP server)\n", + ((unsigned char *)options->val[routersOnSubnet])[0], ((unsigned char *)options->val[routersOnSubnet])[1], + ((unsigned char *)options->val[routersOnSubnet])[2], ((unsigned char *)options->val[routersOnSubnet])[3]); } -#endif - if ( options->val[dhcpIPaddrLeaseTime] && options->len[dhcpIPaddrLeaseTime] == 4 ) + if (options->val[dhcpIPaddrLeaseTime] && options->len[dhcpIPaddrLeaseTime] == 4) { if ( *(unsigned int *)options->val[dhcpIPaddrLeaseTime] == 0 ) { unsigned int lease_time = htonl (DHCP_DEFAULT_LEASETIME); memcpy (options->val[dhcpIPaddrLeaseTime], &lease_time, 4); - if ( DebugFlag ) - syslog(LOG_DEBUG,"dhcpIPaddrLeaseTime=0 in DHCP server response. Assuming %u sec\n", lease_time); + if (DebugFlag) + syslog (LOG_DEBUG, "dhcpIPaddrLeaseTime=0 in DHCP server response. Assuming %u sec\n", lease_time); } else { - if ( DebugFlag ) - syslog(LOG_DEBUG,"dhcpIPaddrLeaseTime = %u in DHCP server response.\n", - ntohl(*(unsigned int *)options->val[dhcpIPaddrLeaseTime])); + if (DebugFlag) + syslog (LOG_DEBUG, "dhcpIPaddrLeaseTime = %u in DHCP server response.\n", + ntohl (*(unsigned int *)options->val[dhcpIPaddrLeaseTime])); } } else /* did not get dhcpIPaddrLeaseTime */ @@ -224,60 +223,60 @@ swend: options->len[dhcpIPaddrLeaseTime] = 4; options->num++; if ( DebugFlag ) - syslog(LOG_DEBUG,"dhcpIPaddrLeaseTime option is missing in DHCP server response. Assuming %u sec\n", lease_time); + syslog (LOG_DEBUG, "dhcpIPaddrLeaseTime option is missing in DHCP server response. Assuming %u sec\n", lease_time); } - if ( options->val[dhcpT1value] && options->len[dhcpT1value] == 4 ) + if (options->val[dhcpT1value] && options->len[dhcpT1value] == 4) { - if ( *(unsigned int *)options->val[dhcpT1value] == 0 ) + if (*(unsigned int *)options->val[dhcpT1value] == 0) { - unsigned t2 = 0.5 * ntohl(*(unsigned int *)options->val[dhcpIPaddrLeaseTime]); - int t1 = htonl(t2); + unsigned t2 = 0.5 * ntohl (*(unsigned int *)options->val[dhcpIPaddrLeaseTime]); + int t1 = htonl (t2); memcpy (options->val[dhcpT1value],&t1,4); options->len[dhcpT1value] = 4; - if ( DebugFlag ) - syslog(LOG_DEBUG,"dhcpT1value is missing in DHCP server response. Assuming %u sec\n",t2); + if (DebugFlag) + syslog (LOG_DEBUG, "dhcpT1value is missing in DHCP server response. Assuming %u sec\n", t2); } } else /* did not get T1 */ { - unsigned t2 = 0.5*ntohl(*(unsigned int *)options->val[dhcpIPaddrLeaseTime]); - int t1 = htonl(t2); + unsigned t2 = 0.5 * ntohl (*(unsigned int *)options->val[dhcpIPaddrLeaseTime]); + int t1 = htonl (t2); options->val[dhcpT1value] = malloc(4); memcpy (options->val[dhcpT1value],&t1,4); options->len[dhcpT1value] = 4; options->num++; - if ( DebugFlag ) - syslog(LOG_DEBUG,"dhcpT1value is missing in DHCP server response. Assuming %u sec\n",t2); + if (DebugFlag) + syslog (LOG_DEBUG, "dhcpT1value is missing in DHCP server response. Assuming %u sec\n", t2); } - if ( options->val[dhcpT2value] && options->len[dhcpT2value] == 4 ) + if (options->val[dhcpT2value] && options->len[dhcpT2value] == 4) { - if ( *(unsigned int *)options->val[dhcpT2value] == 0 ) + if (*(unsigned int *)options->val[dhcpT2value] == 0) { - unsigned t2 = 0.875*ntohl(*(unsigned int *)options->val[dhcpIPaddrLeaseTime]); - int t1 = htonl(t2); - memcpy(options->val[dhcpT2value],&t1,4); + unsigned t2 = 0.875 * ntohl (*(unsigned int *)options->val[dhcpIPaddrLeaseTime]); + int t1 = htonl (t2); + memcpy (options->val[dhcpT2value],&t1,4); options->len[dhcpT2value] = 4; - if ( DebugFlag ) - syslog(LOG_DEBUG,"dhcpT2value is missing in DHCP server response. Assuming %u sec\n",t2); + if (DebugFlag) + syslog (LOG_DEBUG, "dhcpT2value is missing in DHCP server response. Assuming %u sec\n", t2); } } else /* did not get T2 */ { - unsigned t2 = 0.875*ntohl(*(unsigned int *)options->val[dhcpIPaddrLeaseTime]); - int t1 = htonl(t2); + unsigned t2 = 0.875 * ntohl (*(unsigned int *)options->val[dhcpIPaddrLeaseTime]); + int t1 = htonl (t2); options->val[dhcpT2value] = malloc(4); - memcpy(options->val[dhcpT2value],&t1,4); + memcpy (options->val[dhcpT2value],&t1,4); options->len[dhcpT2value] = 4; options->num++; - if ( DebugFlag ) - syslog(LOG_DEBUG,"dhcpT2value is missing in DHCP server response. Assuming %u sec\n",t2); + if (DebugFlag) + syslog (LOG_DEBUG, "dhcpT2value is missing in DHCP server response. Assuming %u sec\n", t2); } - if ( options->val[dhcpMessageType] ) + if (options->val[dhcpMessageType]) return *(unsigned char *)options->val[dhcpMessageType]; return -1; } /*****************************************************************************/ -void classIDsetup(dhcp_interface *iface, const char *g_cls_id) +void class_id_setup (dhcp_interface *iface, const char *g_cls_id) { unsigned int g_cls_id_len = 0; @@ -301,7 +300,7 @@ void classIDsetup(dhcp_interface *iface, const char *g_cls_id) } } /*****************************************************************************/ -void clientIDsetup(dhcp_interface *iface, const char *g_cli_id) +void client_id_setup (dhcp_interface *iface, const char *g_cli_id) { unsigned int g_cli_id_len = 0; unsigned char *c = iface->cli_id; @@ -322,13 +321,13 @@ void clientIDsetup(dhcp_interface *iface, const char *g_cli_id) else { *c++ = ETH_ALEN + 1; /* length: 6 (MAC Addr) + 1 (# field) */ - *c++ = (iface->bTokenRing) ? ARPHRD_IEEE802_TR : ARPHRD_ETHER; /* type: Ethernet address */ + *c++ = ARPHRD_ETHER; /* type: Ethernet address */ memcpy (c, iface->chaddr, ETH_ALEN); iface->cli_id_len = ETH_ALEN + 3; } } /*****************************************************************************/ -void releaseDhcpOptions (dhcp_interface *iface) +void release_dhcp_options (dhcp_interface *iface) { register int i; for ( i = 1; i < 256; i++ ) @@ -337,114 +336,13 @@ void releaseDhcpOptions (dhcp_interface *iface) free(iface->dhcp_options.val[i]); } - memset(&(iface->dhcp_options), 0, sizeof(dhcpOptions)); -} -/*****************************************************************************/ -#ifdef DEBUG -static void dumpframe(const char *title, struct packed_ether_header *frame) -{ - int i; - unsigned char *dp; - - printf("%s:", title); - dp = (unsigned char *)frame; - for (i = 0; i < 32; i++) - { - if ((i % 16) == 0) - printf("\n"); - printf("0x%02X ", *dp++); - } -} -#endif /* DEBUG */ -/*****************************************************************************/ -/***** convert ethernet and token-ring frames *****/ -int eth2tr(struct packed_ether_header *frame, int datalen) -{ - struct trh_hdr *phdr; - struct trllc *pllc; - char trheader[sizeof(struct trh_hdr) - sizeof(phdr->rseg) + sizeof(struct trllc)]; - int len; - -#ifdef DEBUG - dumpframe("eth2tr: Incoming eth frame", frame); -#endif - memset(trheader, 0, sizeof(trheader)); - phdr = (struct trh_hdr *)trheader; - phdr->ac = AC; - phdr->fc = LLC_FRAME; - memcpy(phdr->daddr, frame->ether_dhost, TR_ALEN); - memcpy(phdr->saddr, frame->ether_shost, TR_ALEN); - if (phdr->daddr[0] & 0x80) - { /* Destination is a broadcast */ - phdr->rcf = sizeof(phdr->rcf) | htons(TR_RCF_BROADCAST | 0x70); /* Unlimited frame length */ - pllc = (struct trllc *)&phdr->rseg[0]; - phdr->saddr[0] |= TR_RII; /* Set source-route indicator */ - len = sizeof(trheader); - } - else - { - pllc = (struct trllc *)&phdr->rcf; - len = sizeof(trheader) - sizeof(phdr->rcf); - } - pllc->dsap = EXTENDED_SAP; - pllc->ssap = EXTENDED_SAP; - pllc->llc = UI_CMD; - pllc->protid[0] = pllc->protid[1] = pllc->protid[2] = 0; - pllc->ethertype = frame->ether_type; - /* Make room for larger TR header */ - memmove((char *)(frame + 1) + (len - sizeof(struct packed_ether_header)), frame + 1, datalen); - memcpy(frame, trheader, len); /* Install TR header */ -#ifdef DEBUG - dumpframe("eth2tr: Outgoing tr frame", frame); -#endif - return len + datalen; -} -/*****************************************************************************/ -int tr2eth(struct packed_ether_header *frame) -{ - struct trh_hdr hdr; - struct trllc *pllc; - int hlen = 0; - -#ifdef DEBUG - dumpframe("tr2eth: Incoming tr frame", frame); -#endif - hdr = *((struct trh_hdr *)frame); - if (hdr.saddr[0] & TR_RII) - { - fake_rif: - hlen = hdr.rcf & ntohs(TR_RCF_LEN_MASK); - #ifdef DEBUG - printf("rcf = 0x%X SR len %d\n", hdr.rcf, hlen); - #endif - if (hlen < sizeof(hdr.rcf) || (hlen & 1)) - return 1; - hdr.saddr[0] &= ~TR_RII; - } - pllc = (struct trllc *)(((__u8 *)frame) + sizeof(struct trh_hdr) - TR_MAXRIFLEN + hlen); - if (pllc->dsap != EXTENDED_SAP || pllc->llc != UI_CMD) - { - if (hlen == 0) - goto fake_rif; /* Bug in 2.2.3 kernel */ - #ifdef DEBUG - printf("corrupted TR-IP packet of ui=0x%x and dsap 0x%x discarded\n", pllc->llc, pllc->dsap); - #endif - return 1; - } - memcpy(frame->ether_dhost, hdr.daddr, ETH_ALEN); - memcpy(frame->ether_shost, hdr.saddr, ETH_ALEN); - frame->ether_type = pllc->ethertype; - memmove(frame + 1, pllc + 1, IPPACKET_SIZE); /* Move data portion: Overlapping buffer */ -#ifdef DEBUG - dumpframe("tr2eth: Outgoing eth frame", frame); -#endif - return 0; + memset (&(iface->dhcp_options), 0, sizeof (dhcpOptions)); } /*****************************************************************************/ /* Subtract the `struct timeval' values X and Y, storing the result in RESULT. Return 1 if the difference is negative, otherwise 0. */ -static int timeval_subtract(struct timeval *result, struct timeval *x, struct timeval *y) +static int timeval_subtract (struct timeval *result, struct timeval *x, struct timeval *y) { /* Perform the carry for the later subtraction by updating Y. */ if (x->tv_usec < y->tv_usec) @@ -469,266 +367,299 @@ static int timeval_subtract(struct timeval *result, struct timeval *x, struct ti return x->tv_sec < y->tv_sec; } /*****************************************************************************/ -int peekfd (dhcp_interface *iface, time_t tv_usec) +/* Ripped from pump. + */ +int verify_checksum(void * buf, int length, void * buf2, int length2) { - fd_set fs; - struct timeval begin; - time_t i = tv_usec; + unsigned int csum; + unsigned short * sp; - FD_ZERO (&fs); - FD_SET (iface->sk, &fs); - gettimeofday (&begin, NULL); + csum = 0; + for (sp = (unsigned short *) buf; length > 0; (length -= 2), sp++) + csum += *sp; + + /* this matches rfc 1071, but not Steven's */ + if (length) + csum += *((unsigned char *) sp); + + for (sp = (unsigned short *) buf2; length2 > 0; (length2 -= 2), sp++) + csum += *sp; + + /* this matches rfc 1071, but not Steven's */ + if (length) + csum += *((unsigned char *) sp); + + while (csum >> 16) + csum = (csum & 0xffff) + (csum >> 16); + + if (csum!=0x0000 && csum != 0xffff) + return 0; + + return 1; +} +/*****************************************************************************/ +/* "timeout" should be the future point in time when we wish to stop + * checking for data on the socket. + */ +int peekfd (dhcp_interface *iface, int sk, struct timeval *timeout) +{ + struct timeval diff; + struct timeval now; /* Wake up each second to check whether or not we've been told - * to stop with iface->cease + * to stop with iface->cease and check our timeout. */ - while (i > 0) + gettimeofday (&now, NULL); + syslog (LOG_INFO, "DHCP waiting for data, overall timeout = {%ds, %dus}\n", (int)timeout->tv_sec, (int)timeout->tv_usec); + while (timeval_subtract (&diff, timeout, &now) == 0) { - struct timeval now; - struct timeval diff; + fd_set fs; struct timeval wait = {1, 0}; + syslog (LOG_INFO, "DHCP waiting for data, remaining timeout = {%ds, %dus}\n", (int)diff.tv_sec, (int)diff.tv_usec); - if ( select (iface->sk+1, &fs, NULL, NULL, &wait) == -1 ) + FD_ZERO (&fs); + FD_SET (sk, &fs); + + if (select (sk+1, &fs, NULL, NULL, &wait) == -1) return RET_DHCP_ERROR; - if ( FD_ISSET(iface->sk, &fs) ) + if (FD_ISSET(sk, &fs)) return RET_DHCP_SUCCESS; - gettimeofday (&now, NULL); - timeval_subtract (&diff, &now, &begin); - i = tv_usec - ((diff.tv_sec * 1000000) + diff.tv_usec); if (iface->cease) return RET_DHCP_CEASED; - } + gettimeofday (&now, NULL); + }; return RET_DHCP_TIMEOUT; } /*****************************************************************************/ -int dhcpSendAndRecv (dhcp_interface *iface, unsigned int expected_reply_type, - dhcp_msg_build_proc buildUdpIpMsg, udpipMessage **return_msg) +int dhcp_handle_transaction (dhcp_interface *iface, unsigned int expected_reply_type, + dhcp_msg_build_proc build_dhcp_msg, dhcp_response_return *dhcp_return) { - udpipMessage *udp_msg_recv = NULL; - struct sockaddr addr; - int len, err = RET_DHCP_TIMEOUT, local_timeout = 0; - int j = DHCP_INITIAL_RTO / 2; - struct timeval local_begin, current, diff; - struct timeval overall_end; + char *pkt_recv = NULL; + int recv_sk = -1; + struct sockaddr_in addr; + int tries = -1; + int dhcp_send_len, err = RET_DHCP_TIMEOUT; + dhcpMessage *dhcp_send = NULL; + struct timeval recv_timeout, overall_end, diff, current; - *return_msg = NULL; + if (!dhcp_return) + return RET_DHCP_ERROR; + memset (dhcp_return, 0, sizeof (dhcp_response_return)); + pkt_recv = malloc (sizeof (char) * ETH_FRAME_LEN); + if (!pkt_recv) + return RET_DHCP_ERROR; + + /* Call the specific DHCP message building routine for this request */ + if (!(dhcp_send = build_dhcp_msg (iface, &dhcp_send_len, &addr))) + { + err = RET_DHCP_ERROR; + goto out; + } + + recv_sk = socket (AF_PACKET, SOCK_DGRAM, ntohs (ETH_P_IP)); + if (recv_sk < 0) + { + err = RET_DHCP_ERROR; + goto out; + } + + /* Setup the time in the future to quit doing DHCP stuff. If we reach this time, + * we return RET_DHCP_TIMEOUT. + */ gettimeofday (&overall_end, NULL); overall_end.tv_sec += iface->client_options->base_timeout; + /* Send the request, then wait for the reply for a certain period of time + * that increases with each failed request. Quit when we reach our end time though. + */ + syslog (LOG_INFO, "DHCP: Starting request loop"); do { - udpipMessage *udp_msg_send = buildUdpIpMsg (iface); - int send_err = 0; - - if (!udp_msg_send) - return RET_DHCP_ERROR; - - j += j; - if (j > DHCP_MAX_RTO) - j = DHCP_MAX_RTO; - - /* Make sure waiting j seconds isn't greater than our overall time left - * on this operation, and clamp j to the overall time left if it is. - */ - gettimeofday (¤t, NULL); - if (timeval_subtract (&diff, &overall_end, ¤t)) - { - free (udp_msg_send); - return RET_DHCP_TIMEOUT; - } - if (j > ((diff.tv_sec * 1000000) + diff.tv_usec)) - j = (diff.tv_sec * 1000000) + diff.tv_usec; - - if (iface->bTokenRing) /* Here we convert a Eth frame into an TR frame */ - len = eth2tr (&(udp_msg_send->ethhdr), sizeof(udpiphdr) + sizeof(dhcpMessage)); - else - len = sizeof (struct packed_ether_header) + sizeof(udpiphdr) + sizeof(dhcpMessage); - - memset (&addr, 0, sizeof(struct sockaddr)); - memcpy (addr.sa_data, iface->iface, strlen (iface->iface)); - do - { - send_err = sendto (iface->sk, udp_msg_send, len, MSG_DONTWAIT, &addr, sizeof(struct sockaddr)); - if (iface->cease || ((send_err == -1) && (errno != EAGAIN))) - { - free (udp_msg_send); - return iface->cease ? RET_DHCP_CEASED : RET_DHCP_ERROR; - } - } while ((send_err == -1) && (errno == EAGAIN)); - - free (udp_msg_send); - gettimeofday (&local_begin, NULL); - err = peekfd (iface, (j + random () % 200000)); - if (iface->cease || (err == RET_DHCP_CEASED)) - return RET_DHCP_CEASED; - } while ( err == RET_DHCP_TIMEOUT ); - - do - { - struct ip ipRecv_local; + struct iphdr *ip_hdr; + struct udphdr *udp_hdr; char *tmp_ip; - const struct udphdr *udp_msg_recv_hdr; - dhcpMessage *dhcp_msg_recv; + dhcpMessage *dhcp_msg_recv = NULL; int reply_type = -1; char foobuf[512]; - int i, o; + struct sockaddr_ll server_hw_addr; + int o; + char ethPacket[ETH_FRAME_LEN]; + int len; - udp_msg_recv = calloc (1, sizeof (udpipMessage)); - o = sizeof (struct sockaddr); + /* Send the DHCP request */ + syslog (LOG_INFO, "DHCP: Sending request packet..."); do { - len = recvfrom (iface->sk, udp_msg_recv, sizeof(udpipMessage), MSG_DONTWAIT, (struct sockaddr *)&addr, &o); - if (iface->cease || ((len == -1) && (errno != EAGAIN))) + err = sendto (iface->sk, dhcp_send, dhcp_send_len, MSG_DONTWAIT, (struct sockaddr *)&addr, sizeof (struct sockaddr)); + if (iface->cease || ((err == -1) && (errno != EAGAIN))) { - free (udp_msg_recv); - return iface->cease ? RET_DHCP_CEASED : RET_DHCP_ERROR; + syslog (LOG_INFO, "DHCP: error sending, cease = %d, err = %d, errno = %d", iface->cease, err, errno); + err = iface->cease ? RET_DHCP_CEASED : RET_DHCP_ERROR; + goto out; } - } while ((len == -1) && (errno == EAGAIN)); - if (iface->bTokenRing) - { /* Here we convert a TR frame into an Eth frame */ - if (tr2eth (&(udp_msg_recv->ethhdr))) + /* Return if we've exceeded our timeout */ + gettimeofday (¤t, NULL); + if (timeval_subtract (&diff, &overall_end, ¤t) != 0) { - free (udp_msg_recv); - continue; + err = RET_DHCP_TIMEOUT; + syslog (LOG_INFO, "DHCP: Send timeout"); + goto out; } - } + } while ((err == -1) && (errno == EAGAIN)); + syslog (LOG_INFO, "DHCP: Sent request packet."); - gettimeofday (¤t, NULL); - timeval_subtract (&diff, ¤t, &local_begin); - local_timeout = j - diff.tv_sec * 1000000 - diff.tv_usec + random() % 200000; - - /* Make sure waiting local_timeout seconds isn't greater than our overall time left - * on this operation, and clamp local_timeout to the overall time left if it is. + /* Set up the future time at which point to stop waiting for data + * on our socket and try the request again. If that future point is + * later than our overall DHCP operation timeout (overall_end) then + * clamp the receive timeout to overall_end. */ - if (timeval_subtract (&diff, &overall_end, ¤t)) - { - free (udp_msg_recv); - return RET_DHCP_TIMEOUT; - } - if ((local_timeout*1000000) > ((diff.tv_sec * 1000000) + diff.tv_usec)) - local_timeout = (diff.tv_sec * 1000000) + diff.tv_usec; + tries++; + gettimeofday (&recv_timeout, NULL); + recv_timeout.tv_sec += (tries * DHCP_INITIAL_RTO); + recv_timeout.tv_sec += (random () % 200000); + if (timeval_subtract (&diff, &overall_end, &recv_timeout) != 0) + memcpy (&recv_timeout, &overall_end, sizeof (struct timeval)); - /* Ignore non-IP packets */ - if ( udp_msg_recv->ethhdr.ether_type != htons(ETHERTYPE_IP) ) + /* Wait for some kind of data to appear on the socket */ + syslog (LOG_INFO, "DHCP: Waiting for reply..."); + if ((err = peekfd (iface, recv_sk, &recv_timeout) != RET_DHCP_SUCCESS)) { - free (udp_msg_recv); - continue; + if (err == RET_DHCP_TIMEOUT) + continue; + goto out; } + syslog (LOG_INFO, "DHCP: Got some data to check for reply packet."); - tmp_ip = udp_msg_recv->udpipmsg; - for (i = 0; i < sizeof (struct ip) - 2; i += 2) + /* Peek from the data until we get a full amount or a timeout has occurred */ + memset (pkt_recv, 0, ETH_FRAME_LEN); + o = sizeof (struct sockaddr_ll); + do { - if ( ( udp_msg_recv->udpipmsg[i] == 0x45 ) && ( udp_msg_recv->udpipmsg[i+1] == 0x00 ) ) + o = sizeof (server_hw_addr); + len = recvfrom (recv_sk, ethPacket, sizeof (ethPacket), MSG_DONTWAIT | MSG_PEEK, (struct sockaddr *)&server_hw_addr, &o); + if (iface->cease || ((len == -1) && (errno != EAGAIN)) || (len == 0)) { - tmp_ip = &(udp_msg_recv->udpipmsg[i]); - break; + err = iface->cease ? RET_DHCP_CEASED : RET_DHCP_ERROR; + goto out; } - } - /* Use local copy because ipRecv is not aligned. */ - memcpy (&ipRecv_local, ((struct udpiphdr *)tmp_ip)->ip, sizeof(struct ip)); - udp_msg_recv_hdr = (struct udphdr *)((char*)(((struct udpiphdr*)tmp_ip)->ip)+sizeof(struct ip)); - if ( ipRecv_local.ip_p != IPPROTO_UDP ) - { - free (udp_msg_recv); - continue; - } - - if ( iface->bTokenRing && (udp_msg_recv_hdr->uh_dport != htons(DHCP_CLIENT_PORT))) - { - free (udp_msg_recv); - continue; - } - - len -= sizeof(struct packed_ether_header); - i = (int)ntohs (ipRecv_local.ip_len); - if ( len < i ) - { - if ( DebugFlag ) - syslog(LOG_DEBUG, "corrupted IP packet of size=%d and ip_len=%d discarded\n", len,i); - free (udp_msg_recv); - continue; - } - - len = i - (ipRecv_local.ip_hl << 2); - i = (int)ntohs(udp_msg_recv_hdr->uh_ulen); - if ( len < i ) - { - if ( DebugFlag ) - syslog(LOG_DEBUG, "corrupted UDP msg of size=%d and uh_ulen=%d discarded\n", len,i); - free (udp_msg_recv); - continue; - } - - if ( iface->client_options->do_checksum && (len = udpipchk((udpiphdr *)tmp_ip))) - { - if ( DebugFlag ) + /* Return if we've exceeded our timeout */ + gettimeofday (¤t, NULL); + if (timeval_subtract (&diff, &overall_end, ¤t) != 0) { - switch ( len ) - { - case -1: - syslog(LOG_DEBUG, "corrupted IP packet with ip_len=%d discarded\n", (int)ntohs(ipRecv_local.ip_len)); - break; - case -2: - syslog(LOG_DEBUG, "corrupted UDP msg with uh_ulen=%d discarded\n", (int)ntohs(udp_msg_recv_hdr->uh_ulen)); - break; - } + err = RET_DHCP_TIMEOUT; + goto out; } - free (udp_msg_recv); - continue; - } + syslog (LOG_INFO, "DHCP: Received data of len %d, looking for at least %d", len, (sizeof (struct iphdr) + sizeof (struct udphdr))); + } while (len < (sizeof (struct iphdr) + sizeof (struct udphdr))); - dhcp_msg_recv = (dhcpMessage *)&(tmp_ip[(ipRecv_local.ip_hl << 2) + sizeof(struct udphdr)]); - if ( dhcp_msg_recv->xid != iface->xid ) + /* Ok, we allegedly have the data we need, so grab it from the queue */ + o = sizeof (struct sockaddr_ll); + len = recvfrom (recv_sk, pkt_recv, ETH_FRAME_LEN, 0, (struct sockaddr *)&server_hw_addr, &o); + syslog (LOG_INFO, "DHCP: actual data length was %d", len); + if (len < (sizeof (struct iphdr) + sizeof (struct udphdr))) { - free (udp_msg_recv); + syslog (LOG_INFO, "DHCP: Data length failed minimum length check (should be %d, got %d)", (sizeof (struct iphdr) + sizeof (struct udphdr)), len); continue; } - if ( dhcp_msg_recv->htype != ARPHRD_ETHER && dhcp_msg_recv->htype != (char)ARPHRD_IEEE802_TR ) + ip_hdr = (struct iphdr *) pkt_recv; + if (!verify_checksum (NULL, 0, ip_hdr, sizeof (struct iphdr))) { - if ( DebugFlag ) - syslog (LOG_DEBUG,"wrong msg htype 0x%X discarded\n", dhcp_msg_recv->htype); - free (udp_msg_recv); + syslog (LOG_INFO, "DHCP: Reply message had bad IP checksum, won't use it."); continue; } - if ( dhcp_msg_recv->op != DHCP_BOOTREPLY ) + if (ntohs (ip_hdr->tot_len) > len) { - free (udp_msg_recv); + syslog (LOG_INFO, "DHCP: Reply message had mismatch in length (IP header said %d, packet was really %d), won't use it.", ntohs (ip_hdr->tot_len), len); + continue; + } + len = ntohs (ip_hdr->tot_len); + + if (ip_hdr->protocol != IPPROTO_UDP) + { + syslog (LOG_INFO, "DHCP: Reply message was not not UDP (ip_hdr->protocol = %d, IPPROTO_UDP = %d), won't use it.", ip_hdr->protocol, IPPROTO_UDP); continue; } - while ((iface->foo_sk > 0) && recvfrom (iface->foo_sk, (void *)foobuf, sizeof(foobuf), 0, NULL, NULL) != -1); + udp_hdr = (struct udphdr *) (pkt_recv + sizeof (struct iphdr)); + if (ntohs (udp_hdr->source) != DHCP_SERVER_PORT) + { + syslog (LOG_INFO, "DHCP: Reply message's source port was not the DHCP server port number, won't use it."); + continue; + } + if (ntohs (udp_hdr->dest) != DHCP_CLIENT_PORT) + { + syslog (LOG_INFO, "DHCP: Reply message's destination port was not the DHCP client port number, won't use it."); + continue; + } + + /* Ok, packet appears to be OK */ + /* Ensure DHCP packet is 0xFF terminated, which isn't the case on Cisco 800 series ISDN router */ + dhcp_msg_recv = malloc (sizeof (dhcpMessage)); + memset (dhcp_msg_recv, 0xFF, sizeof (dhcpMessage)); + memcpy (dhcp_msg_recv, (char *) udp_hdr + sizeof (struct udphdr), len - sizeof (struct iphdr) - sizeof (struct udphdr)); + + if (dhcp_msg_recv->xid != iface->xid) + { + syslog (LOG_INFO, "DHCP: Reply message's XID does not match expected XID (message %d, expected %d), won't use it.", dhcp_msg_recv->xid, iface->xid); + free (dhcp_msg_recv); + continue; + } + + if (dhcp_msg_recv->htype != ARPHRD_ETHER) + { + if (DebugFlag) + syslog (LOG_DEBUG, "DHCP: Reply message's header type was not ARPHRD_ETHER (messgae %d, expected %d), won't use it.", dhcp_msg_recv->htype, ARPHRD_ETHER); + free (dhcp_msg_recv); + continue; + } + + if (dhcp_msg_recv->op != DHCP_BOOTREPLY) + { + syslog (LOG_INFO, "DHCP: Reply message was not a bootp/DHCP reply, won't use it."); + free (dhcp_msg_recv); + continue; + } + + /* Clear out all data remaining on the interface in preparation for another broadcast if needed */ + while ((iface->foo_sk > 0) && recvfrom (iface->foo_sk, (void *)foobuf, sizeof (foobuf), 0, NULL, NULL) != -1); /* Copy DHCP response options from received packet into local options list */ - reply_type = parseDhcpMsgRecv (udp_msg_recv, &(iface->dhcp_options)); - if ( expected_reply_type == reply_type ) + reply_type = parse_dhcp_reply (ip_hdr, &server_hw_addr, dhcp_msg_recv, &(iface->dhcp_options)); + if (expected_reply_type == reply_type) { - *return_msg = udp_msg_recv; - return RET_DHCP_SUCCESS; + memcpy (&dhcp_return->server_ip_addr, &(ip_hdr->saddr), 4); + memcpy (&dhcp_return->server_hw_addr, &server_hw_addr, ETH_ALEN); + memcpy (&dhcp_return->dhcp_msg, dhcp_msg_recv, sizeof (dhcpMessage)); + free (dhcp_msg_recv); + err = RET_DHCP_SUCCESS; + goto out; } - - free (udp_msg_recv); - udp_msg_recv = NULL; + free (dhcp_msg_recv); if (reply_type == DHCP_NAK) { - if ( iface->dhcp_options.val[dhcpMsg] ) - syslog(LOG_ERR, "DHCP_NAK server response received: %s\n", (char *)iface->dhcp_options.val[dhcpMsg]); + if (iface->dhcp_options.val[dhcpMsg]) + syslog (LOG_ERR, "DHCP: DHCP_NAK response received: %s.", (char *)iface->dhcp_options.val[dhcpMsg]); else - syslog(LOG_ERR, "DHCP_NAK server response received\n"); - return RET_DHCP_NAK; + syslog (LOG_ERR, "DHCP: DHCP_NAK response received."); + err = RET_DHCP_NAK; + goto out; } + gettimeofday (¤t, NULL); + } while (timeval_subtract (&diff, &overall_end, ¤t) == 0); - err = peekfd (iface, local_timeout); - if (iface->cease || (err == RET_DHCP_CEASED)) - return RET_DHCP_CEASED; - } while ((local_timeout > 0) && (err == RET_DHCP_SUCCESS)); - - return RET_DHCP_TIMEOUT; +out: + free (dhcp_send); + if (err != RET_DHCP_SUCCESS) + free (pkt_recv); + if (recv_sk >= 0) + close (recv_sk); + return err; } /*****************************************************************************/ int dhcp_reboot (dhcp_interface *iface) @@ -744,19 +675,18 @@ int dhcp_reboot (dhcp_interface *iface) if (!iface) return RET_DHCP_ERROR; - releaseDhcpOptions (iface); - return dhcp_request (iface, &buildDhcpReboot); + release_dhcp_options (iface); + return dhcp_request (iface, &build_dhcp_reboot); } /*****************************************************************************/ int dhcp_init (dhcp_interface *iface) { - udpipMessage *msg = NULL; - dhcpMessage *dhcp_msg = NULL; - int err; + dhcp_response_return dhcp_resp; + int err; if (!iface) return RET_DHCP_ERROR; - releaseDhcpOptions (iface); + release_dhcp_options (iface); #ifdef DEBUG syslog (LOG_DEBUG, "ClassID = \"%s\"\n" @@ -769,93 +699,84 @@ int dhcp_init (dhcp_interface *iface) if ( DebugFlag ) syslog (LOG_INFO, "Broadcasting DHCP_DISCOVER\n"); iface->xid = random (); - err = dhcpSendAndRecv (iface, DHCP_OFFER, &buildDhcpDiscover, &msg); + err = dhcp_handle_transaction (iface, DHCP_OFFER, &build_dhcp_discover, &dhcp_resp); if (err != RET_DHCP_SUCCESS) return err; - dhcp_msg = (dhcpMessage *)&(msg->udpipmsg[sizeof(udpiphdr)]); - if ( iface->client_options->send_second_discover ) + if (iface->client_options->send_second_discover) { - udpipMessage *msg2 = NULL; + dhcp_response_return dhcp_resp2; if (DebugFlag) syslog (LOG_INFO, "Broadcasting second DHCP_DISCOVER\n"); - iface->xid = dhcp_msg->xid; - err = dhcpSendAndRecv (iface, DHCP_OFFER, &buildDhcpDiscover, &msg2); + iface->xid = dhcp_resp.dhcp_msg.xid; + err = dhcp_handle_transaction (iface, DHCP_OFFER, &build_dhcp_discover, &dhcp_resp2); if (err == RET_DHCP_SUCCESS) - { - free (msg); - msg = msg2; - } - dhcp_msg = (dhcpMessage *)&(msg->udpipmsg[sizeof(udpiphdr)]); + memcpy (&dhcp_resp, &dhcp_resp2, sizeof (dhcp_response_return)); } - iface->ciaddr = dhcp_msg->yiaddr; + iface->ciaddr = dhcp_resp.dhcp_msg.yiaddr; memcpy (&(iface->siaddr), iface->dhcp_options.val[dhcpServerIdentifier], 4); - memcpy (iface->shaddr, msg->ethhdr.ether_shost, ETH_ALEN); - iface->xid = dhcp_msg->xid; + memcpy (iface->shaddr, dhcp_resp.server_hw_addr, ETH_ALEN); + iface->xid = dhcp_resp.dhcp_msg.xid; /* DHCP_OFFER received */ - if ( DebugFlag ) + if (DebugFlag) { - syslog (LOG_INFO, "DHCP_OFFER received from %s (%u.%u.%u.%u)\n", dhcp_msg->sname, + syslog (LOG_INFO, "DHCP_OFFER received from %s (%u.%u.%u.%u)\n", dhcp_resp.dhcp_msg.sname, ((unsigned char *)(iface->dhcp_options.val[dhcpServerIdentifier]))[0], ((unsigned char *)(iface->dhcp_options.val[dhcpServerIdentifier]))[1], ((unsigned char *)(iface->dhcp_options.val[dhcpServerIdentifier]))[2], ((unsigned char *)(iface->dhcp_options.val[dhcpServerIdentifier]))[3]); } - free (msg); - return dhcp_request (iface, &buildDhcpRequest); + return dhcp_request (iface, &build_dhcp_request); } /*****************************************************************************/ int dhcp_request(dhcp_interface *iface, dhcp_msg_build_proc buildDhcpMsg) { - udpipMessage *msg = NULL; - int err; + dhcp_response_return dhcp_resp; + int err; /* DHCP state REQUEST: request an address from a _particular_ DHCP server */ if (!iface) return RET_DHCP_ERROR; - if ( DebugFlag ) + if (DebugFlag) { syslog (LOG_INFO, "Broadcasting DHCP_REQUEST for %u.%u.%u.%u\n", ((unsigned char *)&(iface->ciaddr))[0], ((unsigned char *)&(iface->ciaddr))[1], ((unsigned char *)&(iface->ciaddr))[2], ((unsigned char *)&(iface->ciaddr))[3]); } - err = dhcpSendAndRecv (iface, DHCP_ACK, buildDhcpMsg, &msg); + err = dhcp_handle_transaction (iface, DHCP_ACK, buildDhcpMsg, &dhcp_resp); if (err != RET_DHCP_SUCCESS) return err; - if ( DebugFlag ) + if (DebugFlag) { - dhcpMessage *dhcp_msg = (dhcpMessage *)&(msg->udpipmsg[sizeof(udpiphdr)]); - syslog (LOG_INFO, "DHCP_ACK received from %s (%u.%u.%u.%u)\n", dhcp_msg->sname, + syslog (LOG_INFO, "DHCP_ACK received from %s (%u.%u.%u.%u)\n", dhcp_resp.dhcp_msg.sname, ((unsigned char *)(iface->dhcp_options.val[dhcpServerIdentifier]))[0], ((unsigned char *)(iface->dhcp_options.val[dhcpServerIdentifier]))[1], ((unsigned char *)(iface->dhcp_options.val[dhcpServerIdentifier]))[2], ((unsigned char *)(iface->dhcp_options.val[dhcpServerIdentifier]))[3]); } - iface->req_sent_time = time (NULL); - #ifdef ARPCHECK /* check if the offered IP address already in use */ - if ( arpCheck(iface) ) + if (arpCheck(iface)) { - if ( DebugFlag ) + if (DebugFlag) syslog (LOG_INFO, "requested %u.%u.%u.%u address is in use\n", ((unsigned char *)&(iface->ciaddr))[0], ((unsigned char *)&(iface->ciaddr))[1], ((unsigned char *)&(iface->ciaddr))[2], ((unsigned char *)&(iface->ciaddr))[3]); - dhcpDecline(); + dhcpDecline (); iface->ciaddr = 0; return RET_DHCP_ADDRESS_IN_USE; } - if ( DebugFlag ) + if (DebugFlag) { syslog (LOG_INFO, "verified %u.%u.%u.%u address is not in use\n", ((unsigned char *)&(iface->ciaddr))[0], ((unsigned char *)&(iface->ciaddr))[1], @@ -865,39 +786,17 @@ int dhcp_request(dhcp_interface *iface, dhcp_msg_build_proc buildDhcpMsg) /* Successfull ACK: Use the fields obtained for future requests */ memcpy (&(iface->siaddr), iface->dhcp_options.val[dhcpServerIdentifier], 4); - memcpy (iface->shaddr, msg->ethhdr.ether_shost, ETH_ALEN); - free (msg); + memcpy (iface->shaddr, dhcp_resp.server_hw_addr, ETH_ALEN); return RET_DHCP_BOUND; } /*****************************************************************************/ -#if 0 -int dhcp_bound(dhcp_interface *iface) -{ - int i; - - i = iface->req_sent_time + ntohl(*(unsigned int *)(iface->dhcp_options.val[dhcpT1value])) - time (NULL); - if ( i > 0 ) - alarm(i); - else - return STATE_DHCP_RENEW; - sleep (ntohl(*(u_int *)(iface->dhcp_options.val[dhcpT1value]))); - - return STATE_DHCP_RENEW; -} -#endif -/*****************************************************************************/ int dhcp_renew(dhcp_interface *iface) { - udpipMessage *msg = NULL; - int err; + dhcp_response_return dhcp_resp; + int err; /* DHCP state RENEW: request renewal of our lease from the original DHCP server */ - -#if 0 - i = iface->req_sent_time + ntohl(*(unsigned int *)(iface->dhcp_options.val[dhcpT2value])) - time(NULL); -#endif - if (!iface) return RET_DHCP_ERROR; if ( DebugFlag ) @@ -910,40 +809,31 @@ int dhcp_renew(dhcp_interface *iface) } iface->xid = random(); - err = dhcpSendAndRecv (iface, DHCP_ACK, &buildDhcpRenew, &msg); + err = dhcp_handle_transaction (iface, DHCP_ACK, &build_dhcp_renew, &dhcp_resp); if (err != RET_DHCP_SUCCESS); return err; - iface->req_sent_time = time (NULL); - - if ( DebugFlag ) + if (DebugFlag) { - dhcpMessage *dhcp_msg = (dhcpMessage *)&(msg->udpipmsg[sizeof(udpiphdr)]); - syslog (LOG_INFO, "DHCP_ACK received from %s (%u.%u.%u.%u)\n", dhcp_msg->sname, + syslog (LOG_INFO, "DHCP_ACK received from %s (%u.%u.%u.%u)\n", dhcp_resp.dhcp_msg.sname, ((unsigned char *)(iface->dhcp_options.val[dhcpServerIdentifier]))[0], ((unsigned char *)(iface->dhcp_options.val[dhcpServerIdentifier]))[1], ((unsigned char *)(iface->dhcp_options.val[dhcpServerIdentifier]))[2], ((unsigned char *)(iface->dhcp_options.val[dhcpServerIdentifier]))[3]); } - free (msg); return RET_DHCP_BOUND; } /*****************************************************************************/ int dhcp_rebind(dhcp_interface *iface) { - udpipMessage *msg = NULL; - int err; + dhcp_response_return dhcp_resp; + int err; /* DHCP state REBIND: request renewal of our lease from _any_ DHCP server */ - -#if 0 - i = iface->req_sent_time + ntohl(*(unsigned int *)(iface->dhcp_options.val[dhcpIPaddrLeaseTime])) - time(NULL); -#endif - if (!iface) return RET_DHCP_ERROR; - if ( DebugFlag ) + if (DebugFlag) { syslog (LOG_INFO,"Broadcasting DHCP_REQUEST for %u.%u.%u.%u\n", ((unsigned char *)&(iface->ciaddr))[0], @@ -953,16 +843,13 @@ int dhcp_rebind(dhcp_interface *iface) } iface->xid = random (); - err = dhcpSendAndRecv(iface, DHCP_ACK, &buildDhcpRebind, &msg); + err = dhcp_handle_transaction(iface, DHCP_ACK, &build_dhcp_rebind, &dhcp_resp); if (err != RET_DHCP_SUCCESS) return err; - iface->req_sent_time = time (NULL); - - if ( DebugFlag ) + if (DebugFlag) { - dhcpMessage *dhcp_msg = (dhcpMessage *)&(msg->udpipmsg[sizeof(udpiphdr)]); - syslog (LOG_INFO, "DHCP_ACK received from %s (%u.%u.%u.%u)\n", dhcp_msg->sname, + syslog (LOG_INFO, "DHCP_ACK received from %s (%u.%u.%u.%u)\n", dhcp_resp.dhcp_msg.sname, ((unsigned char *)(iface->dhcp_options.val[dhcpServerIdentifier]))[0], ((unsigned char *)(iface->dhcp_options.val[dhcpServerIdentifier]))[1], ((unsigned char *)(iface->dhcp_options.val[dhcpServerIdentifier]))[2], @@ -971,22 +858,23 @@ int dhcp_rebind(dhcp_interface *iface) /* Successfull ACK: Use the fields obtained for future requests */ memcpy (&(iface->siaddr), iface->dhcp_options.val[dhcpServerIdentifier], 4); - memcpy (iface->shaddr, msg->ethhdr.ether_shost, ETH_ALEN); - free (msg); + memcpy (iface->shaddr, dhcp_resp.server_hw_addr, ETH_ALEN); return RET_DHCP_BOUND; } /*****************************************************************************/ int dhcp_release(dhcp_interface *iface) { - struct sockaddr addr; - udpipMessage *msg; + struct sockaddr_in addr; + socklen_t addr_len = sizeof (struct sockaddr_in); + int len; + dhcpMessage *msg; if ( iface->ciaddr == 0 ) return RET_DHCP_ERROR; iface->xid = random(); - if (!(msg = buildDhcpRelease (iface))) + if (!(msg = build_dhcp_release (iface, &len, &addr))) return RET_DHCP_ERROR; if (DebugFlag) @@ -998,9 +886,7 @@ int dhcp_release(dhcp_interface *iface) ((unsigned char *)&(iface->siaddr))[2], ((unsigned char *)&(iface->siaddr))[3]); } - memset (&addr, 0, sizeof(struct sockaddr)); - memcpy (addr.sa_data, iface->iface, strlen (iface->iface)); - if ( sendto (iface->sk, msg, sizeof(struct packed_ether_header) + sizeof(udpiphdr) + sizeof(dhcpMessage), 0, &addr, sizeof(struct sockaddr)) == -1 ) + if (sendto (iface->sk, msg, sizeof (dhcpMessage), 0, (struct sockaddr *)&addr, addr_len)) syslog (LOG_ERR, "dhcpRelease: sendto: %m\n"); free (msg); @@ -1013,19 +899,19 @@ int dhcp_release(dhcp_interface *iface) #ifdef ARPCHECK int dhcp_decline(dhcp_interface *iface) { - udpipMessage *msg; - struct sockaddr addr; + struct sockaddr_in addr; + socklen_t addr_len = sizeof (struct sockaddr_in); + int len; + dhcpMessage *msg; iface->xid = random (); - if (!(msg = buildDhcpDecline (iface))) + if (!(msg = build_dhcp_decline (iface, &len, &addr))) return RET_DHCP_ERROR; - memset (&addr, 0, sizeof(struct sockaddr)); - memcpy (addr.sa_data, iface->iface, strlen (iface->iface)); - if ( DebugFlag ) + if (DebugFlag) syslog (LOG_INFO, "Broadcasting DHCP_DECLINE\n"); - if ( sendto (iface->sk, msg, sizeof(struct packed_ether_header) + sizeof(udpiphdr)+sizeof(dhcpMessage), 0, &addr, sizeof(struct sockaddr)) == -1 ) + if (sendto (iface->sk, msg, sizeof (dhcpMessage), 0, &addr, addr_len)) syslog (LOG_ERR,"dhcpDecline: sendto: %m\n"); free (msg); @@ -1035,46 +921,42 @@ int dhcp_decline(dhcp_interface *iface) /*****************************************************************************/ int dhcp_inform(dhcp_interface *iface) { - udpipMessage *msg = NULL; - int err; + dhcp_response_return dhcp_resp; + int err; - if ( DebugFlag ) + if (DebugFlag) { syslog (LOG_INFO, "Broadcasting DHCP_INFORM for %u.%u.%u.%u\n", - ((unsigned char *)&(iface->ciaddr))[0], - ((unsigned char *)&(iface->ciaddr))[1], - ((unsigned char *)&(iface->ciaddr))[2], - ((unsigned char *)&(iface->ciaddr))[3]); + ((unsigned char *)&(iface->ciaddr))[0], ((unsigned char *)&(iface->ciaddr))[1], + ((unsigned char *)&(iface->ciaddr))[2], ((unsigned char *)&(iface->ciaddr))[3]); } iface->xid = random (); - err = dhcpSendAndRecv (iface, DHCP_ACK, buildDhcpInform, &msg); + err = dhcp_handle_transaction (iface, DHCP_ACK, build_dhcp_inform, &dhcp_resp); if (err != RET_DHCP_SUCCESS) return err; - if ( DebugFlag ) + if (DebugFlag) { - dhcpMessage *dhcp_msg = (dhcpMessage *)&(msg->udpipmsg[sizeof(udpiphdr)]); - syslog (LOG_INFO, "DHCP_ACK received from %s (%u.%u.%u.%u)\n", dhcp_msg->sname, + syslog (LOG_INFO, "DHCP_ACK received from %s (%u.%u.%u.%u)\n", dhcp_resp.dhcp_msg.sname, ((unsigned char *)(iface->dhcp_options.val[dhcpServerIdentifier]))[0], ((unsigned char *)(iface->dhcp_options.val[dhcpServerIdentifier]))[1], ((unsigned char *)(iface->dhcp_options.val[dhcpServerIdentifier]))[2], ((unsigned char *)(iface->dhcp_options.val[dhcpServerIdentifier]))[3]); } - free (msg); #ifdef ARPCHECK /* check if the offered IP address already in use */ - if ( arpCheck(iface) ) + if (arpCheck(iface)) { - if ( DebugFlag ) + if (DebugFlag) syslog (LOG_INFO, "Requested %u.%u.%u.%u address is in use\n", ((unsigned char *)&(iface->ciaddr))[0], ((unsigned char *)&(iface->ciaddr))[1], ((unsigned char *)&(iface->ciaddr))[2], ((unsigned char *)&(iface->ciaddr))[3]); dhcpDecline (iface); return RET_DHCP_SUCCESS; } - if ( DebugFlag ) + if (DebugFlag) { syslog (LOG_INFO, "Verified %u.%u.%u.%u address is not in use\n", ((unsigned char *)&(iface->ciaddr))[0], ((unsigned char *)&(iface->ciaddr))[1], @@ -1097,17 +979,16 @@ char *get_dhcp_option_name (int i) } /*****************************************************************************/ -void debug_dump_dhcp_options (udpipMessage *udp_msg, dhcpOptions *options) +void debug_dump_dhcp_options (struct sockaddr_ll *saddr, dhcpMessage *dhcp_msg, dhcpOptions *options) { int i,j; - dhcpMessage *dhcp_msg = (dhcpMessage *)&(udp_msg->udpipmsg[sizeof(udpiphdr)]); - syslog (LOG_INFO, "parseDhcpMsgRecv: %d options received:\n", options->num); + syslog (LOG_INFO, "debug_dump_dhcp_options: %d options received:\n", options->num); for (i = 1; i < 255; i++) { - if ( options->val[i] ) + if (options->val[i]) { - switch ( i ) + switch (i) { case 1: /* subnet mask */ case 3: /* routers on subnet */ @@ -1167,20 +1048,18 @@ void debug_dump_dhcp_options (udpipMessage *udp_msg, dhcpOptions *options) } } - syslog (LOG_INFO, "dhcp_msg->yiaddr = %u.%u.%u.%u\n" - "dhcp_msg->siaddr = %u.%u.%u.%u\n" - "dhcp_msg->giaddr = %u.%u.%u.%u\n" - "dhcp_msg->sname = \"%s\"\n" - "ServerHardwareAddr = %02X.%02X.%02X.%02X.%02X.%02X\n", + syslog (LOG_INFO, "dhcp_msg->yiaddr = %u.%u.%u.%u", ((unsigned char *)&dhcp_msg->yiaddr)[0], ((unsigned char *)&dhcp_msg->yiaddr)[1], - ((unsigned char *)&dhcp_msg->yiaddr)[2], ((unsigned char *)&dhcp_msg->yiaddr)[3], + ((unsigned char *)&dhcp_msg->yiaddr)[2], ((unsigned char *)&dhcp_msg->yiaddr)[3]); + syslog (LOG_INFO, "dhcp_msg->siaddr = %u.%u.%u.%u", ((unsigned char *)&dhcp_msg->siaddr)[0], ((unsigned char *)&dhcp_msg->siaddr)[1], - ((unsigned char *)&dhcp_msg->siaddr)[2], ((unsigned char *)&dhcp_msg->siaddr)[3], + ((unsigned char *)&dhcp_msg->siaddr)[2], ((unsigned char *)&dhcp_msg->siaddr)[3]); + syslog (LOG_INFO, "dhcp_msg->giaddr = %u.%u.%u.%u", ((unsigned char *)&dhcp_msg->giaddr)[0], ((unsigned char *)&dhcp_msg->giaddr)[1], - ((unsigned char *)&dhcp_msg->giaddr)[2], ((unsigned char *)&dhcp_msg->giaddr)[3], - dhcp_msg->sname, - udp_msg->ethhdr.ether_shost[0], udp_msg->ethhdr.ether_shost[1], - udp_msg->ethhdr.ether_shost[2], udp_msg->ethhdr.ether_shost[3], - udp_msg->ethhdr.ether_shost[4], udp_msg->ethhdr.ether_shost[5]); + ((unsigned char *)&dhcp_msg->giaddr)[2], ((unsigned char *)&dhcp_msg->giaddr)[3]); + syslog (LOG_INFO, "dhcp_msg->sname = \"%s\"", dhcp_msg->sname); + syslog (LOG_INFO, "Server Hardware Address = %02X.%02X.%02X.%02X.%02X.%02X\n", + saddr->sll_addr[0], saddr->sll_addr[1], saddr->sll_addr[2], saddr->sll_addr[3], + saddr->sll_addr[4], saddr->sll_addr[5]); } diff --git a/dhcpcd/client.h b/dhcpcd/client.h index 1095115c0..38255c9b9 100644 --- a/dhcpcd/client.h +++ b/dhcpcd/client.h @@ -30,14 +30,15 @@ #include "dhcpcd.h" -#define IPPACKET_SIZE 1500 -#define MAGIC_COOKIE 0x63825363 -#define BROADCAST_FLAG 0x8000 -#define MAC_BCAST_ADDR "\xff\xff\xff\xff\xff\xff" +#define IPPACKET_SIZE 1500 +#define MAGIC_COOKIE 0x63825363 +#define BROADCAST_FLAG 0x8000 +#define MAC_BCAST_ADDR "\xff\xff\xff\xff\xff\xff" +#define IP_BCAST_ADDR 0xFFFFFFFF #ifndef AF_PACKET #define AF_PACKET 17 /* should have been in socketbits.h */ #endif -#define HWADDR_TRIES 3 +#define HWADDR_TRIES 3 /* UDP port numbers for DHCP */ #define DHCP_SERVER_PORT 67 /* from client to server */ @@ -45,20 +46,21 @@ /* DHCP message OP code */ #define DHCP_BOOTREQUEST 1 -#define DHCP_BOOTREPLY 2 +#define DHCP_BOOTREPLY 2 /* DHCP message type */ -#define DHCP_DISCOVER 1 +#define DHCP_DISCOVER 1 #define DHCP_OFFER 2 -#define DHCP_REQUEST 3 -#define DHCP_DECLINE 4 +#define DHCP_REQUEST 3 +#define DHCP_DECLINE 4 #define DHCP_ACK 5 #define DHCP_NAK 6 -#define DHCP_RELEASE 7 +#define DHCP_RELEASE 7 #define DHCP_INFORM 8 -/* DHCP RETRANSMISSION TIMEOUT (microseconds) */ -#define DHCP_INITIAL_RTO (4*1000000) -#define DHCP_MAX_RTO (64*1000000) +/* DHCP RETRANSMISSION TIMEOUT (seconds) */ +#define DHCP_INITIAL_RTO (4) +#define DHCP_MAX_RTO (64) +#define DHCP_OPTIONS_LENGTH 312 typedef struct dhcpMessage { @@ -76,24 +78,9 @@ typedef struct dhcpMessage u_char chaddr[16]; /* client's hardware address */ u_char sname[64]; /* server host name, null terminated string */ u_char file[128]; /* boot file name, null terminated string */ - u_char options[312]; /* message options */ + u_char options[DHCP_OPTIONS_LENGTH]; /* message options */ } __attribute__((packed)) dhcpMessage; -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)); - -#define TOKEN_RING_HEADER_PAD sizeof(struct trh_hdr) + sizeof(struct trllc) -typedef struct udpipMessage -{ - struct packed_ether_header ethhdr; - char udpipmsg[IPPACKET_SIZE]; - char pad_for_tokenring_header[TOKEN_RING_HEADER_PAD]; -} __attribute__((packed)) udpipMessage; - typedef struct dhcpOptions { u_char num; @@ -110,9 +97,7 @@ typedef struct dhcp_interface int sk; int foo_sk; short int saved_if_flags; - int bTokenRing; unsigned int default_lease_time; - time_t req_sent_time; struct in_addr default_router; int ciaddr; @@ -120,7 +105,6 @@ typedef struct dhcp_interface int siaddr; unsigned char shaddr[ETH_ALEN]; unsigned int xid; - unsigned short ip_id; unsigned char cls_id[DHCP_CLASS_ID_MAX_LEN]; int cls_id_len; unsigned char cli_id[DHCP_CLIENT_ID_MAX_LEN]; @@ -202,7 +186,7 @@ static dhcp_option_table dhcp_opt_table[] = { -1, NULL, -1 } }; -typedef udpipMessage *(*dhcp_msg_build_proc)(dhcp_interface *); +typedef dhcpMessage *(*dhcp_msg_build_proc)(dhcp_interface *, int *msg_len, struct sockaddr_in *dest_addr); int dhcp_reboot(dhcp_interface *iface); int dhcp_init(dhcp_interface *iface); diff --git a/dhcpcd/dhcpcd.c b/dhcpcd/dhcpcd.c index 219395388..c4a71f083 100644 --- a/dhcpcd/dhcpcd.c +++ b/dhcpcd/dhcpcd.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include "dhcpcd.h" @@ -45,20 +46,21 @@ * Location: http://www.phystech.com/download/ */ -void classIDsetup(dhcp_interface *iface, const char *g_cls_id); -void clientIDsetup(dhcp_interface *iface, const char *g_cli_id); -void releaseDhcpOptions (dhcp_interface *iface); +extern void class_id_setup (dhcp_interface *iface, const char *g_cls_id); +extern void client_id_setup (dhcp_interface *iface, const char *g_cli_id); +extern void release_dhcp_options (dhcp_interface *iface); /*****************************************************************************/ dhcp_interface *dhcp_interface_init (const char *if_name, dhcp_client_options *in_opts) { int o = 1; - unsigned i = 0; + unsigned i = 3; struct ifreq ifr; - struct sockaddr_pkt sap; - struct sockaddr_in clientAddr; + struct sockaddr_in addr; dhcp_interface *iface = NULL; dhcp_client_options *opts = NULL; + struct rtentry route; + struct sockaddr_in *addrp; if (!if_name || !in_opts) return NULL; @@ -76,60 +78,93 @@ dhcp_interface *dhcp_interface_init (const char *if_name, dhcp_client_options *i memcpy (opts, in_opts, sizeof (dhcp_client_options)); iface->client_options = opts; - classIDsetup (iface, iface->client_options->class_id); - clientIDsetup (iface, iface->client_options->client_id); + class_id_setup (iface, iface->client_options->class_id); + client_id_setup (iface, iface->client_options->client_id); memset (&ifr, 0, sizeof(struct ifreq)); memcpy (ifr.ifr_name, iface->iface, strlen (iface->iface)); - iface->sk = socket (AF_PACKET, SOCK_PACKET, htons(ETH_P_ALL)); + iface->sk = socket (AF_INET, SOCK_DGRAM, 0); if (iface->sk == -1) { syslog (LOG_ERR,"dhcp_interface_init: socket: %m\n"); goto err_out; } - if ( ioctl (iface->sk, SIOCGIFHWADDR, &ifr) ) - { - syslog(LOG_ERR,"dhcpStart: ioctl SIOCGIFHWADDR: %m\n"); - goto err_out; - } - - if (setsockopt (iface->sk, SOL_SOCKET, SO_BROADCAST, &o, sizeof(o)) == -1) - { - syslog (LOG_ERR,"dhcp_interface_init: setsockopt: %m\n"); - goto err_out; - } - if (ioctl (iface->sk, SIOCGIFFLAGS, &ifr)) { syslog (LOG_ERR, "dhcp_interface_init: ioctl SIOCGIFFLAGS: %m\n"); goto err_out; } - iface->saved_if_flags = ifr.ifr_flags; - ifr.ifr_flags = iface->saved_if_flags | IFF_UP | IFF_BROADCAST | IFF_NOTRAILERS | IFF_RUNNING; - if (ioctl (iface->sk, SIOCSIFFLAGS, &ifr)) + + /* Try to get a valid MAC address. Sometimes when you bring a card up, especially ones + * with downloadable firmware, it takes a couple tries to get a valid MAC address + * since the firmware is busy for a bit doing who knows what. + */ + do { - syslog (LOG_ERR,"dhcp_interface_init: ioctl SIOCSIFFLAGS: %m\n"); - goto err_out; - } + if ( ioctl (iface->sk, SIOCGIFHWADDR, &ifr) ) + { + syslog(LOG_ERR,"dhcp_interface_init: ioctl SIOCGIFHWADDR: %m\n"); + goto err_out; + } + memcpy (iface->chaddr, ifr.ifr_hwaddr.sa_data, ETH_ALEN); - memset (&sap, 0, sizeof(sap)); - sap.spkt_protocol = htons (ETH_P_ALL); - memcpy (sap.spkt_device, iface->iface, strlen (iface->iface)); - sap.spkt_family = AF_PACKET; - if ( bind (iface->sk, (void*)&sap, sizeof(struct sockaddr)) == -1 ) - syslog (LOG_ERR,"dhcp_interface_init: bind: %m\n"); + if (setsockopt (iface->sk, SOL_SOCKET, SO_BROADCAST, &o, sizeof(o)) == -1) + { + syslog (LOG_ERR,"dhcp_interface_init: setsockopt (SO_BROADCAST): %m\n"); + goto err_out; + } - memcpy (iface->chaddr, ifr.ifr_hwaddr.sa_data, ETH_ALEN); - fprintf(stdout,"dhcpcd: MAC address = %02x:%02x:%02x:%02x:%02x:%02x\n", - iface->chaddr[0], iface->chaddr[1], iface->chaddr[2], - iface->chaddr[3], iface->chaddr[4], iface->chaddr[5]); + ifr.ifr_flags = iface->saved_if_flags | IFF_UP | IFF_BROADCAST | IFF_NOTRAILERS | IFF_RUNNING; + if (ioctl (iface->sk, SIOCSIFFLAGS, &ifr)) + { + syslog (LOG_ERR,"dhcp_interface_init: ioctl SIOCSIFFLAGS: %m"); + goto err_out; + } - i = time (NULL) + iface->chaddr[5] + 4*iface->chaddr[4] + 8*iface->chaddr[3] + - 16*iface->chaddr[2] + 32*iface->chaddr[1] + 64*iface->chaddr[0]; - srandom (i); - iface->ip_id = i & 0xffff; + memset (&ifr, 0, sizeof (ifr)); + addrp = (struct sockaddr_in *) &ifr.ifr_addr; + strcpy (ifr.ifr_name, iface->iface); + addrp->sin_family = AF_INET; + addrp->sin_port = 0; + memset (&addrp->sin_addr, 0, sizeof (addrp->sin_addr)); + addrp->sin_addr.s_addr = htonl (0); + if (ioctl (iface->sk, SIOCSIFADDR, &ifr)) + { + syslog (LOG_ERR, "dhcp_interface_init: SIOCSIFADDR returned errno %d", errno); + goto err_out; + } + + o = 1; + if (setsockopt (iface->sk, SOL_SOCKET, SO_REUSEADDR, &o, sizeof(o)) == -1) + { + syslog (LOG_ERR,"dhcp_interface_init: setsockopt (SO_REUSEADDR): %m"); + goto err_out; + } + + if (setsockopt (iface->sk, SOL_SOCKET, SO_BINDTODEVICE, iface->iface, strlen (iface->iface)+1)) + { + syslog (LOG_ERR, "dhcp_interface_init: SO_BINDTODEVICE %s (%d) failed: %s", iface->iface, strlen (iface->iface), strerror (errno)); + } + + memset (&addr, 0, sizeof (addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons (DHCP_CLIENT_PORT); + if ( bind (iface->sk, (struct sockaddr *)&addr, sizeof(addr)) != 0 ) + syslog (LOG_ERR,"dhcp_interface_init: bind: %m\n"); + + if (ioctl (iface->sk, SIOCGIFHWADDR, &ifr)) + { + syslog (LOG_ERR,"dhcp_interface_init: ioctl SIOCGIFHWADDR: %m"); + goto err_out; + } + + memcpy (iface->chaddr, ifr.ifr_hwaddr.sa_data, ETH_ALEN); + syslog (LOG_INFO, "dhcp_interface_init: MAC address = %02x:%02x:%02x:%02x:%02x:%02x\n", + iface->chaddr[0], iface->chaddr[1], iface->chaddr[2], iface->chaddr[3], iface->chaddr[4], iface->chaddr[5]); + i--; + } while (iface->chaddr[0] && iface->chaddr[1] && iface->chaddr[2] && iface->chaddr[3] && iface->chaddr[4] && iface->chaddr[5] && (i > 0)); iface->foo_sk = socket (AF_INET, SOCK_DGRAM, 0); if ( iface->foo_sk == -1 ) @@ -140,10 +175,7 @@ dhcp_interface *dhcp_interface_init (const char *if_name, dhcp_client_options *i if (setsockopt (iface->foo_sk, SOL_SOCKET, SO_BROADCAST, &o, sizeof(o))) syslog (LOG_ERR,"dhcp_interface_init: setsockopt: %m\n"); - memset (&clientAddr.sin_addr, 0, sizeof (&clientAddr.sin_addr)); - clientAddr.sin_family = AF_INET; - clientAddr.sin_port = htons (DHCP_CLIENT_PORT); - if ( bind (iface->foo_sk, (struct sockaddr *)&clientAddr, sizeof(clientAddr)) ) + if ( bind (iface->foo_sk, (struct sockaddr *)&addr, sizeof(addr)) ) { if (errno != EADDRINUSE) syslog (LOG_ERR,"dhcp_interface_init: bind: %m\n"); @@ -156,6 +188,28 @@ dhcp_interface *dhcp_interface_init (const char *if_name, dhcp_client_options *i goto err_out; } + /* Set up at least the broadcast route or something */ + memset (&addr, 0, sizeof (addr)); + addr.sin_family = AF_INET; + addr.sin_port = 0; + + memset (&route, 0, sizeof (route)); + memcpy (&route.rt_gateway, &addr, sizeof (addr)); + + addr.sin_addr.s_addr = INADDR_ANY; + memcpy (&route.rt_dst, &addr, sizeof(addr)); + memcpy (&route.rt_genmask, &addr, sizeof(addr)); + + route.rt_dev = iface->iface; + route.rt_flags = RTF_UP; + route.rt_metric = 0; + + if (ioctl (iface->sk, SIOCADDRT, &route) && (errno != EEXIST)) + { + syslog (LOG_ERR, "dhcp_interface_init: SIOCADDRT failed, errno = %d, dev = %s\n", errno, iface->iface); + goto err_out; + } + return iface; err_out: @@ -171,7 +225,7 @@ void dhcp_interface_free (dhcp_interface *iface) if (!iface) return; - releaseDhcpOptions (iface); + release_dhcp_options (iface); if (iface->foo_sk >= 0) close (iface->foo_sk); diff --git a/dhcpcd/udpipgen.c b/dhcpcd/udpipgen.c deleted file mode 100644 index 382c8ed65..000000000 --- a/dhcpcd/udpipgen.c +++ /dev/null @@ -1,119 +0,0 @@ -/* - * dhcpcd - DHCP client daemon - - * Copyright (C) January, 1998 Sergei Viznyuk - * - * 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 -#include "udpipgen.h" -#include "client.h" - -/*****************************************************************************/ -unsigned short in_cksum(unsigned short *addr, int len) -{ - register int sum = 0; - register u_short *w = addr; - register int nleft = len; - while ( nleft > 1 ) - { - sum += *w++; - nleft -= 2; - } - if ( nleft == 1 ) - { - u_char a = 0; - memcpy(&a,w,1); - sum += a; - } - sum = (sum >> 16) + (sum & 0xffff); - sum += (sum >> 16); - return ~sum; -} -/*****************************************************************************/ -void udpipgen (udpiphdr *udpip, unsigned int saddr, unsigned int daddr, unsigned short *ip_id) -{ - /* Use local copy because udpip->ip is not aligned. */ - struct ip ip_local; - struct ip *ip = &ip_local; - struct ipovly *io = (struct ipovly *)udpip->ip; - struct udphdr *udp = (struct udphdr *)udpip->udp; - - io->ih_next = io->ih_prev = 0; - io->ih_x1 = 0; - io->ih_pr = IPPROTO_UDP; - io->ih_len = htons(sizeof(dhcpMessage) + sizeof(struct udphdr)); - io->ih_src.s_addr = saddr; - io->ih_dst.s_addr = daddr; - udp->uh_sport = htons(DHCP_CLIENT_PORT); - udp->uh_dport = htons(DHCP_SERVER_PORT); - udp->uh_ulen = io->ih_len; - udp->uh_sum = 0; - udp->uh_sum = in_cksum((unsigned short *)udpip, sizeof(dhcpMessage) + sizeof(udpiphdr)); - if ( udp->uh_sum == 0 ) - udp->uh_sum = 0xffff; - memcpy(ip,(struct ip *)udpip->ip,sizeof(ip_local)); - ip->ip_hl = 5; - ip->ip_v = IPVERSION; - ip->ip_tos = 0; /* normal service */ - ip->ip_len = htons(sizeof(dhcpMessage) + sizeof(udpiphdr)); - ip->ip_id = htons(*ip_id); *ip_id++; - ip->ip_off = 0; - ip->ip_ttl = IPDEFTTL; /* time to live, 64 by default */ - ip->ip_p = IPPROTO_UDP; - ip->ip_src.s_addr = saddr; - ip->ip_dst.s_addr = daddr; - ip->ip_sum = 0; - memcpy(udpip->ip,ip,sizeof(ip_local)); - ip->ip_sum = in_cksum((unsigned short *)&ip_local,sizeof(struct ip)); - memcpy(udpip->ip,ip,sizeof(ip_local)); -} -/*****************************************************************************/ -int udpipchk(udpiphdr *udpip) -{ - int hl; - struct ip save_ip; - struct ip *ip = (struct ip *)udpip->ip; - struct ipovly *io = (struct ipovly *)udpip->ip; - struct udphdr *udp = (struct udphdr *)udpip->udp; - udpiphdr *nudpip = udpip; - - hl = ip->ip_hl<<2; - if ( in_cksum((unsigned short *)udpip,hl) ) - return -1; - memcpy(&save_ip, udpip->ip, sizeof(struct ip)); - hl -= sizeof(struct ip); - if ( hl ) - { - /* thrash IP options */ - nudpip = (udpiphdr *)((char *)udpip+hl); - memmove((char *)nudpip,udpip,sizeof(struct ip)); - io = (struct ipovly *)nudpip->ip; - ip = (struct ip *)nudpip->ip; - udp = (struct udphdr *)nudpip->udp; - } - if ( udp->uh_sum == 0 ) - return 0; /* no checksum has been done by sender */ - io->ih_next = io->ih_prev = 0; - io->ih_x1 = 0; - io->ih_len = udp->uh_ulen; - hl = ntohs(udp->uh_ulen)+sizeof(struct ip); - if ( in_cksum((unsigned short *)nudpip,hl) ) - return -2; - memcpy(udpip->ip, &save_ip, sizeof(struct ip)); - return 0; -} diff --git a/dhcpcd/udpipgen.h b/dhcpcd/udpipgen.h deleted file mode 100644 index f1aa13e1f..000000000 --- a/dhcpcd/udpipgen.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * dhcpcd - DHCP client daemon - - * Copyright (C) January, 1998 Sergei Viznyuk - * - * 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. - */ - -#ifndef UDPIPGEN_H -#define UDPIPGEN_H - -#include - -#ifndef IPDEFTTL -#define IPDEFTTL 64 -#endif - -struct ipovly -{ - int ih_next,ih_prev; - u_char ih_x1; - u_char ih_pr; - u_short ih_len; - struct in_addr ih_src; - struct in_addr ih_dst; -} __attribute__((packed)); - -struct udphdr -{ - u_int16_t uh_sport; - u_int16_t uh_dport; - u_int16_t uh_ulen; - u_int16_t uh_sum; -} __attribute__((packed)); - -typedef struct udpiphdr -{ - char ip[sizeof(struct ip)]; - char udp[sizeof(struct udphdr)]; -} __attribute__((packed)) udpiphdr; - -void udpipgen (udpiphdr *udpip, unsigned int saddr, unsigned int daddr, unsigned short *ip_id); -int udpipchk (udpiphdr *udpip); - -#endif diff --git a/src/Makefile.am b/src/Makefile.am index 322af9c05..e2f7cedae 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,4 +1,3 @@ - INCLUDES = -I${top_srcdir} AM_CPPFLAGS = \ diff --git a/src/NetworkManager.c b/src/NetworkManager.c index 0c2691757..f9e0d621f 100644 --- a/src/NetworkManager.c +++ b/src/NetworkManager.c @@ -207,6 +207,11 @@ void nm_remove_device_from_list (NMData *data, const char *udi) } else syslog( LOG_ERR, "nm_remove_device_from_list() could not acquire device list mutex." ); } +/* Hal doesn't really give us any way to pass a GMainContext to our + * mainloop integration function unfortunately. So we have to use + * a global. + */ +GMainContext *main_context = NULL; /* * nm_hal_mainloop_integration @@ -214,7 +219,7 @@ void nm_remove_device_from_list (NMData *data, const char *udi) */ static void nm_hal_mainloop_integration (LibHalContext *ctx, DBusConnection * dbus_connection) { - dbus_connection_setup_with_g_main (dbus_connection, NULL); + dbus_connection_setup_with_g_main (dbus_connection, main_context); } @@ -511,6 +516,9 @@ static NMData *nm_data_new (gboolean enable_test_devices) data->enable_test_devices = enable_test_devices; data->starting_up = TRUE; + data->main_context = g_main_context_new (); + data->main_loop = g_main_loop_new (data->main_context, FALSE); + return (data); } @@ -537,6 +545,9 @@ static void nm_data_free (NMData *data) nm_ap_list_unref (data->allowed_ap_list); nm_ap_list_unref (data->invalid_ap_list); + g_object_unref (data->main_loop); + g_object_unref (data->main_context); + memset (data, 0, sizeof (NMData)); } @@ -587,12 +598,10 @@ static void nm_print_usage (void) int main( int argc, char *argv[] ) { LibHalContext *ctx = NULL; - guint link_source; - guint policy_source; - guint wireless_scan_source; + guint link_source_id, policy_source_id, wscan_source_id; + GSource *link_source, *policy_source, *wscan_source; gboolean become_daemon = TRUE; gboolean enable_test_devices = FALSE; - GMainLoop *loop = NULL; if ((int)getuid() != 0) { @@ -676,6 +685,12 @@ int main( int argc, char *argv[] ) nm_data->info_daemon_avail = nm_dbus_is_info_daemon_running (nm_data->dbus_connection); nm_data->update_ap_lists = TRUE; + /* Right before we init hal, we have to make sure our mainloop integration function + * knows about our GMainContext. HAL doesn't give us any way to pass that into its + * mainloop integration callback, so its got to be a global. + */ + main_context = nm_data->main_context; + /* Initialize libhal. We get a connection to the hal daemon here. */ if ((ctx = hal_initialize (&hal_functions, FALSE)) == NULL) { @@ -700,15 +715,21 @@ int main( int argc, char *argv[] ) /* Create a watch function that monitors cards for link status (hal doesn't do * this for wireless cards yet). */ - link_source = g_timeout_add (5000, nm_link_state_monitor, nm_data); + link_source = g_timeout_source_new (5000); + g_source_set_callback (link_source, nm_link_state_monitor, nm_data, NULL); + link_source_id = g_source_attach (link_source, nm_data->main_context); /* Another watch function which handles networking state changes and applies * the correct policy on a change. */ - policy_source = g_timeout_add (500, nm_state_modification_monitor, nm_data); + policy_source = g_timeout_source_new (500); + g_source_set_callback (policy_source, nm_state_modification_monitor, nm_data, NULL); + policy_source_id = g_source_attach (policy_source, nm_data->main_context); /* Keep a current list of access points */ - wireless_scan_source = g_timeout_add (10000, nm_wireless_scan_monitor, nm_data); + wscan_source = g_timeout_source_new (10000); + g_source_set_callback (wscan_source, nm_wireless_scan_monitor, nm_data, NULL); + wscan_source_id = g_source_attach (wscan_source, nm_data->main_context); if (become_daemon && daemon (0, 0) < 0) { @@ -717,15 +738,14 @@ int main( int argc, char *argv[] ) } /* Wheeee!!! */ - loop = g_main_loop_new (NULL, FALSE); - g_main_loop_run (loop); + g_main_loop_run (nm_data->main_loop); - syslog (LOG_NOTICE, "exiting"); + syslog (LOG_NOTICE, "exiting..."); /* Kill the watch functions */ - g_source_remove (link_source); - g_source_remove (policy_source); - g_source_remove (wireless_scan_source); + g_source_remove (link_source_id); + g_source_remove (policy_source_id); + g_source_remove (wscan_source_id); /* Cleanup */ if (hal_shutdown (nm_data->hal_ctx) != 0) diff --git a/src/NetworkManagerDbus.c b/src/NetworkManagerDbus.c index c3b4dd252..65302823e 100644 --- a/src/NetworkManagerDbus.c +++ b/src/NetworkManagerDbus.c @@ -1653,7 +1653,7 @@ DBusConnection *nm_dbus_init (NMData *data) } dbus_connection_set_exit_on_disconnect (connection, FALSE); - dbus_connection_setup_with_g_main (connection, NULL); + dbus_connection_setup_with_g_main (connection, data->main_context); success = dbus_connection_register_object_path (connection, NM_DBUS_PATH, &nm_vtable, data); if (!success) diff --git a/src/NetworkManagerDevice.c b/src/NetworkManagerDevice.c index dde393034..5f05d702f 100644 --- a/src/NetworkManagerDevice.c +++ b/src/NetworkManagerDevice.c @@ -1617,6 +1617,7 @@ static gpointer nm_device_activation_worker (gpointer user_data) success = nm_device_activate_wireless (dev); else if (nm_device_is_wired (dev)) success = nm_device_activation_configure_ip (dev); + syslog (LOG_DEBUG, "Activation (%s) IP configuration/DHCP returned = %d\n", nm_device_get_iface (dev), success); /* If we were told to quit activation, stop the thread and return */ if (nm_device_activation_should_cancel (dev)) @@ -1624,6 +1625,7 @@ static gpointer nm_device_activation_worker (gpointer user_data) if (!success) { + syslog (LOG_DEBUG, "Activation (%s) IP configuration/DHCP unsuccessful! Ending activation...\n", nm_device_get_iface (dev)); dev->activating = FALSE; dev->just_activated = FALSE; dev->activation_failed = TRUE; @@ -1635,14 +1637,16 @@ static gpointer nm_device_activation_worker (gpointer user_data) dev->activating = FALSE; dev->activation_failed = FALSE; dev->quit_activation = FALSE; + syslog (LOG_DEBUG, "Activation (%s) IP configuration/DHCP successful!\n", nm_device_get_iface (dev)); /* If we were told to quit activation, stop the thread and return */ if (nm_device_activation_should_cancel (dev)) + { + syslog (LOG_DEBUG, "Activation (%s) told to cancel. Ending activation...\n", nm_device_get_iface (dev)); goto out; + } - nm_device_update_ip4_address (dev); - - syslog (LOG_DEBUG, "nm_device_activation_worker(%s): device activated", nm_device_get_iface (dev)); + syslog (LOG_INFO, "nm_device_activation_worker(%s): device activated", nm_device_get_iface (dev)); if (!nm_device_config_get_use_dhcp (dev) || !dev->dhcp_iface) goto out; @@ -1658,11 +1662,19 @@ static gpointer nm_device_activation_worker (gpointer user_data) g_source_remove (dev->rebind_timeout); g_main_loop_unref (dev->loop); g_main_context_unref (dev->context); - dev->context = NULL; - dev->loop = NULL; out: + dev->context = NULL; + dev->loop = NULL; + if (dev->dhcp_iface) + { + dhcp_interface_free (dev->dhcp_iface); + dev->dhcp_iface = NULL; + } + nm_device_unref (dev); + + syslog (LOG_DEBUG, "Activation (%s) ending thread.\n", nm_device_get_iface (dev)); return (NULL); } diff --git a/src/NetworkManagerMain.h b/src/NetworkManagerMain.h index c20152586..ef045a5fc 100644 --- a/src/NetworkManagerMain.h +++ b/src/NetworkManagerMain.h @@ -33,6 +33,8 @@ typedef struct NMData { LibHalContext *hal_ctx; DBusConnection *dbus_connection; + GMainContext *main_context; + GMainLoop *main_loop; gboolean info_daemon_avail; gboolean enable_test_devices; gboolean starting_up; /* Hack for not taking down an already-set-up wired device when we launch */ diff --git a/src/NetworkManagerSystem.c b/src/NetworkManagerSystem.c index 17b508201..88d216b44 100644 --- a/src/NetworkManagerSystem.c +++ b/src/NetworkManagerSystem.c @@ -82,11 +82,9 @@ gboolean nm_system_device_set_ip4_address (NMDevice *dev, int ip4_address) else { success = TRUE; - fprintf(stderr, "Your IP address = %u.%u.%u.%u\n", - ((unsigned char *)&ip4_address)[0], - ((unsigned char *)&ip4_address)[1], - ((unsigned char *)&ip4_address)[2], - ((unsigned char *)&ip4_address)[3]); + syslog (LOG_INFO, "Your IP address = %u.%u.%u.%u\n", + ((unsigned char *)&ip4_address)[0], ((unsigned char *)&ip4_address)[1], + ((unsigned char *)&ip4_address)[2], ((unsigned char *)&ip4_address)[3]); } close (sk); diff --git a/src/backends/NetworkManagerGentoo.c b/src/backends/NetworkManagerGentoo.c index 1a07a0eea..54588e699 100644 --- a/src/backends/NetworkManagerGentoo.c +++ b/src/backends/NetworkManagerGentoo.c @@ -291,6 +291,7 @@ void nm_system_device_update_config_info (NMDevice *dev) guint32 ip4_address = 0; guint32 ip4_netmask = 0; guint32 ip4_gateway = 0; + guint32 ip4_broadcast = 0; g_return_if_fail (dev != NULL);