getpeer
[unix-history] / usr / src / sys / netinet / in_pcb.c
CommitLineData
a7343092 1/* in_pcb.c 4.41 83/07/25 */
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
a7343092
SL
179in_setpeeraddr(inp, nam)
180 register struct inpcb *inp;
181 struct mbuf *nam;
182{
183 register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
184
185 nam->m_len = sizeof (*sin);
186 sin = mtod(nam, struct sockaddr_in *);
187 bzero((caddr_t)sin, sizeof (*sin));
188 sin->sin_family = AF_INET;
189 sin->sin_port = inp->inp_fport;
190 sin->sin_addr = inp->inp_faddr;
191}
192
72e4f44e
SL
193/*
194 * Pass an error to all internet connections
195 * associated with address sin. Call the
196 * protocol specific routine to clean up the
197 * mess afterwards.
198 */
199in_pcbnotify(head, dst, errno, abort)
200 struct inpcb *head;
201 register struct in_addr *dst;
202 int errno, (*abort)();
203{
204 register struct inpcb *inp, *oinp;
205 int s = splimp();
206
72e4f44e
SL
207 for (inp = head->inp_next; inp != head;) {
208 if (inp->inp_faddr.s_addr != dst->s_addr) {
209 next:
210 inp = inp->inp_next;
211 continue;
212 }
213 if (inp->inp_socket == 0)
214 goto next;
215 inp->inp_socket->so_error = errno;
216 oinp = inp;
217 inp = inp->inp_next;
218 (*abort)(oinp);
219 }
220 splx(s);
221}
222
cdad2eb1 223struct inpcb *
ebcadd38 224in_pcblookup(head, faddr, fport, laddr, lport, flags)
af092e86 225 struct inpcb *head;
4ad99bae 226 struct in_addr faddr, laddr;
af092e86 227 u_short fport, lport;
ebcadd38 228 int flags;
af092e86 229{
1aa87517
BJ
230 register struct inpcb *inp, *match = 0;
231 int matchwild = 3, wildcard;
af092e86 232
405c9168 233 for (inp = head->inp_next; inp != head; inp = inp->inp_next) {
1aa87517 234 if (inp->inp_lport != lport)
405c9168 235 continue;
1aa87517 236 wildcard = 0;
5cdc4d65
SL
237 if (inp->inp_laddr.s_addr != INADDR_ANY) {
238 if (laddr.s_addr == INADDR_ANY)
1acff8ec
BJ
239 wildcard++;
240 else if (inp->inp_laddr.s_addr != laddr.s_addr)
1aa87517
BJ
241 continue;
242 } else {
5cdc4d65 243 if (laddr.s_addr != INADDR_ANY)
1aa87517
BJ
244 wildcard++;
245 }
5cdc4d65
SL
246 if (inp->inp_faddr.s_addr != INADDR_ANY) {
247 if (faddr.s_addr == INADDR_ANY)
1acff8ec
BJ
248 wildcard++;
249 else if (inp->inp_faddr.s_addr != faddr.s_addr ||
ebcadd38 250 inp->inp_fport != fport)
1aa87517
BJ
251 continue;
252 } else {
5cdc4d65 253 if (faddr.s_addr != INADDR_ANY)
1aa87517
BJ
254 wildcard++;
255 }
ebcadd38 256 if (wildcard && (flags & INPLOOKUP_WILDCARD) == 0)
405c9168 257 continue;
1aa87517
BJ
258 if (wildcard < matchwild) {
259 match = inp;
260 matchwild = wildcard;
261 if (matchwild == 0)
262 break;
405c9168 263 }
1aa87517 264 }
405c9168 265 return (match);
af092e86 266}