Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 24 Oct 2001 10:02:50 -0500 (CDT)
From:      tinguely@web.cs.ndsu.nodak.edu
To:        FreeBSD-gnats-submit@freebsd.org
Cc:        tinguely@rrnet.com
Subject:   bin/31476: ifconfig's lladdr is ethernet specific
Message-ID:  <200110241502.f9OF2oT04781@web.cs.ndsu.nodak.edu>

next in thread | raw e-mail | index | archive | help

>Number:         31476
>Category:       bin
>Synopsis:       ifconfig's lladdr is ethernet specific
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Wed Oct 24 08:10:00 PDT 2001
>Closed-Date:
>Last-Modified:
>Originator:     mark tinguely
>Release:        FreeBSD 4.4 i386
>Organization:
Mark Tinguely Consulting
>Environment:
System: FreeBSD web.cs.ndsu.nodak.edu 4.4-RELEASE FreeBSD 4.3-STABLE #0: Tue Oct  2 09:13:48 CDT 2001 root@web.cs.ndsu.nodak.edu:/usr/obj/usr/src/sys/WEB44 i386


>Description:
	ifconfig's lladdr feature that allows the setting of the link-level
	address on an interface. lladdr is documented to not be
	ethernet-specific, but the implementation uses ether_aton() which
	requires the link level address to be EXACTLY ETHER_ADDR_LEN in
	length.

	I want to add support for changing a ARCNET link-level address which
	is only one octect long.

>How-To-Repeat:
	ifconfig INTERFACE lladdr 88
>Fix:

	I added a routine to ifconfig called generic_atoi that will
	allow abitraty length link-level addresses. generic_atoi() will
	assume ETHER_ADDR_LEN length if the caller does not include
	an integer to get the count of octets in the specified link-level
	address.

	The patch also adds "arc" as a new address family. My apologies
	for adding two features into one bug-report patch, but they go
	hand-in-hand.

	The SIOCSIFLLADDR ioctl processing in sys/net/if.c will not
	allow a person to set the wrong length link-level address, so
	this will not break anything in the kernel.


diff -ur ifconfig.orig/ifconfig.c ifconfig/ifconfig.c
--- ifconfig.orig/ifconfig.c	Mon Aug 20 13:38:41 2001
+++ ifconfig/ifconfig.c	Wed Oct 24 09:29:11 2001
@@ -157,6 +157,7 @@
 void	tunnel_status __P((int s));
 void	usage __P((void));
 void	ifmaybeload __P((char *name));
+struct ether_addr	*generic_aton __P((const char *a, int *cnt));
 
 #ifdef INET6
 void	in6_fillscopeid __P((struct sockaddr_in6 *sin6));
@@ -292,7 +293,7 @@
 typedef void af_getprefix __P((const char *, int));
 
 af_status	in_status, at_status, ether_status;
-af_getaddr	in_getaddr, at_getaddr, ether_getaddr;
+af_getaddr	in_getaddr, at_getaddr, ether_getaddr, arc_getaddr;
 
 #ifndef NO_IPX
 af_status	ipx_status;
@@ -342,6 +343,8 @@
 #endif
 	{ "ether", AF_LINK, ether_status, ether_getaddr, NULL,
 	     0, SIOCSIFLLADDR, NULL, C(ridreq) },
+	{ "arc", AF_LINK, ether_status, arc_getaddr, NULL,
+	     0, SIOCSIFLLADDR, NULL, C(ridreq) },
 #if 0	/* XXX conflicts with the media command */
 #ifdef USE_IF_MEDIA
 	{ "media", AF_UNSPEC, media_status, NULL, NULL, }, /* XXX not real!! */
@@ -1059,6 +1062,54 @@
 		warn("ioctl (set mtu)");
 }
 
+/*
+ * generic_aton() converts up to ETHER_ADDR_LEN ASCII hexadecimal strings
+ * seperated by colons into a ether_addr structure.
+ * generic_aton(a, NULL) is the same as ether_aton(a)
+ * Return values:
+ *    function returns converted input from a as an ether_addr structure
+ *    cnt returns the number of entries found.
+ */
+struct ether_addr *
+generic_aton(a, cnt)
+        const char *a;
+	int *cnt;
+{
+	int i;
+	char *s, *e;
+        static struct ether_addr o;
+
+	i = 0;
+
+	s = (char *) a;
+	while ((*s == ':' || ishexnumber(*s)) && i < ETHER_ADDR_LEN) {
+		o.octet[i] = strtol(s, &e, 16);
+		s = e;
+		if (*s == ':') {
+			i++;
+			s++;
+		}
+	}
+
+	++i;		/* complete last item */
+
+	if (cnt != NULL) {
+		if ((i == 1 && o.octet[0] == 0) || *s != '\0') {
+			*cnt = 0;
+			return (NULL);	/* no info, or too long */
+		} else
+			*cnt = i;	/* save number of entries */
+	} else if (i != ETHER_ADDR_LEN)
+		return (NULL);
+
+
+		/* empty unused part of structure */
+	for (; i < ETHER_ADDR_LEN; i++)
+        	o.octet[i] = 0;
+
+        return ((struct ether_addr *)&o);
+}
+
 void
 setiflladdr(val, dummy, s, afp)
 	const char *val;
@@ -1066,17 +1117,18 @@
 	int s;
 	const struct afswtch *afp;
 {
+	int i;
 	struct ether_addr	*ea;
 
-	ea = ether_aton(val);
+	ea = generic_aton(val, &i);
 	if (ea == NULL) {
 		warn("malformed link-level address");
 		return;
 	}
 	strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
-	ifr.ifr_addr.sa_len = ETHER_ADDR_LEN;
+	ifr.ifr_addr.sa_len = i;
 	ifr.ifr_addr.sa_family = AF_LINK;
-	bcopy(ea, ifr.ifr_addr.sa_data, ETHER_ADDR_LEN);
+	bcopy(ea, ifr.ifr_addr.sa_data, i);
 	if (ioctl(s, SIOCSIFLLADDR, (caddr_t)&ifr) < 0)
 		warn("ioctl (set lladdr)");
 
@@ -1773,6 +1825,25 @@
 	sea->sa_family = AF_LINK;
 	sea->sa_len = ETHER_ADDR_LEN;
 	bcopy(ea, sea->sa_data, ETHER_ADDR_LEN);
+}
+
+void
+arc_getaddr(addr, which)
+	const char *addr;
+	int which;
+{
+	struct ether_addr *la;
+	struct sockaddr *sea = &ridreq.ifr_addr;
+	int i;
+
+	la = generic_aton(addr, &i);
+	if (la == NULL || i != 1)
+		errx(1, "malformed arc address");
+	if (which == MASK)
+		errx(1, "Arcnet does not use netmasks");
+	sea->sa_family = AF_LINK;
+	sea->sa_len = 1;
+	bcopy(la, sea->sa_data, 1);
 }
 
 /* XXX  FIXME -- should use strtoul for better parsing. */
>Release-Note:
>Audit-Trail:
>Unformatted:

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-bugs" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200110241502.f9OF2oT04781>