Correct erroneous copyright information.
[unix-history] / usr / src / sys / netns / ns_pcb.c
CommitLineData
8ae0e4b4 1/*
79b7ed8c 2 * Copyright (c) 1984, 1985 Regents of the University of California.
8ae0e4b4
KM
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
5 *
79b7ed8c 6 * @(#)ns_pcb.c 6.6 (Berkeley) %G%
8ae0e4b4 7 */
2d433de1
KS
8
9#include "param.h"
10#include "systm.h"
11#include "dir.h"
12#include "user.h"
13#include "mbuf.h"
14#include "socket.h"
15#include "socketvar.h"
16#include "../net/if.h"
17#include "../net/route.h"
18#include "protosw.h"
19
20#include "ns.h"
21#include "ns_if.h"
22#include "ns_pcb.h"
23
24struct ns_addr zerons_addr;
25
26ns_pcballoc(so, head)
27 struct socket *so;
f97be0c9 28 struct nspcb *head;
2d433de1
KS
29{
30 struct mbuf *m;
31 register struct nspcb *nsp;
32
33 m = m_getclr(M_DONTWAIT, MT_PCB);
34 if (m == NULL)
35 return (ENOBUFS);
36 nsp = mtod(m, struct nspcb *);
37 nsp->nsp_socket = so;
38 insque(nsp, head);
39 so->so_pcb = (caddr_t)nsp;
40 return (0);
41}
42
43ns_pcbbind(nsp, nam)
44 register struct nspcb *nsp;
45 struct mbuf *nam;
46{
47 register struct sockaddr_ns *sns;
48 u_short lport = 0;
49
50 if(nsp->nsp_lport || !ns_nullhost(nsp->nsp_laddr))
51 return (EINVAL);
52 if (nam == 0)
53 goto noname;
54 sns = mtod(nam, struct sockaddr_ns *);
55 if (nam->m_len != sizeof (*sns))
56 return (EINVAL);
57 if (!ns_nullhost(sns->sns_addr)) {
58 int tport = sns->sns_port;
59
60 sns->sns_port = 0; /* yech... */
61 if (ifa_ifwithaddr((struct sockaddr *)sns) == 0)
62 return (EADDRNOTAVAIL);
63 sns->sns_port = tport;
64 }
65 lport = sns->sns_port;
66 if (lport) {
67 u_short aport = ntohs(lport);
68
69 if (aport < NSPORT_RESERVED && u.u_uid != 0)
70 return (EACCES);
71 if (ns_pcblookup(&zerons_addr, lport, 0))
72 return (EADDRINUSE);
73 }
74 nsp->nsp_laddr = sns->sns_addr;
75noname:
76 if (lport == 0)
77 do {
78 if (nspcb.nsp_lport++ < NSPORT_RESERVED)
79 nspcb.nsp_lport = NSPORT_RESERVED;
80 lport = htons(nspcb.nsp_lport);
81 } while (ns_pcblookup(&zerons_addr, lport, 0));
82 nsp->nsp_lport = lport;
83 return (0);
84}
85
86/*
87 * Connect from a socket to a specified address.
88 * Both address and port must be specified in argument sns.
89 * If don't have a local address for this socket yet,
90 * then pick one.
91 */
92ns_pcbconnect(nsp, nam)
93 struct nspcb *nsp;
94 struct mbuf *nam;
95{
96 struct ns_ifaddr *ia;
2d433de1 97 register struct sockaddr_ns *sns = mtod(nam, struct sockaddr_ns *);
aa6e5222 98 register struct ns_addr *dst;
2d433de1
KS
99
100 if (nam->m_len != sizeof (*sns))
101 return (EINVAL);
102 if (sns->sns_family != AF_NS)
103 return (EAFNOSUPPORT);
104 if (sns->sns_port==0 || ns_nullhost(sns->sns_addr))
105 return (EADDRNOTAVAIL);
106 if (ns_nullhost(nsp->nsp_laddr) &&
aa6e5222
KS
107 (!ns_neteq(nsp->nsp_lastdst, sns->sns_addr))) {
108 register struct route *ro;
109 struct ifnet *ifp;
110 ro = &nsp->nsp_route;
111 dst = &satons_addr(ro->ro_dst);
2d433de1 112
aa6e5222
KS
113 ia = ns_iaonnetof(&sns->sns_addr);
114 if (ia == 0) {
2d433de1
KS
115 /*
116 * If route is known or can be allocated now,
117 * our src addr is taken from the i/f, else punt.
118 */
2d433de1 119 if (ro->ro_rt &&
aa6e5222 120 !ns_hosteq(*dst, sns->sns_addr)) {
2d433de1
KS
121 RTFREE(ro->ro_rt);
122 ro->ro_rt = (struct rtentry *)0;
123 }
124 if ((ro->ro_rt == (struct rtentry *)0) ||
125 (ifp = ro->ro_rt->rt_ifp) == (struct ifnet *)0) {
126 /* No route yet, so try to acquire one */
127 ro->ro_dst.sa_family = AF_NS;
aa6e5222
KS
128 *dst = sns->sns_addr;
129 dst->x_port = 0;
2d433de1
KS
130 rtalloc(ro);
131 if (ro->ro_rt == 0)
86e2c76a 132 ifp = (struct ifnet *)0;
2d433de1 133 else
86e2c76a
KS
134 ifp = ro->ro_rt->rt_ifp;
135 }
136 if (ifp) {
137 for (ia = ns_ifaddr; ia; ia = ia->ia_next)
2d433de1
KS
138 if (ia->ia_ifp == ifp)
139 break;
140 }
141 if (ia == 0)
142 ia = ns_ifaddr;
143 if (ia == 0)
144 return (EADDRNOTAVAIL);
aa6e5222
KS
145 } else if (ro->ro_rt) {
146 if (ns_neteq(*dst, sns->sns_addr)) {
147 /*
148 * This assume that we have no GH
149 * type routes.
150 */
151 if (ro->ro_rt->rt_flags & RTF_HOST) {
152 if (!ns_hosteq(*dst, sns->sns_addr))
153 goto re_route;
154
155 }
156 if ((ro->ro_rt->rt_flags & RTF_GATEWAY) == 0) {
157 dst->x_host = sns->sns_addr.x_host;
158 }
159 /*
160 * Otherwise, we go through the same gateway
161 * and dst is already set up.
162 */
163 } else {
164 re_route:
165 RTFREE(ro->ro_rt);
166 ro->ro_rt = (struct rtentry *)0;
167 }
2d433de1 168 }
aa6e5222
KS
169 nsp->nsp_laddr.x_net = satons_addr(ia->ia_addr).x_net;
170 nsp->nsp_lastdst = sns->sns_addr;
2d433de1
KS
171 }
172 if (ns_pcblookup(&sns->sns_addr, nsp->nsp_lport, 0))
173 return (EADDRINUSE);
174 if (ns_nullhost(nsp->nsp_laddr)) {
175 if (nsp->nsp_lport == 0)
f97be0c9 176 (void) ns_pcbbind(nsp, (struct mbuf *)0);
2d433de1
KS
177 nsp->nsp_laddr.x_host = ns_thishost;
178 }
179 nsp->nsp_faddr = sns->sns_addr;
180 /* Includes nsp->nsp_fport = sns->sns_port; */
181 return (0);
182}
183
184ns_pcbdisconnect(nsp)
185 struct nspcb *nsp;
186{
187
188 nsp->nsp_faddr = zerons_addr;
189 if (nsp->nsp_socket->so_state & SS_NOFDREF)
190 ns_pcbdetach(nsp);
191}
192
193ns_pcbdetach(nsp)
194 struct nspcb *nsp;
195{
196 struct socket *so = nsp->nsp_socket;
197
198 so->so_pcb = 0;
199 sofree(so);
200 if (nsp->nsp_route.ro_rt)
201 rtfree(nsp->nsp_route.ro_rt);
202 remque(nsp);
203 (void) m_free(dtom(nsp));
204}
205
206ns_setsockaddr(nsp, nam)
207 register struct nspcb *nsp;
208 struct mbuf *nam;
209{
210 register struct sockaddr_ns *sns = mtod(nam, struct sockaddr_ns *);
211
212 nam->m_len = sizeof (*sns);
213 sns = mtod(nam, struct sockaddr_ns *);
214 bzero((caddr_t)sns, sizeof (*sns));
215 sns->sns_family = AF_NS;
216 sns->sns_addr = nsp->nsp_laddr;
217}
218
219ns_setpeeraddr(nsp, nam)
220 register struct nspcb *nsp;
221 struct mbuf *nam;
222{
223 register struct sockaddr_ns *sns = mtod(nam, struct sockaddr_ns *);
224
225 nam->m_len = sizeof (*sns);
226 sns = mtod(nam, struct sockaddr_ns *);
227 bzero((caddr_t)sns, sizeof (*sns));
228 sns->sns_family = AF_NS;
229 sns->sns_addr = nsp->nsp_faddr;
230}
231
232/*
233 * Pass some notification to all connections of a protocol
234 * associated with address dst. Call the
235 * protocol specific routine to handle each connection.
236 * Also pass an extra paramter via the nspcb. (which may in fact
237 * be a parameter list!)
238 */
239ns_pcbnotify(dst, errno, notify, param)
240 register struct ns_addr *dst;
241 long param;
242 int errno, (*notify)();
243{
244 register struct nspcb *nsp, *oinp;
245 int s = splimp();
246
247 for (nsp = (&nspcb)->nsp_next; nsp != (&nspcb);) {
248 if (!ns_hosteq(*dst,nsp->nsp_faddr)) {
249 next:
250 nsp = nsp->nsp_next;
251 continue;
252 }
253 if (nsp->nsp_socket == 0)
254 goto next;
255 if (errno)
256 nsp->nsp_socket->so_error = errno;
257 oinp = nsp;
258 nsp = nsp->nsp_next;
259 oinp->nsp_notify_param = param;
260 (*notify)(oinp);
261 }
262 splx(s);
263}
264
265/*
266 * After a routing change, flush old routing
267 * and allocate a (hopefully) better one.
268 */
269ns_rtchange(nsp)
270 struct nspcb *nsp;
271{
272 if (nsp->nsp_route.ro_rt) {
273 rtfree(nsp->nsp_route.ro_rt);
274 nsp->nsp_route.ro_rt = 0;
275 /*
276 * A new route can be allocated the next time
277 * output is attempted.
278 */
279 }
280 /* SHOULD NOTIFY HIGHER-LEVEL PROTOCOLS */
281}
282
283struct nspcb *
284ns_pcblookup(faddr, lport, wildp)
285 struct ns_addr *faddr;
286 u_short lport;
287{
288 register struct nspcb *nsp, *match = 0;
289 int matchwild = 3, wildcard;
290 u_short fport;
291
292 fport = faddr->x_port;
293 for (nsp = (&nspcb)->nsp_next; nsp != (&nspcb); nsp = nsp->nsp_next) {
294 if (nsp->nsp_lport != lport)
295 continue;
296 wildcard = 0;
297 if (ns_nullhost(nsp->nsp_faddr)) {
298 if (!ns_nullhost(*faddr))
299 wildcard++;
300 } else {
301 if (ns_nullhost(*faddr))
302 wildcard++;
303 else {
304 if (!ns_hosteq(nsp->nsp_faddr, *faddr))
305 continue;
306 if( nsp->nsp_fport != fport) {
307 if(nsp->nsp_fport != 0)
308 continue;
309 else
310 wildcard++;
311 }
312 }
313 }
314 if (wildcard && wildp==0)
315 continue;
316 if (wildcard < matchwild) {
317 match = nsp;
318 matchwild = wildcard;
319 if (wildcard == 0)
320 break;
321 }
322 }
323 return (match);
324}