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