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