more cleanup
[unix-history] / usr / src / sys / netinet / in_pcb.c
CommitLineData
405c9168 1/* in_pcb.c 4.11 81/12/02 */
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.
43 */
44
4ad99bae
BJ
45/*
46 * Allocate a protocol control block, space
47 * for send and receive data, and local host information.
48 * Return error. If no error make socket point at pcb.
49 */
405c9168 50in_pcbattach(so, head, sndcc, rcvcc, sin)
4ad99bae
BJ
51 struct socket *so;
52 struct inpcb *head;
53 int sndcc, rcvcc;
54 struct sockaddr_in *sin;
af092e86 55{
af092e86 56 struct mbuf *m;
7545cf09 57 register struct inpcb *inp, *xp;
4ad99bae
BJ
58 struct ifnet *ifp;
59 u_long lport;
af092e86 60
405c9168 61COUNT(IN_PCBATTACH);
4ad99bae
BJ
62 if (sin) {
63 if (sin->sin_family != AF_INET)
64 return (EAFNOSUPPORT);
65 ifp = if_ifwithaddr(sin->sin_addr);
66 if (ifp == 0)
67 return (EADDRNOTAVAIL);
68 lport = sin->sin_port;
69 if (lport) {
7545cf09 70 xp = head->inp_next;
f1b2fa5b 71 for (; xp != head; xp = xp->inp_next)
7545cf09 72 if (xp->inp_laddr.s_addr ==
4ad99bae 73 sin->sin_addr.s_addr &&
7545cf09
BJ
74 xp->inp_lport == lport &&
75 xp->inp_faddr.s_addr == 0)
4ad99bae
BJ
76 return (EADDRINUSE);
77 }
78 } else {
79 ifp = if_ifwithaddr(ifnet->if_addr);
80 lport = 0;
81 }
af092e86 82 m = m_getclr(M_WAIT);
4ad99bae 83 if (m == 0)
7545cf09 84 return (ENOBUFS);
4ad99bae
BJ
85 if (sbreserve(&so->so_snd, sndcc) == 0)
86 goto bad;
87 if (sbreserve(&so->so_rcv, rcvcc) == 0)
88 goto bad2;
89 inp = mtod(m, struct inpcb *);
90 inp->inp_laddr = ifp->if_addr;
91 if (lport)
92 goto gotport;
93again:
94 if (head->inp_lport++ < 1024)
95 head->inp_lport = 1024;
7545cf09
BJ
96 for (xp = head->inp_next; xp != head; xp = xp->inp_next)
97 if (xp->inp_lport == head->inp_lport)
4ad99bae 98 goto again;
405c9168 99 lport = htons(head->inp_lport);
4ad99bae 100gotport:
7545cf09 101 inp->inp_socket = so;
4ad99bae 102 inp->inp_lport = lport;
7545cf09 103 insque(inp, head);
4ad99bae 104 so->so_pcb = (caddr_t)inp;
d8bd11cd
BJ
105 sin = (struct sockaddr_in *)&so->so_addr;
106 sin->sin_family = AF_INET;
107 sin->sin_addr = inp->inp_laddr;
108 sin->sin_port = inp->inp_lport;
4ad99bae
BJ
109 return (0);
110bad2:
111 sbrelease(&so->so_snd);
112bad:
2752c877 113 (void) m_free(m);
4ad99bae 114 return (ENOBUFS);
af092e86
BJ
115}
116
405c9168 117in_pcbconnect(inp, sin)
4ad99bae
BJ
118 struct inpcb *inp;
119 struct sockaddr_in *sin;
2b4b57cd 120{
2b4b57cd 121
405c9168 122COUNT(IN_PCBCONNECT);
4ad99bae
BJ
123 if (sin->sin_family != AF_INET)
124 return (EAFNOSUPPORT);
125 if (sin->sin_addr.s_addr == 0 || sin->sin_port == 0)
126 return (EADDRNOTAVAIL);
127 /* should check not already in use... */
128 inp->inp_faddr = sin->sin_addr;
129 inp->inp_fport = sin->sin_port;
2b4b57cd
BJ
130 return (0);
131}
132
405c9168
BJ
133in_pcbdisconnect(inp)
134 struct inpcb *inp;
135{
136
137COUNT(IN_PCBDISCONNECT);
138 inp->inp_faddr.s_addr = 0;
139 if (inp->inp_socket->so_state & SS_USERGONE)
140 in_pcbdetach(inp);
141}
142
143in_pcbdetach(inp)
af092e86
BJ
144 struct inpcb *inp;
145{
146 struct socket *so = inp->inp_socket;
147
ba55c9af
BJ
148 so->so_pcb = 0;
149 sofree(so);
7545cf09 150 remque(inp);
cdad2eb1 151 (void) m_free(dtom(inp));
af092e86
BJ
152}
153
405c9168
BJ
154/*
155 * Look for a control block to accept a segment.
156 * First choice is an exact address match.
157 * Second choice is a match of local address, with
158 * unspecified foreign address.
159 */
cdad2eb1 160struct inpcb *
4ad99bae 161in_pcblookup(head, faddr, fport, laddr, lport)
af092e86 162 struct inpcb *head;
4ad99bae 163 struct in_addr faddr, laddr;
af092e86
BJ
164 u_short fport, lport;
165{
166 register struct inpcb *inp;
405c9168 167 struct inpcb *match = 0;
af092e86 168
405c9168
BJ
169 for (inp = head->inp_next; inp != head; inp = inp->inp_next) {
170 if (inp->inp_laddr.s_addr != laddr.s_addr ||
171 inp->inp_lport != lport)
172 continue;
173 if (inp->inp_faddr.s_addr == 0) {
174 match = inp;
175 continue;
176 }
4ad99bae 177 if (inp->inp_faddr.s_addr == faddr.s_addr &&
405c9168 178 inp->inp_fport == fport)
af092e86 179 return (inp);
405c9168
BJ
180 }
181 return (match);
af092e86 182}