silly window fix causes panics; fix ``fix''
[unix-history] / usr / src / sys / netiso / tp_usrreq.c
CommitLineData
4a61b6ff 1/***********************************************************
7b25382f 2 Copyright IBM Corporation 1987
4a61b6ff
KS
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 $
03733bb1 32 * @(#)tp_usrreq.c 7.6 (Berkeley) %G%
4a61b6ff
KS
33 *
34 * tp_usrreq(), the fellow that gets called from most of the socket code.
35 * Pretty straighforward.
36 * THe only really awful stuff here is the OOB processing, which is done
37 * wholly here.
38 * tp_rcvoob() and tp_sendoob() are contained here and called by tp_usrreq().
39 */
40
41#ifndef lint
42static char *rcsid = "$Header: tp_usrreq.c,v 5.4 88/11/18 17:29:18 nhall Exp $";
43#endif lint
44
45#include "param.h"
46#include "systm.h"
4a61b6ff
KS
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
a50e2bc0
KS
55#include "tp_param.h"
56#include "tp_timer.h"
57#include "tp_stat.h"
58#include "tp_seq.h"
59#include "tp_ip.h"
60#include "tp_pcb.h"
61#include "argo_debug.h"
62#include "tp_trace.h"
63#include "tp_meas.h"
64#include "iso.h"
65#include "iso_errno.h"
4a61b6ff
KS
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) {
a50e2bc0
KS
94 printf("%x : Len %x Data %x A %x Nx %x Tp %x\n",
95 n, n->m_len, n->m_data, n->m_act, n->m_next, n->m_type);
4a61b6ff
KS
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 */
4a61b6ff
KS
138tp_rcvoob(tpcb, so, m, outflags, inflags)
139 struct tp_pcb *tpcb;
140 register struct socket *so;
141 register struct mbuf *m;
142 int *outflags;
143 int inflags;
144{
145 register struct mbuf *n;
a50e2bc0 146 register struct sockbuf *sb = &so->so_rcv;
4a61b6ff
KS
147 struct tp_event E;
148 int error = 0;
a50e2bc0 149 register struct mbuf **nn;
4a61b6ff
KS
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:
4a61b6ff
KS
160 if ((((so->so_state & SS_ISCONNECTED) == 0)
161 || (so->so_state & SS_ISDISCONNECTING) != 0) &&
162 (so->so_proto->pr_flags & PR_CONNREQUIRED)) {
163 return ENOTCONN;
164 }
165
a50e2bc0
KS
166 /* Take the first mbuf off the chain.
167 * Each XPD TPDU gives you a complete TSDU so the chains don't get
168 * coalesced, but one TSDU may span several mbufs.
169 * Nevertheless, since n should have a most 16 bytes, it
170 * will fit into m. (size was checked in tp_input() )
171 */
172
173 /*
174 * Code for excision of OOB data should be added to
175 * uipc_socket2.c (like sbappend).
176 */
177
44f52ea5 178 sblock(sb);
a50e2bc0
KS
179 for (nn = &sb->sb_mb; n = *nn; nn = &n->m_act)
180 if (n->m_type == MT_OOBDATA)
181 break;
182
183 if (n == 0) {
4a61b6ff
KS
184 ASSERT( (tpcb->tp_flags & TPF_DISC_DATA_IN) == 0 );
185 IFDEBUG(D_XPD)
186 printf("RCVOOB: empty queue!\n");
187 ENDDEBUG
44f52ea5 188 sbunlock(sb);
4a61b6ff
KS
189 if (so->so_state & SS_NBIO) {
190 return EWOULDBLOCK;
191 }
4a61b6ff
KS
192 sbwait(sb);
193 goto restart;
194 }
4a61b6ff
KS
195 m->m_len = 0;
196
197 /* Assuming at most one xpd tpdu is in the buffer at once */
198 while ( n != MNULL ) {
199 m->m_len += n->m_len;
a50e2bc0
KS
200 bcopy(mtod(n, caddr_t), mtod(m, caddr_t), (unsigned)n->m_len);
201 m->m_data += n->m_len; /* so mtod() in bcopy() above gives right addr */
4a61b6ff
KS
202 n = n->m_next;
203 }
a50e2bc0
KS
204 m->m_data = m->m_dat;
205 m->m_flags |= M_EOR;
4a61b6ff
KS
206
207 IFDEBUG(D_XPD)
208 printf("tp_rcvoob: xpdlen 0x%x\n", m->m_len);
209 dump_mbuf(so->so_rcv.sb_mb, "RCVOOB: Rcv socketbuf");
210 dump_mbuf(sb->sb_mb, "RCVOOB: Xrcv socketbuf");
211 ENDDEBUG
212
a50e2bc0
KS
213 if( (inflags & MSG_PEEK) == 0 ) {
214 n = *nn;
215 *nn = n->m_act;
216 sb->sb_cc -= m->m_len;
217 }
4a61b6ff
KS
218
219release:
220 sbunlock(sb);
221
222 IFTRACE(D_XPD)
223 tptraceTPCB(TPPTmisc, "PRU_RCVOOB @ release sb_cc m_len",
224 tpcb->tp_Xrcv.sb_cc, m->m_len,0,0 );
225 ENDTRACE
4a61b6ff
KS
226 if (error == 0)
227 error = DoEvent(T_USR_Xrcvd);
228 return error;
229}
230
231/*
232 * CALLED FROM:
233 * tp_usrreq(), PRU_SENDOOB
234 * FUNCTION and ARGUMENTS:
235 * Send what's in the mbuf chain (m) as an XPD TPDU.
236 * The mbuf may not contain more then 16 bytes of data.
237 * XPD TSDUs aren't segmented, so they translate into
238 * exactly one XPD TPDU, with EOT bit set.
239 * RETURN VALUE:
240 * EWOULDBLOCK if socket is in non-blocking mode and the previous
241 * xpd data haven't been acked yet.
242 * EMSGSIZE if trying to send > max-xpd bytes (16)
243 * ENOBUFS if ran out of mbufs
244 */
4a61b6ff
KS
245tp_sendoob(tpcb, so, xdata, outflags)
246 struct tp_pcb *tpcb;
247 register struct socket *so;
248 register struct mbuf *xdata;
249 int *outflags; /* not used */
250{
251 /*
252 * Each mbuf chain represents a sequence # in the XPD seq space.
253 * The first one in the queue has sequence # tp_Xuna.
254 * When we add to the XPD queue, we stuff a zero-length
255 * mbuf (mark) into the DATA queue, with its sequence number in m_next
256 * to be assigned to this XPD tpdu, so data xfer can stop
257 * when it reaches the zero-length mbuf if this XPD TPDU hasn't
258 * yet been acknowledged.
259 */
260 register struct sockbuf *sb = &(tpcb->tp_Xsnd);
261 register struct mbuf *xmark;
262 register int len=0;
263 struct tp_event E;
264
265 IFDEBUG(D_XPD)
266 printf("tp_sendoob:");
267 if(xdata)
268 printf("xdata len 0x%x\n", xdata->m_len);
269 ENDDEBUG
4a61b6ff
KS
270 /* DO NOT LOCK the Xsnd buffer!!!! You can have at MOST one
271 * socket buf locked at any time!!! (otherwise you might
272 * sleep() in sblock() w/ a signal pending and cause the
273 * system call to be aborted w/ a locked socketbuf, which
274 * is a problem. So the so_snd buffer lock
275 * (done in sosend()) serves as the lock for Xpd.
276 */
44f52ea5 277 if (sb->sb_mb) { /* Anything already in eXpedited data sockbuf? */
4a61b6ff
KS
278 if (so->so_state & SS_NBIO) {
279 return EWOULDBLOCK;
280 }
44f52ea5
KS
281 while (sb->sb_mb) {
282 sbunlock(&so->so_snd); /* already locked by sosend */
283 sbwait(&so->so_snd);
284 sblock(&so->so_snd); /* sosend will unlock on return */
285 }
4a61b6ff
KS
286 }
287
288 if (xdata == (struct mbuf *)0) {
289 /* empty xpd packet */
a50e2bc0 290 MGETHDR(xdata, M_WAIT, MT_OOBDATA);
4a61b6ff
KS
291 if (xdata == NULL) {
292 return ENOBUFS;
293 }
294 xdata->m_len = 0;
a50e2bc0 295 xdata->m_pkthdr.len = 0;
4a61b6ff
KS
296 }
297 IFDEBUG(D_XPD)
298 printf("tp_sendoob 1:");
299 if(xdata)
300 printf("xdata len 0x%x\n", xdata->m_len);
301 ENDDEBUG
302 xmark = xdata; /* temporary use of variable xmark */
303 while (xmark) {
304 len += xmark->m_len;
305 xmark = xmark->m_next;
306 }
307 if (len > TP_MAX_XPD_DATA) {
308 return EMSGSIZE;
309 }
310 IFDEBUG(D_XPD)
311 printf("tp_sendoob 2:");
312 if(xdata)
313 printf("xdata len 0x%x\n", len);
314 ENDDEBUG
315
4a61b6ff
KS
316
317 IFTRACE(D_XPD)
44f52ea5 318 tptraceTPCB(TPPTmisc, "XPD mark m_next ", xdata->m_next, 0, 0, 0);
4a61b6ff
KS
319 ENDTRACE
320
4a61b6ff
KS
321 sbappendrecord(sb, xdata);
322
323 IFDEBUG(D_XPD)
324 printf("tp_sendoob len 0x%x\n", len);
325 dump_mbuf(so->so_snd.sb_mb, "XPD request Regular sndbuf:");
326 dump_mbuf(tpcb->tp_Xsnd.sb_mb, "XPD request Xsndbuf:");
327 ENDDEBUG
4a61b6ff 328 return DoEvent(T_XPD_req);
4a61b6ff
KS
329}
330
331/*
332 * CALLED FROM:
333 * the socket routines
334 * FUNCTION and ARGUMENTS:
335 * Handles all "user requests" except the [gs]ockopts() requests.
336 * The argument (req) is the request type (PRU*),
337 * (m) is an mbuf chain, generally used for send and
338 * receive type requests only.
339 * (nam) is used for addresses usually, in particular for the bind request.
340 *
4a61b6ff
KS
341 */
342/*ARGSUSED*/
343ProtoHook
a50e2bc0 344tp_usrreq(so, req, m, nam, rightsp, controlp)
4a61b6ff
KS
345 struct socket *so;
346 u_int req;
a50e2bc0 347 struct mbuf *m, *nam, *rightsp, *controlp;
4a61b6ff
KS
348{
349 register struct tp_pcb *tpcb = sototpcb(so);
350 int s = splnet();
351 int error = 0;
a50e2bc0 352 int flags, *outflags = &flags;
4a61b6ff
KS
353 u_long eotsdu = 0;
354 struct tp_event E;
355
356 IFDEBUG(D_REQUEST)
357 printf("usrreq(0x%x,%d,0x%x,0x%x,0x%x)\n",so,req,m,nam,outflags);
358 if(so->so_error)
359 printf("WARNING!!! so->so_error is 0x%x\n", so->so_error);
360 ENDDEBUG
361 IFTRACE(D_REQUEST)
362 tptraceTPCB(TPPTusrreq, "req so m state [", req, so, m,
363 tpcb?tpcb->tp_state:0);
364 ENDTRACE
365
366 if ((u_int)tpcb == 0 && req != PRU_ATTACH) {
367 IFTRACE(D_REQUEST)
368 tptraceTPCB(TPPTusrreq, "req failed NO TPCB[", 0, 0, 0, 0);
369 ENDTRACE
370 splx(s);
371 return ENOTCONN;
372 }
373
4a61b6ff
KS
374 switch (req) {
375
376 case PRU_ATTACH:
377 if (tpcb) {
378 error = EISCONN;
379 break;
380 }
381 if( error = tp_attach(so, so->so_proto->pr_domain->dom_family ) )
382 break;
383 tpcb = sototpcb(so);
384 break;
385
386 case PRU_ABORT: /* called from close() */
387 /* called for each incoming connect queued on the
388 * parent (accepting) socket
389 */
390 if( tpcb->tp_state == TP_OPEN ) {
391 E.ATTR(T_DISC_req).e_reason = E_TP_NO_SESSION;
392 error = DoEvent(T_DISC_req); /* pretend it was a close() */
393 break;
394 } /* else DROP THROUGH */
395
396 case PRU_DETACH: /* called from close() */
397 /* called only after disconnect was called */
398 error = DoEvent(T_DETACH);
a50e2bc0
KS
399 if (tpcb->tp_state == TP_CLOSED) {
400 free((caddr_t)tpcb, M_PCB);
401 tpcb = 0;
402 }
4a61b6ff
KS
403 break;
404
405 case PRU_SHUTDOWN:
406 /* recv end may have been released; local credit might be zero */
407 case PRU_DISCONNECT:
408 E.ATTR(T_DISC_req).e_reason = E_TP_NORMAL_DISC;
409 error = DoEvent(T_DISC_req);
410 break;
411
412 case PRU_BIND:
413 error = (tpcb->tp_nlproto->nlp_pcbbind)( so->so_pcb, nam );
414 if (error == 0) {
a50e2bc0
KS
415 (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_lsuffixlen,
416 tpcb->tp_lsuffix, TP_LOCAL );
4a61b6ff
KS
417 }
418 break;
419
420 case PRU_LISTEN:
44f52ea5 421 if( tpcb->tp_lsuffixlen == 0) {
4a61b6ff
KS
422 if( error = (tpcb->tp_nlproto->nlp_pcbbind)(so->so_pcb, MNULL) )
423 break;
a50e2bc0
KS
424 (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_lsuffixlen,
425 tpcb->tp_lsuffix, TP_LOCAL );
4a61b6ff
KS
426 }
427 IFDEBUG(D_TPISO)
428 if(tpcb->tp_state != TP_CLOSED)
429 printf("LISTEN ERROR: state 0x%x\n", tpcb->tp_state);
430 ENDDEBUG
431 error = DoEvent(T_LISTEN_req);
432 break;
433
434 case PRU_CONNECT2:
435 error = EOPNOTSUPP; /* for unix domain sockets */
436 break;
437
438 case PRU_CONNECT:
439 IFTRACE(D_CONN)
440 tptraceTPCB(TPPTmisc,
a50e2bc0 441 "PRU_CONNECT: so 0x%x *SHORT_LSUFXP(tpcb) 0x%x lsuflen 0x%x, class 0x%x",
4a61b6ff
KS
442 tpcb->tp_sock, *SHORT_LSUFXP(tpcb), tpcb->tp_lsuffixlen,
443 tpcb->tp_class);
444 ENDTRACE
445 IFDEBUG(D_CONN)
446 printf("PRU_CONNECT: so *SHORT_LSUFXP(tpcb) 0x%x lsuflen 0x%x, class 0x%x",
447 tpcb->tp_sock, *SHORT_LSUFXP(tpcb), tpcb->tp_lsuffixlen,
448 tpcb->tp_class);
449 ENDDEBUG
44f52ea5 450 if( tpcb->tp_lsuffixlen == 0) {
4a61b6ff
KS
451 if( error = (tpcb->tp_nlproto->nlp_pcbbind)(so->so_pcb, MNULL) ) {
452 IFDEBUG(D_CONN)
453 printf("pcbbind returns error 0x%x\n", error );
454 ENDDEBUG
455 break;
456 }
a50e2bc0
KS
457 (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_lsuffixlen,
458 tpcb->tp_lsuffix, TP_LOCAL );
459 }
4a61b6ff
KS
460
461 IFDEBUG(D_CONN)
462 printf("isop 0x%x isop->isop_socket offset 12 :\n", tpcb->tp_npcb);
463 dump_buf( tpcb->tp_npcb, 16);
464 ENDDEBUG
465 if( error = tp_route_to( nam, tpcb, /* channel */0) )
466 break;
467 IFDEBUG(D_CONN)
468 printf(
469 "PRU_CONNECT after tpcb 0x%x so 0x%x npcb 0x%x flags 0x%x\n",
470 tpcb, so, tpcb->tp_npcb, tpcb->tp_flags);
471 printf("isop 0x%x isop->isop_socket offset 12 :\n", tpcb->tp_npcb);
472 dump_buf( tpcb->tp_npcb, 16);
473 ENDDEBUG
a50e2bc0 474 if( tpcb->tp_fsuffixlen == 0) {
4a61b6ff 475 /* didn't set peer extended suffix */
a50e2bc0
KS
476 (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_fsuffixlen,
477 tpcb->tp_fsuffix, TP_FOREIGN );
4a61b6ff
KS
478 }
479 (void) (tpcb->tp_nlproto->nlp_mtu)(so, so->so_pcb,
480 &tpcb->tp_l_tpdusize, &tpcb->tp_tpdusize, 0);
481 if( tpcb->tp_state == TP_CLOSED) {
482 soisconnecting(so);
483 error = DoEvent(T_CONN_req);
484 } else {
485 (tpcb->tp_nlproto->nlp_pcbdisc)(so->so_pcb);
486 error = EISCONN;
487 }
488 IFPERF(tpcb)
489 u_int lsufx, fsufx;
7b25382f
KS
490 lsufx = *(u_short *)(tpcb->tp_lsuffix);
491 fsufx = *(u_short *)(tpcb->tp_fsuffix);
4a61b6ff
KS
492
493 tpmeas( tpcb->tp_lref,
494 TPtime_open | (tpcb->tp_xtd_format <<4 ),
495 &time, lsufx, fsufx, tpcb->tp_fref);
496 ENDPERF
497 break;
498
499 case PRU_ACCEPT:
44f52ea5 500 (tpcb->tp_nlproto->nlp_getnetaddr)(so->so_pcb, nam, TP_FOREIGN);
4a61b6ff 501 IFDEBUG(D_REQUEST)
44f52ea5
KS
502 printf("ACCEPT PEERADDDR:");
503 dump_buf(mtod(nam, char *), nam->m_len);
4a61b6ff 504 ENDDEBUG
4a61b6ff
KS
505 IFPERF(tpcb)
506 u_int lsufx, fsufx;
7b25382f
KS
507 lsufx = *(u_short *)(tpcb->tp_lsuffix);
508 fsufx = *(u_short *)(tpcb->tp_fsuffix);
4a61b6ff
KS
509
510 tpmeas( tpcb->tp_lref, TPtime_open,
511 &time, lsufx, fsufx, tpcb->tp_fref);
512 ENDPERF
513 break;
514
515 case PRU_RCVD:
44f52ea5
KS
516 if (so->so_state & SS_ISCONFIRMING) {
517 if (tpcb->tp_state == TP_CONFIRMING)
518 error = tp_confirm(tpcb);
519 break;
520 }
4a61b6ff
KS
521 IFTRACE(D_DATA)
522 tptraceTPCB(TPPTmisc,
523 "RCVD BF: lcredit sent_lcdt cc hiwat \n",
524 tpcb->tp_lcredit, tpcb->tp_sent_lcdt,
525 so->so_rcv.sb_cc, so->so_rcv.sb_hiwat);
526 LOCAL_CREDIT(tpcb);
527 tptraceTPCB(TPPTmisc,
528 "PRU_RCVD AF sbspace lcredit hiwat cc",
529 sbspace(&so->so_rcv), tpcb->tp_lcredit,
530 so->so_rcv.sb_cc, so->so_rcv.sb_hiwat);
531 ENDTRACE
a50e2bc0
KS
532 IFDEBUG(D_REQUEST)
533 printf("RCVD: cc %d space %d hiwat %d\n",
534 so->so_rcv.sb_cc, sbspace(&so->so_rcv),
535 so->so_rcv.sb_hiwat);
536 ENDDEBUG
537 if (((int)nam) & MSG_OOB)
538 error = DoEvent(T_USR_Xrcvd);
539 else
540 error = DoEvent(T_USR_rcvd);
4a61b6ff
KS
541 break;
542
543 case PRU_RCVOOB:
544 if ((so->so_state & SS_ISCONNECTED) == 0) {
545 error = ENOTCONN;
546 break;
547 }
548 if( ! tpcb->tp_xpd_service ) {
549 error = EOPNOTSUPP;
550 break;
551 }
552 /* kludge - nam is really flags here */
553 error = tp_rcvoob(tpcb, so, m, outflags, (int)nam);
554 break;
555
44f52ea5 556 case PRU_SEND:
4a61b6ff 557 case PRU_SENDOOB:
a50e2bc0 558 if (controlp && (error = tp_snd_control(controlp, so, &m)))
4a61b6ff 559 break;
44f52ea5
KS
560 if (so->so_state & SS_ISCONFIRMING) {
561 if (tpcb->tp_state == TP_CONFIRMING)
562 error = tp_confirm(tpcb);
563 if (m) {
564 if (error == 0 && m->m_len != 0)
565 error = ENOTCONN;
566 m_freem(m);
567 m = 0;
568 }
569 break;
570 }
a50e2bc0
KS
571 if (m == 0)
572 break;
44f52ea5
KS
573
574 if (req == PRU_SENDOOB) {
575 if (tpcb->tp_xpd_service == 0) {
576 error = EOPNOTSUPP;
577 break;
578 }
579 error = tp_sendoob(tpcb, so, m, outflags);
4a61b6ff
KS
580 break;
581 }
4a61b6ff
KS
582 /*
583 * The protocol machine copies mbuf chains,
584 * prepends headers, assigns seq numbers, and
585 * puts the packets on the device.
586 * When they are acked they are removed from the socket buf.
587 *
588 * sosend calls this up until sbspace goes negative.
589 * Sbspace may be made negative by appending this mbuf chain,
590 * possibly by a whole cluster.
591 */
4a61b6ff 592 {
a50e2bc0 593 register struct mbuf *n = m;
4a61b6ff
KS
594 register int len=0;
595 register struct sockbuf *sb = &so->so_snd;
a50e2bc0
KS
596 int maxsize = tpcb->tp_l_tpdusize
597 - tp_headersize(DT_TPDU_type, tpcb)
598 - (tpcb->tp_use_checksum?4:0) ;
599 int totlen = n->m_pkthdr.len;
7b25382f 600 struct mbuf *nn;
a50e2bc0
KS
601
602 /*
603 * Could have eotsdu and no data.(presently MUST have
604 * an mbuf though, even if its length == 0)
605 */
44f52ea5 606 if (n->m_flags & M_EOR) {
a50e2bc0 607 eotsdu = 1;
44f52ea5
KS
608 n->m_flags &= ~M_EOR;
609 }
4a61b6ff 610 IFPERF(tpcb)
a50e2bc0 611 PStat(tpcb, Nb_from_sess) += totlen;
4a61b6ff 612 tpmeas(tpcb->tp_lref, TPtime_from_session, 0, 0,
a50e2bc0 613 PStat(tpcb, Nb_from_sess), totlen);
4a61b6ff
KS
614 ENDPERF
615 IFDEBUG(D_SYSCALL)
616 printf(
617 "PRU_SEND: eot %d before sbappend 0x%x len 0x%x to sb @ 0x%x\n",
a50e2bc0 618 eotsdu, m,len, sb);
4a61b6ff
KS
619 dump_mbuf(sb->sb_mb, "so_snd.sb_mb");
620 dump_mbuf(m, "m : to be added");
621 ENDDEBUG
a50e2bc0
KS
622 /*
623 * Pre-packetize the data in the sockbuf
624 * according to negotiated mtu. Do it here
625 * where we can safely wait for mbufs.
7b25382f
KS
626 *
627 * This presumes knowledge of sockbuf conventions.
4a61b6ff 628 */
7b25382f
KS
629 len = 0;
630 if (n = sb->sb_mb)
631 while (n->m_act)
632 n = n->m_act;
03733bb1 633 if ((nn = n) && n->m_pkthdr.len < maxsize) {
7b25382f 634 int space = maxsize - n->m_pkthdr.len;
03733bb1
KS
635
636 do {
637 if (n->m_flags & M_EOR)
638 goto on1;
639 } while (n->m_next && (n = n->m_next));
640 nn->m_pkthdr.len += space;
7b25382f
KS
641 if (m->m_pkthdr.len <= space) {
642 n->m_next = m;
03733bb1 643 sballoc(sb, m);
7b25382f
KS
644 if (eotsdu)
645 nn->m_flags |= M_EOR;
646 goto on2;
647 } else {
03733bb1
KS
648 nn->m_next = m_copym(m, 0, space, M_WAIT);
649 sballoc(sb, nn->m_next);
650 m_adj(m, space);
7b25382f
KS
651 }
652 }
653 on1: len++;
654 for (n = m; n->m_pkthdr.len > maxsize;) {
655 nn = m_copym(n, 0, len, M_WAIT);
a50e2bc0
KS
656 sbappendrecord(sb, nn);
657 m_adj(n, maxsize);
7b25382f 658 len++;
a50e2bc0 659 }
7b25382f 660 if (eotsdu)
44f52ea5 661 n->m_flags |= M_EOR;
7b25382f
KS
662 sbappendrecord(sb, n);
663 on2:
664 IFTRACE(D_DATA)
665 tptraceTPCB(TPPTmisc,
666 "SEND BF: maxsize totlen frags eotsdu",
667 maxsize, totlen, len, eotsdu);
668 ENDTRACE
4a61b6ff
KS
669 IFDEBUG(D_SYSCALL)
670 printf("PRU_SEND: eot %d after sbappend 0x%x len 0x%x\n",
a50e2bc0 671 eotsdu, n, len);
4a61b6ff
KS
672 dump_mbuf(sb->sb_mb, "so_snd.sb_mb");
673 ENDDEBUG
4a61b6ff
KS
674 error = DoEvent(T_DATA_req);
675 IFDEBUG(D_SYSCALL)
676 printf("PRU_SEND: after driver error 0x%x \n",error);
a50e2bc0
KS
677 printf("so_snd 0x%x cc 0t%d mbcnt 0t%d\n",
678 sb, sb->sb_cc, sb->sb_mbcnt);
679 dump_mbuf(sb->sb_mb, "so_snd.sb_mb after driver");
4a61b6ff
KS
680 ENDDEBUG
681 }
682 break;
683
a50e2bc0
KS
684 case PRU_SOCKADDR:
685 (tpcb->tp_nlproto->nlp_getnetaddr)(so->so_pcb, nam, TP_LOCAL);
4a61b6ff
KS
686 break;
687
688 case PRU_PEERADDR:
44f52ea5 689 (tpcb->tp_nlproto->nlp_getnetaddr)(so->so_pcb, nam, TP_FOREIGN);
4a61b6ff
KS
690 break;
691
692 case PRU_CONTROL:
693 error = EOPNOTSUPP;
694 break;
695
696 case PRU_PROTOSEND:
697 case PRU_PROTORCV:
698 case PRU_SENSE:
699 case PRU_SLOWTIMO:
700 case PRU_FASTTIMO:
701 error = EOPNOTSUPP;
702 break;
703
704 default:
705#ifdef ARGO_DEBUG
706 printf("tp_usrreq UNKNOWN PRU %d\n", req);
707#endif ARGO_DEBUG
708 error = EOPNOTSUPP;
709 }
710
711 IFDEBUG(D_REQUEST)
44f52ea5
KS
712 printf("%s, so 0x%x, tpcb 0x%x, error %d, state %d\n",
713 "returning from tp_usrreq", so, tpcb, error,
714 tpcb ? 0 : tpcb->tp_state);
4a61b6ff
KS
715 ENDDEBUG
716 IFTRACE(D_REQUEST)
717 tptraceTPCB(TPPTusrreq, "END req so m state [", req, so, m,
718 tpcb?0:tpcb->tp_state);
719 ENDTRACE
720 splx(s);
721 return error;
722}
7b25382f
KS
723tp_ltrace(so, uio)
724struct socket *so;
725struct uio *uio;
726{
727 IFTRACE(D_DATA)
728 register struct tp_pcb *tpcb = sototpcb(so);
729 if (tpcb) {
730 tptraceTPCB(TPPTmisc, "sosend so resid iovcnt", so,
731 uio->uio_resid, uio->uio_iovcnt, 0);
732 }
733 ENDTRACE
734}
a50e2bc0 735
44f52ea5
KS
736tp_confirm(tpcb)
737register struct tp_pcb *tpcb;
a50e2bc0 738{
44f52ea5
KS
739 struct tp_event E;
740 if (tpcb->tp_state == TP_CONFIRMING)
741 return DoEvent(T_ACPT_req);
742 printf("Tp confirm called when not confirming; tpcb 0x%x, state 0x%x\n",
743 tpcb, tpcb->tp_state);
744 return 0;
a50e2bc0
KS
745}
746
747/*
748 * Process control data sent with sendmsg()
749 */
750tp_snd_control(m0, so, data)
751 register struct mbuf *m0;
752 struct socket *so;
753 register struct mbuf **data;
754{
755 register struct tp_control_hdr *ch;
756 struct mbuf *m;
757 int error = 0;
758
759 if (m0 && m0->m_len) {
760 ch = mtod(m0, struct tp_control_hdr *);
761 m0->m_len -= sizeof (*ch);
762 m0->m_data += sizeof (*ch);
763 m = m_copym(m0, 0, M_COPYALL, M_WAIT);
764 error = tp_ctloutput(PRCO_SETOPT,
765 so, ch->cmsg_level, ch->cmsg_type, &m);
766 if (m)
767 m_freem(m);
768 if (ch->cmsg_type == TPOPT_DISC_DATA) {
769 if (data && *data) {
770 m_freem(*data);
771 *data = 0;
772 }
773 m0 = 0;
774 error = tp_usrreq(so, PRU_DISCONNECT, m0, (caddr_t)0, m0, m0);
775 }
776 }
777 return error;
778}