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