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