exit on end-of-file if file shorter than a screen, regardless
[unix-history] / usr / src / sys / netiso / tp_usrreq.c
CommitLineData
4a61b6ff
KS
1/***********************************************************
2 Copyright IBM Corporation 1987
3
4 All Rights Reserved
5
6Permission to use, copy, modify, and distribute this software and its
7documentation for any purpose and without fee is hereby granted,
8provided that the above copyright notice appear in all copies and that
9both that copyright notice and this permission notice appear in
10supporting documentation, and that the name of IBM not be
11used in advertising or publicity pertaining to distribution of the
12software without specific, written prior permission.
13
14IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
15ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
16IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
17ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
18WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
19ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
20SOFTWARE.
21
22******************************************************************/
23
24/*
25 * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
26 */
27/*
28 * ARGO TP
29 *
30 * $Header: tp_usrreq.c,v 5.4 88/11/18 17:29:18 nhall Exp $
31 * $Source: /usr/argo/sys/netiso/RCS/tp_usrreq.c,v $
32 *
33 * tp_usrreq(), the fellow that gets called from most of the socket code.
34 * Pretty straighforward.
35 * THe only really awful stuff here is the OOB processing, which is done
36 * wholly here.
37 * tp_rcvoob() and tp_sendoob() are contained here and called by tp_usrreq().
38 */
39
40#ifndef lint
41static char *rcsid = "$Header: tp_usrreq.c,v 5.4 88/11/18 17:29:18 nhall Exp $";
42#endif lint
43
44#include "param.h"
45#include "systm.h"
46#include "dir.h"
47#include "user.h"
48#include "mbuf.h"
49#include "socket.h"
50#include "socketvar.h"
51#include "domain.h"
52#include "protosw.h"
53#include "errno.h"
54
55#include "../netiso/tp_param.h"
56#include "../netiso/tp_timer.h"
57#include "../netiso/tp_stat.h"
58#include "../netiso/tp_seq.h"
59#include "../netiso/tp_ip.h"
60#include "../netiso/tp_pcb.h"
61#include "../netiso/argo_debug.h"
62#include "../netiso/tp_trace.h"
63#include "../netiso/tp_meas.h"
64#include "../netiso/iso.h"
65#include "../netiso/iso_errno.h"
66
67int tp_attach(), tp_driver();
68
69#ifdef ARGO_DEBUG
70/*
71 * CALLED FROM:
72 * anywhere you want to debug...
73 * FUNCTION and ARGUMENTS:
74 * print (str) followed by the control info in the mbufs of an mbuf chain (n)
75 */
76void
77dump_mbuf(n, str)
78 struct mbuf *n;
79 char *str;
80{
81 struct mbuf *nextrecord;
82
83 printf("dump %s\n", str);
84
85 if( n == MNULL) {
86 printf("EMPTY:\n");
87 return;
88 }
89
90 for(;n;) {
91 nextrecord = n->m_act;
92 printf("RECORD:\n");
93 while (n) {
94 printf("%x : Len %x Of %x A %x Nx %x Tp %x\n",
95 n, n->m_len, n->m_off, n->m_act, n->m_next, n->m_type);
96#ifdef notdef
97 {
98 register char *p = mtod(n, char *);
99 register int i;
100
101 printf("data: ");
102 for(i=0; i < n->m_len; i++ ) {
103 if(i%8 == 0)
104 printf("\n");
105 printf("0x%x ", *(p+i));
106 }
107 printf("\n");
108 }
109#endif notdef
110 if( n->m_next == n ) {
111 printf("LOOP!\n");
112 return;
113 }
114 n = n->m_next;
115 }
116 n = nextrecord;
117 }
118 printf("\n");
119}
120
121#endif ARGO_DEBUG
122
123/*
124 * CALLED FROM:
125 * tp_usrreq(), PRU_RCVOOB
126 * FUNCTION and ARGUMENTS:
127 * Copy data from the expedited data socket buffer into
128 * the pre-allocated mbuf m.
129 * There is an isomorphism between XPD TPDUs and expedited data TSDUs.
130 * XPD tpdus are limited to 16 bytes of data so they fit in one mbuf.
131 * RETURN VALUE:
132 * EINVAL if debugging is on and a disaster has occurred
133 * ENOTCONN if the socket isn't connected
134 * EWOULDBLOCK if the socket is in non-blocking mode and there's no
135 * xpd data in the buffer
136 * E* whatever is returned from the fsm.
137 */
138static int
139tp_rcvoob(tpcb, so, m, outflags, inflags)
140 struct tp_pcb *tpcb;
141 register struct socket *so;
142 register struct mbuf *m;
143 int *outflags;
144 int inflags;
145{
146 register struct mbuf *n;
147 register struct sockbuf *sb = &tpcb->tp_Xrcv;
148 struct tp_event E;
149 int error = 0;
150
151 IFDEBUG(D_XPD)
152 printf("PRU_RCVOOB, sostate 0x%x\n", so->so_state);
153 ENDDEBUG
154
155 /* if you use soreceive */
156 if (m==MNULL)
157 return ENOBUFS;
158
159restart:
160 sblock(sb);
161
162 if ((((so->so_state & SS_ISCONNECTED) == 0)
163 || (so->so_state & SS_ISDISCONNECTING) != 0) &&
164 (so->so_proto->pr_flags & PR_CONNREQUIRED)) {
165 return ENOTCONN;
166 }
167
168 if ( sb->sb_cc == 0) {
169 ASSERT( (tpcb->tp_flags & TPF_DISC_DATA_IN) == 0 );
170 IFDEBUG(D_XPD)
171 printf("RCVOOB: empty queue!\n");
172 ENDDEBUG
173 if (so->so_state & SS_NBIO) {
174 return EWOULDBLOCK;
175 }
176 sbunlock(sb);
177 sbwait(sb);
178 goto restart;
179 }
180 /* Take the first mbuf off the chain.
181 * Each XPD TPDU gives you a complete TSDU so the chains don't get
182 * coalesced, but one TSDU may span several mbufs.
183 * Nevertheless, since n should have a most 16 bytes, it
184 * will fit into m. (size was checked in tp_input() )
185 */
186
187 n = sb->sb_mb;
188 ASSERT((n->m_type == TPMT_DATA) ||
189 n->m_type == TPMT_IPHDR || n->m_type == TPMT_TPHDR);
190
191 /*
192 * mtod doesn't work for cluster-type mbufs, hence this disaster check:
193 */
194 if( n->m_off > MMAXOFF )
195 panic("tp_rcvoob: unexpected cluster ");
196
197 m->m_next = MNULL;
198 m->m_act = MNULL;
199 m->m_off = MMINOFF;
200 m->m_len = 0;
201
202 /* Assuming at most one xpd tpdu is in the buffer at once */
203 while ( n != MNULL ) {
204 m->m_len += n->m_len;
205 bcopy(mtod(n, caddr_t), mtod(m, caddr_t), n->m_len);
206 m->m_off += n->m_len; /* so mtod() in bcopy() above gives right addr */
207 n = n->m_next;
208 }
209 m->m_off = MMINOFF; /* restore it to its proper value */
210
211 IFDEBUG(D_XPD)
212 printf("tp_rcvoob: xpdlen 0x%x\n", m->m_len);
213 dump_mbuf(so->so_rcv.sb_mb, "RCVOOB: Rcv socketbuf");
214 dump_mbuf(sb->sb_mb, "RCVOOB: Xrcv socketbuf");
215 ENDDEBUG
216
217 if( (inflags & MSG_PEEK) == 0 )
218 sbdrop(sb, m->m_len);
219
220release:
221 sbunlock(sb);
222
223 IFTRACE(D_XPD)
224 tptraceTPCB(TPPTmisc, "PRU_RCVOOB @ release sb_cc m_len",
225 tpcb->tp_Xrcv.sb_cc, m->m_len,0,0 );
226 ENDTRACE
227 if(outflags)
228 *outflags = MSG_OOB | MSG_EOTSDU | inflags; /* always on xpd recv */
229 if (error == 0)
230 error = DoEvent(T_USR_Xrcvd);
231 return error;
232}
233
234/*
235 * CALLED FROM:
236 * tp_usrreq(), PRU_SENDOOB
237 * FUNCTION and ARGUMENTS:
238 * Send what's in the mbuf chain (m) as an XPD TPDU.
239 * The mbuf may not contain more then 16 bytes of data.
240 * XPD TSDUs aren't segmented, so they translate into
241 * exactly one XPD TPDU, with EOT bit set.
242 * RETURN VALUE:
243 * EWOULDBLOCK if socket is in non-blocking mode and the previous
244 * xpd data haven't been acked yet.
245 * EMSGSIZE if trying to send > max-xpd bytes (16)
246 * ENOBUFS if ran out of mbufs
247 */
248static int
249tp_sendoob(tpcb, so, xdata, outflags)
250 struct tp_pcb *tpcb;
251 register struct socket *so;
252 register struct mbuf *xdata;
253 int *outflags; /* not used */
254{
255 /*
256 * Each mbuf chain represents a sequence # in the XPD seq space.
257 * The first one in the queue has sequence # tp_Xuna.
258 * When we add to the XPD queue, we stuff a zero-length
259 * mbuf (mark) into the DATA queue, with its sequence number in m_next
260 * to be assigned to this XPD tpdu, so data xfer can stop
261 * when it reaches the zero-length mbuf if this XPD TPDU hasn't
262 * yet been acknowledged.
263 */
264 register struct sockbuf *sb = &(tpcb->tp_Xsnd);
265 register struct mbuf *xmark;
266 register int len=0;
267 struct tp_event E;
268
269 IFDEBUG(D_XPD)
270 printf("tp_sendoob:");
271 if(xdata)
272 printf("xdata len 0x%x\n", xdata->m_len);
273 ENDDEBUG
274oob_again:
275 /* DO NOT LOCK the Xsnd buffer!!!! You can have at MOST one
276 * socket buf locked at any time!!! (otherwise you might
277 * sleep() in sblock() w/ a signal pending and cause the
278 * system call to be aborted w/ a locked socketbuf, which
279 * is a problem. So the so_snd buffer lock
280 * (done in sosend()) serves as the lock for Xpd.
281 */
282 if (sb->sb_mb) { /* anything already in this sockbuf? */
283 if (so->so_state & SS_NBIO) {
284 return EWOULDBLOCK;
285 }
286 sbunlock(&so->so_snd);
287 sbwait(&so->so_snd);
288 sblock(&so->so_snd);
289 goto oob_again;
290 }
291
292 if (xdata == (struct mbuf *)0) {
293 /* empty xpd packet */
294 MGET(xdata, M_WAIT, TPMT_DATA);
295 if (xdata == NULL) {
296 return ENOBUFS;
297 }
298 xdata->m_len = 0;
299 xdata->m_act = MNULL;
300 }
301 IFDEBUG(D_XPD)
302 printf("tp_sendoob 1:");
303 if(xdata)
304 printf("xdata len 0x%x\n", xdata->m_len);
305 ENDDEBUG
306 xmark = xdata; /* temporary use of variable xmark */
307 while (xmark) {
308 len += xmark->m_len;
309 xmark = xmark->m_next;
310 }
311 if (len > TP_MAX_XPD_DATA) {
312 return EMSGSIZE;
313 }
314 IFDEBUG(D_XPD)
315 printf("tp_sendoob 2:");
316 if(xdata)
317 printf("xdata len 0x%x\n", len);
318 ENDDEBUG
319
320 /* stick an xpd mark in the normal data queue
321 * make sure we have enough mbufs before we stick anything into any queues
322 */
323 MGET(xmark,M_WAIT, TPMT_XPD);
324 if (xmark == MNULL) {
325 return ENOBUFS;
326 }
327 xmark->m_len = 0;
328 xmark->m_act = MNULL;
329
330 { /* stash the xpd sequence number in the mark */
331 SeqNum *Xuna = mtod(xmark, SeqNum *);
332 *Xuna = tpcb->tp_Xuna;
333 }
334
335 IFTRACE(D_XPD)
336 tptraceTPCB(TPPTmisc, "XPD mark m_next ", xmark->m_next, 0, 0, 0);
337 ENDTRACE
338
339 sbappendrecord(&so->so_snd, xmark); /* the mark */
340 sbappendrecord(sb, xdata);
341
342 IFDEBUG(D_XPD)
343 printf("tp_sendoob len 0x%x\n", len);
344 dump_mbuf(so->so_snd.sb_mb, "XPD request Regular sndbuf:");
345 dump_mbuf(tpcb->tp_Xsnd.sb_mb, "XPD request Xsndbuf:");
346 ENDDEBUG
347 u.u_r.r_val1 += len;
348 return DoEvent(T_XPD_req);
349
350}
351
352/*
353 * CALLED FROM:
354 * the socket routines
355 * FUNCTION and ARGUMENTS:
356 * Handles all "user requests" except the [gs]ockopts() requests.
357 * The argument (req) is the request type (PRU*),
358 * (m) is an mbuf chain, generally used for send and
359 * receive type requests only.
360 * (nam) is used for addresses usually, in particular for the bind request.
361 *
362 * The last argument (rights in most usrreq()s) has been stolen for
363 * returning flags values. Since rights can't be passed around w/ tp,
364 * this field is used only for RCVOOB user requests, and is assumed
365 * to be either 0 (as soreceive() would have it) or a ptr to the int flags
366 * (as recvv()'s version of soreceive() would have it
367 */
368/*ARGSUSED*/
369ProtoHook
370tp_usrreq(so, req, m, nam, rightsp, outflags)
371 struct socket *so;
372 u_int req;
373 struct mbuf *m, *nam, *rightsp /* not used */;
374 int *outflags;
375{
376 register struct tp_pcb *tpcb = sototpcb(so);
377 int s = splnet();
378 int error = 0;
379 u_long eotsdu = 0;
380 struct tp_event E;
381
382 IFDEBUG(D_REQUEST)
383 printf("usrreq(0x%x,%d,0x%x,0x%x,0x%x)\n",so,req,m,nam,outflags);
384 if(so->so_error)
385 printf("WARNING!!! so->so_error is 0x%x\n", so->so_error);
386 ENDDEBUG
387 IFTRACE(D_REQUEST)
388 tptraceTPCB(TPPTusrreq, "req so m state [", req, so, m,
389 tpcb?tpcb->tp_state:0);
390 ENDTRACE
391
392 if ((u_int)tpcb == 0 && req != PRU_ATTACH) {
393 IFTRACE(D_REQUEST)
394 tptraceTPCB(TPPTusrreq, "req failed NO TPCB[", 0, 0, 0, 0);
395 ENDTRACE
396 splx(s);
397 return ENOTCONN;
398 }
399
400
401 IFDEBUG(D_XPD)
402 extern struct mbuf *mfree;
403 struct mbuf *m = mfree, *n=MNULL;
404
405 if ( (u_int) tpcb != 0 ) {
406 n = tpcb->tp_Xrcv.sb_mb;
407 if(n) while(m) {
408 if(m == n) {
409 printf("enter usrreq %d Xrcv sb_mb 0x%x is on freelist!\n",
410 req, n);
411 }
412 m = m->m_next;
413 }
414 }
415 ENDDEBUG
416
417 switch (req) {
418
419 case PRU_ATTACH:
420 if (tpcb) {
421 error = EISCONN;
422 break;
423 }
424 if( error = tp_attach(so, so->so_proto->pr_domain->dom_family ) )
425 break;
426 tpcb = sototpcb(so);
427 break;
428
429 case PRU_ABORT: /* called from close() */
430 /* called for each incoming connect queued on the
431 * parent (accepting) socket
432 */
433 if( tpcb->tp_state == TP_OPEN ) {
434 E.ATTR(T_DISC_req).e_reason = E_TP_NO_SESSION;
435 error = DoEvent(T_DISC_req); /* pretend it was a close() */
436 break;
437 } /* else DROP THROUGH */
438
439 case PRU_DETACH: /* called from close() */
440 /* called only after disconnect was called */
441 error = DoEvent(T_DETACH);
442 break;
443
444 case PRU_SHUTDOWN:
445 /* recv end may have been released; local credit might be zero */
446 case PRU_DISCONNECT:
447 E.ATTR(T_DISC_req).e_reason = E_TP_NORMAL_DISC;
448 error = DoEvent(T_DISC_req);
449 break;
450
451 case PRU_BIND:
452 error = (tpcb->tp_nlproto->nlp_pcbbind)( so->so_pcb, nam );
453 if (error == 0) {
454 tpcb->tp_lsuffixlen = sizeof(short); /* default */
455 *(u_short *)(tpcb->tp_lsuffix) = (u_short)
456 (tpcb->tp_nlproto->nlp_getsufx)( so->so_pcb, TP_LOCAL );
457 }
458 break;
459
460 case PRU_LISTEN:
461 if ( *SHORT_LSUFXP(tpcb) == (short)0 ) {
462 /* note: this suffix is independent of the extended suffix */
463 if( error = (tpcb->tp_nlproto->nlp_pcbbind)(so->so_pcb, MNULL) )
464 break;
465 }
466 if( tpcb->tp_lsuffixlen == 0) {
467 tpcb->tp_lsuffixlen = sizeof(short); /* default */
468 *SHORT_LSUFXP(tpcb) = (short)
469 (tpcb->tp_nlproto->nlp_getsufx)( so->so_pcb, TP_LOCAL );
470 }
471 IFDEBUG(D_TPISO)
472 if(tpcb->tp_state != TP_CLOSED)
473 printf("LISTEN ERROR: state 0x%x\n", tpcb->tp_state);
474 ENDDEBUG
475 error = DoEvent(T_LISTEN_req);
476 break;
477
478 case PRU_CONNECT2:
479 error = EOPNOTSUPP; /* for unix domain sockets */
480 break;
481
482 case PRU_CONNECT:
483 IFTRACE(D_CONN)
484 tptraceTPCB(TPPTmisc,
485 "PRU_CONNECT: so *SHORT_LSUFXP(tpcb) 0x%x lsuflen 0x%x, class 0x%x",
486 tpcb->tp_sock, *SHORT_LSUFXP(tpcb), tpcb->tp_lsuffixlen,
487 tpcb->tp_class);
488 ENDTRACE
489 IFDEBUG(D_CONN)
490 printf("PRU_CONNECT: so *SHORT_LSUFXP(tpcb) 0x%x lsuflen 0x%x, class 0x%x",
491 tpcb->tp_sock, *SHORT_LSUFXP(tpcb), tpcb->tp_lsuffixlen,
492 tpcb->tp_class);
493 ENDDEBUG
494 if (*SHORT_LSUFXP(tpcb) == (short)0) {
495 /* no bind was done */
496 /* note: this suffix is independent of the extended suffix */
497 if( error = (tpcb->tp_nlproto->nlp_pcbbind)(so->so_pcb, MNULL) ) {
498 IFDEBUG(D_CONN)
499 printf("pcbbind returns error 0x%x\n", error );
500 ENDDEBUG
501 break;
502 }
503 }
504 if (tpcb->tp_lsuffixlen == 0) {
505 /* didn't set an extended suffix */
506 tpcb->tp_lsuffixlen = sizeof(short);
507 *SHORT_LSUFXP(tpcb) = (short)
508 (tpcb->tp_nlproto->nlp_getsufx)( so->so_pcb, TP_LOCAL );
509 }
510
511 IFDEBUG(D_CONN)
512 printf("isop 0x%x isop->isop_socket offset 12 :\n", tpcb->tp_npcb);
513 dump_buf( tpcb->tp_npcb, 16);
514 ENDDEBUG
515 if( error = tp_route_to( nam, tpcb, /* channel */0) )
516 break;
517 IFDEBUG(D_CONN)
518 printf(
519 "PRU_CONNECT after tpcb 0x%x so 0x%x npcb 0x%x flags 0x%x\n",
520 tpcb, so, tpcb->tp_npcb, tpcb->tp_flags);
521 printf("isop 0x%x isop->isop_socket offset 12 :\n", tpcb->tp_npcb);
522 dump_buf( tpcb->tp_npcb, 16);
523 ENDDEBUG
524 if( tpcb->tp_fsuffixlen == 0 ) {
525 /* didn't set peer extended suffix */
526 tpcb->tp_fsuffixlen = sizeof(short);
527 *SHORT_FSUFXP(tpcb) = (short)
528 (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, TP_FOREIGN);
529 }
530 (void) (tpcb->tp_nlproto->nlp_mtu)(so, so->so_pcb,
531 &tpcb->tp_l_tpdusize, &tpcb->tp_tpdusize, 0);
532 if( tpcb->tp_state == TP_CLOSED) {
533 soisconnecting(so);
534 error = DoEvent(T_CONN_req);
535 } else {
536 (tpcb->tp_nlproto->nlp_pcbdisc)(so->so_pcb);
537 error = EISCONN;
538 }
539 IFPERF(tpcb)
540 u_int lsufx, fsufx;
541 lsufx = *(u_int *)(tpcb->tp_lsuffix);
542 fsufx = *(u_int *)(tpcb->tp_fsuffix);
543
544 tpmeas( tpcb->tp_lref,
545 TPtime_open | (tpcb->tp_xtd_format <<4 ),
546 &time, lsufx, fsufx, tpcb->tp_fref);
547 ENDPERF
548 break;
549
550 case PRU_ACCEPT:
551 /* all this garbage is to keep accept from returning
552 * before the 3-way handshake is done in class 4.
553 * it'll have to be modified for other classes
554 */
555 IFDEBUG(D_REQUEST)
556 printf("PRU_ACCEPT so_error 0x%x\n", so->so_error);
557 ENDDEBUG
558 so->so_error = 0;
559 if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTED)== 0) {
560 error = EWOULDBLOCK;
561 break;
562 }
563 while ((so->so_state & SS_ISCONNECTED) == 0 && so->so_error == 0) {
564 sleep((caddr_t)&so->so_timeo, PZERO+1);
565 }
566 if (so->so_error) {
567 error = so->so_error;
568 } else {
569 struct sockaddr *sa = mtod(nam, struct sockaddr *);
570
571 nam->m_len = sizeof (struct sockaddr);
572 (tpcb->tp_nlproto->nlp_getnetaddr)(so->so_pcb, sa, TP_FOREIGN);
573
574 switch(sa->sa_family = sototpcb(so)->tp_domain) {
575 case AF_INET:
576 satosin(sa)->sin_port =
577 (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, TP_FOREIGN);
578 break;
579 case AF_ISO:
580 satosiso(sa)->siso_tsuffix =
581 (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, TP_FOREIGN);
582 /* doesn't cover the case where the suffix is extended -
583 * grotesque - the user *has* to do the getsockopt */
584 break;
585 }
586 IFDEBUG(D_REQUEST)
587 printf("ACCEPT PEERADDDR:");
588 dump_buf(sa, sizeof(struct sockaddr));
589 ENDDEBUG
590 }
591 IFPERF(tpcb)
592 u_int lsufx, fsufx;
593 lsufx = *(u_int *)(tpcb->tp_lsuffix);
594 fsufx = *(u_int *)(tpcb->tp_fsuffix);
595
596 tpmeas( tpcb->tp_lref, TPtime_open,
597 &time, lsufx, fsufx, tpcb->tp_fref);
598 ENDPERF
599 break;
600
601 case PRU_RCVD:
602 IFTRACE(D_DATA)
603 tptraceTPCB(TPPTmisc,
604 "RCVD BF: lcredit sent_lcdt cc hiwat \n",
605 tpcb->tp_lcredit, tpcb->tp_sent_lcdt,
606 so->so_rcv.sb_cc, so->so_rcv.sb_hiwat);
607 LOCAL_CREDIT(tpcb);
608 tptraceTPCB(TPPTmisc,
609 "PRU_RCVD AF sbspace lcredit hiwat cc",
610 sbspace(&so->so_rcv), tpcb->tp_lcredit,
611 so->so_rcv.sb_cc, so->so_rcv.sb_hiwat);
612 ENDTRACE
613 error = DoEvent(T_USR_rcvd);
614 break;
615
616 case PRU_RCVOOB:
617 if ((so->so_state & SS_ISCONNECTED) == 0) {
618 error = ENOTCONN;
619 break;
620 }
621 if( ! tpcb->tp_xpd_service ) {
622 error = EOPNOTSUPP;
623 break;
624 }
625 /* kludge - nam is really flags here */
626 error = tp_rcvoob(tpcb, so, m, outflags, (int)nam);
627 break;
628
629 case PRU_SENDOOB:
630 if ((so->so_state & SS_ISCONNECTED) == 0) {
631 error = ENOTCONN;
632 break;
633 }
634 if( ! tpcb->tp_xpd_service ) {
635 error = EOPNOTSUPP;
636 break;
637 }
638 error = tp_sendoob(tpcb, so, m, outflags);
639 break;
640
641 case PRU_SENDEOT:
642 eotsdu = 1;
643 /* fall through */
644 case PRU_SEND:
645 /*
646 * The protocol machine copies mbuf chains,
647 * prepends headers, assigns seq numbers, and
648 * puts the packets on the device.
649 * When they are acked they are removed from the socket buf.
650 *
651 * sosend calls this up until sbspace goes negative.
652 * Sbspace may be made negative by appending this mbuf chain,
653 * possibly by a whole cluster.
654 */
655 if ((so->so_state & SS_ISCONNECTED) == 0) {
656 error = ENOTCONN;
657 break;
658 }
659 {
660 register struct mbuf *n;
661 register int len=0;
662 register struct sockbuf *sb = &so->so_snd;
663
664 n = m;
665 while (n) { /* Could have eotsdu and no data.(presently MUST have
666 * an mbuf though, even if its length == 0)
667 */
668 len += n->m_len;
669 if( n->m_next == MNULL && eotsdu ) {
670 CHANGE_MTYPE(n, TPMT_EOT);
671 }
672 n = n->m_next;
673 }
674 IFPERF(tpcb)
675 PStat(tpcb, Nb_from_sess) += len;
676 tpmeas(tpcb->tp_lref, TPtime_from_session, 0, 0,
677 PStat(tpcb, Nb_from_sess), len);
678 ENDPERF
679 IFDEBUG(D_SYSCALL)
680 printf(
681 "PRU_SEND: eot %d before sbappend 0x%x len 0x%x to sb @ 0x%x\n",
682 eotsdu, m,len, &sb->sb_mb);
683 dump_mbuf(sb->sb_mb, "so_snd.sb_mb");
684 dump_mbuf(m, "m : to be added");
685 ENDDEBUG
686 /* The last mbuf has type TPMT_EOT so it will never be compressed
687 * with TPMT_DATA mbufs, but if this was an EOTSDU request w/o
688 * any data, the only way to keep this mbuf from being thrown
689 * away is to link it through the m_act field
690 * We are ASSUMING that if there are any data at all with this
691 * request, the last mbuf will be non-empty!!!
692 */
693 if( m->m_type == TPMT_EOT ) /* first mbuf in chain is EOT? */
694 sbappendrecord(sb, m); /* to keep 2 TPMT_EOTs from being
695 compressed */
696 else
697 sbappend(sb, m);
698 IFDEBUG(D_SYSCALL)
699 printf("PRU_SEND: eot %d after sbappend 0x%x len 0x%x\n",
700 eotsdu, m,len);
701 dump_mbuf(sb->sb_mb, "so_snd.sb_mb");
702 ENDDEBUG
703 u.u_r.r_val1 += len;
704 error = DoEvent(T_DATA_req);
705 IFDEBUG(D_SYSCALL)
706 printf("PRU_SEND: after driver error 0x%x \n",error);
707 ENDDEBUG
708 }
709 break;
710
711 case PRU_SOCKADDR: {
712 struct sockaddr *sa = mtod(nam, struct sockaddr *);
713
714 nam->m_len = sizeof (struct sockaddr);
715 (tpcb->tp_nlproto->nlp_getnetaddr)(so->so_pcb, sa, TP_LOCAL);
716 switch ( sa->sa_family = sototpcb(so)->tp_domain ) {
717 case AF_INET:
718 satosin(sa)->sin_port =
719 (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, TP_LOCAL);
720 break;
721 case AF_ISO:
722 satosiso(sa)->siso_tsuffix =
723 (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, TP_LOCAL);
724 break;
725 }
726 }
727 break;
728
729 case PRU_PEERADDR:
730 if( (so->so_state & SS_ISCONNECTED) &&
731 (so->so_state & SS_ISDISCONNECTING) == 0) {
732 struct sockaddr *sa = mtod(nam, struct sockaddr *);
733
734 nam->m_len = sizeof (struct sockaddr);
735
736 (tpcb->tp_nlproto->nlp_getnetaddr)(so->so_pcb, sa, TP_FOREIGN);
737
738 switch ( sa->sa_family = sototpcb(so)->tp_domain ) {
739 case AF_INET:
740 satosin(sa)->sin_port =
741 (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, TP_FOREIGN);
742 break;
743 case AF_ISO:
744 satosiso(sa)->siso_tsuffix =
745 (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, TP_FOREIGN);
746 break;
747 }
748 IFDEBUG(D_REQUEST)
749 printf("PEERADDDR:");
750 dump_buf(sa, sizeof(struct sockaddr));
751 ENDDEBUG
752 } else
753 error = ENOTCONN;
754 break;
755
756 case PRU_CONTROL:
757 error = EOPNOTSUPP;
758 break;
759
760 case PRU_PROTOSEND:
761 case PRU_PROTORCV:
762 case PRU_SENSE:
763 case PRU_SLOWTIMO:
764 case PRU_FASTTIMO:
765 error = EOPNOTSUPP;
766 break;
767
768 default:
769#ifdef ARGO_DEBUG
770 printf("tp_usrreq UNKNOWN PRU %d\n", req);
771#endif ARGO_DEBUG
772 error = EOPNOTSUPP;
773 }
774
775 IFDEBUG(D_REQUEST)
776 printf("returning from tp_usrreq(so 0x%x) error 0x%x\n", so, error);
777 ENDDEBUG
778 IFTRACE(D_REQUEST)
779 tptraceTPCB(TPPTusrreq, "END req so m state [", req, so, m,
780 tpcb?0:tpcb->tp_state);
781 ENDTRACE
782 splx(s);
783 return error;
784}