spl's
[unix-history] / usr / src / sys / netinet / in_pcb.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 *
552918f2 6 * @(#)in_pcb.c 6.12 (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) {
552918f2 138 ia = in_iaonnetof(in_netof(sin->sin_addr));
5d305bdd 139 if (ia == (struct in_ifaddr *)0) {
99578149 140 register struct route *ro;
5d305bdd 141 struct ifnet *ifp;
99578149
MK
142
143 /*
144 * If route is known or can be allocated now,
145 * our src addr is taken from the i/f, else punt.
72e4f44e 146 */
99578149 147 ro = &inp->inp_route;
99578149
MK
148 if (ro->ro_rt &&
149 satosin(&ro->ro_dst)->sin_addr.s_addr !=
150 sin->sin_addr.s_addr) {
151 RTFREE(ro->ro_rt);
152 ro->ro_rt = (struct rtentry *)0;
153 }
154 if ((ro->ro_rt == (struct rtentry *)0) ||
155 (ifp = ro->ro_rt->rt_ifp) == (struct ifnet *)0) {
156 /* No route yet, so try to acquire one */
157 ro->ro_dst.sa_family = AF_INET;
158 ((struct sockaddr_in *) &ro->ro_dst)->sin_addr =
159 sin->sin_addr;
160 rtalloc(ro);
552918f2 161 if (ro->ro_rt == (struct rtentry *)0)
3f319daa 162 ifp = (struct ifnet *)0;
99578149 163 else
3f319daa 164 ifp = ro->ro_rt->rt_ifp;
99578149 165 }
3f319daa
MK
166 if (ifp) {
167 for (ia = in_ifaddr; ia; ia = ia->ia_next)
168 if (ia->ia_ifp == ifp)
169 break;
552918f2 170 }
5d305bdd
MK
171 if (ia == 0)
172 ia = in_ifaddr;
173 if (ia == 0)
72e4f44e 174 return (EADDRNOTAVAIL);
ee787340 175 }
5d305bdd 176 ifaddr = (struct sockaddr_in *)&ia->ia_addr;
1aa87517
BJ
177 }
178 if (in_pcblookup(inp->inp_head,
1acff8ec
BJ
179 sin->sin_addr,
180 sin->sin_port,
ee787340 181 inp->inp_laddr.s_addr ? inp->inp_laddr : ifaddr->sin_addr,
1acff8ec
BJ
182 inp->inp_lport,
183 0))
b454c3ea 184 return (EADDRINUSE);
3cd2053b
SL
185 if (inp->inp_laddr.s_addr == INADDR_ANY) {
186 if (inp->inp_lport == 0)
187 in_pcbbind(inp, (struct mbuf *)0);
ee787340 188 inp->inp_laddr = ifaddr->sin_addr;
3cd2053b 189 }
4ad99bae
BJ
190 inp->inp_faddr = sin->sin_addr;
191 inp->inp_fport = sin->sin_port;
2b4b57cd
BJ
192 return (0);
193}
194
405c9168
BJ
195in_pcbdisconnect(inp)
196 struct inpcb *inp;
197{
198
5cdc4d65 199 inp->inp_faddr.s_addr = INADDR_ANY;
ebcadd38 200 inp->inp_fport = 0;
8f0d18de 201 if (inp->inp_socket->so_state & SS_NOFDREF)
405c9168
BJ
202 in_pcbdetach(inp);
203}
204
205in_pcbdetach(inp)
af092e86
BJ
206 struct inpcb *inp;
207{
208 struct socket *so = inp->inp_socket;
209
ba55c9af
BJ
210 so->so_pcb = 0;
211 sofree(so);
c9aca561
MK
212 if (inp->inp_options)
213 m_free(inp->inp_options);
c124e997 214 if (inp->inp_route.ro_rt)
f6311fb6 215 rtfree(inp->inp_route.ro_rt);
7545cf09 216 remque(inp);
cdad2eb1 217 (void) m_free(dtom(inp));
af092e86
BJ
218}
219
8075bb0e 220in_setsockaddr(inp, nam)
126472ab 221 register struct inpcb *inp;
8075bb0e 222 struct mbuf *nam;
126472ab 223{
8075bb0e
BJ
224 register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
225
226 nam->m_len = sizeof (*sin);
227 sin = mtod(nam, struct sockaddr_in *);
126472ab
SL
228 bzero((caddr_t)sin, sizeof (*sin));
229 sin->sin_family = AF_INET;
230 sin->sin_port = inp->inp_lport;
231 sin->sin_addr = inp->inp_laddr;
232}
233
a7343092
SL
234in_setpeeraddr(inp, nam)
235 register struct inpcb *inp;
236 struct mbuf *nam;
237{
238 register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
239
240 nam->m_len = sizeof (*sin);
241 sin = mtod(nam, struct sockaddr_in *);
242 bzero((caddr_t)sin, sizeof (*sin));
243 sin->sin_family = AF_INET;
244 sin->sin_port = inp->inp_fport;
245 sin->sin_addr = inp->inp_faddr;
246}
247
72e4f44e 248/*
842b6bb5 249 * Pass some notification to all connections of a protocol
c9aca561
MK
250 * associated with address dst. Call the protocol specific
251 * routine (if any) to handle each connection.
72e4f44e 252 */
842b6bb5 253in_pcbnotify(head, dst, errno, notify)
72e4f44e
SL
254 struct inpcb *head;
255 register struct in_addr *dst;
842b6bb5 256 int errno, (*notify)();
72e4f44e
SL
257{
258 register struct inpcb *inp, *oinp;
259 int s = splimp();
260
72e4f44e 261 for (inp = head->inp_next; inp != head;) {
c9aca561
MK
262 if (inp->inp_faddr.s_addr != dst->s_addr ||
263 inp->inp_socket == 0) {
72e4f44e
SL
264 inp = inp->inp_next;
265 continue;
266 }
842b6bb5
MK
267 if (errno)
268 inp->inp_socket->so_error = errno;
72e4f44e
SL
269 oinp = inp;
270 inp = inp->inp_next;
c9aca561
MK
271 if (notify)
272 (*notify)(oinp);
72e4f44e
SL
273 }
274 splx(s);
275}
276
2ba2de86
MK
277/*
278 * Check for alternatives when higher level complains
279 * about service problems. For now, invalidate cached
280 * routing information. If the route was created dynamically
281 * (by a redirect), time to try a default gateway again.
282 */
283in_losing(inp)
284 struct inpcb *inp;
285{
286 register struct rtentry *rt;
287
288 if ((rt = inp->inp_route.ro_rt)) {
289 if (rt->rt_flags & RTF_DYNAMIC)
290 rtrequest(SIOCDELRT, rt);
291 rtfree(rt);
292 inp->inp_route.ro_rt = 0;
293 /*
294 * A new route can be allocated
295 * the next time output is attempted.
296 */
297 }
298}
299
842b6bb5
MK
300/*
301 * After a routing change, flush old routing
302 * and allocate a (hopefully) better one.
303 */
304in_rtchange(inp)
2ba2de86 305 register struct inpcb *inp;
842b6bb5
MK
306{
307 if (inp->inp_route.ro_rt) {
308 rtfree(inp->inp_route.ro_rt);
309 inp->inp_route.ro_rt = 0;
310 /*
311 * A new route can be allocated the next time
312 * output is attempted.
313 */
314 }
842b6bb5
MK
315}
316
cdad2eb1 317struct inpcb *
ebcadd38 318in_pcblookup(head, faddr, fport, laddr, lport, flags)
af092e86 319 struct inpcb *head;
4ad99bae 320 struct in_addr faddr, laddr;
af092e86 321 u_short fport, lport;
ebcadd38 322 int flags;
af092e86 323{
1aa87517
BJ
324 register struct inpcb *inp, *match = 0;
325 int matchwild = 3, wildcard;
af092e86 326
405c9168 327 for (inp = head->inp_next; inp != head; inp = inp->inp_next) {
1aa87517 328 if (inp->inp_lport != lport)
405c9168 329 continue;
1aa87517 330 wildcard = 0;
5cdc4d65
SL
331 if (inp->inp_laddr.s_addr != INADDR_ANY) {
332 if (laddr.s_addr == INADDR_ANY)
1acff8ec
BJ
333 wildcard++;
334 else if (inp->inp_laddr.s_addr != laddr.s_addr)
1aa87517
BJ
335 continue;
336 } else {
5cdc4d65 337 if (laddr.s_addr != INADDR_ANY)
1aa87517
BJ
338 wildcard++;
339 }
5cdc4d65
SL
340 if (inp->inp_faddr.s_addr != INADDR_ANY) {
341 if (faddr.s_addr == INADDR_ANY)
1acff8ec
BJ
342 wildcard++;
343 else if (inp->inp_faddr.s_addr != faddr.s_addr ||
ebcadd38 344 inp->inp_fport != fport)
1aa87517
BJ
345 continue;
346 } else {
5cdc4d65 347 if (faddr.s_addr != INADDR_ANY)
1aa87517
BJ
348 wildcard++;
349 }
ebcadd38 350 if (wildcard && (flags & INPLOOKUP_WILDCARD) == 0)
405c9168 351 continue;
1aa87517
BJ
352 if (wildcard < matchwild) {
353 match = inp;
354 matchwild = wildcard;
355 if (matchwild == 0)
356 break;
405c9168 357 }
1aa87517 358 }
405c9168 359 return (match);
af092e86 360}