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