localize header files
[unix-history] / usr / src / sys / netinet / in_pcb.c
CommitLineData
fcfe450e 1/* in_pcb.c 4.32 82/10/09 */
af092e86
BJ
2
3#include "../h/param.h"
4ad99bae
BJ
4#include "../h/systm.h"
5#include "../h/dir.h"
6#include "../h/user.h"
af092e86
BJ
7#include "../h/mbuf.h"
8#include "../h/socket.h"
9#include "../h/socketvar.h"
fcfe450e
BJ
10#include "../netinet/in.h"
11#include "../netinet/in_systm.h"
4ad99bae 12#include "../net/if.h"
c124e997 13#include "../net/route.h"
fcfe450e 14#include "../netinet/in_pcb.h"
1acff8ec 15#include "../h/protosw.h"
af092e86 16
1a3dbf93 17struct in_addr zeroin_addr;
405c9168 18
8f0d18de
BJ
19in_pcbreserve(so, sndcc, rcvcc)
20 struct socket *so;
21 int sndcc, rcvcc;
22{
23
24 if (sbreserve(&so->so_snd, sndcc) == 0)
25 goto bad;
26 if (sbreserve(&so->so_rcv, rcvcc) == 0)
27 goto bad2;
28 return (0);
29bad2:
30 sbrelease(&so->so_snd);
31bad:
32 return (ENOBUFS);
33}
34
35in_pcballoc(so, head)
36 struct socket *so;
37 struct inpcb *head;
38{
39 struct mbuf *m;
40 register struct inpcb *inp;
41
42 m = m_getclr(M_DONTWAIT);
43 if (m == 0)
44 return (ENOBUFS);
45 inp = mtod(m, struct inpcb *);
46 inp->inp_head = head;
47 inp->inp_socket = so;
48 insque(inp, head);
49 so->so_pcb = (caddr_t)inp;
50 return (0);
51}
52
8075bb0e 53in_pcbbind(inp, nam)
8f0d18de 54 register struct inpcb *inp;
8075bb0e 55 struct mbuf *nam;
8f0d18de
BJ
56{
57 register struct socket *so = inp->inp_socket;
58 register struct inpcb *head = inp->inp_head;
8075bb0e 59 register struct sockaddr_in *sin;
8f0d18de
BJ
60 u_short lport = 0;
61
62 if (ifnet == 0)
63 return (EADDRNOTAVAIL);
8075bb0e
BJ
64 if (inp->inp_lport || inp->inp_laddr.s_addr)
65 return (EINVAL);
66 if (nam == 0)
67 goto noname;
68 sin = mtod(nam, struct sockaddr_in *);
69 if (nam->m_len != sizeof (*sin))
70 return (EINVAL);
71 if (sin->sin_addr.s_addr) {
72 int tport = sin->sin_port;
8f0d18de 73
8075bb0e
BJ
74 sin->sin_port = 0; /* yech... */
75 if (if_ifwithaddr((struct sockaddr *)sin) == 0)
76 return (EADDRNOTAVAIL);
77 sin->sin_port = tport;
8f0d18de 78 }
8075bb0e
BJ
79 lport = sin->sin_port;
80 if (lport) {
81 u_short aport = lport;
82 int wild = 0;
c124e997 83
1aa87517 84#if vax
8075bb0e 85 aport = htons(aport);
1aa87517 86#endif
8075bb0e
BJ
87 /* GROSS */
88 if (aport < IPPORT_RESERVED && u.u_uid != 0)
89 return (EACCES);
90 if ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0)
91 wild = INPLOOKUP_WILDCARD;
92 if (in_pcblookup(head,
93 zeroin_addr, 0, sin->sin_addr, lport, wild))
94 return (EADDRINUSE);
4ad99bae 95 }
8075bb0e
BJ
96 inp->inp_laddr = sin->sin_addr;
97noname:
b454c3ea
BJ
98 if (lport == 0)
99 do {
1aa87517
BJ
100 if (head->inp_lport++ < IPPORT_RESERVED)
101 head->inp_lport = IPPORT_RESERVED;
b454c3ea 102 lport = htons(head->inp_lport);
1aa87517
BJ
103 } while (in_pcblookup(head,
104 zeroin_addr, 0, inp->inp_laddr, lport, 0));
4ad99bae 105 inp->inp_lport = lport;
4ad99bae 106 return (0);
af092e86
BJ
107}
108
1acff8ec
BJ
109/*
110 * Connect from a socket to a specified address.
111 * Both address and port must be specified in argument sin.
112 * If don't have a local address for this socket yet,
113 * then pick one.
114 */
8075bb0e 115in_pcbconnect(inp, nam)
4ad99bae 116 struct inpcb *inp;
8075bb0e 117 struct mbuf *nam;
2b4b57cd 118{
1aa87517 119 struct ifnet *ifp;
ee787340 120 struct sockaddr_in *ifaddr;
8075bb0e 121 register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
2b4b57cd 122
8075bb0e
BJ
123 if (nam->m_len != sizeof (*sin))
124 return (EINVAL);
4ad99bae
BJ
125 if (sin->sin_family != AF_INET)
126 return (EAFNOSUPPORT);
127 if (sin->sin_addr.s_addr == 0 || sin->sin_port == 0)
128 return (EADDRNOTAVAIL);
1aa87517 129 if (inp->inp_laddr.s_addr == 0) {
6187f8f4 130 ifp = if_ifonnetof(in_netof(sin->sin_addr));
ee787340 131 if (ifp == 0) {
72e4f44e
SL
132 /*
133 * We should select the interface based on
134 * the route to be used, but for udp this would
135 * result in two calls to rtalloc for each packet
136 * sent; hardly worthwhile...
137 */
ee787340
SL
138 ifp = if_ifwithaf(AF_INET);
139 if (ifp == 0)
72e4f44e 140 return (EADDRNOTAVAIL);
ee787340
SL
141 }
142 ifaddr = (struct sockaddr_in *)&ifp->if_addr;
1aa87517
BJ
143 }
144 if (in_pcblookup(inp->inp_head,
1acff8ec
BJ
145 sin->sin_addr,
146 sin->sin_port,
ee787340 147 inp->inp_laddr.s_addr ? inp->inp_laddr : ifaddr->sin_addr,
1acff8ec
BJ
148 inp->inp_lport,
149 0))
b454c3ea 150 return (EADDRINUSE);
126472ab 151 if (inp->inp_laddr.s_addr == 0)
ee787340 152 inp->inp_laddr = ifaddr->sin_addr;
4ad99bae
BJ
153 inp->inp_faddr = sin->sin_addr;
154 inp->inp_fport = sin->sin_port;
2b4b57cd
BJ
155 return (0);
156}
157
405c9168
BJ
158in_pcbdisconnect(inp)
159 struct inpcb *inp;
160{
161
405c9168 162 inp->inp_faddr.s_addr = 0;
ebcadd38 163 inp->inp_fport = 0;
8f0d18de 164 if (inp->inp_socket->so_state & SS_NOFDREF)
405c9168
BJ
165 in_pcbdetach(inp);
166}
167
168in_pcbdetach(inp)
af092e86
BJ
169 struct inpcb *inp;
170{
171 struct socket *so = inp->inp_socket;
172
ba55c9af
BJ
173 so->so_pcb = 0;
174 sofree(so);
c124e997 175 if (inp->inp_route.ro_rt)
f6311fb6 176 rtfree(inp->inp_route.ro_rt);
7545cf09 177 remque(inp);
cdad2eb1 178 (void) m_free(dtom(inp));
af092e86
BJ
179}
180
8075bb0e 181in_setsockaddr(inp, nam)
126472ab 182 register struct inpcb *inp;
8075bb0e 183 struct mbuf *nam;
126472ab 184{
8075bb0e
BJ
185 register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
186
187 nam->m_len = sizeof (*sin);
188 sin = mtod(nam, struct sockaddr_in *);
126472ab
SL
189 bzero((caddr_t)sin, sizeof (*sin));
190 sin->sin_family = AF_INET;
191 sin->sin_port = inp->inp_lport;
192 sin->sin_addr = inp->inp_laddr;
193}
194
72e4f44e
SL
195/*
196 * Pass an error to all internet connections
197 * associated with address sin. Call the
198 * protocol specific routine to clean up the
199 * mess afterwards.
200 */
201in_pcbnotify(head, dst, errno, abort)
202 struct inpcb *head;
203 register struct in_addr *dst;
204 int errno, (*abort)();
205{
206 register struct inpcb *inp, *oinp;
207 int s = splimp();
208
72e4f44e
SL
209 for (inp = head->inp_next; inp != head;) {
210 if (inp->inp_faddr.s_addr != dst->s_addr) {
211 next:
212 inp = inp->inp_next;
213 continue;
214 }
215 if (inp->inp_socket == 0)
216 goto next;
217 inp->inp_socket->so_error = errno;
218 oinp = inp;
219 inp = inp->inp_next;
220 (*abort)(oinp);
221 }
222 splx(s);
223}
224
cdad2eb1 225struct inpcb *
ebcadd38 226in_pcblookup(head, faddr, fport, laddr, lport, flags)
af092e86 227 struct inpcb *head;
4ad99bae 228 struct in_addr faddr, laddr;
af092e86 229 u_short fport, lport;
ebcadd38 230 int flags;
af092e86 231{
1aa87517
BJ
232 register struct inpcb *inp, *match = 0;
233 int matchwild = 3, wildcard;
af092e86 234
405c9168 235 for (inp = head->inp_next; inp != head; inp = inp->inp_next) {
1aa87517 236 if (inp->inp_lport != lport)
405c9168 237 continue;
1aa87517
BJ
238 wildcard = 0;
239 if (inp->inp_laddr.s_addr != 0) {
1acff8ec
BJ
240 if (laddr.s_addr == 0)
241 wildcard++;
242 else if (inp->inp_laddr.s_addr != laddr.s_addr)
1aa87517
BJ
243 continue;
244 } else {
245 if (laddr.s_addr != 0)
246 wildcard++;
247 }
248 if (inp->inp_faddr.s_addr != 0) {
1acff8ec
BJ
249 if (faddr.s_addr == 0)
250 wildcard++;
251 else if (inp->inp_faddr.s_addr != faddr.s_addr ||
ebcadd38 252 inp->inp_fport != fport)
1aa87517
BJ
253 continue;
254 } else {
255 if (faddr.s_addr != 0)
256 wildcard++;
257 }
ebcadd38 258 if (wildcard && (flags & INPLOOKUP_WILDCARD) == 0)
405c9168 259 continue;
1aa87517
BJ
260 if (wildcard < matchwild) {
261 match = inp;
262 matchwild = wildcard;
263 if (matchwild == 0)
264 break;
405c9168 265 }
1aa87517 266 }
405c9168 267 return (match);
af092e86 268}