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>
26 const char default_conf[] = "/etc/mactab";
27 const char *fname = default_conf;
34 syslog(LOG_ERR,"%s: %m", msg);
41 void complain(char *fmt, ...)
46 vsyslog(LOG_ERR,fmt,ap);
48 vfprintf(stderr,fmt,ap);
55 void warning(char *fmt, ...)
60 vsyslog(LOG_ERR,fmt,ap);
62 vfprintf(stderr,fmt,ap);
68 int parsemac(char *str, unsigned char *mac)
71 while ((s = strsep(&str, ":")) != NULL) {
73 if (sscanf(s,"%x", &byte)!=1 || byte > 0xff)
80 void *xmalloc(unsigned sz)
82 void *p = calloc(sz,1);
83 if (!p) errno=ENOMEM, err("xmalloc");
90 ctl_sk = socket(PF_INET,SOCK_DGRAM,0);
94 #define ifr_newname ifr_ifru.ifru_slave
97 int setname(char *oldname, char *newname)
101 memset(&ifr,0,sizeof(struct ifreq));
102 strcpy(ifr.ifr_name, oldname);
103 strcpy(ifr.ifr_newname, newname);
104 return ioctl(ctl_sk, SIOCSIFNAME, &ifr);
107 int getmac(char *name, unsigned char *mac)
112 memset(&ifr,0,sizeof(struct ifreq));
113 strcpy(ifr.ifr_name, name);
114 r = ioctl(ctl_sk, SIOCGIFHWADDR, &ifr);
115 memcpy(mac, ifr.ifr_hwaddr.sa_data, 6);
122 char ifname[IFNAMSIZ+1];
123 unsigned char mac[6];
125 struct change *clist;
127 struct change *lookupmac(unsigned char *mac)
130 for (ch = clist;ch;ch = ch->next)
131 if (!memcmp(ch->mac, mac, 6))
136 int addchange(char *p, struct change *ch, char *pos)
138 if (strchr(ch->ifname, ':'))
139 warning(_("alias device %s at %s probably has no mac"),
141 if (parsemac(p,ch->mac) < 0)
142 complain(_("cannot parse MAC `%s' at %s"), p, pos);
157 ifh = fopen(fname, "r");
159 complain(_("opening configuration file %s: %s"),fname,strerror(errno));
164 while (getdelim(&line, &linel, '\n', ifh) > 0) {
165 struct change *ch = xmalloc(sizeof(struct change));
168 sprintf(pos, _("line %d"), linenum);
170 if ((p = strchr(line,'#')) != NULL)
177 n = strcspn(p, " \t");
179 complain(_("interface name too long at line %d"), line);
180 memcpy(ch->ifname, p, n);
183 p += strspn(p, " \t");
184 n = strspn(p, "0123456789ABCDEFabcdef:");
186 addchange(p, ch, pos);
192 struct option lopt[] = {
193 {"syslog", 0, NULL, 's' },
194 {"config-file", 1, NULL, 'c' },
195 {"help", 0, NULL, '?' },
201 fprintf(stderr, _("usage: nameif [-c configurationfile] [-s] {ifname macaddress}\n"));
205 int main(int ac, char **av)
215 int c = getopt_long(ac,av,"c:s",lopt,NULL);
231 openlog("nameif",0,LOG_LOCAL0);
233 while (optind < ac) {
234 struct change *ch = xmalloc(sizeof(struct change));
239 if (strlen(av[optind])+1>IFNAMSIZ)
240 complain(_("interface name `%s' too long"), av[optind]);
241 strcpy(ch->ifname, av[optind]);
243 sprintf(pos,_("argument %d"),optind);
244 addchange(av[optind], ch, pos);
248 if (!clist || fname != default_conf)
251 ifh = fopen("/proc/net/dev", "r");
252 if (!ifh) complain(_("open of /proc/net/dev: %s"), strerror(errno));
256 while (getdelim(&line, &linel, '\n', ifh) > 0) {
258 unsigned char mac[6];
266 n = strcspn(p, ": \t");
270 complain(_("interface name `%s' too long"), p);
272 if (getmac(p, mac) < 0)
280 if (strcmp(p, ch->ifname)) {
281 if (setname(p, ch->ifname) < 0)
282 complain(_("cannot change name of %s to %s: %s"),
283 p, ch->ifname, strerror(errno));
289 struct change *ch = clist;
292 warning(_("interface '%s' not found"), ch->ifname);