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