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