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