date and time created 85/05/30 19:10:47 by sklower
[unix-history] / usr / src / sys / netns / idp_usrreq.c
CommitLineData
b1fca4bf
KS
1/* idp_usrreq.c 6.1 85/05/30 */
2
3#include "param.h"
4#include "dir.h"
5#include "user.h"
6#include "mbuf.h"
7#include "protosw.h"
8#include "socket.h"
9#include "socketvar.h"
10#include "errno.h"
11#include "stat.h"
12
13#include "../net/if.h"
14#include "../net/route.h"
15
16#include "ns.h"
17#include "ns_pcb.h"
18#include "idp.h"
19#include "idp_var.h"
20#include "ns_error.h"
21
22/*
23 * IDP protocol implementation.
24 */
25
26struct sockaddr_ns idp_ns = { AF_NS };
27
28int
29idp_input_panic = 1;
30idp_input(m, nsp)
31 struct mbuf *m;
32 register struct nspcb *nsp;
33{
34 register struct idp *idp = mtod(m, struct idp *);
35 if (idp_input_panic) {
36 if ((nsp==0) || ((idp->idp_pt==5) && (!(nsp->nsp_flags&NSP_RAWIN))))
37 panic("Impossible idp_input");
38 }
39
40 /*
41 * Construct sockaddr format source address.
42 * Stuff source address and datagram in user buffer.
43 */
44 idp_ns.sns_addr = idp->idp_sna;
45 nsp->nsp_rpt = idp->idp_pt;
46 if ( ! (nsp->nsp_flags & NSP_RAWIN) ) {
47 m->m_len -= sizeof (struct idp);
48 m->m_off += sizeof (struct idp);
49 }
50 if (sbappendaddr(&nsp->nsp_socket->so_rcv, (struct sockaddr *)&idp_ns,
51 m, (struct mbuf *)0) == 0)
52 goto bad;
53 sorwakeup(nsp->nsp_socket);
54 return;
55bad:
56 m_freem(m);
57}
58
59idp_abort(nsp)
60 struct nspcb *nsp;
61{
62 struct socket *so = nsp->nsp_socket;
63
64 ns_pcbdisconnect(nsp);
65 soisdisconnected(so);
66}
67
68idp_output(nsp, m0)
69 struct nspcb *nsp;
70 struct mbuf *m0;
71{
72 register struct mbuf *m;
73 register struct idp *idp;
74 register struct socket *so;
75 register int len = 0;
76 register struct route *ro;
77 struct mbuf *mprev;
78 extern int idpcksum;
79
80 /*
81 * Calculate data length.
82 */
83 for (m = m0; m; m = m->m_next) {
84 mprev = m;
85 len += m->m_len;
86 }
87 /*
88 * Make sure packet is actually of even length.
89 */
90
91 if (len & 1) {
92 m = mprev;
93 if (m->m_len + m->m_off < MMAXOFF) {
94 m->m_len++;
95 } else {
96 struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA);
97
98 if (m1 == 0) return (ENOBUFS);
99 m1->m_len = 1;
100 m1->m_off = MMAXOFF - 1;
101 * mtod(m1, char *) = 0;
102 m->m_next = m1;
103 }
104 }
105
106 /*
107 * Fill in mbuf with extended IDP header
108 * and addresses and length put into network format.
109 */
110 if (nsp->nsp_flags & NSP_RAWOUT) {
111 m = m0;
112 idp = mtod(m, struct idp *);
113 } else {
114 m = m_get(M_DONTWAIT, MT_HEADER);
115 if (m == 0) {
116 m_freem(m0);
117 return (ENOBUFS);
118 }
119 m->m_off = MMAXOFF - sizeof (struct idp);
120 m->m_len = sizeof (struct idp);
121 m->m_next = m0;
122 idp = mtod(m, struct idp *);
123 idp->idp_tc = 0;
124 idp->idp_pt = nsp->nsp_dpt;
125 idp->idp_sna = nsp->nsp_laddr;
126 idp->idp_dna = nsp->nsp_faddr;
127 len += sizeof (struct idp);
128 }
129
130 idp->idp_len = htons((u_short)len);
131
132 if (idpcksum) {
133 idp->idp_sum = 0;
134 len = ((len - 1) | 1) + 1;
135 idp->idp_sum = ns_cksum(m, len);
136 } else
137 idp->idp_sum = 0xffff;
138
139 /*
140 * Output datagram.
141 */
142 so = nsp->nsp_socket;
143 if (so->so_options & SO_DONTROUTE)
144 return (ns_output(m, (struct route *)0,
145 (so->so_options & SO_BROADCAST) | NS_ROUTETOIF));
146 /*
147 * Use cached route for previous datagram if
148 * this is also to the same destination.
149 *
150 * NB: We don't handle broadcasts because that
151 * would require 3 subroutine calls.
152 */
153 ro = &nsp->nsp_route;
154 if (ro->ro_rt &&
155 ((*(long *)&nsp->nsp_lastnet)!=ns_netof(idp->idp_dna)) &&
156 !(ns_hosteq(satons_addr(ro->ro_dst), idp->idp_dna))) {
157 RTFREE(ro->ro_rt);
158 ro->ro_rt = (struct rtentry *)0;
159 nsp->nsp_lastnet = idp->idp_dna.x_net;
160 }
161 return (ns_output(m, ro, so->so_options & SO_BROADCAST));
162}
163/*ARGSUSED*/
164idp_ctloutput(req, so, level, name, value)
165 int req, level;
166 struct socket *so;
167 int name;
168 struct mbuf **value;
169{
170 register struct mbuf *m;
171 struct nspcb *nsp = sotonspcb(so);
172 int mask, error = 0;
173
174 if (nsp == NULL) {
175 error = EINVAL;
176 goto release;
177 }
178
179 switch (req) {
180 case PRCO_GETOPT:
181 if (value==NULL) {
182 error = EINVAL;
183 goto release;
184 }
185 m = m_get(M_DONTWAIT, MT_DATA);
186 switch (name) {
187 case SO_HEADERS_ON_INPUT:
188 mask = NSP_RAWIN;
189 goto get_flags;
190 case SO_HEADERS_ON_OUTPUT:
191 mask = NSP_RAWOUT;
192 get_flags:
193 m->m_len = sizeof(short);
194 m->m_off = MMAXOFF - sizeof(short);
195 *mtod(m, short *) = nsp->nsp_flags & mask;
196 break;
197 case SO_DEFAULT_HEADERS:
198 m->m_len = sizeof(struct idp);
199 m->m_off = MMAXOFF - sizeof(struct idp);
200 {
201 register struct idp *idp = mtod(m, struct idp *);
202 idp->idp_len = 0;
203 idp->idp_sum = 0;
204 idp->idp_tc = 0;
205 idp->idp_pt = nsp->nsp_dpt;
206 idp->idp_dna = nsp->nsp_faddr;
207 idp->idp_sna = nsp->nsp_laddr;
208 }
209 }
210 *value = m;
211 break;
212 case PRCO_SETOPT:
213 switch (name) {
214 int mask, *ok;
215
216 case SO_HEADERS_ON_INPUT:
217 mask = NSP_RAWIN;
218 goto set_head;
219 case SO_HEADERS_ON_OUTPUT:
220 mask = NSP_RAWOUT;
221 set_head:
222 if (value && *value) {
223 ok = mtod(*value, int *);
224 if (*ok)
225 nsp->nsp_flags |= mask;
226 else
227 nsp->nsp_flags &= ~mask;
228 } else error = EINVAL;
229 break;
230 case SO_DEFAULT_HEADERS:
231 {
232 register struct idp *idp
233 = mtod(*value, struct idp *);
234 nsp->nsp_dpt = idp->idp_pt;
235 }
236#ifdef NSIP
237 break;
238 case SO_NSIP_ROUTE:
239 error = nsip_route(*value);
240 break;
241#endif NSIP
242 }
243 if (value && *value)
244 m_freem(*value);
245 break;
246 }
247 release:
248 return(error);
249}
250
251/*ARGSUSED*/
252idp_usrreq(so, req, m, nam, rights)
253 struct socket *so;
254 int req;
255 struct mbuf *m, *nam, *rights;
256{
257 struct nspcb *nsp = sotonspcb(so);
258 int error = 0;
259
260 if (req == PRU_CONTROL)
261 return (ns_control(so, (int)m, (caddr_t)nam,
262 (struct ifnet *)rights));
263 if (rights && rights->m_len) {
264 error = EINVAL;
265 goto release;
266 }
267 if (nsp == NULL && req != PRU_ATTACH) {
268 error = EINVAL;
269 goto release;
270 }
271 switch (req) {
272
273 case PRU_ATTACH:
274 if (nsp != NULL) {
275 error = EINVAL;
276 break;
277 }
278 error = ns_pcballoc(so, &nspcb);
279 if (error)
280 break;
281 error = soreserve(so, 2048, 2048);
282 if (error)
283 break;
284 break;
285
286 case PRU_DETACH:
287 if (nsp == NULL) {
288 error = ENOTCONN;
289 break;
290 }
291 ns_pcbdetach(nsp);
292 break;
293
294 case PRU_BIND:
295 error = ns_pcbbind(nsp, nam);
296 break;
297
298 case PRU_LISTEN:
299 error = EOPNOTSUPP;
300 break;
301
302 case PRU_CONNECT:
303 if (!ns_nullhost(nsp->nsp_faddr)) {
304 error = EISCONN;
305 break;
306 }
307 error = ns_pcbconnect(nsp, nam);
308 if (error == 0)
309 soisconnected(so);
310 break;
311
312 case PRU_CONNECT2:
313 error = EOPNOTSUPP;
314 break;
315
316 case PRU_ACCEPT:
317 error = EOPNOTSUPP;
318 break;
319
320 case PRU_DISCONNECT:
321 if (ns_nullhost(nsp->nsp_faddr)) {
322 error = ENOTCONN;
323 break;
324 }
325 ns_pcbdisconnect(nsp);
326 soisdisconnected(so);
327 break;
328
329 case PRU_SHUTDOWN:
330 socantsendmore(so);
331 break;
332
333 case PRU_SEND:
334 {
335 struct ns_addr laddr;
336 int s;
337
338 if (nam) {
339 laddr = nsp->nsp_laddr;
340 if (!ns_nullhost(nsp->nsp_faddr)) {
341 error = EISCONN;
342 break;
343 }
344 /*
345 * Must block input while temporarily connected.
346 */
347 s = splnet();
348 error = ns_pcbconnect(nsp, nam);
349 if (error) {
350 splx(s);
351 break;
352 }
353 } else {
354 if (ns_nullhost(nsp->nsp_faddr)) {
355 error = ENOTCONN;
356 break;
357 }
358 }
359 error = idp_output(nsp, m);
360 m = NULL;
361 if (nam) {
362 ns_pcbdisconnect(nsp);
363 splx(s);
364 nsp->nsp_laddr.x_host = laddr.x_host;
365 nsp->nsp_laddr.x_port = laddr.x_port;
366 }
367 }
368 break;
369
370 case PRU_ABORT:
371 ns_pcbdetach(nsp);
372 sofree(so);
373 soisdisconnected(so);
374 break;
375
376 case PRU_SOCKADDR:
377 ns_setsockaddr(nsp, nam);
378 break;
379
380 case PRU_PEERADDR:
381 ns_setpeeraddr(nsp, nam);
382 break;
383
384 case PRU_SENSE:
385 /*
386 * stat: don't bother with a blocksize.
387 */
388 return (0);
389
390 case PRU_SENDOOB:
391 case PRU_FASTTIMO:
392 case PRU_SLOWTIMO:
393 case PRU_PROTORCV:
394 case PRU_PROTOSEND:
395 error = EOPNOTSUPP;
396 break;
397
398 case PRU_CONTROL:
399 case PRU_RCVD:
400 case PRU_RCVOOB:
401 return (EOPNOTSUPP); /* do not free mbuf's */
402
403 default:
404 panic("idp_usrreq");
405 }
406release:
407 if (m != NULL)
408 m_freem(m);
409 return (error);
410}
411/*ARGSUSED*/
412idp_raw_usrreq(so, req, m, nam, rights)
413 struct socket *so;
414 int req;
415 struct mbuf *m, *nam, *rights;
416{
417 int error = 0;
418 struct nspcb *nsp = sotonspcb(so);
419 extern struct nspcb nsrawpcb;
420
421 switch (req) {
422
423 case PRU_ATTACH:
424
425 if (nsp != NULL) {
426 error = EINVAL;
427 break;
428 }
429 error = ns_pcballoc(so, &nsrawpcb);
430 if (error)
431 break;
432 error = soreserve(so, 2048, 2048);
433 if (error)
434 break;
435 nsp = sotonspcb(so);
436 nsp->nsp_faddr.x_host = ns_broadhost;
437 nsp->nsp_flags = NSP_RAWIN | NSP_RAWOUT;
438 break;
439 default:
440 error = idp_usrreq(so, req, m, nam, rights);
441 }
442 return(error);
443}
444