1/*	$NetBSD: device.c,v 1.13 2016/06/08 01:11:49 christos Exp $	*/
2
3/*
4 * Copyright (c) 1993-95 Mats O Jansson.  All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include "port.h"
28#ifndef lint
29__RCSID("$NetBSD: device.c,v 1.13 2016/06/08 01:11:49 christos Exp $");
30#endif
31
32#include "os.h"
33#include "common.h"
34#include "device.h"
35#include "mopdef.h"
36#include "pf.h"
37#include "log.h"
38
39struct	if_info *iflist;		/* Interface List		*/
40
41void	deviceOpen(const char *, u_short, int);
42
43/*
44 * Return ethernet address for interface
45 */
46
47void
48deviceEthAddr(const char *ifname, u_char *eaddr)
49{
50#ifndef AF_LINK
51	int fd;
52	struct ifreq ifr;
53
54	/* Use datagram socket to get Ethernet address. */
55	if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
56		mopLogErr("deviceEthAddr: socket");
57
58	strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
59	if (ioctl(fd, SIOCGIFHWADDR, &ifr) == -1)
60		mopLogErr("deviceEthAddr: SIOGIFHWADDR");
61	memcpy(eaddr, ifr.ifr_hwaddr.sa_data, 6);
62	close(fd);
63#else
64	struct sockaddr_dl *sdl;
65	struct ifaddrs *ifap, *ifa;
66
67	if (getifaddrs(&ifap) != 0)
68		mopLogErr("deviceEthAddr: getifaddrs");
69
70	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
71		sdl = (struct sockaddr_dl *)ifa->ifa_addr;
72		if (sdl->sdl_family != AF_LINK || sdl->sdl_type != IFT_ETHER ||
73		    sdl->sdl_alen != 6)
74			continue;
75		if (!strcmp(ifa->ifa_name, ifname)) {
76			memmove((caddr_t)eaddr, (caddr_t)LLADDR(sdl), 6);
77			freeifaddrs(ifap);
78			return;
79		}
80	}
81
82	freeifaddrs(ifap);
83	mopLogErrX("deviceEthAddr: Never saw interface `%s'!", ifname);
84#endif
85}
86
87void
88deviceOpen(const char *ifname, u_short proto, int trans)
89{
90	struct if_info *p, tmp;
91
92	strlcpy(tmp.if_name, ifname, sizeof(tmp.if_name));
93	tmp.iopen   = pfInit;
94
95	switch (proto) {
96	case MOP_K_PROTO_RC:
97		tmp.read = mopReadRC;
98		tmp.fd   = mopOpenRC(&tmp, trans);
99		break;
100	case MOP_K_PROTO_DL:
101		tmp.read = mopReadDL;
102		tmp.fd   = mopOpenDL(&tmp, trans);
103		break;
104	default:
105		break;
106	}
107
108	if (tmp.fd != -1) {
109		p = malloc(sizeof(*p));
110		if (p == 0)
111			mopLogErr("deviceOpen: malloc");
112
113		p->next = iflist;
114		iflist = p;
115
116		strlcpy(p->if_name, tmp.if_name, sizeof(p->if_name));
117		p->iopen   = tmp.iopen;
118		p->write   = pfWrite;
119		p->read    = tmp.read;
120		memset((char *)p->eaddr, 0, sizeof(p->eaddr));
121		p->fd      = tmp.fd;
122
123#ifdef	DEV_NEW_CONF
124		deviceEthAddr(p->if_name,&p->eaddr[0]);
125#else
126		p->eaddr[0]= tmp.eaddr[0];
127		p->eaddr[1]= tmp.eaddr[1];
128		p->eaddr[2]= tmp.eaddr[2];
129		p->eaddr[3]= tmp.eaddr[3];
130		p->eaddr[4]= tmp.eaddr[4];
131		p->eaddr[5]= tmp.eaddr[5];
132#endif	/* DEV_NEW_CONF */
133
134	}
135}
136
137void
138deviceInitOne(const char *ifname)
139{
140	char	interface[IFNAME_SIZE];
141	struct if_info *p;
142	int	trans;
143#ifdef _AIX
144	char	dev[IFNAME_SIZE];
145	int	unit,j;
146
147	unit = 0;
148	for (j = 0; j < strlen(ifname); j++) {
149		if (isalpha(ifname[j])) {
150			dev[j] = ifname[j];
151		} else {
152			if (isdigit(ifname[j])) {
153				unit = unit*10 + ifname[j] - '0';
154				dev[j] = '\0';
155			}
156		}
157	}
158
159	if ((strlen(dev) == 2) &&
160	    (dev[0] == 'e') &&
161	    ((dev[1] == 'n') || (dev[1] == 't'))) {
162		snprintf(interface, sizeof(interface), "ent%d\0", unit);
163	} else {
164		snprintf(interface, sizeof(interface), "%s%d\0", dev, unit);
165	}
166#else
167	snprintf(interface, sizeof(interface), "%s", ifname);
168#endif /* _AIX */
169
170	/* Ok, init it just once */
171
172	p = iflist;
173	for (p = iflist; p; p = p->next)  {
174		if (strcmp(p->if_name,interface) == 0) {
175			return;
176		}
177	}
178
179	if (!mopInteractive)
180		syslog(LOG_INFO, "Initialized %s", interface);
181
182	/* Ok, get transport information */
183
184	trans = pfTrans(interface);
185
186#ifndef NORC
187	/* Start with MOP Remote Console */
188
189	switch (trans) {
190	case TRANS_ETHER:
191		deviceOpen(interface,MOP_K_PROTO_RC,TRANS_ETHER);
192		break;
193	case TRANS_8023:
194		deviceOpen(interface,MOP_K_PROTO_RC,TRANS_8023);
195		break;
196	case TRANS_ETHER+TRANS_8023:
197		deviceOpen(interface,MOP_K_PROTO_RC,TRANS_ETHER);
198		deviceOpen(interface,MOP_K_PROTO_RC,TRANS_8023);
199		break;
200	case TRANS_ETHER+TRANS_8023+TRANS_AND:
201		deviceOpen(interface,MOP_K_PROTO_RC,TRANS_ETHER+TRANS_8023);
202		break;
203	}
204#endif
205
206#ifndef NODL
207	/* and next MOP Dump/Load */
208
209	switch (trans) {
210	case TRANS_ETHER:
211		deviceOpen(interface,MOP_K_PROTO_DL,TRANS_ETHER);
212		break;
213	case TRANS_8023:
214		deviceOpen(interface,MOP_K_PROTO_DL,TRANS_8023);
215		break;
216	case TRANS_ETHER+TRANS_8023:
217		deviceOpen(interface,MOP_K_PROTO_DL,TRANS_ETHER);
218		deviceOpen(interface,MOP_K_PROTO_DL,TRANS_8023);
219		break;
220	case TRANS_ETHER+TRANS_8023+TRANS_AND:
221		deviceOpen(interface,MOP_K_PROTO_DL,TRANS_ETHER+TRANS_8023);
222		break;
223	}
224#endif
225
226}
227
228/*
229 * Initialize all "candidate" interfaces that are in the system
230 * configuration list.  A "candidate" is up, not loopback and not
231 * point to point.
232 */
233void
234deviceInitAll(void)
235{
236	struct ifaddrs *ifap, *ifa;
237
238	if (getifaddrs(&ifap) != 0)
239		mopLogErr("deviceInitAll: socket");
240
241	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
242#ifdef	AF_LINK
243		struct sockaddr_dl *sdl;
244		sdl = (struct sockaddr_dl *)ifa->ifa_addr;
245		if (sdl->sdl_family != AF_LINK || sdl->sdl_type != IFT_ETHER ||
246		    sdl->sdl_alen != 6)
247			continue;
248#endif
249		if ((ifa->ifa_flags &
250		    (IFF_UP | IFF_LOOPBACK | IFF_POINTOPOINT)) != IFF_UP)
251			continue;
252		deviceInitOne(ifa->ifa_name);
253	}
254
255	freeifaddrs(ifap);
256}
257