ip_output takes 5 args now; other miscelleny due to prototypes in header files
[unix-history] / usr / src / sys / netiso / tp_usrreq.c
CommitLineData
7bcd1bb8
KB
1/*-
2 * Copyright (c) 1991 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * %sccs.include.redist.c%
6 *
4d8170e5 7 * @(#)tp_usrreq.c 7.28 (Berkeley) %G%
7bcd1bb8
KB
8 */
9
4a61b6ff 10/***********************************************************
7b25382f 11 Copyright IBM Corporation 1987
4a61b6ff
KS
12
13 All Rights Reserved
14
15Permission to use, copy, modify, and distribute this software and its
16documentation for any purpose and without fee is hereby granted,
17provided that the above copyright notice appear in all copies and that
18both that copyright notice and this permission notice appear in
19supporting documentation, and that the name of IBM not be
20used in advertising or publicity pertaining to distribution of the
21software without specific, written prior permission.
22
23IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
24ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
25IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
26ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
27WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
28ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
29SOFTWARE.
30
31******************************************************************/
32
33/*
34 * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
35 */
36/*
37 * ARGO TP
38 *
39 * $Header: tp_usrreq.c,v 5.4 88/11/18 17:29:18 nhall Exp $
40 * $Source: /usr/argo/sys/netiso/RCS/tp_usrreq.c,v $
41 *
42 * tp_usrreq(), the fellow that gets called from most of the socket code.
43 * Pretty straighforward.
44 * THe only really awful stuff here is the OOB processing, which is done
45 * wholly here.
46 * tp_rcvoob() and tp_sendoob() are contained here and called by tp_usrreq().
47 */
48
5548a02f
KB
49#include <sys/param.h>
50#include <sys/systm.h>
51#include <sys/mbuf.h>
52#include <sys/socket.h>
53#include <sys/socketvar.h>
54#include <sys/domain.h>
55#include <sys/protosw.h>
56#include <sys/errno.h>
57#include <sys/time.h>
4a61b6ff 58
5548a02f
KB
59#include <netiso/tp_param.h>
60#include <netiso/tp_timer.h>
61#include <netiso/tp_stat.h>
62#include <netiso/tp_seq.h>
63#include <netiso/tp_ip.h>
64#include <netiso/tp_pcb.h>
65#include <netiso/argo_debug.h>
66#include <netiso/tp_trace.h>
67#include <netiso/tp_meas.h>
68#include <netiso/iso.h>
69#include <netiso/iso_errno.h>
4a61b6ff 70
fe70f7ca 71int tp_attach(), tp_driver(), tp_pcbbind();
873c981f
KS
72int TNew;
73int TPNagle1, TPNagle2;
63f88aec 74struct tp_pcb *tp_listeners, *tp_intercepts;
4a61b6ff
KS
75
76#ifdef ARGO_DEBUG
77/*
78 * CALLED FROM:
79 * anywhere you want to debug...
80 * FUNCTION and ARGUMENTS:
81 * print (str) followed by the control info in the mbufs of an mbuf chain (n)
82 */
83void
84dump_mbuf(n, str)
85 struct mbuf *n;
86 char *str;
87{
88 struct mbuf *nextrecord;
89
90 printf("dump %s\n", str);
91
bc624f15 92 if (n == MNULL) {
4a61b6ff
KS
93 printf("EMPTY:\n");
94 return;
95 }
96
bc624f15 97 while (n) {
4a61b6ff
KS
98 nextrecord = n->m_act;
99 printf("RECORD:\n");
100 while (n) {
a50e2bc0
KS
101 printf("%x : Len %x Data %x A %x Nx %x Tp %x\n",
102 n, n->m_len, n->m_data, n->m_act, n->m_next, n->m_type);
4a61b6ff
KS
103#ifdef notdef
104 {
105 register char *p = mtod(n, char *);
106 register int i;
107
108 printf("data: ");
bc624f15
KS
109 for (i = 0; i < n->m_len; i++) {
110 if (i%8 == 0)
4a61b6ff
KS
111 printf("\n");
112 printf("0x%x ", *(p+i));
113 }
114 printf("\n");
115 }
4d8170e5 116#endif /* notdef */
bc624f15 117 if (n->m_next == n) {
4a61b6ff
KS
118 printf("LOOP!\n");
119 return;
120 }
121 n = n->m_next;
122 }
123 n = nextrecord;
124 }
125 printf("\n");
126}
127
4d8170e5 128#endif /* ARGO_DEBUG */
4a61b6ff
KS
129
130/*
131 * CALLED FROM:
132 * tp_usrreq(), PRU_RCVOOB
133 * FUNCTION and ARGUMENTS:
134 * Copy data from the expedited data socket buffer into
135 * the pre-allocated mbuf m.
136 * There is an isomorphism between XPD TPDUs and expedited data TSDUs.
137 * XPD tpdus are limited to 16 bytes of data so they fit in one mbuf.
138 * RETURN VALUE:
139 * EINVAL if debugging is on and a disaster has occurred
140 * ENOTCONN if the socket isn't connected
141 * EWOULDBLOCK if the socket is in non-blocking mode and there's no
142 * xpd data in the buffer
143 * E* whatever is returned from the fsm.
144 */
4a61b6ff
KS
145tp_rcvoob(tpcb, so, m, outflags, inflags)
146 struct tp_pcb *tpcb;
147 register struct socket *so;
148 register struct mbuf *m;
149 int *outflags;
150 int inflags;
151{
152 register struct mbuf *n;
a50e2bc0 153 register struct sockbuf *sb = &so->so_rcv;
4a61b6ff
KS
154 struct tp_event E;
155 int error = 0;
a50e2bc0 156 register struct mbuf **nn;
4a61b6ff
KS
157
158 IFDEBUG(D_XPD)
159 printf("PRU_RCVOOB, sostate 0x%x\n", so->so_state);
160 ENDDEBUG
161
162 /* if you use soreceive */
bc624f15 163 if (m == MNULL)
4a61b6ff
KS
164 return ENOBUFS;
165
166restart:
4a61b6ff
KS
167 if ((((so->so_state & SS_ISCONNECTED) == 0)
168 || (so->so_state & SS_ISDISCONNECTING) != 0) &&
169 (so->so_proto->pr_flags & PR_CONNREQUIRED)) {
170 return ENOTCONN;
171 }
172
a50e2bc0
KS
173 /* Take the first mbuf off the chain.
174 * Each XPD TPDU gives you a complete TSDU so the chains don't get
175 * coalesced, but one TSDU may span several mbufs.
176 * Nevertheless, since n should have a most 16 bytes, it
177 * will fit into m. (size was checked in tp_input() )
178 */
179
180 /*
181 * Code for excision of OOB data should be added to
182 * uipc_socket2.c (like sbappend).
183 */
184
a57b86d5 185 sblock(sb, M_WAITOK);
a50e2bc0
KS
186 for (nn = &sb->sb_mb; n = *nn; nn = &n->m_act)
187 if (n->m_type == MT_OOBDATA)
188 break;
189
190 if (n == 0) {
4a61b6ff
KS
191 IFDEBUG(D_XPD)
192 printf("RCVOOB: empty queue!\n");
193 ENDDEBUG
44f52ea5 194 sbunlock(sb);
4a61b6ff
KS
195 if (so->so_state & SS_NBIO) {
196 return EWOULDBLOCK;
197 }
4a61b6ff
KS
198 sbwait(sb);
199 goto restart;
200 }
4a61b6ff
KS
201 m->m_len = 0;
202
203 /* Assuming at most one xpd tpdu is in the buffer at once */
bc624f15 204 while (n != MNULL) {
4a61b6ff 205 m->m_len += n->m_len;
a50e2bc0
KS
206 bcopy(mtod(n, caddr_t), mtod(m, caddr_t), (unsigned)n->m_len);
207 m->m_data += n->m_len; /* so mtod() in bcopy() above gives right addr */
4a61b6ff
KS
208 n = n->m_next;
209 }
a50e2bc0
KS
210 m->m_data = m->m_dat;
211 m->m_flags |= M_EOR;
4a61b6ff
KS
212
213 IFDEBUG(D_XPD)
214 printf("tp_rcvoob: xpdlen 0x%x\n", m->m_len);
215 dump_mbuf(so->so_rcv.sb_mb, "RCVOOB: Rcv socketbuf");
216 dump_mbuf(sb->sb_mb, "RCVOOB: Xrcv socketbuf");
217 ENDDEBUG
218
bc624f15 219 if ((inflags & MSG_PEEK) == 0) {
a50e2bc0
KS
220 n = *nn;
221 *nn = n->m_act;
222 sb->sb_cc -= m->m_len;
223 }
4a61b6ff
KS
224
225release:
226 sbunlock(sb);
227
228 IFTRACE(D_XPD)
229 tptraceTPCB(TPPTmisc, "PRU_RCVOOB @ release sb_cc m_len",
bc624f15 230 tpcb->tp_Xrcv.sb_cc, m->m_len, 0, 0);
4a61b6ff 231 ENDTRACE
4a61b6ff
KS
232 if (error == 0)
233 error = DoEvent(T_USR_Xrcvd);
234 return error;
235}
236
237/*
238 * CALLED FROM:
239 * tp_usrreq(), PRU_SENDOOB
240 * FUNCTION and ARGUMENTS:
241 * Send what's in the mbuf chain (m) as an XPD TPDU.
242 * The mbuf may not contain more then 16 bytes of data.
243 * XPD TSDUs aren't segmented, so they translate into
244 * exactly one XPD TPDU, with EOT bit set.
245 * RETURN VALUE:
246 * EWOULDBLOCK if socket is in non-blocking mode and the previous
247 * xpd data haven't been acked yet.
248 * EMSGSIZE if trying to send > max-xpd bytes (16)
249 * ENOBUFS if ran out of mbufs
250 */
4a61b6ff
KS
251tp_sendoob(tpcb, so, xdata, outflags)
252 struct tp_pcb *tpcb;
253 register struct socket *so;
254 register struct mbuf *xdata;
255 int *outflags; /* not used */
256{
257 /*
258 * Each mbuf chain represents a sequence # in the XPD seq space.
259 * The first one in the queue has sequence # tp_Xuna.
260 * When we add to the XPD queue, we stuff a zero-length
261 * mbuf (mark) into the DATA queue, with its sequence number in m_next
262 * to be assigned to this XPD tpdu, so data xfer can stop
263 * when it reaches the zero-length mbuf if this XPD TPDU hasn't
264 * yet been acknowledged.
265 */
266 register struct sockbuf *sb = &(tpcb->tp_Xsnd);
267 register struct mbuf *xmark;
268 register int len=0;
269 struct tp_event E;
270
271 IFDEBUG(D_XPD)
272 printf("tp_sendoob:");
bc624f15 273 if (xdata)
4a61b6ff
KS
274 printf("xdata len 0x%x\n", xdata->m_len);
275 ENDDEBUG
4a61b6ff
KS
276 /* DO NOT LOCK the Xsnd buffer!!!! You can have at MOST one
277 * socket buf locked at any time!!! (otherwise you might
278 * sleep() in sblock() w/ a signal pending and cause the
279 * system call to be aborted w/ a locked socketbuf, which
280 * is a problem. So the so_snd buffer lock
281 * (done in sosend()) serves as the lock for Xpd.
282 */
44f52ea5 283 if (sb->sb_mb) { /* Anything already in eXpedited data sockbuf? */
4a61b6ff
KS
284 if (so->so_state & SS_NBIO) {
285 return EWOULDBLOCK;
286 }
44f52ea5
KS
287 while (sb->sb_mb) {
288 sbunlock(&so->so_snd); /* already locked by sosend */
289 sbwait(&so->so_snd);
a57b86d5 290 sblock(&so->so_snd, M_WAITOK); /* sosend will unlock on return */
44f52ea5 291 }
4a61b6ff
KS
292 }
293
294 if (xdata == (struct mbuf *)0) {
295 /* empty xpd packet */
a50e2bc0 296 MGETHDR(xdata, M_WAIT, MT_OOBDATA);
4a61b6ff
KS
297 if (xdata == NULL) {
298 return ENOBUFS;
299 }
300 xdata->m_len = 0;
a50e2bc0 301 xdata->m_pkthdr.len = 0;
4a61b6ff
KS
302 }
303 IFDEBUG(D_XPD)
304 printf("tp_sendoob 1:");
bc624f15 305 if (xdata)
4a61b6ff
KS
306 printf("xdata len 0x%x\n", xdata->m_len);
307 ENDDEBUG
308 xmark = xdata; /* temporary use of variable xmark */
309 while (xmark) {
310 len += xmark->m_len;
311 xmark = xmark->m_next;
312 }
313 if (len > TP_MAX_XPD_DATA) {
314 return EMSGSIZE;
315 }
316 IFDEBUG(D_XPD)
317 printf("tp_sendoob 2:");
bc624f15 318 if (xdata)
4a61b6ff
KS
319 printf("xdata len 0x%x\n", len);
320 ENDDEBUG
321
4a61b6ff
KS
322
323 IFTRACE(D_XPD)
44f52ea5 324 tptraceTPCB(TPPTmisc, "XPD mark m_next ", xdata->m_next, 0, 0, 0);
4a61b6ff
KS
325 ENDTRACE
326
4a61b6ff
KS
327 sbappendrecord(sb, xdata);
328
329 IFDEBUG(D_XPD)
330 printf("tp_sendoob len 0x%x\n", len);
331 dump_mbuf(so->so_snd.sb_mb, "XPD request Regular sndbuf:");
332 dump_mbuf(tpcb->tp_Xsnd.sb_mb, "XPD request Xsndbuf:");
333 ENDDEBUG
4a61b6ff 334 return DoEvent(T_XPD_req);
4a61b6ff
KS
335}
336
337/*
338 * CALLED FROM:
339 * the socket routines
340 * FUNCTION and ARGUMENTS:
341 * Handles all "user requests" except the [gs]ockopts() requests.
342 * The argument (req) is the request type (PRU*),
343 * (m) is an mbuf chain, generally used for send and
344 * receive type requests only.
345 * (nam) is used for addresses usually, in particular for the bind request.
346 *
4a61b6ff
KS
347 */
348/*ARGSUSED*/
349ProtoHook
ec6503d1 350tp_usrreq(so, req, m, nam, controlp)
4a61b6ff
KS
351 struct socket *so;
352 u_int req;
ec6503d1 353 struct mbuf *m, *nam, *controlp;
4a61b6ff
KS
354{
355 register struct tp_pcb *tpcb = sototpcb(so);
356 int s = splnet();
357 int error = 0;
a50e2bc0 358 int flags, *outflags = &flags;
4a61b6ff
KS
359 u_long eotsdu = 0;
360 struct tp_event E;
361
362 IFDEBUG(D_REQUEST)
363 printf("usrreq(0x%x,%d,0x%x,0x%x,0x%x)\n",so,req,m,nam,outflags);
bc624f15 364 if (so->so_error)
4a61b6ff
KS
365 printf("WARNING!!! so->so_error is 0x%x\n", so->so_error);
366 ENDDEBUG
367 IFTRACE(D_REQUEST)
368 tptraceTPCB(TPPTusrreq, "req so m state [", req, so, m,
369 tpcb?tpcb->tp_state:0);
370 ENDTRACE
371
372 if ((u_int)tpcb == 0 && req != PRU_ATTACH) {
373 IFTRACE(D_REQUEST)
374 tptraceTPCB(TPPTusrreq, "req failed NO TPCB[", 0, 0, 0, 0);
375 ENDTRACE
376 splx(s);
377 return ENOTCONN;
378 }
379
4a61b6ff
KS
380 switch (req) {
381
382 case PRU_ATTACH:
383 if (tpcb) {
384 error = EISCONN;
01acbfa1
KS
385 } else if ((error = tp_attach(so, (int)nam)) == 0)
386 tpcb = sototpcb(so);
4a61b6ff
KS
387 break;
388
389 case PRU_ABORT: /* called from close() */
390 /* called for each incoming connect queued on the
391 * parent (accepting) socket
392 */
01acbfa1 393 if (tpcb->tp_state == TP_OPEN || tpcb->tp_state == TP_CONFIRMING) {
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 */
401 error = DoEvent(T_DETACH);
a50e2bc0 402 if (tpcb->tp_state == TP_CLOSED) {
fab7bc7c
KS
403 if (tpcb->tp_notdetached) {
404 IFDEBUG(D_CONN)
405 printf("PRU_DETACH: not detached\n");
406 ENDDEBUG
407 tp_detach(tpcb);
408 }
a50e2bc0
KS
409 free((caddr_t)tpcb, M_PCB);
410 tpcb = 0;
411 }
4a61b6ff
KS
412 break;
413
414 case PRU_SHUTDOWN:
415 /* recv end may have been released; local credit might be zero */
416 case PRU_DISCONNECT:
417 E.ATTR(T_DISC_req).e_reason = E_TP_NORMAL_DISC;
418 error = DoEvent(T_DISC_req);
419 break;
420
421 case PRU_BIND:
fe70f7ca 422 error = tp_pcbbind(tpcb, nam);
4a61b6ff
KS
423 break;
424
425 case PRU_LISTEN:
fe70f7ca
KS
426 if (tpcb->tp_state != TP_CLOSED || tpcb->tp_lsuffixlen == 0 ||
427 tpcb->tp_next == 0)
428 error = EINVAL;
429 else {
a93c255c 430 register struct tp_pcb **tt;
fe70f7ca 431 remque(tpcb);
a93c255c
KS
432 tpcb->tp_next = tpcb->tp_prev = tpcb;
433 for (tt = &tp_listeners; *tt; tt = &((*tt)->tp_nextlisten))
434 if ((*tt)->tp_lsuffixlen)
435 break;
436 tpcb->tp_nextlisten = *tt;
437 *tt = tpcb;
fe70f7ca 438 error = DoEvent(T_LISTEN_req);
63f88aec 439 }
4a61b6ff
KS
440 break;
441
442 case PRU_CONNECT2:
443 error = EOPNOTSUPP; /* for unix domain sockets */
444 break;
445
446 case PRU_CONNECT:
447 IFTRACE(D_CONN)
448 tptraceTPCB(TPPTmisc,
a50e2bc0 449 "PRU_CONNECT: so 0x%x *SHORT_LSUFXP(tpcb) 0x%x lsuflen 0x%x, class 0x%x",
4a61b6ff
KS
450 tpcb->tp_sock, *SHORT_LSUFXP(tpcb), tpcb->tp_lsuffixlen,
451 tpcb->tp_class);
452 ENDTRACE
453 IFDEBUG(D_CONN)
454 printf("PRU_CONNECT: so *SHORT_LSUFXP(tpcb) 0x%x lsuflen 0x%x, class 0x%x",
455 tpcb->tp_sock, *SHORT_LSUFXP(tpcb), tpcb->tp_lsuffixlen,
456 tpcb->tp_class);
457 ENDDEBUG
bc624f15 458 if (tpcb->tp_lsuffixlen == 0) {
01acbfa1 459 if (error = tp_pcbbind(tpcb, MNULL)) {
4a61b6ff 460 IFDEBUG(D_CONN)
bc624f15 461 printf("pcbbind returns error 0x%x\n", error);
4a61b6ff
KS
462 ENDDEBUG
463 break;
464 }
a50e2bc0 465 }
4a61b6ff
KS
466 IFDEBUG(D_CONN)
467 printf("isop 0x%x isop->isop_socket offset 12 :\n", tpcb->tp_npcb);
bc624f15 468 dump_buf(tpcb->tp_npcb, 16);
4a61b6ff 469 ENDDEBUG
bc624f15 470 if (error = tp_route_to(nam, tpcb, /* channel */0))
4a61b6ff
KS
471 break;
472 IFDEBUG(D_CONN)
473 printf(
474 "PRU_CONNECT after tpcb 0x%x so 0x%x npcb 0x%x flags 0x%x\n",
475 tpcb, so, tpcb->tp_npcb, tpcb->tp_flags);
476 printf("isop 0x%x isop->isop_socket offset 12 :\n", tpcb->tp_npcb);
bc624f15 477 dump_buf(tpcb->tp_npcb, 16);
4a61b6ff 478 ENDDEBUG
bc624f15 479 if (tpcb->tp_fsuffixlen == 0) {
4a61b6ff 480 /* didn't set peer extended suffix */
f15f73d2 481 (tpcb->tp_nlproto->nlp_getsufx)(tpcb->tp_npcb, &tpcb->tp_fsuffixlen,
bc624f15 482 tpcb->tp_fsuffix, TP_FOREIGN);
4a61b6ff 483 }
bc624f15 484 if (tpcb->tp_state == TP_CLOSED) {
4a61b6ff
KS
485 soisconnecting(so);
486 error = DoEvent(T_CONN_req);
487 } else {
f15f73d2 488 (tpcb->tp_nlproto->nlp_pcbdisc)(tpcb->tp_npcb);
4a61b6ff
KS
489 error = EISCONN;
490 }
491 IFPERF(tpcb)
492 u_int lsufx, fsufx;
7b25382f
KS
493 lsufx = *(u_short *)(tpcb->tp_lsuffix);
494 fsufx = *(u_short *)(tpcb->tp_fsuffix);
4a61b6ff 495
bc624f15
KS
496 tpmeas(tpcb->tp_lref,
497 TPtime_open | (tpcb->tp_xtd_format << 4),
4a61b6ff
KS
498 &time, lsufx, fsufx, tpcb->tp_fref);
499 ENDPERF
500 break;
501
502 case PRU_ACCEPT:
f15f73d2 503 (tpcb->tp_nlproto->nlp_getnetaddr)(tpcb->tp_npcb, nam, TP_FOREIGN);
4a61b6ff 504 IFDEBUG(D_REQUEST)
44f52ea5
KS
505 printf("ACCEPT PEERADDDR:");
506 dump_buf(mtod(nam, char *), nam->m_len);
4a61b6ff 507 ENDDEBUG
4a61b6ff
KS
508 IFPERF(tpcb)
509 u_int lsufx, fsufx;
7b25382f
KS
510 lsufx = *(u_short *)(tpcb->tp_lsuffix);
511 fsufx = *(u_short *)(tpcb->tp_fsuffix);
4a61b6ff 512
bc624f15 513 tpmeas(tpcb->tp_lref, TPtime_open,
4a61b6ff
KS
514 &time, lsufx, fsufx, tpcb->tp_fref);
515 ENDPERF
516 break;
517
518 case PRU_RCVD:
44f52ea5
KS
519 if (so->so_state & SS_ISCONFIRMING) {
520 if (tpcb->tp_state == TP_CONFIRMING)
521 error = tp_confirm(tpcb);
522 break;
523 }
4a61b6ff
KS
524 IFTRACE(D_DATA)
525 tptraceTPCB(TPPTmisc,
526 "RCVD BF: lcredit sent_lcdt cc hiwat \n",
527 tpcb->tp_lcredit, tpcb->tp_sent_lcdt,
528 so->so_rcv.sb_cc, so->so_rcv.sb_hiwat);
529 LOCAL_CREDIT(tpcb);
530 tptraceTPCB(TPPTmisc,
531 "PRU_RCVD AF sbspace lcredit hiwat cc",
532 sbspace(&so->so_rcv), tpcb->tp_lcredit,
533 so->so_rcv.sb_cc, so->so_rcv.sb_hiwat);
534 ENDTRACE
a50e2bc0
KS
535 IFDEBUG(D_REQUEST)
536 printf("RCVD: cc %d space %d hiwat %d\n",
537 so->so_rcv.sb_cc, sbspace(&so->so_rcv),
538 so->so_rcv.sb_hiwat);
539 ENDDEBUG
540 if (((int)nam) & MSG_OOB)
541 error = DoEvent(T_USR_Xrcvd);
542 else
543 error = DoEvent(T_USR_rcvd);
4a61b6ff
KS
544 break;
545
546 case PRU_RCVOOB:
547 if ((so->so_state & SS_ISCONNECTED) == 0) {
548 error = ENOTCONN;
549 break;
550 }
bc624f15 551 if (! tpcb->tp_xpd_service) {
4a61b6ff
KS
552 error = EOPNOTSUPP;
553 break;
554 }
555 /* kludge - nam is really flags here */
556 error = tp_rcvoob(tpcb, so, m, outflags, (int)nam);
557 break;
558
44f52ea5 559 case PRU_SEND:
4a61b6ff 560 case PRU_SENDOOB:
f8f1c826
KS
561 if (controlp) {
562 error = tp_snd_control(controlp, so, &m);
563 controlp = NULL;
564 if (error)
565 break;
566 }
c1c68a51
KS
567 if ((so->so_state & SS_ISCONFIRMING) &&
568 (tpcb->tp_state == TP_CONFIRMING) &&
569 (error = tp_confirm(tpcb)))
570 break;
571 if (req == PRU_SENDOOB) {
572 error = (tpcb->tp_xpd_service == 0) ?
573 EOPNOTSUPP : tp_sendoob(tpcb, so, m, outflags);
44f52ea5
KS
574 break;
575 }
a50e2bc0
KS
576 if (m == 0)
577 break;
c1c68a51
KS
578 if (m->m_flags & M_EOR) {
579 eotsdu = 1;
580 m->m_flags &= ~M_EOR;
581 }
582 if (eotsdu == 0 && m->m_pkthdr.len == 0)
583 break;
584 if (tpcb->tp_state != TP_AKWAIT && tpcb->tp_state != TP_OPEN) {
585 error = ENOTCONN;
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
KS
599 /*
600 * Could have eotsdu and no data.(presently MUST have
601 * an mbuf though, even if its length == 0)
602 */
4a154e63
KS
603 int totlen = m->m_pkthdr.len;
604 struct sockbuf *sb = &so->so_snd;
4a61b6ff 605 IFPERF(tpcb)
a50e2bc0 606 PStat(tpcb, Nb_from_sess) += totlen;
4a61b6ff 607 tpmeas(tpcb->tp_lref, TPtime_from_session, 0, 0,
a50e2bc0 608 PStat(tpcb, Nb_from_sess), totlen);
4a61b6ff
KS
609 ENDPERF
610 IFDEBUG(D_SYSCALL)
611 printf(
612 "PRU_SEND: eot %d before sbappend 0x%x len 0x%x to sb @ 0x%x\n",
873c981f 613 eotsdu, m, totlen, sb);
4a61b6ff
KS
614 dump_mbuf(sb->sb_mb, "so_snd.sb_mb");
615 dump_mbuf(m, "m : to be added");
616 ENDDEBUG
4a154e63 617 tp_packetize(tpcb, m, eotsdu);
4a61b6ff 618 IFDEBUG(D_SYSCALL)
4a154e63 619 printf("PRU_SEND: eot %d after sbappend 0x%x\n", eotsdu, m);
4a61b6ff
KS
620 dump_mbuf(sb->sb_mb, "so_snd.sb_mb");
621 ENDDEBUG
c1c68a51
KS
622 if (tpcb->tp_state == TP_OPEN)
623 error = DoEvent(T_DATA_req);
4a61b6ff
KS
624 IFDEBUG(D_SYSCALL)
625 printf("PRU_SEND: after driver error 0x%x \n",error);
a50e2bc0
KS
626 printf("so_snd 0x%x cc 0t%d mbcnt 0t%d\n",
627 sb, sb->sb_cc, sb->sb_mbcnt);
628 dump_mbuf(sb->sb_mb, "so_snd.sb_mb after driver");
4a61b6ff
KS
629 ENDDEBUG
630 }
631 break;
632
a50e2bc0 633 case PRU_SOCKADDR:
f15f73d2 634 (tpcb->tp_nlproto->nlp_getnetaddr)(tpcb->tp_npcb, nam, TP_LOCAL);
4a61b6ff
KS
635 break;
636
637 case PRU_PEERADDR:
f15f73d2 638 (tpcb->tp_nlproto->nlp_getnetaddr)(tpcb->tp_npcb, nam, TP_FOREIGN);
4a61b6ff
KS
639 break;
640
641 case PRU_CONTROL:
642 error = EOPNOTSUPP;
643 break;
644
645 case PRU_PROTOSEND:
646 case PRU_PROTORCV:
647 case PRU_SENSE:
648 case PRU_SLOWTIMO:
649 case PRU_FASTTIMO:
650 error = EOPNOTSUPP;
651 break;
652
653 default:
654#ifdef ARGO_DEBUG
655 printf("tp_usrreq UNKNOWN PRU %d\n", req);
4d8170e5 656#endif /* ARGO_DEBUG */
4a61b6ff
KS
657 error = EOPNOTSUPP;
658 }
659
660 IFDEBUG(D_REQUEST)
44f52ea5
KS
661 printf("%s, so 0x%x, tpcb 0x%x, error %d, state %d\n",
662 "returning from tp_usrreq", so, tpcb, error,
23152bcc 663 tpcb ? tpcb->tp_state : 0);
4a61b6ff
KS
664 ENDDEBUG
665 IFTRACE(D_REQUEST)
666 tptraceTPCB(TPPTusrreq, "END req so m state [", req, so, m,
23152bcc 667 tpcb ? tpcb->tp_state : 0);
4a61b6ff 668 ENDTRACE
f8f1c826
KS
669 if (controlp) {
670 m_freem(controlp);
671 printf("control data unexpectedly retained in tp_usrreq()");
672 }
4a61b6ff
KS
673 splx(s);
674 return error;
675}
7b25382f
KS
676tp_ltrace(so, uio)
677struct socket *so;
678struct uio *uio;
679{
680 IFTRACE(D_DATA)
681 register struct tp_pcb *tpcb = sototpcb(so);
682 if (tpcb) {
683 tptraceTPCB(TPPTmisc, "sosend so resid iovcnt", so,
684 uio->uio_resid, uio->uio_iovcnt, 0);
685 }
686 ENDTRACE
687}
a50e2bc0 688
44f52ea5
KS
689tp_confirm(tpcb)
690register struct tp_pcb *tpcb;
a50e2bc0 691{
44f52ea5
KS
692 struct tp_event E;
693 if (tpcb->tp_state == TP_CONFIRMING)
694 return DoEvent(T_ACPT_req);
695 printf("Tp confirm called when not confirming; tpcb 0x%x, state 0x%x\n",
696 tpcb, tpcb->tp_state);
697 return 0;
a50e2bc0
KS
698}
699
700/*
701 * Process control data sent with sendmsg()
702 */
f8f1c826
KS
703tp_snd_control(m, so, data)
704 struct mbuf *m;
a50e2bc0
KS
705 struct socket *so;
706 register struct mbuf **data;
707{
a0df93bc 708 register struct cmsghdr *ch;
a50e2bc0
KS
709 int error = 0;
710
f8f1c826 711 if (m && m->m_len) {
a0df93bc 712 ch = mtod(m, struct cmsghdr *);
f8f1c826
KS
713 m->m_len -= sizeof (*ch);
714 m->m_data += sizeof (*ch);
a50e2bc0
KS
715 error = tp_ctloutput(PRCO_SETOPT,
716 so, ch->cmsg_level, ch->cmsg_type, &m);
a50e2bc0
KS
717 if (ch->cmsg_type == TPOPT_DISC_DATA) {
718 if (data && *data) {
719 m_freem(*data);
720 *data = 0;
721 }
f8f1c826
KS
722 error = tp_usrreq(so, PRU_DISCONNECT, (struct mbuf *)0,
723 (caddr_t)0, (struct mbuf *)0);
a50e2bc0
KS
724 }
725 }
f8f1c826
KS
726 if (m)
727 m_freem(m);
a50e2bc0
KS
728 return error;
729}