Subject: bin/6546: dhclient vs. Shaw@Home
To: None <gnats-bugs@gnats.netbsd.org>
From: John Nemeth <jnemeth@fibrenet.com>
List: netbsd-bugs
Date: 12/08/1998 03:27:09
>Number:         6546
>Category:       bin
>Synopsis:       dhclient doesn't work with Shaw@Home in some places
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    bin-bug-people (Utility Bug People)
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Tue Dec  8 03:35:01 1998
>Last-Modified:
>Originator:     John Nemeth
>Organization:
access Computer Systems
>Release:        NetBSD-1.3.2
>Environment:
	
System: NetBSD www 1.3.2 NetBSD 1.3.2 (WWW) #3: Mon Dec 7 23:14:30 PST 1998 jnemeth@access:/usr/src/sys/arch/i386/compile/WWW i386


>Description:
	In some locations, dhclient doesn't with Shaw@Home cable
modems.  There are two problems.  The first is that dhclient sets
the BROADCAST flag and it seems that there is a bug in either
Shaw@Home's dhcp server or their dhcp relay, which prevents broadcast
replies from getting back to dhclient.  The second is that the dhcp
software doesn't generate or check UDP checksums.  This is most
likely because there is a bug in UDP checksum code.
>How-To-Repeat:
	Use dhclient with a Shaw@Home cable modem in a location
where it has to go through a dhcp relay.
>Fix:
	To fix the first problem (BROADCAST packet), simply use
regular packets.  The problem with the UDP checksum code is that
it fails to include the destination address in the IP pseudo header
(see RFC 768).  Here is a patch to fix both problems:

diff -c -r dhcp.orig/client/dhclient.c dhcp/client/dhclient.c
*** dhcp.orig/client/dhclient.c	Tue Dec  8 02:58:59 1998
--- dhcp/client/dhclient.c	Tue Dec  8 03:00:48 1998
***************
*** 1369,1375 ****
  	ip -> client -> packet.hops = 0;
  	ip -> client -> packet.xid = random ();
  	ip -> client -> packet.secs = 0; /* filled in by send_discover. */
! 	ip -> client -> packet.flags = htons (BOOTP_BROADCAST); /* XXX */
  	memset (&(ip -> client -> packet.ciaddr),
  		0, sizeof ip -> client -> packet.ciaddr);
  	memset (&(ip -> client -> packet.yiaddr),
--- 1369,1376 ----
  	ip -> client -> packet.hops = 0;
  	ip -> client -> packet.xid = random ();
  	ip -> client -> packet.secs = 0; /* filled in by send_discover. */
! /* some servers don't handle BROADCAST properly -- JMN 981208 */
! /*	ip -> client -> packet.flags = htons (BOOTP_BROADCAST); /* XXX */
  	memset (&(ip -> client -> packet.ciaddr),
  		0, sizeof ip -> client -> packet.ciaddr);
  	memset (&(ip -> client -> packet.yiaddr),
***************
*** 1476,1482 ****
  	ip -> client -> packet.hops = 0;
  	ip -> client -> packet.xid = ip -> client -> xid;
  	ip -> client -> packet.secs = 0; /* Filled in by send_request. */
! 	ip -> client -> packet.flags = htons (BOOTP_BROADCAST);
  
  	/* If we own the address we're requesting, put it in ciaddr;
  	   otherwise set ciaddr to zero. */
--- 1477,1484 ----
  	ip -> client -> packet.hops = 0;
  	ip -> client -> packet.xid = ip -> client -> xid;
  	ip -> client -> packet.secs = 0; /* Filled in by send_request. */
! /* some servers don't handle BROADCAST properly -- JMN 981208 */
! /*	ip -> client -> packet.flags = htons (BOOTP_BROADCAST); */
  
  	/* If we own the address we're requesting, put it in ciaddr;
  	   otherwise set ciaddr to zero. */
diff -c -r dhcp.orig/common/packet.c dhcp/common/packet.c
*** dhcp.orig/common/packet.c	Tue Dec  8 02:58:14 1998
--- dhcp/common/packet.c	Tue Dec  8 02:44:19 1998
***************
*** 194,210 ****
  	/* Compute UDP checksums, including the ``pseudo-header'', the UDP
  	   header and the data. */
  
- #if 0
  	udp.uh_sum =
  		wrapsum (checksum ((unsigned char *)&udp, sizeof udp,
  				   checksum (data, len, 
  					     checksum ((unsigned char *)
  						       &ip.ip_src,
! 						       sizeof ip.ip_src,
  						       IPPROTO_UDP +
  						       (u_int32_t)
  						       ntohs (udp.uh_ulen)))));
- #endif
  
  	/* Copy the udp header into the buffer... */
  	memcpy (&buf [*bufix], &udp, sizeof udp);
--- 194,208 ----
  	/* Compute UDP checksums, including the ``pseudo-header'', the UDP
  	   header and the data. */
  
  	udp.uh_sum =
  		wrapsum (checksum ((unsigned char *)&udp, sizeof udp,
  				   checksum (data, len, 
  					     checksum ((unsigned char *)
  						       &ip.ip_src,
! 						       2 * sizeof ip.ip_src,
  						       IPPROTO_UDP +
  						       (u_int32_t)
  						       ntohs (udp.uh_ulen)))));
  
  	/* Copy the udp header into the buffer... */
  	memcpy (&buf [*bufix], &udp, sizeof udp);
***************
*** 284,290 ****
  	  len -= ip_len + sizeof *udp;
    }
  
- #if 0
    usum = udp -> uh_sum;
    udp -> uh_sum = 0;
  
--- 282,287 ----
***************
*** 292,298 ****
  			   checksum (data, len,
  				     checksum ((unsigned char *)
  					       &ip -> ip_src,
! 					       sizeof ip -> ip_src,
  					       IPPROTO_UDP +
  					       (u_int32_t)
  					       ntohs (udp -> uh_ulen)))));
--- 289,295 ----
  			   checksum (data, len,
  				     checksum ((unsigned char *)
  					       &ip -> ip_src,
! 					       2 * sizeof ip -> ip_src,
  					       IPPROTO_UDP +
  					       (u_int32_t)
  					       ntohs (udp -> uh_ulen)))));
***************
*** 301,307 ****
  	  note ("Bad udp checksum: %x %x", usum, sum);
  	  return -1;
    }
- #endif
  
    /* Copy out the port... */
    memcpy (&from -> sin_port, &udp -> uh_sport, sizeof udp -> uh_sport);
--- 298,303 ----
>Audit-Trail:
>Unformatted:
>class:		sw-bug