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