xref: /netbsd/usr.sbin/mopd/common/device.c (revision c4a72b64)
1 /*	$NetBSD: device.c,v 1.5 2002/08/22 07:18:42 itojun 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  * 3. All advertising materials mentioning features or use of this software
15  *    must display the following acknowledgement:
16  *	This product includes software developed by Mats O Jansson.
17  * 4. The name of the author may not be used to endorse or promote products
18  *    derived from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include <sys/cdefs.h>
33 #ifndef lint
34 __RCSID("$NetBSD: device.c,v 1.5 2002/08/22 07:18:42 itojun Exp $");
35 #endif
36 
37 #include "os.h"
38 #include "common.h"
39 #include "device.h"
40 #include "mopdef.h"
41 #include "pf.h"
42 
43 struct	if_info *iflist;		/* Interface List		*/
44 
45 void	deviceOpen __P((char *, u_short, int));
46 
47 #ifdef	DEV_NEW_CONF
48 /*
49  * Return ethernet adress for interface
50  */
51 
52 void
53 deviceEthAddr(ifname, eaddr)
54 	char *ifname;
55         u_char *eaddr;
56 {
57 	char inbuf[8192];
58 	struct ifconf ifc;
59 	struct ifreq *ifr;
60 	struct sockaddr_dl *sdl;
61 	int fd;
62 	int i, len;
63 
64 	/* We cannot use SIOCGIFADDR on the BPF descriptor.
65 	   We must instead get all the interfaces with SIOCGIFCONF
66 	   and find the right one.  */
67 
68 	/* Use datagram socket to get Ethernet address. */
69 	if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
70 		syslog(LOG_ERR, "deviceEthAddr: socket: %m");
71 		exit(1);
72 	}
73 
74 	ifc.ifc_len = sizeof(inbuf);
75 	ifc.ifc_buf = inbuf;
76 	if (ioctl(fd, SIOCGIFCONF, (caddr_t)&ifc) < 0 ||
77 	    ifc.ifc_len < sizeof(struct ifreq)) {
78 		syslog(LOG_ERR, "deviceEthAddr: SIOGIFCONF: %m");
79 		exit(1);
80 	}
81 	ifr = ifc.ifc_req;
82 	for (i = 0; i < ifc.ifc_len;
83 	     i += len, ifr = (struct ifreq *)((caddr_t)ifr + len)) {
84 		len = sizeof(ifr->ifr_name) + ifr->ifr_addr.sa_len;
85 		sdl = (struct sockaddr_dl *)&ifr->ifr_addr;
86 		if (sdl->sdl_family != AF_LINK || sdl->sdl_type != IFT_ETHER ||
87 		    sdl->sdl_alen != 6)
88 			continue;
89 		if (!strncmp(ifr->ifr_name, ifname, sizeof(ifr->ifr_name))) {
90 			memmove((caddr_t)eaddr, (caddr_t)LLADDR(sdl), 6);
91 			return;
92 		}
93 	}
94 
95 	syslog(LOG_ERR, "deviceEthAddr: Never saw interface `%s'!", ifname);
96 	exit(1);
97 }
98 #endif	/* DEV_NEW_CONF */
99 
100 void
101 deviceOpen(ifname, proto, trans)
102 	char	*ifname;
103 	u_short	 proto;
104 	int	 trans;
105 {
106 	struct if_info *p, tmp;
107 
108 	strlcpy(tmp.if_name, ifname, sizeof(tmp.if_name));
109 	tmp.iopen   = pfInit;
110 
111 	switch (proto) {
112 	case MOP_K_PROTO_RC:
113 		tmp.read = mopReadRC;
114 		tmp.fd   = mopOpenRC(&tmp, trans);
115 		break;
116 	case MOP_K_PROTO_DL:
117 		tmp.read = mopReadDL;
118 		tmp.fd   = mopOpenDL(&tmp, trans);
119 		break;
120 	default:
121 		break;
122 	}
123 
124 	if (tmp.fd != -1) {
125 
126 		p = (struct if_info *)malloc(sizeof(*p));
127 		if (p == 0) {
128 		syslog(LOG_ERR, "deviceOpen: malloc: %m");
129 		exit(1);
130 		}
131 
132 		p->next = iflist;
133 		iflist = p;
134 
135 		strcpy(p->if_name,tmp.if_name);
136 		p->iopen   = tmp.iopen;
137 		p->write   = pfWrite;
138 		p->read    = tmp.read;
139 		memset((char *)p->eaddr, 0, sizeof(p->eaddr));
140 		p->fd      = tmp.fd;
141 
142 #ifdef	DEV_NEW_CONF
143 		deviceEthAddr(p->if_name,&p->eaddr[0]);
144 #else
145 		p->eaddr[0]= tmp.eaddr[0];
146 		p->eaddr[1]= tmp.eaddr[1];
147 		p->eaddr[2]= tmp.eaddr[2];
148 		p->eaddr[3]= tmp.eaddr[3];
149 		p->eaddr[4]= tmp.eaddr[4];
150 		p->eaddr[5]= tmp.eaddr[5];
151 #endif	/* DEV_NEW_CONF */
152 
153 	}
154 }
155 
156 void
157 deviceInitOne(ifname)
158 	char	*ifname;
159 {
160 	char	interface[IFNAME_SIZE];
161 	struct if_info *p;
162 	int	trans;
163 #ifdef _AIX
164 	char	dev[IFNAME_SIZE];
165 	int	unit,j;
166 
167 	unit = 0;
168 	for (j = 0; j < strlen(ifname); j++) {
169 		if (isalpha(ifname[j])) {
170 			dev[j] = ifname[j];
171 		} else {
172 			if (isdigit(ifname[j])) {
173 				unit = unit*10 + ifname[j] - '0';
174 				dev[j] = '\0';
175 			}
176 		}
177 	}
178 
179 	if ((strlen(dev) == 2) &&
180 	    (dev[0] == 'e') &&
181 	    ((dev[1] == 'n') || (dev[1] == 't'))) {
182 		snprintf(interface, sizeof(interface), "ent%d\0", unit);
183 	} else {
184 		snprintf(interface, sizeof(interface), "%s%d\0", dev, unit);
185 	}
186 #else
187 	snprintf(interface, sizeof(interface), "%s", ifname);
188 #endif /* _AIX */
189 
190 	/* Ok, init it just once */
191 
192 	p = iflist;
193 	for (p = iflist; p; p = p->next)  {
194 		if (strcmp(p->if_name,interface) == 0) {
195 			return;
196 		}
197 	}
198 
199 	syslog(LOG_INFO, "Initialized %s", interface);
200 
201 	/* Ok, get transport information */
202 
203 	trans = pfTrans(interface);
204 
205 #ifndef NORC
206 	/* Start with MOP Remote Console */
207 
208 	switch (trans) {
209 	case TRANS_ETHER:
210 		deviceOpen(interface,MOP_K_PROTO_RC,TRANS_ETHER);
211 		break;
212 	case TRANS_8023:
213 		deviceOpen(interface,MOP_K_PROTO_RC,TRANS_8023);
214 		break;
215 	case TRANS_ETHER+TRANS_8023:
216 		deviceOpen(interface,MOP_K_PROTO_RC,TRANS_ETHER);
217 		deviceOpen(interface,MOP_K_PROTO_RC,TRANS_8023);
218 		break;
219 	case TRANS_ETHER+TRANS_8023+TRANS_AND:
220 		deviceOpen(interface,MOP_K_PROTO_RC,TRANS_ETHER+TRANS_8023);
221 		break;
222 	}
223 #endif
224 
225 #ifndef NODL
226 	/* and next MOP Dump/Load */
227 
228 	switch (trans) {
229 	case TRANS_ETHER:
230 		deviceOpen(interface,MOP_K_PROTO_DL,TRANS_ETHER);
231 		break;
232 	case TRANS_8023:
233 		deviceOpen(interface,MOP_K_PROTO_DL,TRANS_8023);
234 		break;
235 	case TRANS_ETHER+TRANS_8023:
236 		deviceOpen(interface,MOP_K_PROTO_DL,TRANS_ETHER);
237 		deviceOpen(interface,MOP_K_PROTO_DL,TRANS_8023);
238 		break;
239 	case TRANS_ETHER+TRANS_8023+TRANS_AND:
240 		deviceOpen(interface,MOP_K_PROTO_DL,TRANS_ETHER+TRANS_8023);
241 		break;
242 	}
243 #endif
244 
245 }
246 
247 /*
248  * Initialize all "candidate" interfaces that are in the system
249  * configuration list.  A "candidate" is up, not loopback and not
250  * point to point.
251  */
252 void
253 deviceInitAll()
254 {
255 #ifdef	DEV_NEW_CONF
256 	char inbuf[8192];
257 	struct ifconf ifc;
258 	struct ifreq *ifr;
259 	struct sockaddr_dl *sdl;
260 	int fd;
261 	int i, len;
262 
263 	if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
264 		syslog(LOG_ERR, "deviceInitAll: socket: %m");
265 		exit(1);
266 	}
267 
268 	ifc.ifc_len = sizeof(inbuf);
269 	ifc.ifc_buf = inbuf;
270 	if (ioctl(fd, SIOCGIFCONF, (caddr_t)&ifc) < 0 ||
271 	    ifc.ifc_len < sizeof(struct ifreq)) {
272 		syslog(LOG_ERR, "deviceInitAll: SIOCGIFCONF: %m");
273 		exit(1);
274 	}
275 	ifr = ifc.ifc_req;
276 	for (i = 0; i < ifc.ifc_len;
277 	     i += len, ifr = (struct ifreq *)((caddr_t)ifr + len)) {
278 		len = sizeof(ifr->ifr_name) + ifr->ifr_addr.sa_len;
279 		sdl = (struct sockaddr_dl *)&ifr->ifr_addr;
280 		if (sdl->sdl_family != AF_LINK || sdl->sdl_type != IFT_ETHER ||
281 		    sdl->sdl_alen != 6)
282 			continue;
283 		if (ioctl(fd, SIOCGIFFLAGS, (caddr_t)ifr) < 0) {
284 			syslog(LOG_ERR, "deviceInitAll: SIOCGIFFLAGS: %m");
285 			continue;
286 		}
287 		if ((ifr->ifr_flags &
288 		    (IFF_UP | IFF_LOOPBACK | IFF_POINTOPOINT)) != IFF_UP)
289 			continue;
290 		deviceInitOne(ifr->ifr_name);
291 	}
292 	(void) close(fd);
293 #else
294 	int fd;
295 	int n;
296 	struct ifreq ibuf[8], *ifrp;
297 	struct ifconf ifc;
298 
299 	if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
300 		syslog(LOG_ERR, "deviceInitAll: old socket: %m");
301 		exit(1);
302 	}
303 	ifc.ifc_len = sizeof ibuf;
304 	ifc.ifc_buf = (caddr_t)ibuf;
305 	if (ioctl(fd, SIOCGIFCONF, (char *)&ifc) < 0 ||
306 	    ifc.ifc_len < sizeof(struct ifreq)) {
307 		syslog(LOG_ERR, "deviceInitAll: old SIOCGIFCONF: %m");
308 		exit(1);
309 	}
310 	ifrp = ibuf;
311 	n = ifc.ifc_len / sizeof(*ifrp);
312 	for (; --n >= 0; ++ifrp) {
313 		if (ioctl(fd, SIOCGIFFLAGS, (char *)ifrp) < 0) {
314 			continue;
315 		}
316 		if (/*(ifrp->ifr_flags & IFF_UP) == 0 ||*/
317 		    ifrp->ifr_flags & IFF_LOOPBACK ||
318 		    ifrp->ifr_flags & IFF_POINTOPOINT)
319 			continue;
320 		deviceInitOne(ifrp->ifr_name);
321 	}
322 
323 	(void) close(fd);
324 #endif /* DEV_NEW_CONF */
325 }
326