xref: /csrg-svn/sys/net/if.c (revision 16220)
1 /*	if.c	6.4	84/03/22	*/
2 
3 #include "../h/param.h"
4 #include "../h/systm.h"
5 #include "../h/socket.h"
6 #include "../h/protosw.h"
7 #include "../h/dir.h"
8 #include "../h/user.h"
9 #include "../h/kernel.h"
10 #include "../h/ioctl.h"
11 #include "../h/errno.h"
12 
13 #include "../net/if.h"
14 #include "../net/af.h"
15 
16 #include "ether.h"
17 
18 int	ifqmaxlen = IFQ_MAXLEN;
19 
20 /*
21  * Network interface utility routines.
22  *
23  * Routines with if_ifwith* names take sockaddr *'s as
24  * parameters.  Other routines take value parameters,
25  * e.g. if_ifwithnet takes the network number.
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 ifnet *
75 if_ifwithaddr(addr)
76 	struct sockaddr *addr;
77 {
78 	register struct ifnet *ifp;
79 
80 #define	equal(a1, a2) \
81 	(bcmp((caddr_t)((a1)->sa_data), (caddr_t)((a2)->sa_data), 14) == 0)
82 	for (ifp = ifnet; ifp; ifp = ifp->if_next) {
83 		if (ifp->if_addr.sa_family != addr->sa_family)
84 			continue;
85 		if (equal(&ifp->if_addr, addr))
86 			break;
87 		if ((ifp->if_flags & IFF_BROADCAST) &&
88 		    equal(&ifp->if_broadaddr, addr))
89 			break;
90 	}
91 	return (ifp);
92 }
93 
94 /*
95  * Find an interface on a specific network.  If many, choice
96  * is first found.
97  */
98 struct ifnet *
99 if_ifwithnet(addr)
100 	register struct sockaddr *addr;
101 {
102 	register struct ifnet *ifp;
103 	register u_int af = addr->sa_family;
104 	register int (*netmatch)();
105 
106 	if (af >= AF_MAX)
107 		return (0);
108 	netmatch = afswitch[af].af_netmatch;
109 	for (ifp = ifnet; ifp; ifp = ifp->if_next) {
110 		if (af != ifp->if_addr.sa_family)
111 			continue;
112 		if ((*netmatch)(addr, &ifp->if_addr))
113 			break;
114 	}
115 	return (ifp);
116 }
117 
118 /*
119  * As above, but parameter is network number.
120  */
121 struct ifnet *
122 if_ifonnetof(net)
123 	register int net;
124 {
125 	register struct ifnet *ifp;
126 
127 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
128 		if (ifp->if_net == net)
129 			break;
130 	return (ifp);
131 }
132 
133 /*
134  * Find an interface using a specific address family
135  */
136 struct ifnet *
137 if_ifwithaf(af)
138 	register int af;
139 {
140 	register struct ifnet *ifp;
141 
142 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
143 		if (ifp->if_addr.sa_family == af)
144 			break;
145 	return (ifp);
146 }
147 
148 /*
149  * Mark an interface down and notify protocols of
150  * the transition.
151  * NOTE: must be called at splnet or eqivalent.
152  */
153 if_down(ifp)
154 	register struct ifnet *ifp;
155 {
156 
157 	ifp->if_flags &= ~IFF_UP;
158 	pfctlinput(PRC_IFDOWN, (caddr_t)&ifp->if_addr);
159 }
160 
161 /*
162  * Handle interface watchdog timer routines.  Called
163  * from softclock, we decrement timers (if set) and
164  * call the appropriate interface routine on expiration.
165  */
166 if_slowtimo()
167 {
168 	register struct ifnet *ifp;
169 
170 	for (ifp = ifnet; ifp; ifp = ifp->if_next) {
171 		if (ifp->if_timer == 0 || --ifp->if_timer)
172 			continue;
173 		if (ifp->if_watchdog)
174 			(*ifp->if_watchdog)(ifp->if_unit);
175 	}
176 	timeout(if_slowtimo, (caddr_t)0, hz / IFNET_SLOWHZ);
177 }
178 
179 /*
180  * Map interface name to
181  * interface structure pointer.
182  */
183 struct ifnet *
184 ifunit(name)
185 	register char *name;
186 {
187 	register char *cp;
188 	register struct ifnet *ifp;
189 	int unit;
190 
191 	for (cp = name; cp < name + IFNAMSIZ && *cp; cp++)
192 		if (*cp >= '0' && *cp <= '9')
193 			break;
194 	if (*cp == '\0' || cp == name + IFNAMSIZ)
195 		return ((struct ifnet *)0);
196 	unit = *cp - '0';
197 	for (ifp = ifnet; ifp; ifp = ifp->if_next) {
198 		if (bcmp(ifp->if_name, name, (unsigned)(cp - name)))
199 			continue;
200 		if (unit == ifp->if_unit)
201 			break;
202 	}
203 	return (ifp);
204 }
205 
206 /*
207  * Interface ioctls.
208  */
209 ifioctl(cmd, data)
210 	int cmd;
211 	caddr_t data;
212 {
213 	register struct ifnet *ifp;
214 	register struct ifreq *ifr;
215 
216 	switch (cmd) {
217 
218 	case SIOCGIFCONF:
219 		return (ifconf(cmd, data));
220 
221 #if defined(INET) && NETHER > 0
222 	case SIOCSARP:
223 	case SIOCDARP:
224 		if (!suser())
225 			return (u.u_error);
226 		/* FALL THROUGH */
227 	case SIOCGARP:
228 		return (arpioctl(cmd, data));
229 #endif
230 
231 	case SIOCSIFADDR:
232 	case SIOCSIFFLAGS:
233 	case SIOCSIFDSTADDR:
234 		if (!suser())
235 			return (u.u_error);
236 		break;
237 	}
238 	ifr = (struct ifreq *)data;
239 	ifp = ifunit(ifr->ifr_name);
240 	if (ifp == 0)
241 		return (ENXIO);
242 	switch (cmd) {
243 
244 	case SIOCGIFADDR:
245 		ifr->ifr_addr = ifp->if_addr;
246 		break;
247 
248 	case SIOCGIFDSTADDR:
249 		if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
250 			return (EINVAL);
251 		ifr->ifr_dstaddr = ifp->if_dstaddr;
252 		break;
253 
254 	case SIOCGIFFLAGS:
255 		ifr->ifr_flags = ifp->if_flags;
256 		break;
257 
258 	case SIOCSIFFLAGS:
259 		if (ifp->if_flags & IFF_UP && (ifr->ifr_flags & IFF_UP) == 0) {
260 			int s = splimp();
261 			if_down(ifp);
262 			splx(s);
263 		}
264 		ifp->if_flags = ifr->ifr_flags;
265 		break;
266 
267 	default:
268 		if (ifp->if_ioctl == 0)
269 			return (EOPNOTSUPP);
270 		return ((*ifp->if_ioctl)(ifp, cmd, data));
271 	}
272 	return (0);
273 }
274 
275 /*
276  * Return interface configuration
277  * of system.  List may be used
278  * in later ioctl's (above) to get
279  * other information.
280  */
281 /*ARGSUSED*/
282 ifconf(cmd, data)
283 	int cmd;
284 	caddr_t data;
285 {
286 	register struct ifconf *ifc = (struct ifconf *)data;
287 	register struct ifnet *ifp = ifnet;
288 	register char *cp, *ep;
289 	struct ifreq ifr, *ifrp;
290 	int space = ifc->ifc_len, error = 0;
291 
292 	ifrp = ifc->ifc_req;
293 	ep = ifr.ifr_name + sizeof (ifr.ifr_name) - 2;
294 	for (; space > sizeof (ifr) && ifp; ifp = ifp->if_next) {
295 		bcopy(ifp->if_name, ifr.ifr_name, sizeof (ifr.ifr_name) - 2);
296 		for (cp = ifr.ifr_name; cp < ep && *cp; cp++)
297 			;
298 		*cp++ = '0' + ifp->if_unit; *cp = '\0';
299 		ifr.ifr_addr = ifp->if_addr;
300 		error = copyout((caddr_t)&ifr, (caddr_t)ifrp, sizeof (ifr));
301 		if (error)
302 			break;
303 		space -= sizeof (ifr), ifrp++;
304 	}
305 	ifc->ifc_len -= space;
306 	return (error);
307 }
308