xref: /original-bsd/sys/netinet/in.c (revision 6219b5e8)
1 /*	in.c	6.7	85/04/16	*/
2 
3 #include "param.h"
4 #include "ioctl.h"
5 #include "mbuf.h"
6 #include "protosw.h"
7 #include "socket.h"
8 #include "socketvar.h"
9 #include "uio.h"
10 #include "dir.h"
11 #include "user.h"
12 #include "in_systm.h"
13 #include "../net/if.h"
14 #include "../net/route.h"
15 #include "../net/af.h"
16 #include "in.h"
17 #include "in_var.h"
18 
19 #ifdef INET
20 inet_hash(sin, hp)
21 	register struct sockaddr_in *sin;
22 	struct afhash *hp;
23 {
24 	register u_long n;
25 
26 	n = in_netof(sin->sin_addr);
27 	if (n)
28 	    while ((n & 0xff) == 0)
29 		n >>= 8;
30 	hp->afh_nethash = n;
31 	hp->afh_hosthash = ntohl(sin->sin_addr.s_addr);
32 }
33 
34 inet_netmatch(sin1, sin2)
35 	struct sockaddr_in *sin1, *sin2;
36 {
37 
38 	return (in_netof(sin1->sin_addr) == in_netof(sin2->sin_addr));
39 }
40 
41 /*
42  * Formulate an Internet address from network + host.
43  */
44 struct in_addr
45 in_makeaddr(net, host)
46 	u_long net, host;
47 {
48 	register struct in_ifaddr *ia;
49 	register u_long mask;
50 	u_long addr;
51 
52 	if (IN_CLASSA(net))
53 		mask = IN_CLASSA_HOST;
54 	else if (IN_CLASSB(net))
55 		mask = IN_CLASSB_HOST;
56 	else
57 		mask = IN_CLASSC_HOST;
58 	for (ia = in_ifaddr; ia; ia = ia->ia_next)
59 		if ((ia->ia_netmask & net) == ia->ia_net) {
60 			mask = ~ia->ia_subnetmask;
61 			break;
62 		}
63 	addr = htonl(net | (host & mask));
64 	return (*(struct in_addr *)&addr);
65 }
66 
67 /*
68  * Return the network number from an internet address.
69  */
70 in_netof(in)
71 	struct in_addr in;
72 {
73 	register u_long i = ntohl(in.s_addr);
74 	register u_long net;
75 	register struct in_ifaddr *ia;
76 
77 	if (IN_CLASSA(i))
78 		net = i & IN_CLASSA_NET;
79 	else if (IN_CLASSB(i))
80 		net = i & IN_CLASSB_NET;
81 	else
82 		net = i & IN_CLASSC_NET;
83 
84 	/*
85 	 * Check whether network is a subnet;
86 	 * if so, return subnet number.
87 	 */
88 	for (ia = in_ifaddr; ia; ia = ia->ia_next)
89 		if ((ia->ia_netmask & net) == ia->ia_net)
90 			return (i & ia->ia_subnetmask);
91 	return (net);
92 }
93 
94 /*
95  * Return the host portion of an internet address.
96  */
97 in_lnaof(in)
98 	struct in_addr in;
99 {
100 	register u_long i = ntohl(in.s_addr);
101 	register u_long net, host;
102 	register struct in_ifaddr *ia;
103 
104 	if (IN_CLASSA(i)) {
105 		net = i & IN_CLASSA_NET;
106 		host = i & IN_CLASSA_HOST;
107 	} else if (IN_CLASSB(i)) {
108 		net = i & IN_CLASSB_NET;
109 		host = i & IN_CLASSB_HOST;
110 	} else {
111 		net = i & IN_CLASSC_NET;
112 		host = i & IN_CLASSC_HOST;
113 	}
114 
115 	/*
116 	 * Check whether network is a subnet;
117 	 * if so, use the modified interpretation of `host'.
118 	 */
119 	for (ia = in_ifaddr; ia; ia = ia->ia_next)
120 		if ((ia->ia_netmask & net) == ia->ia_net)
121 			return (host &~ ia->ia_subnetmask);
122 	return (host);
123 }
124 
125 /*
126  * Return 1 if an internet address is for a ``local'' host
127  * (one to which we have a connection).
128  */
129 in_localaddr(in)
130 	struct in_addr in;
131 {
132 	register u_long i = ntohl(in.s_addr);
133 	register u_long net;
134 	register struct in_ifaddr *ia;
135 
136 	if (IN_CLASSA(i))
137 		net = i & IN_CLASSA_NET;
138 	else if (IN_CLASSB(i))
139 		net = i & IN_CLASSB_NET;
140 	else
141 		net = i & IN_CLASSC_NET;
142 
143 	for (ia = in_ifaddr; ia; ia = ia->ia_next)
144 		if ((ia->ia_netmask & net) == ia->ia_net)
145 			return (1);
146 	return (0);
147 }
148 
149 /*
150  * Generic internet control operations (ioctl's).
151  * Ifp is 0 if not an interface-specific ioctl.
152  */
153 in_control(so, cmd, data, ifp)
154 	struct socket *so;
155 	int cmd;
156 	caddr_t data;
157 	register struct ifnet *ifp;
158 {
159 	register struct ifreq *ifr = (struct ifreq *)data;
160 	register struct in_ifaddr *ia = 0;
161 	struct ifaddr *ifa;
162 	struct mbuf *m;
163 	int error;
164 
165 	/*
166 	 * Find address for this interface, if it exists.
167 	 */
168 	if (ifp)
169 		for (ia = in_ifaddr; ia; ia = ia->ia_next)
170 			if (ia->ia_ifp == ifp)
171 				break;
172 
173 	switch (cmd) {
174 
175 	case SIOCGIFADDR:
176 	case SIOCGIFBRDADDR:
177 	case SIOCGIFDSTADDR:
178 	case SIOCGIFNETMASK:
179 		if (ia == (struct in_ifaddr *)0)
180 			return (EADDRNOTAVAIL);
181 		break;
182 
183 	case SIOCSIFADDR:
184 	case SIOCSIFDSTADDR:
185 	case SIOCSIFBRDADDR:
186 	case SIOCSIFNETMASK:
187 		if (!suser())
188 			return (u.u_error);
189 
190 		if (ifp == 0)
191 			panic("in_control");
192 		if (ia == (struct in_ifaddr *)0) {
193 			m = m_getclr(M_WAIT, MT_IFADDR);
194 			if (m == (struct mbuf *)NULL)
195 				return (ENOBUFS);
196 			if (ia = in_ifaddr) {
197 				for ( ; ia->ia_next; ia = ia->ia_next)
198 					;
199 				ia->ia_next = mtod(m, struct in_ifaddr *);
200 			} else
201 				in_ifaddr = mtod(m, struct in_ifaddr *);
202 			ia = mtod(m, struct in_ifaddr *);
203 			if (ifa = ifp->if_addrlist) {
204 				for ( ; ifa->ifa_next; ifa = ifa->ifa_next)
205 					;
206 				ifa->ifa_next = (struct ifaddr *) ia;
207 			} else
208 				ifp->if_addrlist = (struct ifaddr *) ia;
209 			ia->ia_ifp = ifp;
210 			IA_SIN(ia)->sin_family = AF_INET;
211 		}
212 		break;
213 	}
214 
215 	switch (cmd) {
216 
217 	case SIOCGIFADDR:
218 		ifr->ifr_addr = ia->ia_addr;
219 		break;
220 
221 	case SIOCGIFBRDADDR:
222 		if ((ifp->if_flags & IFF_BROADCAST) == 0)
223 			return (EINVAL);
224 		ifr->ifr_dstaddr = ia->ia_broadaddr;
225 		break;
226 
227 	case SIOCGIFDSTADDR:
228 		if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
229 			return (EINVAL);
230 		ifr->ifr_dstaddr = ia->ia_dstaddr;
231 		break;
232 
233 	case SIOCGIFNETMASK:
234 #define	satosin(sa)	((struct sockaddr_in *)(sa))
235 		satosin(&ifr->ifr_addr)->sin_family = AF_INET;
236 		satosin(&ifr->ifr_addr)->sin_addr.s_addr = htonl(ia->ia_subnetmask);
237 		break;
238 
239 	case SIOCSIFDSTADDR:
240 		if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
241 			return (EINVAL);
242 		if (ifp->if_ioctl &&
243 		    (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, ia)))
244 			return (error);
245 		ia->ia_dstaddr = ifr->ifr_dstaddr;
246 		break;
247 
248 	case SIOCSIFBRDADDR:
249 		if ((ifp->if_flags & IFF_BROADCAST) == 0)
250 			return (EINVAL);
251 		ia->ia_broadaddr = ifr->ifr_broadaddr;
252 		break;
253 
254 	case SIOCSIFADDR:
255 		return (in_ifinit(ifp, ia, &ifr->ifr_addr));
256 		break;
257 
258 	case SIOCSIFNETMASK:
259 		ia->ia_subnetmask = ntohl(satosin(&ifr->ifr_addr)->sin_addr.s_addr);
260 		break;
261 
262 	default:
263 		if (ifp == 0 || ifp->if_ioctl == 0)
264 			return (EOPNOTSUPP);
265 		return ((*ifp->if_ioctl)(ifp, cmd, data));
266 	}
267 	return (0);
268 }
269 
270 /*
271  * Initialize an interface's internet address
272  * and routing table entry.
273  */
274 in_ifinit(ifp, ia, sin)
275 	register struct ifnet *ifp;
276 	register struct in_ifaddr *ia;
277 	struct sockaddr_in *sin;
278 {
279 	register u_long i = ntohl(sin->sin_addr.s_addr);
280 	struct sockaddr_in netaddr;
281 	int s = splimp(), error;
282 
283 	bzero((caddr_t)&netaddr, sizeof (netaddr));
284 	netaddr.sin_family = AF_INET;
285 	/*
286 	 * Delete any previous route for an old address.
287 	 */
288 	if (ia->ia_flags & IFA_ROUTE) {
289 		if ((ifp->if_flags & IFF_POINTOPOINT) == 0) {
290 		    netaddr.sin_addr = in_makeaddr(ia->ia_subnet, INADDR_ANY);
291 		    rtinit((struct sockaddr *)&netaddr, &ia->ia_addr, -1);
292 		} else
293 		    rtinit((struct sockaddr *)&ia->ia_dstaddr, &ia->ia_addr, -1);
294 		ia->ia_flags &= ~IFA_ROUTE;
295 	}
296 	ia->ia_addr = *(struct sockaddr *)sin;
297 	if (IN_CLASSA(i))
298 		ia->ia_netmask = IN_CLASSA_NET;
299 	else if (IN_CLASSB(i))
300 		ia->ia_netmask = IN_CLASSB_NET;
301 	else
302 		ia->ia_netmask = IN_CLASSC_NET;
303 	ia->ia_net = i & ia->ia_netmask;
304 	/*
305 	 * The subnet mask includes at least the standard network part,
306 	 * but may already have been set to a larger value.
307 	 */
308 	ia->ia_subnetmask |= ia->ia_netmask;
309 	ia->ia_subnet = i & ia->ia_subnetmask;
310 	if (ifp->if_flags & IFF_BROADCAST) {
311 		ia->ia_broadaddr.sa_family = AF_INET;
312 		((struct sockaddr_in *)(&ia->ia_broadaddr))->sin_addr =
313 			in_makeaddr(ia->ia_subnet, INADDR_BROADCAST);
314 	}
315 
316 	/*
317 	 * Give the interface a chance to initialize
318 	 * if this is its first address,
319 	 * and to validate the address if necessary.
320 	 */
321 	if (ifp->if_ioctl && (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, ia))) {
322 		splx(s);
323 		bzero((caddr_t)&ia->ia_addr, sizeof(ia->ia_addr));
324 		return (error);
325 	}
326 	splx(s);
327 	/*
328 	 * Add route for the network.
329 	 */
330 	if ((ifp->if_flags & IFF_POINTOPOINT) == 0) {
331 		netaddr.sin_addr = in_makeaddr(ia->ia_subnet, INADDR_ANY);
332 		rtinit((struct sockaddr *)&netaddr, &ia->ia_addr, RTF_UP);
333 	} else
334 		rtinit((struct sockaddr *)&ia->ia_dstaddr, &ia->ia_addr,
335 			RTF_HOST|RTF_UP);
336 	ia->ia_flags |= IFA_ROUTE;
337 	return (0);
338 }
339 
340 /*
341  * Return address info for specified internet network.
342  */
343 struct in_ifaddr *
344 in_iaonnetof(net)
345 	u_long net;
346 {
347 	register struct in_ifaddr *ia;
348 
349 	for (ia = in_ifaddr; ia; ia = ia->ia_next)
350 		if (ia->ia_subnet == net)
351 			return (ia);
352 	return ((struct in_ifaddr *)0);
353 }
354 
355 /*
356  * Return 1 if the address is a local broadcast address.
357  */
358 in_broadcast(in)
359 	struct in_addr in;
360 {
361 	register struct in_ifaddr *ia;
362 
363 	/*
364 	 * Look through the list of addresses for a match
365 	 * with a broadcast address.
366 	 */
367 	for (ia = in_ifaddr; ia; ia = ia->ia_next)
368 	    if (((struct sockaddr_in *)&ia->ia_broadaddr)->sin_addr.s_addr ==
369 		in.s_addr && (ia->ia_ifp->if_flags & IFF_BROADCAST))
370 		     return (1);
371 	return (0);
372 }
373 #endif
374