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