bounds checking
[unix-history] / usr / src / sys / netinet / in_pcb.c
CommitLineData
ee787340 1/* in_pcb.c 4.22 82/03/28 */
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"
8a13b737
BJ
10#include "../net/in.h"
11#include "../net/in_systm.h"
4ad99bae 12#include "../net/if.h"
8a13b737 13#include "../net/in_pcb.h"
1acff8ec 14#include "../h/protosw.h"
af092e86 15
405c9168
BJ
16/*
17 * Routines to manage internet protocol control blocks.
18 *
19 * At PRU_ATTACH time a protocol control block is allocated in
20 * in_pcballoc() and inserted on a doubly-linked list of such blocks
21 * for the protocol. A port address is either requested (and verified
22 * to not be in use) or assigned at this time. We also allocate
23 * space in the socket sockbuf structures here, although this is
24 * not a clearly correct place to put this function.
25 *
26 * A connectionless protocol will have its protocol control block
27 * removed at PRU_DETACH time, when the socket will be freed (freeing
28 * the space reserved) and the block will be removed from the list of
29 * blocks for its protocol.
30 *
31 * A connection-based protocol may be connected to a remote peer at
32 * PRU_CONNECT time through the routine in_pcbconnect(). In the normal
33 * case a PRU_DISCONNECT occurs causing a in_pcbdisconnect().
34 * It is also possible that higher-level routines will opt out of the
35 * relationship with the connection before the connection shut down
36 * is complete. This often occurs in protocols like TCP where we must
37 * hold on to the protocol control block for a unreasonably long time
38 * after the connection is used up to avoid races in later connection
39 * establishment. To handle this we allow higher-level routines to
40 * disassociate themselves from the socket, marking it SS_USERGONE while
41 * the disconnect is in progress. We notice that this has happened
42 * when the disconnect is complete, and perform the PRU_DETACH operation,
43 * freeing the socket.
b454c3ea
BJ
44 *
45 * TODO:
46 * use hashing
405c9168 47 */
1a3dbf93 48struct in_addr zeroin_addr;
405c9168 49
4ad99bae
BJ
50/*
51 * Allocate a protocol control block, space
52 * for send and receive data, and local host information.
53 * Return error. If no error make socket point at pcb.
54 */
405c9168 55in_pcbattach(so, head, sndcc, rcvcc, sin)
4ad99bae
BJ
56 struct socket *so;
57 struct inpcb *head;
58 int sndcc, rcvcc;
59 struct sockaddr_in *sin;
af092e86 60{
af092e86 61 struct mbuf *m;
1a3dbf93 62 register struct inpcb *inp;
1aa87517 63 u_short lport = 0;
af092e86 64
405c9168 65COUNT(IN_PCBATTACH);
1aa87517
BJ
66 if (ifnet == 0)
67 return (EADDRNOTAVAIL);
4ad99bae
BJ
68 if (sin) {
69 if (sin->sin_family != AF_INET)
70 return (EAFNOSUPPORT);
1aa87517 71 if (sin->sin_addr.s_addr &&
ee787340 72 if_ifwithaddr((struct sockaddr *)sin) == 0)
1aa87517 73 return (EADDRNOTAVAIL);
4ad99bae 74 lport = sin->sin_port;
1aa87517
BJ
75 if (lport) {
76 u_short aport = lport;
1acff8ec 77 int wild = 0;
1aa87517
BJ
78#if vax
79 aport = htons(aport);
80#endif
81 /* GROSS */
82 if (aport < IPPORT_RESERVED && u.u_uid != 0)
83 return (EPERM);
1acff8ec
BJ
84 if ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 ||
85 (so->so_options & SO_ACCEPTCONN) == 0)
86 wild = INPLOOKUP_WILDCARD;
1aa87517 87 if (in_pcblookup(head,
1acff8ec 88 zeroin_addr, 0, sin->sin_addr, lport, wild))
1aa87517
BJ
89 return (EADDRINUSE);
90 }
4ad99bae 91 }
e6b33a03 92 m = m_getclr(M_DONTWAIT);
4ad99bae 93 if (m == 0)
7545cf09 94 return (ENOBUFS);
4ad99bae
BJ
95 if (sbreserve(&so->so_snd, sndcc) == 0)
96 goto bad;
97 if (sbreserve(&so->so_rcv, rcvcc) == 0)
98 goto bad2;
99 inp = mtod(m, struct inpcb *);
b454c3ea 100 inp->inp_head = head;
1aa87517
BJ
101 if (sin)
102 inp->inp_laddr = sin->sin_addr;
b454c3ea
BJ
103 if (lport == 0)
104 do {
1aa87517
BJ
105 if (head->inp_lport++ < IPPORT_RESERVED)
106 head->inp_lport = IPPORT_RESERVED;
b454c3ea 107 lport = htons(head->inp_lport);
1aa87517
BJ
108 } while (in_pcblookup(head,
109 zeroin_addr, 0, inp->inp_laddr, lport, 0));
4ad99bae 110 inp->inp_lport = lport;
b454c3ea 111 inp->inp_socket = so;
7545cf09 112 insque(inp, head);
4ad99bae 113 so->so_pcb = (caddr_t)inp;
1aa87517 114 in_setsockaddr(inp);
4ad99bae
BJ
115 return (0);
116bad2:
117 sbrelease(&so->so_snd);
118bad:
2752c877 119 (void) m_free(m);
4ad99bae 120 return (ENOBUFS);
af092e86
BJ
121}
122
1acff8ec
BJ
123/*
124 * Connect from a socket to a specified address.
125 * Both address and port must be specified in argument sin.
126 * If don't have a local address for this socket yet,
127 * then pick one.
128 */
405c9168 129in_pcbconnect(inp, sin)
4ad99bae
BJ
130 struct inpcb *inp;
131 struct sockaddr_in *sin;
2b4b57cd 132{
1aa87517 133 struct ifnet *ifp;
ee787340 134 struct sockaddr_in *ifaddr;
2b4b57cd 135
405c9168 136COUNT(IN_PCBCONNECT);
4ad99bae
BJ
137 if (sin->sin_family != AF_INET)
138 return (EAFNOSUPPORT);
139 if (sin->sin_addr.s_addr == 0 || sin->sin_port == 0)
140 return (EADDRNOTAVAIL);
1aa87517 141 if (inp->inp_laddr.s_addr == 0) {
ee787340
SL
142 ifp = if_ifonnetof(sin->sin_addr.s_net);
143 if (ifp == 0) {
144 ifp = if_ifwithaf(AF_INET);
145 if (ifp == 0)
146 return (EADDRNOTAVAIL); /* XXX */
147 }
148 ifaddr = (struct sockaddr_in *)&ifp->if_addr;
1aa87517
BJ
149 }
150 if (in_pcblookup(inp->inp_head,
1acff8ec
BJ
151 sin->sin_addr,
152 sin->sin_port,
ee787340 153 inp->inp_laddr.s_addr ? inp->inp_laddr : ifaddr->sin_addr,
1acff8ec
BJ
154 inp->inp_lport,
155 0))
b454c3ea 156 return (EADDRINUSE);
c48203e2
BJ
157 if (inp->inp_laddr.s_addr == 0) {
158 struct sockaddr_in *sin2 =
159 (struct sockaddr_in *)&inp->inp_socket->so_addr;
160
ee787340 161 inp->inp_laddr = ifaddr->sin_addr;
c48203e2
BJ
162 sin2->sin_addr = inp->inp_laddr;
163 }
4ad99bae
BJ
164 inp->inp_faddr = sin->sin_addr;
165 inp->inp_fport = sin->sin_port;
2b4b57cd
BJ
166 return (0);
167}
168
1aa87517 169in_setsockaddr(inp)
f6f20b2c 170 struct inpcb *inp;
f6f20b2c 171{
1aa87517
BJ
172 register struct sockaddr_in *sin =
173 (struct sockaddr_in *)&inp->inp_socket->so_addr;
f6f20b2c
BJ
174
175 sin->sin_family = AF_INET;
1aa87517
BJ
176 sin->sin_addr = inp->inp_laddr;
177 sin->sin_port = inp->inp_lport;
f6f20b2c
BJ
178}
179
405c9168
BJ
180in_pcbdisconnect(inp)
181 struct inpcb *inp;
182{
183
184COUNT(IN_PCBDISCONNECT);
185 inp->inp_faddr.s_addr = 0;
ebcadd38 186 inp->inp_fport = 0;
405c9168
BJ
187 if (inp->inp_socket->so_state & SS_USERGONE)
188 in_pcbdetach(inp);
189}
190
191in_pcbdetach(inp)
af092e86
BJ
192 struct inpcb *inp;
193{
194 struct socket *so = inp->inp_socket;
195
ba55c9af
BJ
196 so->so_pcb = 0;
197 sofree(so);
7545cf09 198 remque(inp);
cdad2eb1 199 (void) m_free(dtom(inp));
af092e86
BJ
200}
201
405c9168 202/*
1aa87517 203 * SHOULD ALLOW MATCH ON MULTI-HOMING ONLY
405c9168 204 */
cdad2eb1 205struct inpcb *
ebcadd38 206in_pcblookup(head, faddr, fport, laddr, lport, flags)
af092e86 207 struct inpcb *head;
4ad99bae 208 struct in_addr faddr, laddr;
af092e86 209 u_short fport, lport;
ebcadd38 210 int flags;
af092e86 211{
1aa87517
BJ
212 register struct inpcb *inp, *match = 0;
213 int matchwild = 3, wildcard;
af092e86 214
405c9168 215 for (inp = head->inp_next; inp != head; inp = inp->inp_next) {
1aa87517 216 if (inp->inp_lport != lport)
405c9168 217 continue;
1aa87517
BJ
218 wildcard = 0;
219 if (inp->inp_laddr.s_addr != 0) {
1acff8ec
BJ
220 if (laddr.s_addr == 0)
221 wildcard++;
222 else if (inp->inp_laddr.s_addr != laddr.s_addr)
1aa87517
BJ
223 continue;
224 } else {
225 if (laddr.s_addr != 0)
226 wildcard++;
227 }
228 if (inp->inp_faddr.s_addr != 0) {
1acff8ec
BJ
229 if (faddr.s_addr == 0)
230 wildcard++;
231 else if (inp->inp_faddr.s_addr != faddr.s_addr ||
ebcadd38 232 inp->inp_fport != fport)
1aa87517
BJ
233 continue;
234 } else {
235 if (faddr.s_addr != 0)
236 wildcard++;
237 }
ebcadd38 238 if (wildcard && (flags & INPLOOKUP_WILDCARD) == 0)
405c9168 239 continue;
1aa87517
BJ
240 if (wildcard < matchwild) {
241 match = inp;
242 matchwild = wildcard;
243 if (matchwild == 0)
244 break;
405c9168 245 }
1aa87517 246 }
405c9168 247 return (match);
af092e86 248}