/* ******************************************************************** * * ni_fallbackhwaddr.c version 0.01 2-3-09 * * * * COPYRIGHT 2008-2009 Michael Robinton * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of either: * * * * a) the GNU General Public License as published by the Free * * Software Foundation; either version 2, or (at your option) any * * later version, or * * * * b) the "Artistic License" which comes with this distribution. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See either * * the GNU General Public License or the Artistic License for more * * details. * * * * You should have received a copy of the Artistic License with this * * distribution, in the file named "Artistic". If not, I'll be glad * * to provide one. * * * * You should also have received a copy of the GNU General Public * * License along with this program in the file named "Copying". If not, * * write to the * * * * Free Software Foundation, Inc. * * 59 Temple Place, Suite 330 * * Boston, MA 02111-1307, USA * * * * or visit their web page on the internet at: * * * * http://www.gnu.org/copyleft/gpl.html. * * ******************************************************************** */ #include "localconf.h" unsigned char * ni_fallbackhwaddr(u_int af, void * vifr) { struct nifreq * ifr = (struct nifreq * )vifr; int i, n, dflgs, ppa, fd = -1; char * p; #ifdef HAVE_STRUCT_IFDEVEA struct ifdevea physaddr; #endif #ifdef HAVE_NETIO_H struct fis * ioctl_arg; #endif #ifdef HAVE_SYS_DLPI_H char name[IFNAMSIZ +5], dlpbuf[DL_MAXIMUM]; struct strbuf ctrl; union DL_primitives dlp; dl_info_ack_t * dlpi = (dl_info_ack_t *)dlpbuf; # ifdef DL_ATTACH_REQ dl_ok_ack_t * dlpa = (dl_ok_ack_t *)dlpbuf; dl_bind_ack_t * dlpb = (dl_bind_ack_t *)dlpbuf; dl_phys_addr_ack_t * dlpp = (dl_phys_addr_ack_t *)dlpbuf; # endif #endif #if defined (SIOCGIFHWADDR) || defined (SIOCGENADR) || (defined (HAVE_STRUCT_IFDEVEA) && defined (SIOCPHYSADDR)) if ((fd = ni_clos_reopn_dgrm(fd,af)) < 0) goto dgrm_failed; # ifdef SIOCGIFHWADDR if (ioctl(fd,SIOCGIFHWADDR,ifr) != -1 && NI_MAC_NOT_ZERO(&ifr->ni_saddr.sa_data)) { close(fd); return (unsigned char *)(&ifr->ni_saddr.sa_data); } # endif # ifdef SIOCGENADDR if (ioctl(fd,SIOCGENADDR,ifr) != -1 && NI_MAC_NOT_ZERO(&ifr->ni_char)) { close(fd); return (unsigned char *)&ifr->ni_char; } # endif # if defined (HAVE_STRUCT_IFDEVEA) && defined (SIOCSPHYSADDR) bzero(phys.ifr_name,sizeof(physaddr)); strlcpy(physaddr.ifr_name,ifr->ni_ifr_name,IFNAMSIZ); if (ioctl(fd,SIOCPHYSADDR,&physaddr) >= 0 && NI_MAC_NOT_ZERO(physaddr.current_pa)) { memcpy(&ifr->ni_char,&physaddr.current_pa[0]); close(fd); return (unsigned char *)&ifr->ni_char; } # endif close(fd); dgrm_failed: #endif /* all that stuff above */ /* ok, could not get the MAC address the easy way, try harder */ #ifdef HAVE_NIT_IF_H if ((fd = open("/dev/nit",0)) >= 0) { if (ioctl(fd,NIOCBIND,ifr) >= 0 && ioctl(fd,SIOCGIFADDR) >= 0) { close(fd); if (NI_MAC_NOT_ZERO(&ifr->ni_char)) return (unsigned char *)&ifr->ni_char; else close(fd); } #endif /* http://www.informatik.uni-frankfurt.de/doc/man/hpux/lan.7.html */ #ifdef HAVE_NETIO_H if ((fd = open(&ifr->ni_ifr_name,O_RDONLY)) >= 0) { bzero(&ioctl_arg,sizeof(struct fis)); ioctl_arg.reqtype = LOCAL_ADDRESS; if (ioctl(fd,NETSTAT,&ioctl_arg) >= 0) { close(fd); if (ioctl_arg.vtype == 6) { memcpy(&ifr->ni_char,&ioctl_arg.value.s[0],6); return (unsigned char *)&ifr->ni_char; } } close(fd); } #endif #ifdef HAVE_SYS_DLPI_H ppa = -1; sprintf(name,"/dev/%s",&ifr->ni_ifr_name); if ((fd = open(name,O_RDWR)) < 0) { /* try opening without the ppa number */ n = strlen(name); p = name; p += 5; for(i=5;idl_primitive != DL_INFO_ACK) goto dlpi_error; /* have hardware mac, might not be current mac */ memcpy(&ifr->ni_ifr_name,(dlpbuf + dlpi->dl_addr_offset),6); # ifdef DL_ATTACH_REQ if (ppa < 0 || dlpi->dl_provider_style != DL_STYLE2) goto dlpi_ret_hw; bzero(&ctrl,sizeof(ctrl)); dlp.attach_req.dl_primitive = DL_ATTACH_REQ; dlp.attach_req.dl_ppa = ppa; ctrl.buf = (char *)&dlp; ctrl.len = DL_ATTACH_REQ_SIZE; if (putmsg(fd,&ctrl,NULL,0) < 0) goto dlpi_ret_hw; ctrl.buf = (char *)&dlpbuf; ctrl.len = 0; ctrl.maxlen = DL_MAXIMUM; i = RS_HIPRI; /* flags */ bzero(dlpbuf,DL_OK_ACK_SIZE); if (getmsg(fd,&ctrl,NULL,&i) < 0) goto dlpi_ret_hw; if (dlpa->dl_primitive != DL_OK_ACK) goto dlpi_ret_hw; # endif /* DL_ATTACH_REQ */ bzero(&ctrl,sizeof(ctrl)); dlp.dl_primitive = DL_PHYS_ADDR_REQ; dlp.physaddr_req.dl_addr_type = DL_CURR_PHYS_ADDR; ctrl.buf = (char *)&dlp; ctrl.len = DL_PHYS_ADDR_REQ_SIZE; if (putmsg(fd,&ctrl,NULL,0) < 0) goto dlpi_ret_hw; ctrl.buf = (char *)&dlpbuf; ctrl.len = 0; ctrl.maxlen = DL_MAXIMUM; i = RS_HIPRI; /* flags */ bzero(dlpbuf,DL_MAXIMUM); if (getmsg(fd,&ctrl,NULL,&i) < 0) goto dlpi_ret_hw; if (dlpi->dl_primitive != DL_PHYS_ADDR_ACK) goto dlpi_ret_hw; /* have current MAC address, return it */ memcpy(ifr->ni_ifr_name,(dlpbuf + dlpp->dl_addr_offset),6); dlpi_ret_hw: close(fd); return (unsigned char *)&ifr->ni_ifr_name[0]; dlpi_error: close(fd); #endif /* HAVE_SYS_DLPI_H */ hwaddr_error: errno = ENOSYS; return NULL; }