From tinguely@web.cs.ndsu.nodak.edu  Wed Oct 24 08:02:52 2001
Return-Path: <tinguely@web.cs.ndsu.nodak.edu>
Received: from web.cs.ndsu.nodak.edu (web.cs.ndsu.NoDak.edu [134.129.125.7])
	by hub.freebsd.org (Postfix) with ESMTP id E53B537B406
	for <FreeBSD-gnats-submit@freebsd.org>; Wed, 24 Oct 2001 08:02:51 -0700 (PDT)
Received: (from tinguely@localhost)
	by web.cs.ndsu.nodak.edu (8.11.4/8.11.4) id f9OF2oT04781;
	Wed, 24 Oct 2001 10:02:50 -0500 (CDT)
	(envelope-from tinguely)
Message-Id: <200110241502.f9OF2oT04781@web.cs.ndsu.nodak.edu>
Date: Wed, 24 Oct 2001 10:02:50 -0500 (CDT)
From: tinguely@web.cs.ndsu.nodak.edu
Reply-To: tinguely@web.cs.ndsu.nodak.edu
To: FreeBSD-gnats-submit@freebsd.org
Cc: tinguely@rrnet.com
Subject: ifconfig's lladdr is ethernet specific
X-Send-Pr-Version: 3.113
X-GNATS-Notify:

>Number:         31476
>Category:       bin
>Synopsis:       ifconfig's lladdr is ethernet specific
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    ru
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Wed Oct 24 08:10:00 PDT 2001
>Closed-Date:    Wed Apr 03 03:50:29 PST 2002
>Last-Modified:  Wed Apr 03 03:50:29 PST 2002
>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:

From: Ruslan Ermilov <ru@FreeBSD.ORG>
To: tinguely@web.cs.ndsu.nodak.edu
Cc: FreeBSD-gnats-submit@FreeBSD.ORG, tinguely@rrnet.com
Subject: Re: bin/31476: ifconfig's lladdr is ethernet specific
Date: Wed, 24 Oct 2001 20:25:17 +0300

 On Wed, Oct 24, 2001 at 10:02:50AM -0500, tinguely@web.cs.ndsu.nodak.edu wrote:
 > 
 > 	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 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.
 > 
 Can't we just use link_addr(3) for that?  Here's the patch (lightly
 tested) for RELENG_4:
 
 Index: ifconfig.c
 ===================================================================
 RCS file: /home/ncvs/src/sbin/ifconfig/ifconfig.c,v
 retrieving revision 1.51.2.13
 diff -u -p -r1.51.2.13 ifconfig.c
 --- ifconfig.c	2001/08/20 18:38:41	1.51.2.13
 +++ ifconfig.c	2001/10/24 17:24:09
 @@ -1066,17 +1066,24 @@ setiflladdr(val, dummy, s, afp)
  	int s;
  	const struct afswtch *afp;
  {
 -	struct ether_addr	*ea;
 +	char *newval;
 +	struct sockaddr_dl	sdl;
  
 -	ea = ether_aton(val);
 -	if (ea == NULL) {
 +	if ((newval = malloc(strlen(val) + 1)) == NULL)
 +		errx(1, "malloc failed");
 +	newval[0] = ':';
 +	strcpy(newval + 1, val);
 +	sdl.sdl_len = sizeof(sdl);
 +	link_addr(newval, &sdl);
 +	free(newval);
 +	if (sdl.sdl_alen > sizeof(ifr.ifr_addr.sa_data)) {
  		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 = sdl.sdl_alen;
  	ifr.ifr_addr.sa_family = AF_LINK;
 -	bcopy(ea, ifr.ifr_addr.sa_data, ETHER_ADDR_LEN);
 +	bcopy(LLADDR(&sdl), ifr.ifr_addr.sa_data, sdl.sdl_alen);
  	if (ioctl(s, SIOCSIFLLADDR, (caddr_t)&ifr) < 0)
  		warn("ioctl (set lladdr)");
  
 
 Cheers,
 -- 
 Ruslan Ermilov		Oracle Developer/DBA,
 ru@sunbay.com		Sunbay Software AG,
 ru@FreeBSD.org		FreeBSD committer,
 +380.652.512.251	Simferopol, Ukraine
 
 http://www.FreeBSD.org	The Power To Serve
 http://www.oracle.com	Enabling The Information Age

From: mark tinguely <tinguely@web.cs.ndsu.nodak.edu>
To: ru@FreeBSD.ORG, tinguely@web.cs.ndsu.nodak.edu
Cc: FreeBSD-gnats-submit@FreeBSD.ORG, tinguely@rrnet.com
Subject: Re: bin/31476: ifconfig's lladdr is ethernet specific
Date: Mon, 5 Nov 2001 08:33:02 -0600 (CST)

 If no one has an objection to Ruslan Ermilov's Oct 24 solution using
 link_addr() that replaces ether_aton() to make ifconfig(8)'s lladdr 
 option not be ethernet MAC size dependant, could the changes be committed 
 and this bug report closed?
 
 thank you,
 
 --mark tinguely
State-Changed-From-To: open->feedback 
State-Changed-By: ru 
State-Changed-When: Wed Mar 27 07:36:44 PST 2002 
State-Changed-Why:  
Fixed in 5.0-CURRENT, in ifconfig.c,v 1.73 and ifconfig.8,v 1.54. 


Responsible-Changed-From-To: freebsd-bugs->ru 
Responsible-Changed-By: ru 
Responsible-Changed-When: Wed Mar 27 07:36:44 PST 2002 
Responsible-Changed-Why:  
MFC in 1 week. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=31476 
State-Changed-From-To: feedback->closed 
State-Changed-By: ru 
State-Changed-When: Wed Apr 3 03:45:58 PST 2002 
State-Changed-Why:  
Fixed in 4.5-STABLE, in ifconfig.c,v 1.51.2.16 and ifconfig.8,v 1.27.2.18. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=31476 
>Unformatted:
