use the same definition for array dimension and sensibility checks
[unix-history] / usr / src / sys / netinet / in_pcb.c
CommitLineData
8ae0e4b4 1/*
0880b18e 2 * Copyright (c) 1982, 1986 Regents of the University of California.
8ae0e4b4
KM
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
5 *
1bf75d4e 6 * @(#)in_pcb.c 7.3 (Berkeley) %G%
8ae0e4b4 7 */
af092e86 8
20666ad3
JB
9#include "param.h"
10#include "systm.h"
11#include "dir.h"
12#include "user.h"
13#include "mbuf.h"
14#include "socket.h"
15#include "socketvar.h"
2ba2de86 16#include "ioctl.h"
20666ad3
JB
17#include "in.h"
18#include "in_systm.h"
4ad99bae 19#include "../net/if.h"
c124e997 20#include "../net/route.h"
20666ad3 21#include "in_pcb.h"
5d305bdd 22#include "in_var.h"
20666ad3 23#include "protosw.h"
af092e86 24
1a3dbf93 25struct in_addr zeroin_addr;
405c9168 26
8f0d18de
BJ
27in_pcballoc(so, head)
28 struct socket *so;
29 struct inpcb *head;
30{
31 struct mbuf *m;
32 register struct inpcb *inp;
33
cce93e4b 34 m = m_getclr(M_DONTWAIT, MT_PCB);
5cdc4d65 35 if (m == NULL)
8f0d18de
BJ
36 return (ENOBUFS);
37 inp = mtod(m, struct inpcb *);
38 inp->inp_head = head;
39 inp->inp_socket = so;
40 insque(inp, head);
41 so->so_pcb = (caddr_t)inp;
42 return (0);
43}
44
8075bb0e 45in_pcbbind(inp, nam)
8f0d18de 46 register struct inpcb *inp;
8075bb0e 47 struct mbuf *nam;
8f0d18de
BJ
48{
49 register struct socket *so = inp->inp_socket;
50 register struct inpcb *head = inp->inp_head;
8075bb0e 51 register struct sockaddr_in *sin;
8f0d18de
BJ
52 u_short lport = 0;
53
5d305bdd 54 if (in_ifaddr == 0)
8f0d18de 55 return (EADDRNOTAVAIL);
5cdc4d65 56 if (inp->inp_lport || inp->inp_laddr.s_addr != INADDR_ANY)
8075bb0e
BJ
57 return (EINVAL);
58 if (nam == 0)
59 goto noname;
60 sin = mtod(nam, struct sockaddr_in *);
61 if (nam->m_len != sizeof (*sin))
62 return (EINVAL);
5cdc4d65 63 if (sin->sin_addr.s_addr != INADDR_ANY) {
8075bb0e 64 int tport = sin->sin_port;
8f0d18de 65
8075bb0e 66 sin->sin_port = 0; /* yech... */
5d305bdd 67 if (ifa_ifwithaddr((struct sockaddr *)sin) == 0)
8075bb0e
BJ
68 return (EADDRNOTAVAIL);
69 sin->sin_port = tport;
8f0d18de 70 }
8075bb0e
BJ
71 lport = sin->sin_port;
72 if (lport) {
f2d10020 73 u_short aport = ntohs(lport);
8075bb0e 74 int wild = 0;
c124e997 75
8075bb0e
BJ
76 /* GROSS */
77 if (aport < IPPORT_RESERVED && u.u_uid != 0)
78 return (EACCES);
b4a3d4a7
SL
79 /* even GROSSER, but this is the Internet */
80 if ((so->so_options & SO_REUSEADDR) == 0 &&
81 ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 ||
82 (so->so_options & SO_ACCEPTCONN) == 0))
8075bb0e
BJ
83 wild = INPLOOKUP_WILDCARD;
84 if (in_pcblookup(head,
85 zeroin_addr, 0, sin->sin_addr, lport, wild))
86 return (EADDRINUSE);
4ad99bae 87 }
8075bb0e
BJ
88 inp->inp_laddr = sin->sin_addr;
89noname:
b454c3ea
BJ
90 if (lport == 0)
91 do {
f44e5691
MK
92 if (head->inp_lport++ < IPPORT_RESERVED ||
93 head->inp_lport > IPPORT_USERRESERVED)
1aa87517 94 head->inp_lport = IPPORT_RESERVED;
b454c3ea 95 lport = htons(head->inp_lport);
1aa87517
BJ
96 } while (in_pcblookup(head,
97 zeroin_addr, 0, inp->inp_laddr, lport, 0));
4ad99bae 98 inp->inp_lport = lport;
4ad99bae 99 return (0);
af092e86
BJ
100}
101
1acff8ec
BJ
102/*
103 * Connect from a socket to a specified address.
104 * Both address and port must be specified in argument sin.
105 * If don't have a local address for this socket yet,
106 * then pick one.
107 */
8075bb0e 108in_pcbconnect(inp, nam)
4ad99bae 109 struct inpcb *inp;
8075bb0e 110 struct mbuf *nam;
2b4b57cd 111{
5d305bdd 112 struct in_ifaddr *ia;
ee787340 113 struct sockaddr_in *ifaddr;
8075bb0e 114 register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
2b4b57cd 115
8075bb0e
BJ
116 if (nam->m_len != sizeof (*sin))
117 return (EINVAL);
4ad99bae
BJ
118 if (sin->sin_family != AF_INET)
119 return (EAFNOSUPPORT);
5d305bdd 120 if (sin->sin_port == 0)
4ad99bae 121 return (EADDRNOTAVAIL);
5d305bdd 122 if (in_ifaddr) {
3f319daa
MK
123 /*
124 * If the destination address is INADDR_ANY,
125 * use the primary local address.
126 * If the supplied address is INADDR_BROADCAST,
127 * and the primary interface supports broadcast,
128 * choose the broadcast address for that interface.
129 */
5d305bdd
MK
130#define satosin(sa) ((struct sockaddr_in *)(sa))
131 if (sin->sin_addr.s_addr == INADDR_ANY)
3f319daa 132 sin->sin_addr = IA_SIN(in_ifaddr)->sin_addr;
c9aca561 133 else if (sin->sin_addr.s_addr == (u_long)INADDR_BROADCAST &&
3f319daa
MK
134 (in_ifaddr->ia_ifp->if_flags & IFF_BROADCAST))
135 sin->sin_addr = satosin(&in_ifaddr->ia_broadaddr)->sin_addr;
5d305bdd 136 }
5cdc4d65 137 if (inp->inp_laddr.s_addr == INADDR_ANY) {
c198b4ed
MK
138 register struct route *ro;
139 struct ifnet *ifp;
99578149 140
c198b4ed
MK
141 ia = (struct in_ifaddr *)0;
142 /*
143 * If route is known or can be allocated now,
144 * our src addr is taken from the i/f, else punt.
145 */
146 ro = &inp->inp_route;
147 if (ro->ro_rt &&
1bf75d4e
MK
148 (satosin(&ro->ro_dst)->sin_addr.s_addr !=
149 sin->sin_addr.s_addr ||
150 inp->inp_socket->so_options & SO_DONTROUTE)) {
c198b4ed
MK
151 RTFREE(ro->ro_rt);
152 ro->ro_rt = (struct rtentry *)0;
153 }
9f21d23f
MK
154 if ((inp->inp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/
155 (ro->ro_rt == (struct rtentry *)0 ||
d4538fe2 156 ro->ro_rt->rt_ifp == (struct ifnet *)0)) {
c198b4ed
MK
157 /* No route yet, so try to acquire one */
158 ro->ro_dst.sa_family = AF_INET;
159 ((struct sockaddr_in *) &ro->ro_dst)->sin_addr =
160 sin->sin_addr;
161 rtalloc(ro);
ee787340 162 }
d4538fe2
MK
163 /*
164 * If we found a route, use the address
165 * corresponding to the outgoing interface
166 * unless it is the loopback (in case a route
167 * to our address on another net goes to loopback).
168 */
169 if (ro->ro_rt && (ifp = ro->ro_rt->rt_ifp) &&
170 (ifp->if_flags & IFF_LOOPBACK) == 0)
171 for (ia = in_ifaddr; ia; ia = ia->ia_next)
172 if (ia->ia_ifp == ifp)
173 break;
9f21d23f 174 if (ia == 0) {
1bf75d4e
MK
175 int fport = sin->sin_port;
176
177 sin->sin_port = 0;
9f21d23f
MK
178 ia = (struct in_ifaddr *)
179 ifa_ifwithdstaddr((struct sockaddr *)sin);
1bf75d4e 180 sin->sin_port = fport;
9f21d23f
MK
181 if (ia == 0)
182 ia = in_iaonnetof(in_netof(sin->sin_addr));
183 if (ia == 0)
184 ia = in_ifaddr;
185 if (ia == 0)
186 return (EADDRNOTAVAIL);
c198b4ed 187 }
5d305bdd 188 ifaddr = (struct sockaddr_in *)&ia->ia_addr;
1aa87517
BJ
189 }
190 if (in_pcblookup(inp->inp_head,
1acff8ec
BJ
191 sin->sin_addr,
192 sin->sin_port,
ee787340 193 inp->inp_laddr.s_addr ? inp->inp_laddr : ifaddr->sin_addr,
1acff8ec
BJ
194 inp->inp_lport,
195 0))
b454c3ea 196 return (EADDRINUSE);
3cd2053b
SL
197 if (inp->inp_laddr.s_addr == INADDR_ANY) {
198 if (inp->inp_lport == 0)
8011f5df 199 (void)in_pcbbind(inp, (struct mbuf *)0);
ee787340 200 inp->inp_laddr = ifaddr->sin_addr;
3cd2053b 201 }
4ad99bae
BJ
202 inp->inp_faddr = sin->sin_addr;
203 inp->inp_fport = sin->sin_port;
2b4b57cd
BJ
204 return (0);
205}
206
405c9168
BJ
207in_pcbdisconnect(inp)
208 struct inpcb *inp;
209{
210
5cdc4d65 211 inp->inp_faddr.s_addr = INADDR_ANY;
ebcadd38 212 inp->inp_fport = 0;
8f0d18de 213 if (inp->inp_socket->so_state & SS_NOFDREF)
405c9168
BJ
214 in_pcbdetach(inp);
215}
216
217in_pcbdetach(inp)
af092e86
BJ
218 struct inpcb *inp;
219{
220 struct socket *so = inp->inp_socket;
221
ba55c9af
BJ
222 so->so_pcb = 0;
223 sofree(so);
c9aca561 224 if (inp->inp_options)
8011f5df 225 (void)m_free(inp->inp_options);
c124e997 226 if (inp->inp_route.ro_rt)
f6311fb6 227 rtfree(inp->inp_route.ro_rt);
7545cf09 228 remque(inp);
cdad2eb1 229 (void) m_free(dtom(inp));
af092e86
BJ
230}
231
8075bb0e 232in_setsockaddr(inp, nam)
126472ab 233 register struct inpcb *inp;
8075bb0e 234 struct mbuf *nam;
126472ab 235{
8075bb0e
BJ
236 register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
237
238 nam->m_len = sizeof (*sin);
239 sin = mtod(nam, struct sockaddr_in *);
126472ab
SL
240 bzero((caddr_t)sin, sizeof (*sin));
241 sin->sin_family = AF_INET;
242 sin->sin_port = inp->inp_lport;
243 sin->sin_addr = inp->inp_laddr;
244}
245
a7343092
SL
246in_setpeeraddr(inp, nam)
247 register struct inpcb *inp;
248 struct mbuf *nam;
249{
250 register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
251
252 nam->m_len = sizeof (*sin);
253 sin = mtod(nam, struct sockaddr_in *);
254 bzero((caddr_t)sin, sizeof (*sin));
255 sin->sin_family = AF_INET;
256 sin->sin_port = inp->inp_fport;
257 sin->sin_addr = inp->inp_faddr;
258}
259
72e4f44e 260/*
842b6bb5 261 * Pass some notification to all connections of a protocol
c9aca561
MK
262 * associated with address dst. Call the protocol specific
263 * routine (if any) to handle each connection.
72e4f44e 264 */
842b6bb5 265in_pcbnotify(head, dst, errno, notify)
72e4f44e
SL
266 struct inpcb *head;
267 register struct in_addr *dst;
842b6bb5 268 int errno, (*notify)();
72e4f44e
SL
269{
270 register struct inpcb *inp, *oinp;
271 int s = splimp();
272
72e4f44e 273 for (inp = head->inp_next; inp != head;) {
c9aca561
MK
274 if (inp->inp_faddr.s_addr != dst->s_addr ||
275 inp->inp_socket == 0) {
72e4f44e
SL
276 inp = inp->inp_next;
277 continue;
278 }
842b6bb5
MK
279 if (errno)
280 inp->inp_socket->so_error = errno;
72e4f44e
SL
281 oinp = inp;
282 inp = inp->inp_next;
c9aca561
MK
283 if (notify)
284 (*notify)(oinp);
72e4f44e
SL
285 }
286 splx(s);
287}
288
2ba2de86
MK
289/*
290 * Check for alternatives when higher level complains
291 * about service problems. For now, invalidate cached
292 * routing information. If the route was created dynamically
293 * (by a redirect), time to try a default gateway again.
294 */
295in_losing(inp)
296 struct inpcb *inp;
297{
298 register struct rtentry *rt;
299
300 if ((rt = inp->inp_route.ro_rt)) {
301 if (rt->rt_flags & RTF_DYNAMIC)
03510dd5 302 (void) rtrequest((int)SIOCDELRT, rt);
2ba2de86
MK
303 rtfree(rt);
304 inp->inp_route.ro_rt = 0;
305 /*
306 * A new route can be allocated
307 * the next time output is attempted.
308 */
309 }
310}
311
842b6bb5
MK
312/*
313 * After a routing change, flush old routing
314 * and allocate a (hopefully) better one.
315 */
316in_rtchange(inp)
2ba2de86 317 register struct inpcb *inp;
842b6bb5
MK
318{
319 if (inp->inp_route.ro_rt) {
320 rtfree(inp->inp_route.ro_rt);
321 inp->inp_route.ro_rt = 0;
322 /*
323 * A new route can be allocated the next time
324 * output is attempted.
325 */
326 }
842b6bb5
MK
327}
328
cdad2eb1 329struct inpcb *
ebcadd38 330in_pcblookup(head, faddr, fport, laddr, lport, flags)
af092e86 331 struct inpcb *head;
4ad99bae 332 struct in_addr faddr, laddr;
af092e86 333 u_short fport, lport;
ebcadd38 334 int flags;
af092e86 335{
1aa87517
BJ
336 register struct inpcb *inp, *match = 0;
337 int matchwild = 3, wildcard;
af092e86 338
405c9168 339 for (inp = head->inp_next; inp != head; inp = inp->inp_next) {
1aa87517 340 if (inp->inp_lport != lport)
405c9168 341 continue;
1aa87517 342 wildcard = 0;
5cdc4d65
SL
343 if (inp->inp_laddr.s_addr != INADDR_ANY) {
344 if (laddr.s_addr == INADDR_ANY)
1acff8ec
BJ
345 wildcard++;
346 else if (inp->inp_laddr.s_addr != laddr.s_addr)
1aa87517
BJ
347 continue;
348 } else {
5cdc4d65 349 if (laddr.s_addr != INADDR_ANY)
1aa87517
BJ
350 wildcard++;
351 }
5cdc4d65
SL
352 if (inp->inp_faddr.s_addr != INADDR_ANY) {
353 if (faddr.s_addr == INADDR_ANY)
1acff8ec
BJ
354 wildcard++;
355 else if (inp->inp_faddr.s_addr != faddr.s_addr ||
ebcadd38 356 inp->inp_fport != fport)
1aa87517
BJ
357 continue;
358 } else {
5cdc4d65 359 if (faddr.s_addr != INADDR_ANY)
1aa87517
BJ
360 wildcard++;
361 }
ebcadd38 362 if (wildcard && (flags & INPLOOKUP_WILDCARD) == 0)
405c9168 363 continue;
1aa87517
BJ
364 if (wildcard < matchwild) {
365 match = inp;
366 matchwild = wildcard;
367 if (matchwild == 0)
368 break;
405c9168 369 }
1aa87517 370 }
405c9168 371 return (match);
af092e86 372}