2 * Name Interfaces based on MAC address.
3 * Writen 2000 by Andi Kleen.
4 * Subject to the Gnu Public License, version 2.
5 * TODO: make it support token ring etc.
6 * $Id: nameif.c,v 1.4 2003/09/11 03:46:49 ak Exp $
13 #include <sys/syslog.h>
19 #include <sys/socket.h>
20 #include <sys/ioctl.h>
22 #include <linux/sockios.h>
25 #include "net-support.h"
27 const char default_conf[] = "/etc/mactab";
28 const char *fname = default_conf;
35 syslog(LOG_ERR,"%s: %m", msg);
42 void complain(char *fmt, ...)
47 vsyslog(LOG_ERR,fmt,ap);
49 vfprintf(stderr,fmt,ap);
56 void warning(char *fmt, ...)
61 vsyslog(LOG_ERR,fmt,ap);
63 vfprintf(stderr,fmt,ap);
69 int parsemac(char *str, unsigned char *mac)
72 while ((s = strsep(&str, ":")) != NULL) {
74 if (sscanf(s,"%x", &byte)!=1 || byte > 0xff)
81 void *xmalloc(unsigned sz)
83 void *p = calloc(sz,1);
84 if (!p) errno=ENOMEM, err("xmalloc");
91 ctl_sk = socket(PF_INET,SOCK_DGRAM,0);
95 #define ifr_newname ifr_ifru.ifru_slave
98 int setname(char *oldname, char *newname)
102 memset(&ifr,0,sizeof(struct ifreq));
103 strncpy(ifr.ifr_name, oldname, IFNAMSIZ);
104 strncpy(ifr.ifr_newname, newname, IFNAMSIZ);
105 return ioctl(ctl_sk, SIOCSIFNAME, &ifr);
108 int getmac(char *name, unsigned char *mac)
113 memset(&ifr,0,sizeof(struct ifreq));
114 strcpy(ifr.ifr_name, name);
115 r = ioctl(ctl_sk, SIOCGIFHWADDR, &ifr);
116 memcpy(mac, ifr.ifr_hwaddr.sa_data, 6);
123 char ifname[IFNAMSIZ+1];
124 unsigned char mac[6];
126 struct change *clist;
128 struct change *lookupmac(unsigned char *mac)
131 for (ch = clist;ch;ch = ch->next)
132 if (!memcmp(ch->mac, mac, 6))
137 int addchange(char *p, struct change *ch, char *pos)
139 if (strchr(ch->ifname, ':'))
140 warning(_("alias device %s at %s probably has no mac"),
142 if (parsemac(p,ch->mac) < 0)
143 complain(_("cannot parse MAC `%s' at %s"), p, pos);
157 struct change *ch = NULL;
159 ifh = fopen(fname, "r");
161 complain(_("opening configuration file %s: %s"),fname,strerror(errno));
166 while (getdelim(&line, &linel, '\n', ifh) > 0) {
169 sprintf(pos, _("line %d"), linenum);
171 if ((p = strchr(line,'#')) != NULL)
178 n = strcspn(p, " \t");
180 complain(_("interface name too long at line %d"), line);
181 ch = xmalloc(sizeof(struct change));
182 memcpy(ch->ifname, p, n);
185 p += strspn(p, " \t");
186 n = strspn(p, "0123456789ABCDEFabcdef:");
188 addchange(p, ch, pos);
194 struct option lopt[] = {
195 {"syslog", 0, NULL, 's' },
196 {"config-file", 1, NULL, 'c' },
197 {"help", 0, NULL, '?' },
203 fprintf(stderr, _("usage: nameif [-c configurationfile] [-s] {ifname macaddress}\n"));
207 int main(int ac, char **av)
218 int c = getopt_long(ac,av,"c:s",lopt,NULL);
234 openlog("nameif",0,LOG_LOCAL0);
236 while (optind < ac) {
237 struct change *ch = xmalloc(sizeof(struct change));
242 if (strlen(av[optind])+1>IFNAMSIZ)
243 complain(_("interface name `%s' too long"), av[optind]);
244 strcpy(ch->ifname, av[optind]);
246 sprintf(pos,_("argument %d"),optind);
247 addchange(av[optind], ch, pos);
251 if (!clist || fname != default_conf)
254 ifh = fopen("/proc/net/dev", "r");
255 if (!ifh) complain(_("open of /proc/net/dev: %s"), strerror(errno));
259 while (getdelim(&line, &linel, '\n', ifh) > 0) {
261 unsigned char mac[6];
269 n = strcspn(p, ": \t");
273 complain(_("interface name `%s' too long"), p);
275 if (getmac(p, mac) < 0)
283 if (strcmp(p, ch->ifname)) {
284 if (setname(p, ch->ifname) < 0)
285 complain(_("cannot change name of %s to %s: %s"),
286 p, ch->ifname, strerror(errno));
292 struct change *ch = clist;
295 warning(_("interface '%s' not found"), ch->ifname);