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
);