xref: /original-bsd/sys/net/if.c (revision 65901293)
1 /*
2  * Copyright (c) 1980 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  *
6  *	@(#)if.c	6.9 (Berkeley) 09/16/85
7  */
8 
9 #include "param.h"
10 #include "systm.h"
11 #include "socket.h"
12 #include "socketvar.h"
13 #include "protosw.h"
14 #include "dir.h"
15 #include "user.h"
16 #include "kernel.h"
17 #include "ioctl.h"
18 #include "errno.h"
19 
20 #include "if.h"
21 #include "af.h"
22 
23 #include "ether.h"
24 
25 int	ifqmaxlen = IFQ_MAXLEN;
26 
27 /*
28  * Network interface utility routines.
29  *
30  * Routines with ifa_ifwith* names take sockaddr *'s as
31  * parameters.
32  */
33 
34 ifinit()
35 {
36 	register struct ifnet *ifp;
37 
38 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
39 		if (ifp->if_snd.ifq_maxlen == 0)
40 			ifp->if_snd.ifq_maxlen = ifqmaxlen;
41 	if_slowtimo();
42 }
43 
44 #ifdef vax
45 /*
46  * Call each interface on a Unibus reset.
47  */
48 ifubareset(uban)
49 	int uban;
50 {
51 	register struct ifnet *ifp;
52 
53 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
54 		if (ifp->if_reset)
55 			(*ifp->if_reset)(ifp->if_unit, uban);
56 }
57 #endif
58 
59 /*
60  * Attach an interface to the
61  * list of "active" interfaces.
62  */
63 if_attach(ifp)
64 	struct ifnet *ifp;
65 {
66 	register struct ifnet **p = &ifnet;
67 
68 	while (*p)
69 		p = &((*p)->if_next);
70 	*p = ifp;
71 }
72 
73 /*
74  * Locate an interface based on a complete address.
75  */
76 /*ARGSUSED*/
77 struct ifaddr *
78 ifa_ifwithaddr(addr)
79 	struct sockaddr *addr;
80 {
81 	register struct ifnet *ifp;
82 	register struct ifaddr *ifa;
83 
84 #define	equal(a1, a2) \
85 	(bcmp((caddr_t)((a1)->sa_data), (caddr_t)((a2)->sa_data), 14) == 0)
86 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
87 	    for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
88 		if (ifa->ifa_addr.sa_family != addr->sa_family)
89 			continue;
90 		if (equal(&ifa->ifa_addr, addr))
91 			return (ifa);
92 		if ((ifp->if_flags & IFF_BROADCAST) &&
93 		    equal(&ifa->ifa_broadaddr, addr))
94 			return (ifa);
95 	}
96 	return ((struct ifaddr *)0);
97 }
98 /*
99  * Locate the point to point interface with a given destination address.
100  */
101 /*ARGSUSED*/
102 struct ifaddr *
103 ifa_ifwithdstaddr(addr)
104 	struct sockaddr *addr;
105 {
106 	register struct ifnet *ifp;
107 	register struct ifaddr *ifa;
108 
109 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
110 	    if (ifp->if_flags & IFF_POINTOPOINT)
111 		for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
112 			if (ifa->ifa_addr.sa_family != addr->sa_family)
113 				continue;
114 			if (equal(&ifa->ifa_dstaddr, addr))
115 				return (ifa);
116 	}
117 	return ((struct ifaddr *)0);
118 }
119 
120 /*
121  * Find an interface on a specific network.  If many, choice
122  * is first found.
123  */
124 struct ifaddr *
125 ifa_ifwithnet(addr)
126 	register struct sockaddr *addr;
127 {
128 	register struct ifnet *ifp;
129 	register struct ifaddr *ifa;
130 	register u_int af = addr->sa_family;
131 	register int (*netmatch)();
132 
133 	if (af >= AF_MAX)
134 		return (0);
135 	netmatch = afswitch[af].af_netmatch;
136 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
137 	    for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
138 		if (ifa->ifa_addr.sa_family != addr->sa_family)
139 			continue;
140 		if ((*netmatch)(&ifa->ifa_addr, addr))
141 			return (ifa);
142 	}
143 	return ((struct ifaddr *)0);
144 }
145 
146 /*
147  * Find an interface using a specific address family
148  */
149 struct ifaddr *
150 ifa_ifwithaf(af)
151 	register int af;
152 {
153 	register struct ifnet *ifp;
154 	register struct ifaddr *ifa;
155 
156 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
157 	    for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
158 		if (ifa->ifa_addr.sa_family == af)
159 			return (ifa);
160 	return ((struct ifaddr *)0);
161 }
162 
163 /*
164  * Mark an interface down and notify protocols of
165  * the transition.
166  * NOTE: must be called at splnet or eqivalent.
167  */
168 if_down(ifp)
169 	register struct ifnet *ifp;
170 {
171 	register struct ifaddr *ifa;
172 
173 	ifp->if_flags &= ~IFF_UP;
174 	for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
175 		pfctlinput(PRC_IFDOWN, &ifa->ifa_addr);
176 }
177 
178 /*
179  * Handle interface watchdog timer routines.  Called
180  * from softclock, we decrement timers (if set) and
181  * call the appropriate interface routine on expiration.
182  */
183 if_slowtimo()
184 {
185 	register struct ifnet *ifp;
186 
187 	for (ifp = ifnet; ifp; ifp = ifp->if_next) {
188 		if (ifp->if_timer == 0 || --ifp->if_timer)
189 			continue;
190 		if (ifp->if_watchdog)
191 			(*ifp->if_watchdog)(ifp->if_unit);
192 	}
193 	timeout(if_slowtimo, (caddr_t)0, hz / IFNET_SLOWHZ);
194 }
195 
196 /*
197  * Map interface name to
198  * interface structure pointer.
199  */
200 struct ifnet *
201 ifunit(name)
202 	register char *name;
203 {
204 	register char *cp;
205 	register struct ifnet *ifp;
206 	int unit;
207 
208 	for (cp = name; cp < name + IFNAMSIZ && *cp; cp++)
209 		if (*cp >= '0' && *cp <= '9')
210 			break;
211 	if (*cp == '\0' || cp == name + IFNAMSIZ)
212 		return ((struct ifnet *)0);
213 	unit = *cp - '0';
214 	for (ifp = ifnet; ifp; ifp = ifp->if_next) {
215 		if (bcmp(ifp->if_name, name, (unsigned)(cp - name)))
216 			continue;
217 		if (unit == ifp->if_unit)
218 			break;
219 	}
220 	return (ifp);
221 }
222 
223 /*
224  * Interface ioctls.
225  */
226 ifioctl(so, cmd, data)
227 	struct socket *so;
228 	int cmd;
229 	caddr_t data;
230 {
231 	register struct ifnet *ifp;
232 	register struct ifreq *ifr;
233 
234 	switch (cmd) {
235 
236 	case SIOCGIFCONF:
237 		return (ifconf(cmd, data));
238 
239 #if (defined(INET) || defined(BBNNET)) && NETHER > 0
240 	case SIOCSARP:
241 	case SIOCDARP:
242 		if (!suser())
243 			return (u.u_error);
244 		/* FALL THROUGH */
245 	case SIOCGARP:
246 		return (arpioctl(cmd, data));
247 #endif
248 	}
249 	ifr = (struct ifreq *)data;
250 	ifp = ifunit(ifr->ifr_name);
251 	if (ifp == 0)
252 		return (ENXIO);
253 	switch (cmd) {
254 
255 	case SIOCGIFFLAGS:
256 		ifr->ifr_flags = ifp->if_flags;
257 		break;
258 
259 	case SIOCSIFFLAGS:
260 		if (ifp->if_flags & IFF_UP && (ifr->ifr_flags & IFF_UP) == 0) {
261 			int s = splimp();
262 			if_down(ifp);
263 			splx(s);
264 		}
265 		ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) |
266 			(ifr->ifr_flags &~ IFF_CANTCHANGE);
267 		if (ifp->if_ioctl)
268 			(void) (*ifp->if_ioctl)(ifp, cmd, data);
269 		break;
270 
271 	default:
272 		if (so->so_proto == 0)
273 			return (EOPNOTSUPP);
274 		return ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL,
275 			cmd, data, ifp));
276 	}
277 	return (0);
278 }
279 
280 /*
281  * Return interface configuration
282  * of system.  List may be used
283  * in later ioctl's (above) to get
284  * other information.
285  */
286 /*ARGSUSED*/
287 ifconf(cmd, data)
288 	int cmd;
289 	caddr_t data;
290 {
291 	register struct ifconf *ifc = (struct ifconf *)data;
292 	register struct ifnet *ifp = ifnet;
293 	register struct ifaddr *ifa;
294 	register char *cp, *ep;
295 	struct ifreq ifr, *ifrp;
296 	int space = ifc->ifc_len, error = 0;
297 
298 	ifrp = ifc->ifc_req;
299 	ep = ifr.ifr_name + sizeof (ifr.ifr_name) - 2;
300 	for (; space > sizeof (ifr) && ifp; ifp = ifp->if_next) {
301 		bcopy(ifp->if_name, ifr.ifr_name, sizeof (ifr.ifr_name) - 2);
302 		for (cp = ifr.ifr_name; cp < ep && *cp; cp++)
303 			;
304 		*cp++ = '0' + ifp->if_unit; *cp = '\0';
305 		if ((ifa = ifp->if_addrlist) == 0) {
306 			bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr));
307 			error = copyout((caddr_t)&ifr, (caddr_t)ifrp, sizeof (ifr));
308 			if (error)
309 				break;
310 			space -= sizeof (ifr), ifrp++;
311 		} else
312 		    for ( ; space > sizeof (ifr) && ifa; ifa = ifa->ifa_next) {
313 			ifr.ifr_addr = ifa->ifa_addr;
314 			error = copyout((caddr_t)&ifr, (caddr_t)ifrp, sizeof (ifr));
315 			if (error)
316 				break;
317 			space -= sizeof (ifr), ifrp++;
318 		}
319 	}
320 	ifc->ifc_len -= space;
321 	return (error);
322 }
323