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