added my responsibility for the `cpm' port
[unix-history] / sys / netiso / tp_usrreq.c
CommitLineData
15637ed4
RG
1/*-
2 * Copyright (c) 1991 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
43371f85 33 * from: @(#)tp_usrreq.c 7.17 (Berkeley) 6/27/91
fde1aeb2 34 * $Id: tp_usrreq.c,v 1.3 1993/11/25 01:36:15 wollman Exp $
15637ed4
RG
35 */
36
37/***********************************************************
38 Copyright IBM Corporation 1987
39
40 All Rights Reserved
41
42Permission to use, copy, modify, and distribute this software and its
43documentation for any purpose and without fee is hereby granted,
44provided that the above copyright notice appear in all copies and that
45both that copyright notice and this permission notice appear in
46supporting documentation, and that the name of IBM not be
47used in advertising or publicity pertaining to distribution of the
48software without specific, written prior permission.
49
50IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
51ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
52IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
53ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
54WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
55ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
56SOFTWARE.
57
58******************************************************************/
59
60/*
61 * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
62 */
43371f85 63
15637ed4
RG
64/*
65 * ARGO TP
66 *
15637ed4
RG
67 * tp_usrreq(), the fellow that gets called from most of the socket code.
68 * Pretty straighforward.
69 * THe only really awful stuff here is the OOB processing, which is done
70 * wholly here.
71 * tp_rcvoob() and tp_sendoob() are contained here and called by tp_usrreq().
72 */
73
74#include "param.h"
75#include "systm.h"
76#include "mbuf.h"
77#include "socket.h"
78#include "socketvar.h"
79#include "domain.h"
80#include "protosw.h"
81#include "errno.h"
82#include "time.h"
83
84#include "tp_param.h"
85#include "tp_timer.h"
86#include "tp_stat.h"
87#include "tp_seq.h"
88#include "tp_ip.h"
89#include "tp_pcb.h"
90#include "argo_debug.h"
91#include "tp_trace.h"
92#include "tp_meas.h"
93#include "iso.h"
94#include "iso_errno.h"
95
fde1aeb2
GW
96int tp_confirm(struct tp_pcb *);
97
15637ed4
RG
98int tp_attach(), tp_driver();
99int TNew;
100int TPNagle1, TPNagle2;
101struct tp_pcb *tp_listeners, *tp_intercepts;
102
103#ifdef ARGO_DEBUG
104/*
105 * CALLED FROM:
106 * anywhere you want to debug...
107 * FUNCTION and ARGUMENTS:
108 * print (str) followed by the control info in the mbufs of an mbuf chain (n)
109 */
110void
111dump_mbuf(n, str)
112 struct mbuf *n;
113 char *str;
114{
115 struct mbuf *nextrecord;
116
117 printf("dump %s\n", str);
118
119 if (n == MNULL) {
120 printf("EMPTY:\n");
121 return;
122 }
123
124 while (n) {
125 nextrecord = n->m_act;
126 printf("RECORD:\n");
127 while (n) {
128 printf("%x : Len %x Data %x A %x Nx %x Tp %x\n",
129 n, n->m_len, n->m_data, n->m_act, n->m_next, n->m_type);
130#ifdef notdef
131 {
132 register char *p = mtod(n, char *);
133 register int i;
134
135 printf("data: ");
136 for (i = 0; i < n->m_len; i++) {
137 if (i%8 == 0)
138 printf("\n");
139 printf("0x%x ", *(p+i));
140 }
141 printf("\n");
142 }
143#endif notdef
144 if (n->m_next == n) {
145 printf("LOOP!\n");
146 return;
147 }
148 n = n->m_next;
149 }
150 n = nextrecord;
151 }
152 printf("\n");
153}
154
155#endif ARGO_DEBUG
156
157/*
158 * CALLED FROM:
159 * tp_usrreq(), PRU_RCVOOB
160 * FUNCTION and ARGUMENTS:
161 * Copy data from the expedited data socket buffer into
162 * the pre-allocated mbuf m.
163 * There is an isomorphism between XPD TPDUs and expedited data TSDUs.
164 * XPD tpdus are limited to 16 bytes of data so they fit in one mbuf.
165 * RETURN VALUE:
166 * EINVAL if debugging is on and a disaster has occurred
167 * ENOTCONN if the socket isn't connected
168 * EWOULDBLOCK if the socket is in non-blocking mode and there's no
169 * xpd data in the buffer
170 * E* whatever is returned from the fsm.
171 */
4c45483e 172int
15637ed4
RG
173tp_rcvoob(tpcb, so, m, outflags, inflags)
174 struct tp_pcb *tpcb;
175 register struct socket *so;
176 register struct mbuf *m;
177 int *outflags;
178 int inflags;
179{
180 register struct mbuf *n;
181 register struct sockbuf *sb = &so->so_rcv;
182 struct tp_event E;
183 int error = 0;
184 register struct mbuf **nn;
185
186 IFDEBUG(D_XPD)
187 printf("PRU_RCVOOB, sostate 0x%x\n", so->so_state);
188 ENDDEBUG
189
190 /* if you use soreceive */
191 if (m == MNULL)
192 return ENOBUFS;
193
194restart:
195 if ((((so->so_state & SS_ISCONNECTED) == 0)
196 || (so->so_state & SS_ISDISCONNECTING) != 0) &&
197 (so->so_proto->pr_flags & PR_CONNREQUIRED)) {
198 return ENOTCONN;
199 }
200
201 /* Take the first mbuf off the chain.
202 * Each XPD TPDU gives you a complete TSDU so the chains don't get
203 * coalesced, but one TSDU may span several mbufs.
204 * Nevertheless, since n should have a most 16 bytes, it
205 * will fit into m. (size was checked in tp_input() )
206 */
207
208 /*
209 * Code for excision of OOB data should be added to
210 * uipc_socket2.c (like sbappend).
211 */
212
213 sblock(sb);
214 for (nn = &sb->sb_mb; n = *nn; nn = &n->m_act)
215 if (n->m_type == MT_OOBDATA)
216 break;
217
218 if (n == 0) {
219 IFDEBUG(D_XPD)
220 printf("RCVOOB: empty queue!\n");
221 ENDDEBUG
222 sbunlock(sb);
223 if (so->so_state & SS_NBIO) {
224 return EWOULDBLOCK;
225 }
226 sbwait(sb);
227 goto restart;
228 }
229 m->m_len = 0;
230
231 /* Assuming at most one xpd tpdu is in the buffer at once */
232 while (n != MNULL) {
233 m->m_len += n->m_len;
234 bcopy(mtod(n, caddr_t), mtod(m, caddr_t), (unsigned)n->m_len);
235 m->m_data += n->m_len; /* so mtod() in bcopy() above gives right addr */
236 n = n->m_next;
237 }
238 m->m_data = m->m_dat;
239 m->m_flags |= M_EOR;
240
241 IFDEBUG(D_XPD)
242 printf("tp_rcvoob: xpdlen 0x%x\n", m->m_len);
243 dump_mbuf(so->so_rcv.sb_mb, "RCVOOB: Rcv socketbuf");
244 dump_mbuf(sb->sb_mb, "RCVOOB: Xrcv socketbuf");
245 ENDDEBUG
246
247 if ((inflags & MSG_PEEK) == 0) {
248 n = *nn;
249 *nn = n->m_act;
250 sb->sb_cc -= m->m_len;
251 }
252
253release:
254 sbunlock(sb);
255
256 IFTRACE(D_XPD)
257 tptraceTPCB(TPPTmisc, "PRU_RCVOOB @ release sb_cc m_len",
258 tpcb->tp_Xrcv.sb_cc, m->m_len, 0, 0);
259 ENDTRACE
260 if (error == 0)
261 error = DoEvent(T_USR_Xrcvd);
262 return error;
263}
264
265/*
266 * CALLED FROM:
267 * tp_usrreq(), PRU_SENDOOB
268 * FUNCTION and ARGUMENTS:
269 * Send what's in the mbuf chain (m) as an XPD TPDU.
270 * The mbuf may not contain more then 16 bytes of data.
271 * XPD TSDUs aren't segmented, so they translate into
272 * exactly one XPD TPDU, with EOT bit set.
273 * RETURN VALUE:
274 * EWOULDBLOCK if socket is in non-blocking mode and the previous
275 * xpd data haven't been acked yet.
276 * EMSGSIZE if trying to send > max-xpd bytes (16)
277 * ENOBUFS if ran out of mbufs
278 */
4c45483e 279int
15637ed4
RG
280tp_sendoob(tpcb, so, xdata, outflags)
281 struct tp_pcb *tpcb;
282 register struct socket *so;
283 register struct mbuf *xdata;
284 int *outflags; /* not used */
285{
286 /*
287 * Each mbuf chain represents a sequence # in the XPD seq space.
288 * The first one in the queue has sequence # tp_Xuna.
289 * When we add to the XPD queue, we stuff a zero-length
290 * mbuf (mark) into the DATA queue, with its sequence number in m_next
291 * to be assigned to this XPD tpdu, so data xfer can stop
292 * when it reaches the zero-length mbuf if this XPD TPDU hasn't
293 * yet been acknowledged.
294 */
295 register struct sockbuf *sb = &(tpcb->tp_Xsnd);
296 register struct mbuf *xmark;
297 register int len=0;
298 struct tp_event E;
299
300 IFDEBUG(D_XPD)
301 printf("tp_sendoob:");
302 if (xdata)
303 printf("xdata len 0x%x\n", xdata->m_len);
304 ENDDEBUG
305 /* DO NOT LOCK the Xsnd buffer!!!! You can have at MOST one
306 * socket buf locked at any time!!! (otherwise you might
307 * sleep() in sblock() w/ a signal pending and cause the
308 * system call to be aborted w/ a locked socketbuf, which
309 * is a problem. So the so_snd buffer lock
310 * (done in sosend()) serves as the lock for Xpd.
311 */
312 if (sb->sb_mb) { /* Anything already in eXpedited data sockbuf? */
313 if (so->so_state & SS_NBIO) {
314 return EWOULDBLOCK;
315 }
316 while (sb->sb_mb) {
317 sbunlock(&so->so_snd); /* already locked by sosend */
318 sbwait(&so->so_snd);
319 sblock(&so->so_snd); /* sosend will unlock on return */
320 }
321 }
322
323 if (xdata == (struct mbuf *)0) {
324 /* empty xpd packet */
325 MGETHDR(xdata, M_WAIT, MT_OOBDATA);
326 if (xdata == NULL) {
327 return ENOBUFS;
328 }
329 xdata->m_len = 0;
330 xdata->m_pkthdr.len = 0;
331 }
332 IFDEBUG(D_XPD)
333 printf("tp_sendoob 1:");
334 if (xdata)
335 printf("xdata len 0x%x\n", xdata->m_len);
336 ENDDEBUG
337 xmark = xdata; /* temporary use of variable xmark */
338 while (xmark) {
339 len += xmark->m_len;
340 xmark = xmark->m_next;
341 }
342 if (len > TP_MAX_XPD_DATA) {
343 return EMSGSIZE;
344 }
345 IFDEBUG(D_XPD)
346 printf("tp_sendoob 2:");
347 if (xdata)
348 printf("xdata len 0x%x\n", len);
349 ENDDEBUG
350
351
352 IFTRACE(D_XPD)
353 tptraceTPCB(TPPTmisc, "XPD mark m_next ", xdata->m_next, 0, 0, 0);
354 ENDTRACE
355
356 sbappendrecord(sb, xdata);
357
358 IFDEBUG(D_XPD)
359 printf("tp_sendoob len 0x%x\n", len);
360 dump_mbuf(so->so_snd.sb_mb, "XPD request Regular sndbuf:");
361 dump_mbuf(tpcb->tp_Xsnd.sb_mb, "XPD request Xsndbuf:");
362 ENDDEBUG
363 return DoEvent(T_XPD_req);
364}
365
366/*
367 * CALLED FROM:
368 * the socket routines
369 * FUNCTION and ARGUMENTS:
370 * Handles all "user requests" except the [gs]ockopts() requests.
371 * The argument (req) is the request type (PRU*),
372 * (m) is an mbuf chain, generally used for send and
373 * receive type requests only.
374 * (nam) is used for addresses usually, in particular for the bind request.
375 *
376 */
377/*ARGSUSED*/
378ProtoHook
379tp_usrreq(so, req, m, nam, controlp)
380 struct socket *so;
381 u_int req;
382 struct mbuf *m, *nam, *controlp;
383{
384 register struct tp_pcb *tpcb = sototpcb(so);
385 int s = splnet();
386 int error = 0;
387 int flags, *outflags = &flags;
388 u_long eotsdu = 0;
389 struct tp_event E;
390
391 IFDEBUG(D_REQUEST)
392 printf("usrreq(0x%x,%d,0x%x,0x%x,0x%x)\n",so,req,m,nam,outflags);
393 if (so->so_error)
394 printf("WARNING!!! so->so_error is 0x%x\n", so->so_error);
395 ENDDEBUG
396 IFTRACE(D_REQUEST)
397 tptraceTPCB(TPPTusrreq, "req so m state [", req, so, m,
398 tpcb?tpcb->tp_state:0);
399 ENDTRACE
400
401 if ((u_int)tpcb == 0 && req != PRU_ATTACH) {
402 IFTRACE(D_REQUEST)
403 tptraceTPCB(TPPTusrreq, "req failed NO TPCB[", 0, 0, 0, 0);
404 ENDTRACE
405 splx(s);
406 return ENOTCONN;
407 }
408
409 switch (req) {
410
411 case PRU_ATTACH:
412 if (tpcb) {
413 error = EISCONN;
414 break;
415 }
416 if (error = tp_attach(so, so->so_proto->pr_domain->dom_family))
417 break;
418 tpcb = sototpcb(so);
419 break;
420
421 case PRU_ABORT: /* called from close() */
422 /* called for each incoming connect queued on the
423 * parent (accepting) socket
424 */
425 if (tpcb->tp_state == TP_OPEN) {
426 E.ATTR(T_DISC_req).e_reason = E_TP_NO_SESSION;
427 error = DoEvent(T_DISC_req); /* pretend it was a close() */
428 break;
429 } /* else DROP THROUGH */
430
431 case PRU_DETACH: /* called from close() */
432 /* called only after disconnect was called */
433 if (tpcb->tp_state == TP_LISTENING) {
434 register struct tp_pcb **tt;
435 for (tt = &tp_listeners; *tt; tt = &((*tt)->tp_nextlisten))
436 if (*tt == tpcb)
437 break;
438 if (*tt)
439 *tt = tpcb->tp_nextlisten;
440 else {
441 for (tt = &tp_intercepts; *tt; tt = &((*tt)->tp_nextlisten))
442 if (*tt == tpcb)
443 break;
444 if (*tt)
445 *tt = tpcb->tp_nextlisten;
446 else
447 printf("tp_usrreq - detach: should panic\n");
448 }
449 }
450 if (tpcb->tp_next)
451 remque(tpcb);
452 error = DoEvent(T_DETACH);
453 if (tpcb->tp_state == TP_CLOSED) {
454 free((caddr_t)tpcb, M_PCB);
455 tpcb = 0;
456 }
457 break;
458
459 case PRU_SHUTDOWN:
460 /* recv end may have been released; local credit might be zero */
461 case PRU_DISCONNECT:
462 E.ATTR(T_DISC_req).e_reason = E_TP_NORMAL_DISC;
463 error = DoEvent(T_DISC_req);
464 break;
465
466 case PRU_BIND:
467 error = (tpcb->tp_nlproto->nlp_pcbbind)(so->so_pcb, nam);
468 if (error == 0) {
469 (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_lsuffixlen,
470 tpcb->tp_lsuffix, TP_LOCAL);
471 }
472 break;
473
474 case PRU_LISTEN:
475 if (tpcb->tp_lsuffixlen == 0) {
476 if (error = (tpcb->tp_nlproto->nlp_pcbbind)(so->so_pcb, MNULL))
477 break;
478 (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_lsuffixlen,
479 tpcb->tp_lsuffix, TP_LOCAL);
480 }
481 if (tpcb->tp_next == 0) {
482 tpcb->tp_next = tpcb->tp_prev = tpcb;
483 tpcb->tp_nextlisten = tp_listeners;
484 tp_listeners = tpcb;
485 }
486 IFDEBUG(D_TPISO)
487 if (tpcb->tp_state != TP_CLOSED)
488 printf("LISTEN ERROR: state 0x%x\n", tpcb->tp_state);
489 ENDDEBUG
490 error = DoEvent(T_LISTEN_req);
491 break;
492
493 case PRU_CONNECT2:
494 error = EOPNOTSUPP; /* for unix domain sockets */
495 break;
496
497 case PRU_CONNECT:
498 IFTRACE(D_CONN)
499 tptraceTPCB(TPPTmisc,
500 "PRU_CONNECT: so 0x%x *SHORT_LSUFXP(tpcb) 0x%x lsuflen 0x%x, class 0x%x",
501 tpcb->tp_sock, *SHORT_LSUFXP(tpcb), tpcb->tp_lsuffixlen,
502 tpcb->tp_class);
503 ENDTRACE
504 IFDEBUG(D_CONN)
505 printf("PRU_CONNECT: so *SHORT_LSUFXP(tpcb) 0x%x lsuflen 0x%x, class 0x%x",
506 tpcb->tp_sock, *SHORT_LSUFXP(tpcb), tpcb->tp_lsuffixlen,
507 tpcb->tp_class);
508 ENDDEBUG
509 if (tpcb->tp_lsuffixlen == 0) {
510 if (error = (tpcb->tp_nlproto->nlp_pcbbind)(so->so_pcb, MNULL)) {
511 IFDEBUG(D_CONN)
512 printf("pcbbind returns error 0x%x\n", error);
513 ENDDEBUG
514 break;
515 }
516 (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_lsuffixlen,
517 tpcb->tp_lsuffix, TP_LOCAL);
518 }
519
520 IFDEBUG(D_CONN)
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 (error = tp_route_to(nam, tpcb, /* channel */0))
525 break;
526 IFDEBUG(D_CONN)
527 printf(
528 "PRU_CONNECT after tpcb 0x%x so 0x%x npcb 0x%x flags 0x%x\n",
529 tpcb, so, tpcb->tp_npcb, tpcb->tp_flags);
530 printf("isop 0x%x isop->isop_socket offset 12 :\n", tpcb->tp_npcb);
531 dump_buf(tpcb->tp_npcb, 16);
532 ENDDEBUG
533 if (tpcb->tp_fsuffixlen == 0) {
534 /* didn't set peer extended suffix */
535 (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_fsuffixlen,
536 tpcb->tp_fsuffix, TP_FOREIGN);
537 }
538 (void) (tpcb->tp_nlproto->nlp_mtu)(so, so->so_pcb,
539 &tpcb->tp_l_tpdusize, &tpcb->tp_tpdusize, 0);
540 if (tpcb->tp_state == TP_CLOSED) {
541 soisconnecting(so);
542 error = DoEvent(T_CONN_req);
543 } else {
544 (tpcb->tp_nlproto->nlp_pcbdisc)(so->so_pcb);
545 error = EISCONN;
546 }
547 IFPERF(tpcb)
548 u_int lsufx, fsufx;
549 lsufx = *(u_short *)(tpcb->tp_lsuffix);
550 fsufx = *(u_short *)(tpcb->tp_fsuffix);
551
552 tpmeas(tpcb->tp_lref,
553 TPtime_open | (tpcb->tp_xtd_format << 4),
554 &time, lsufx, fsufx, tpcb->tp_fref);
555 ENDPERF
556 break;
557
558 case PRU_ACCEPT:
559 (tpcb->tp_nlproto->nlp_getnetaddr)(so->so_pcb, nam, TP_FOREIGN);
560 IFDEBUG(D_REQUEST)
561 printf("ACCEPT PEERADDDR:");
562 dump_buf(mtod(nam, char *), nam->m_len);
563 ENDDEBUG
564 IFPERF(tpcb)
565 u_int lsufx, fsufx;
566 lsufx = *(u_short *)(tpcb->tp_lsuffix);
567 fsufx = *(u_short *)(tpcb->tp_fsuffix);
568
569 tpmeas(tpcb->tp_lref, TPtime_open,
570 &time, lsufx, fsufx, tpcb->tp_fref);
571 ENDPERF
572 break;
573
574 case PRU_RCVD:
575 if (so->so_state & SS_ISCONFIRMING) {
576 if (tpcb->tp_state == TP_CONFIRMING)
577 error = tp_confirm(tpcb);
578 break;
579 }
580 IFTRACE(D_DATA)
581 tptraceTPCB(TPPTmisc,
582 "RCVD BF: lcredit sent_lcdt cc hiwat \n",
583 tpcb->tp_lcredit, tpcb->tp_sent_lcdt,
584 so->so_rcv.sb_cc, so->so_rcv.sb_hiwat);
585 LOCAL_CREDIT(tpcb);
586 tptraceTPCB(TPPTmisc,
587 "PRU_RCVD AF sbspace lcredit hiwat cc",
588 sbspace(&so->so_rcv), tpcb->tp_lcredit,
589 so->so_rcv.sb_cc, so->so_rcv.sb_hiwat);
590 ENDTRACE
591 IFDEBUG(D_REQUEST)
592 printf("RCVD: cc %d space %d hiwat %d\n",
593 so->so_rcv.sb_cc, sbspace(&so->so_rcv),
594 so->so_rcv.sb_hiwat);
595 ENDDEBUG
596 if (((int)nam) & MSG_OOB)
597 error = DoEvent(T_USR_Xrcvd);
598 else
599 error = DoEvent(T_USR_rcvd);
600 break;
601
602 case PRU_RCVOOB:
603 if ((so->so_state & SS_ISCONNECTED) == 0) {
604 error = ENOTCONN;
605 break;
606 }
607 if (! tpcb->tp_xpd_service) {
608 error = EOPNOTSUPP;
609 break;
610 }
611 /* kludge - nam is really flags here */
612 error = tp_rcvoob(tpcb, so, m, outflags, (int)nam);
613 break;
614
615 case PRU_SEND:
616 case PRU_SENDOOB:
617 if (controlp) {
618 error = tp_snd_control(controlp, so, &m);
619 controlp = NULL;
620 if (error)
621 break;
622 }
623 if ((so->so_state & SS_ISCONFIRMING) &&
624 (tpcb->tp_state == TP_CONFIRMING) &&
625 (error = tp_confirm(tpcb)))
626 break;
627 if (req == PRU_SENDOOB) {
628 error = (tpcb->tp_xpd_service == 0) ?
629 EOPNOTSUPP : tp_sendoob(tpcb, so, m, outflags);
630 break;
631 }
632 if (m == 0)
633 break;
634 if (m->m_flags & M_EOR) {
635 eotsdu = 1;
636 m->m_flags &= ~M_EOR;
637 }
638 if (eotsdu == 0 && m->m_pkthdr.len == 0)
639 break;
640 if (tpcb->tp_state != TP_AKWAIT && tpcb->tp_state != TP_OPEN) {
641 error = ENOTCONN;
642 break;
643 }
644 /*
645 * The protocol machine copies mbuf chains,
646 * prepends headers, assigns seq numbers, and
647 * puts the packets on the device.
648 * When they are acked they are removed from the socket buf.
649 *
650 * sosend calls this up until sbspace goes negative.
651 * Sbspace may be made negative by appending this mbuf chain,
652 * possibly by a whole cluster.
653 */
654 {
655 register struct mbuf *n = m;
656 register struct sockbuf *sb = &so->so_snd;
657 int maxsize = tpcb->tp_l_tpdusize
658 - tp_headersize(DT_TPDU_type, tpcb)
659 - (tpcb->tp_use_checksum?4:0) ;
660 int totlen = n->m_pkthdr.len;
661 int mbufcnt = 0;
662 struct mbuf *nn;
663
664 /*
665 * Could have eotsdu and no data.(presently MUST have
666 * an mbuf though, even if its length == 0)
667 */
668 IFPERF(tpcb)
669 PStat(tpcb, Nb_from_sess) += totlen;
670 tpmeas(tpcb->tp_lref, TPtime_from_session, 0, 0,
671 PStat(tpcb, Nb_from_sess), totlen);
672 ENDPERF
673 IFDEBUG(D_SYSCALL)
674 printf(
675 "PRU_SEND: eot %d before sbappend 0x%x len 0x%x to sb @ 0x%x\n",
676 eotsdu, m, totlen, sb);
677 dump_mbuf(sb->sb_mb, "so_snd.sb_mb");
678 dump_mbuf(m, "m : to be added");
679 ENDDEBUG
680 /*
681 * Pre-packetize the data in the sockbuf
682 * according to negotiated mtu. Do it here
683 * where we can safely wait for mbufs.
684 *
685 * This presumes knowledge of sockbuf conventions.
686 */
687 if (n = sb->sb_mb)
688 while (n->m_act)
689 n = n->m_act;
690 if ((nn = n) && n->m_pkthdr.len < maxsize) {
691 u_int space = maxsize - n->m_pkthdr.len;
692
693 do {
694 if (n->m_flags & M_EOR)
695 goto on1;
696 } while (n->m_next && (n = n->m_next));
697 if (totlen <= space) {
698 TPNagle1++;
699 n->m_next = m;
700 nn->m_pkthdr.len += totlen;
701 while (n = n->m_next)
702 sballoc(sb, n);
703 if (eotsdu)
704 nn->m_flags |= M_EOR;
705 goto on2;
706 } else {
707 /*
708 * Can't sleep here, because when you wake up
709 * packet you want to attach to may be gone!
710 */
711 if (TNew && (n->m_next = m_copym(m, 0, space, M_NOWAIT))) {
712 nn->m_pkthdr.len += space;
713 TPNagle2++;
714 while (n = n->m_next)
715 sballoc(sb, n);
716 m_adj(m, space);
717 }
718 }
719 }
720 on1: mbufcnt++;
721 for (n = m; n->m_pkthdr.len > maxsize;) {
722 nn = m_copym(n, 0, maxsize, M_WAIT);
723 sbappendrecord(sb, nn);
724 m_adj(n, maxsize);
725 mbufcnt++;
726 }
727 if (eotsdu)
728 n->m_flags |= M_EOR;
729 sbappendrecord(sb, n);
730 on2:
731 IFTRACE(D_DATA)
732 tptraceTPCB(TPPTmisc,
733 "SEND BF: maxsize totlen mbufcnt eotsdu",
734 maxsize, totlen, mbufcnt, eotsdu);
735 ENDTRACE
736 IFDEBUG(D_SYSCALL)
737 printf("PRU_SEND: eot %d after sbappend 0x%x mbufcnt 0x%x\n",
738 eotsdu, n, mbufcnt);
739 dump_mbuf(sb->sb_mb, "so_snd.sb_mb");
740 ENDDEBUG
741 if (tpcb->tp_state == TP_OPEN)
742 error = DoEvent(T_DATA_req);
743 IFDEBUG(D_SYSCALL)
744 printf("PRU_SEND: after driver error 0x%x \n",error);
745 printf("so_snd 0x%x cc 0t%d mbcnt 0t%d\n",
746 sb, sb->sb_cc, sb->sb_mbcnt);
747 dump_mbuf(sb->sb_mb, "so_snd.sb_mb after driver");
748 ENDDEBUG
749 }
750 break;
751
752 case PRU_SOCKADDR:
753 (tpcb->tp_nlproto->nlp_getnetaddr)(so->so_pcb, nam, TP_LOCAL);
754 break;
755
756 case PRU_PEERADDR:
757 (tpcb->tp_nlproto->nlp_getnetaddr)(so->so_pcb, nam, TP_FOREIGN);
758 break;
759
760 case PRU_CONTROL:
761 error = EOPNOTSUPP;
762 break;
763
764 case PRU_PROTOSEND:
765 case PRU_PROTORCV:
766 case PRU_SENSE:
767 case PRU_SLOWTIMO:
768 case PRU_FASTTIMO:
769 error = EOPNOTSUPP;
770 break;
771
772 default:
773#ifdef ARGO_DEBUG
774 printf("tp_usrreq UNKNOWN PRU %d\n", req);
775#endif ARGO_DEBUG
776 error = EOPNOTSUPP;
777 }
778
779 IFDEBUG(D_REQUEST)
780 printf("%s, so 0x%x, tpcb 0x%x, error %d, state %d\n",
781 "returning from tp_usrreq", so, tpcb, error,
782 tpcb ? 0 : tpcb->tp_state);
783 ENDDEBUG
784 IFTRACE(D_REQUEST)
785 tptraceTPCB(TPPTusrreq, "END req so m state [", req, so, m,
786 tpcb?0:tpcb->tp_state);
787 ENDTRACE
788 if (controlp) {
789 m_freem(controlp);
790 printf("control data unexpectedly retained in tp_usrreq()");
791 }
792 splx(s);
793 return error;
794}
4c45483e
GW
795
796void
15637ed4
RG
797tp_ltrace(so, uio)
798struct socket *so;
799struct uio *uio;
800{
801 IFTRACE(D_DATA)
802 register struct tp_pcb *tpcb = sototpcb(so);
803 if (tpcb) {
804 tptraceTPCB(TPPTmisc, "sosend so resid iovcnt", so,
805 uio->uio_resid, uio->uio_iovcnt, 0);
806 }
807 ENDTRACE
808}
809
4c45483e 810int
15637ed4 811tp_confirm(tpcb)
fde1aeb2 812 register struct tp_pcb *tpcb;
15637ed4
RG
813{
814 struct tp_event E;
815 if (tpcb->tp_state == TP_CONFIRMING)
816 return DoEvent(T_ACPT_req);
817 printf("Tp confirm called when not confirming; tpcb 0x%x, state 0x%x\n",
818 tpcb, tpcb->tp_state);
819 return 0;
820}
821
822/*
823 * Process control data sent with sendmsg()
824 */
4c45483e 825int
15637ed4
RG
826tp_snd_control(m, so, data)
827 struct mbuf *m;
828 struct socket *so;
829 register struct mbuf **data;
830{
831 register struct cmsghdr *ch;
832 int error = 0;
833
834 if (m && m->m_len) {
835 ch = mtod(m, struct cmsghdr *);
836 m->m_len -= sizeof (*ch);
837 m->m_data += sizeof (*ch);
838 error = tp_ctloutput(PRCO_SETOPT,
839 so, ch->cmsg_level, ch->cmsg_type, &m);
840 if (ch->cmsg_type == TPOPT_DISC_DATA) {
841 if (data && *data) {
842 m_freem(*data);
843 *data = 0;
844 }
845 error = tp_usrreq(so, PRU_DISCONNECT, (struct mbuf *)0,
846 (caddr_t)0, (struct mbuf *)0);
847 }
848 }
849 if (m)
850 m_freem(m);
851 return error;
852}