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