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