Subject: bin/10531: dhcp (client and server) don't work on Token-Ring
To: None <gnats-bugs@gnats.netbsd.org>
From: Onno van der Linden <onno@simplex.nl>
List: netbsd-bugs
Date: 07/07/2000 15:23:30
>Number: 10531
>Category: bin
>Synopsis: dhcp (client and server) don't work on Token-Ring
>Confidential: no
>Severity: serious
>Priority: medium
>Responsible: bin-bug-people
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Fri Jul 07 15:24:01 PDT 2000
>Closed-Date:
>Last-Modified:
>Originator: Onno van der Linden
>Release: 1.5_ALPHA
>Organization:
>Environment:
System: NetBSD sheep 1.5_ALPHA NetBSD 1.5_ALPHA (SHEEP) #15: Fri Jul 7 22:14:13 MEST 2000 onno@sheep:/usr/src/sys/arch/i386/compile/SHEEP i386
>Description:
Token-ring support in the ISC dhcp only works for linux.
>How-To-Repeat:
run the dhcp server or client on tr0
>Fix:
Below is diff that adds a couple of IEEE802 checks and a
changed tr.c to work for NetBSD instead of linux. There's
also a PR "no IEEE802 support for DHCP in the kernel" that
needs to be applied to the NetBSD kernel in order get dhcp
really working.
*** /usr/src/usr.sbin/dhcp/common/bpf.c.orig Sun Jul 2 16:30:35 2000
--- /usr/src/usr.sbin/dhcp/common/bpf.c Fri Jul 7 23:55:22 2000
***************
*** 139,142 ****
--- 139,145 ----
struct interface_info *info;
{
+ #ifdef HAVE_TR_SUPPORT
+ int link_layer;
+ #endif
/* If we're using the bpf API for sending and receiving,
we don't need to register this interface twice. */
***************
*** 146,149 ****
--- 149,161 ----
info -> wfdesc = info -> rfdesc;
#endif
+
+ #ifdef HAVE_TR_SUPPORT
+ if (ioctl(info -> rfdesc, BIOCGDLT, &link_layer) >= 0 &&
+ link_layer == DLT_IEEE802) {
+ int flag = 1;
+ if (ioctl(info->wfdesc, BIOCSHDRCMPLT, &flag))
+ log_fatal("Can't set BIOCSHDRCMPLT: %m");
+ }
+ #endif
if (!quiet_interface_discovery)
log_info ("Sending on BPF/%s/%s%s%s",
***************
*** 238,244 ****
struct bpf_program p;
u_int32_t bits;
! #if defined(DEC_FDDI) || defined(NETBSD_FDDI)
! int link_layer;
! #endif /* DEC_FDDI || NETBSD_FDDI */
/* Open a BPF device and hang it on this interface... */
--- 250,256 ----
struct bpf_program p;
u_int32_t bits;
! #if defined(DEC_FDDI) || defined(NETBSD_FDDI) || defined(HAVE_TR_SUPPORT)
! int link_layer = 0;
! #endif /* DEC_FDDI || NETBSD_FDDI || HAVE_TR_SUPPORT */
/* Open a BPF device and hang it on this interface... */
***************
*** 287,291 ****
p.bf_len = dhcp_bpf_filter_len;
! #if defined(DEC_FDDI) || defined(NETBSD_FDDI)
/* See if this is an FDDI interface, flag it for later. */
if (ioctl(info -> rfdesc, BIOCGDLT, &link_layer) >= 0 &&
--- 299,303 ----
p.bf_len = dhcp_bpf_filter_len;
! #if defined(DEC_FDDI) || defined(NETBSD_FDDI) || defined(HAVE_TR_SUPPORT)
/* See if this is an FDDI interface, flag it for later. */
if (ioctl(info -> rfdesc, BIOCGDLT, &link_layer) >= 0 &&
***************
*** 310,315 ****
}
p.bf_insns = bpf_fddi_filter;
} else
! #endif /* DEC_FDDI || NETBSD_FDDI */
p.bf_insns = dhcp_bpf_filter;
--- 322,330 ----
}
p.bf_insns = bpf_fddi_filter;
+ } else if (link_layer == DLT_IEEE802) {
+ p.bf_len = dhcp_bpf_tr_filter_len;
+ p.bf_insns = dhcp_bpf_tr_filter;
} else
! #endif /* DEC_FDDI || NETBSD_FDDI || HAVE_TR_SUPPORT */
p.bf_insns = dhcp_bpf_filter;
*** /usr/src/usr.sbin/dhcp/common/discover.c.orig Sun Jun 11 12:15:14 2000
--- /usr/src/usr.sbin/dhcp/common/discover.c Fri Jul 7 21:57:24 2000
***************
*** 220,223 ****
--- 220,225 ----
tmp -> hw_address.hbuf [0] = HTYPE_FDDI;
#endif
+ } else if (foo -> sdl_type == IFT_ISO88025) {
+ tmp -> hw_address.hbuf [0] = HTYPE_IEEE802;
} else {
continue;
*** /dev/null Fri Jul 7 22:19:09 2000
--- /usr/src/usr.sbin/dhcp/common/tr.c Fri Jul 7 22:03:26 2000
***************
*** 0 ****
--- 1,325 ----
+ /* tr.c
+
+ token ring interface support
+ Contributed in May of 1999 by Andrew Chittenden */
+
+ /*
+ * Copyright (c) 1996-2000 Internet Software Consortium.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of The Internet Software Consortium nor the names
+ * of its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
+ * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+ #ifndef lint
+ static char copyright[] =
+ "$Id: tr.c,v 1.1.1.1 2000/04/22 07:11:38 mellon Exp $ Copyright (c) 1996-2000 The Internet Software Consortium. All rights reserved.\n";
+ #endif /* not lint */
+
+ #include "dhcpd.h"
+
+ #if defined (HAVE_TR_SUPPORT) && \
+ (defined (PACKET_ASSEMBLY) || defined (PACKET_DECODING))
+ #include "includes/netinet/ip.h"
+ #include "includes/netinet/udp.h"
+ #include "includes/netinet/if_ether.h"
+ #include <net/if_token.h>
+ #include <net/if_llc.h>
+ #include <sys/time.h>
+
+ /*
+ * token ring device handling subroutines. These are required as token-ring
+ * does not have a simple on-the-wire header but requires the use of
+ * source routing
+ */
+
+ static int insert_source_routing PROTO ((struct token_header *trh, struct interface_info *interface));
+ static void save_source_routing PROTO ((struct token_header *trh, struct interface_info *interface));
+ static void expire_routes PROTO ((void));
+
+ /*
+ * As we keep a list of interesting routing information only, a singly
+ * linked list is all we need
+ */
+ struct routing_entry {
+ struct routing_entry *next;
+ unsigned char addr[ISO88025_ADDR_LEN];
+ unsigned char iface[5];
+ u_int16_t tr_rcf; /* route control field */
+ u_int16_t tr_rdf[TOKEN_MAX_BRIDGE]; /* routing registers */
+ unsigned long access_time; /* time we last used this entry */
+ };
+
+ static struct routing_entry *routing_info = NULL;
+
+ static int routing_timeout = 10;
+ static struct timeval routing_timer;
+
+ void assemble_tr_header (interface, buf, bufix, to)
+ struct interface_info *interface;
+ unsigned char *buf;
+ unsigned *bufix;
+ struct hardware *to;
+ {
+ struct token_header *trh;
+ int hdr_len;
+ struct llc *l;
+
+
+ /* set up the token header */
+ trh = (struct token_header *) &buf[*bufix];
+ if (interface -> hw_address.hlen - 1 == sizeof (trh->token_shost))
+ memcpy (trh->token_shost, &interface -> hw_address.hbuf [1],
+ sizeof (trh->token_shost));
+ else
+ memset (trh->token_shost, 0x00, sizeof (trh->token_shost));
+
+ if (to && to -> hlen == 7) /* XXX */
+ memcpy (trh->token_dhost, &to -> hbuf [1], sizeof trh->token_dhost);
+ else
+ memset (trh->token_dhost, 0xff, sizeof (trh->token_dhost));
+
+ hdr_len = insert_source_routing (trh, interface);
+
+ trh->token_ac = TOKEN_AC;
+ trh->token_fc = TOKEN_FC;
+
+ /* set up the llc header for snap encoding after the tr header */
+ l = (struct llc *)(buf + *bufix + hdr_len);
+ l->llc_dsap = LLC_SNAP_LSAP;
+ l->llc_ssap = LLC_SNAP_LSAP;
+ l->llc_control = LLC_UI;
+ l->llc_snap.org_code[0] = 0;
+ l->llc_snap.org_code[1] = 0;
+ l->llc_snap.org_code[2] = 0;
+ l->llc_snap.ether_type = htons(ETHERTYPE_IP);
+
+ hdr_len += sizeof(struct llc);
+
+ *bufix += hdr_len;
+ }
+
+
+ static unsigned char tr_broadcast[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+ ssize_t decode_tr_header (interface, buf, bufix, from)
+ struct interface_info *interface;
+ unsigned char *buf;
+ unsigned bufix;
+ struct hardware *from;
+ {
+ struct token_header *trh = (struct token_header *) (buf + bufix);
+ struct token_rif *trrif = TOKEN_RIF(trh);
+ struct llc *l;
+ struct ip *ip;
+ struct udphdr *udp;
+ unsigned int route_len = 0;
+ ssize_t hdr_len;
+ struct timeval now;
+
+ /* see whether any source routing information has expired */
+ gettimeofday(&now, NULL);
+
+ if (routing_timer.tv_sec == 0)
+ routing_timer.tv_sec = now.tv_sec + routing_timeout;
+ else if ((now.tv_sec - routing_timer.tv_sec) > 0)
+ expire_routes();
+
+ if (trh->token_shost[0] & TOKEN_RI_PRESENT)
+ route_len = (ntohs(trrif->tr_rcf) & TOKEN_RCF_LEN_MASK) >> 8;
+ else
+ route_len = 0;
+
+ hdr_len = sizeof (struct token_header) + route_len;
+
+ /* now filter out unwanted packets: this is based on the packet
+ * filter code in bpf.c */
+ l = (struct llc *)(buf + bufix + hdr_len);
+ ip = (struct ip *) (l + 1);
+ udp = (struct udphdr *) ((unsigned char*) ip + IP_HL (ip));
+
+ /* make sure it is a snap encoded, IP, UDP, unfragmented packet sent
+ * to our port */
+ if (l->llc_dsap != LLC_SNAP_LSAP
+ || ntohs(l->llc_snap.ether_type) != ETHERTYPE_IP
+ || ip->ip_p != IPPROTO_UDP
+ || (ip->ip_off & IP_OFFMASK) != 0
+ || udp->uh_dport != local_port)
+ return -1;
+
+ /* only save source routing information for packets from valued hosts */
+ save_source_routing(trh, interface);
+ return hdr_len + sizeof (struct llc);
+ }
+
+ /* insert_source_routing inserts source route information into the token ring
+ * header
+ */
+ static int insert_source_routing (trh, interface)
+ struct token_header *trh;
+ struct interface_info* interface;
+ {
+ struct routing_entry *rover;
+ struct timeval now;
+ unsigned int route_len = 0;
+ struct token_rif *trrif = TOKEN_RIF(trh);
+
+ gettimeofday(&now, NULL);
+
+ /* single route broadcasts as per rfc 1042 */
+ if (memcmp(trh->token_dhost, tr_broadcast,ISO88025_ADDR_LEN) == 0) {
+ trh->token_shost[0] |= TOKEN_RI_PRESENT;
+ trrif->tr_rcf = ((sizeof(trrif->tr_rcf)) << 8) & TOKEN_RCF_LEN_MASK;
+ trrif->tr_rcf |= (TOKEN_RCF_FRAME2 | TOKEN_RCF_BROADCAST_SINGLE);
+ trrif->tr_rcf = htons(trrif->tr_rcf);
+ } else {
+ /* look for a routing entry */
+ for (rover = routing_info; rover != NULL; rover = rover->next) {
+ if (memcmp(rover->addr, trh->token_dhost, ISO88025_ADDR_LEN) == 0)
+ break;
+ }
+
+ if (rover != NULL) {
+ /* success: route that frame */
+ if ((rover->tr_rcf & TOKEN_RCF_LEN_MASK) >> 8) {
+ u_int16_t rcf = rover->tr_rcf;
+ memcpy(trrif->tr_rdf,rover->tr_rdf,sizeof(trrif->tr_rdf));
+ rcf ^= TOKEN_RCF_DIRECTION;
+ rcf &= ~TOKEN_RCF_BROADCAST_MASK;
+ trrif->tr_rcf = htons(rcf);
+ trh->token_shost[0] |= TOKEN_RI_PRESENT;
+ }
+ rover->access_time = now.tv_sec;
+ } else {
+ /* we don't have any routing information so send a
+ * limited broadcast */
+ trh->token_shost[0] |= TOKEN_RI_PRESENT;
+ trrif->tr_rcf = ((sizeof(trrif->tr_rcf)) << 8) & TOKEN_RCF_LEN_MASK;
+ trrif->tr_rcf |= (TOKEN_RCF_FRAME2 | TOKEN_RCF_BROADCAST_SINGLE);
+ trrif->tr_rcf = htons(trrif->tr_rcf);
+ }
+ }
+
+ /* return how much of the header we've actually used */
+ if (trh->token_shost[0] & TOKEN_RI_PRESENT)
+ route_len = (ntohs(trrif->tr_rcf) & TOKEN_RCF_LEN_MASK) >> 8;
+ else
+ route_len = 0;
+
+ return sizeof (struct token_header) + route_len;
+ }
+
+ /*
+ * save any source routing information
+ */
+ static void save_source_routing(trh, interface)
+ struct token_header *trh;
+ struct interface_info *interface;
+ {
+ struct routing_entry *rover;
+ struct timeval now;
+ unsigned char saddr[ISO88025_ADDR_LEN];
+ u_int16_t rcf = 0;
+ struct token_rif *trrif = TOKEN_RIF(trh);
+
+ gettimeofday(&now, NULL);
+
+ memcpy(saddr, trh->token_shost, sizeof(saddr));
+ saddr[0] &= 0x7f; /* strip off source routing present flag */
+
+ /* scan our table to see if we've got it */
+ for (rover = routing_info; rover != NULL; rover = rover->next) {
+ if (memcmp(&rover->addr[0], &saddr[0], ISO88025_ADDR_LEN) == 0)
+ break;
+ }
+
+ /* found an entry so update it with fresh information */
+ if (rover != NULL) {
+ if ((trh->token_shost[0] & TOKEN_RI_PRESENT) &&
+ ((ntohs(trrif->tr_rcf) & TOKEN_RCF_LEN_MASK) >> 8) > 2) {
+ rcf = ntohs(trrif->tr_rcf);
+ rcf &= ~TOKEN_RCF_BROADCAST_MASK;
+ memcpy(rover->tr_rdf, trrif->tr_rdf, sizeof(rover->tr_rdf));
+ }
+ rover->tr_rcf = rcf;
+ rover->access_time = now.tv_sec;
+ return; /* that's all folks */
+ }
+
+ /* no entry found, so create one */
+ rover = dmalloc (sizeof (struct routing_entry), MDL);
+ if (rover == NULL) {
+ fprintf(stderr,
+ "%s: unable to save source routing information\n",
+ __FILE__);
+ return;
+ }
+
+ memcpy(rover->addr, saddr, sizeof(rover->addr));
+ memcpy(rover->iface, interface->name, 5);
+ rover->access_time = now.tv_sec;
+ if (trh->token_shost[0] & TOKEN_RI_PRESENT) {
+ if (((ntohs(trrif->tr_rcf) & TOKEN_RCF_LEN_MASK) >> 8) > 2) {
+ rcf = ntohs(trrif->tr_rcf);
+ rcf &= ~TOKEN_RCF_BROADCAST_MASK;
+ memcpy(rover->tr_rdf, trrif->tr_rdf, sizeof(rover->tr_rdf));
+ }
+ rover->tr_rcf = rcf;
+ }
+
+ /* insert into list */
+ rover->next = routing_info;
+ routing_info = rover;
+
+ return;
+ }
+
+ /*
+ * get rid of old routes
+ */
+ static void expire_routes()
+ {
+ struct routing_entry *rover;
+ struct routing_entry **prover = &routing_info;
+ struct timeval now;
+
+ gettimeofday(&now, NULL);
+
+ while((rover = *prover) != NULL) {
+ if ((now.tv_sec - rover->access_time) > routing_timeout) {
+ *prover = rover->next;
+ dfree (rover, MDL);
+ } else
+ prover = &rover->next;
+ }
+
+ /* Reset the timer */
+ routing_timer.tv_sec = now.tv_sec + routing_timeout;
+ routing_timer.tv_usec = now.tv_usec;
+ }
+
+ #endif
*** /usr/src/usr.sbin/dhcp/includes/cf/netbsd.h.orig Sun May 28 12:14:35 2000
--- /usr/src/usr.sbin/dhcp/includes/cf/netbsd.h Fri Jun 30 23:10:36 2000
***************
*** 94,97 ****
--- 94,99 ----
#define HAVE_MKSTEMP
+ #define HAVE_TR_SUPPORT
+
#if defined (USE_DEFAULT_NETWORK)
# define USE_BPF
>Release-Note:
>Audit-Trail:
>Unformatted: