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