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