1 /*-
2 * Copyright (c) 1991, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * %sccs.include.redist.c%
6 *
7 * @(#)tp_usrreq.c 8.1 (Berkeley) 06/10/93
8 */
9
10 /***********************************************************
11 Copyright IBM Corporation 1987
12
13 All Rights Reserved
14
15 Permission to use, copy, modify, and distribute this software and its
16 documentation for any purpose and without fee is hereby granted,
17 provided that the above copyright notice appear in all copies and that
18 both that copyright notice and this permission notice appear in
19 supporting documentation, and that the name of IBM not be
20 used in advertising or publicity pertaining to distribution of the
21 software without specific, written prior permission.
22
23 IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
24 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
25 IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
26 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
27 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
28 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
29 SOFTWARE.
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
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>
58
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>
70
71 int tp_attach(), tp_driver(), tp_pcbbind();
72 int TNew;
73 int TPNagle1, TPNagle2;
74 struct tp_pcb *tp_listeners, *tp_intercepts;
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 */
83 void
dump_mbuf(n,str)84 dump_mbuf(n, str)
85 struct mbuf *n;
86 char *str;
87 {
88 struct mbuf *nextrecord;
89
90 printf("dump %s\n", str);
91
92 if (n == MNULL) {
93 printf("EMPTY:\n");
94 return;
95 }
96
97 while (n) {
98 nextrecord = n->m_act;
99 printf("RECORD:\n");
100 while (n) {
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);
103 #ifdef notdef
104 {
105 register char *p = mtod(n, char *);
106 register int i;
107
108 printf("data: ");
109 for (i = 0; i < n->m_len; i++) {
110 if (i%8 == 0)
111 printf("\n");
112 printf("0x%x ", *(p+i));
113 }
114 printf("\n");
115 }
116 #endif /* notdef */
117 if (n->m_next == n) {
118 printf("LOOP!\n");
119 return;
120 }
121 n = n->m_next;
122 }
123 n = nextrecord;
124 }
125 printf("\n");
126 }
127
128 #endif /* ARGO_DEBUG */
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 */
145 tp_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;
153 register struct sockbuf *sb = &so->so_rcv;
154 struct tp_event E;
155 int error = 0;
156 register struct mbuf **nn;
157
158 IFDEBUG(D_XPD)
159 printf("PRU_RCVOOB, sostate 0x%x\n", so->so_state);
160 ENDDEBUG
161
162 /* if you use soreceive */
163 if (m == MNULL)
164 return ENOBUFS;
165
166 restart:
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
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
185 sblock(sb, M_WAITOK);
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) {
191 IFDEBUG(D_XPD)
192 printf("RCVOOB: empty queue!\n");
193 ENDDEBUG
194 sbunlock(sb);
195 if (so->so_state & SS_NBIO) {
196 return EWOULDBLOCK;
197 }
198 sbwait(sb);
199 goto restart;
200 }
201 m->m_len = 0;
202
203 /* Assuming at most one xpd tpdu is in the buffer at once */
204 while (n != MNULL) {
205 m->m_len += n->m_len;
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 */
208 n = n->m_next;
209 }
210 m->m_data = m->m_dat;
211 m->m_flags |= M_EOR;
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
219 if ((inflags & MSG_PEEK) == 0) {
220 n = *nn;
221 *nn = n->m_act;
222 for (; n; n = m_free(n))
223 sbfree(sb, n);
224 }
225
226 release:
227 sbunlock(sb);
228
229 IFTRACE(D_XPD)
230 tptraceTPCB(TPPTmisc, "PRU_RCVOOB @ release sb_cc m_len",
231 tpcb->tp_Xrcv.sb_cc, m->m_len, 0, 0);
232 ENDTRACE
233 if (error == 0)
234 error = DoEvent(T_USR_Xrcvd);
235 return error;
236 }
237
238 /*
239 * CALLED FROM:
240 * tp_usrreq(), PRU_SENDOOB
241 * FUNCTION and ARGUMENTS:
242 * Send what's in the mbuf chain (m) as an XPD TPDU.
243 * The mbuf may not contain more then 16 bytes of data.
244 * XPD TSDUs aren't segmented, so they translate into
245 * exactly one XPD TPDU, with EOT bit set.
246 * RETURN VALUE:
247 * EWOULDBLOCK if socket is in non-blocking mode and the previous
248 * xpd data haven't been acked yet.
249 * EMSGSIZE if trying to send > max-xpd bytes (16)
250 * ENOBUFS if ran out of mbufs
251 */
252 tp_sendoob(tpcb, so, xdata, outflags)
253 struct tp_pcb *tpcb;
254 register struct socket *so;
255 register struct mbuf *xdata;
256 int *outflags; /* not used */
257 {
258 /*
259 * Each mbuf chain represents a sequence # in the XPD seq space.
260 * The first one in the queue has sequence # tp_Xuna.
261 * When we add to the XPD queue, we stuff a zero-length
262 * mbuf (mark) into the DATA queue, with its sequence number in m_next
263 * to be assigned to this XPD tpdu, so data xfer can stop
264 * when it reaches the zero-length mbuf if this XPD TPDU hasn't
265 * yet been acknowledged.
266 */
267 register struct sockbuf *sb = &(tpcb->tp_Xsnd);
268 register struct mbuf *xmark;
269 register int len=0;
270 struct tp_event E;
271
272 IFDEBUG(D_XPD)
273 printf("tp_sendoob:");
274 if (xdata)
275 printf("xdata len 0x%x\n", xdata->m_len);
276 ENDDEBUG
277 /* DO NOT LOCK the Xsnd buffer!!!! You can have at MOST one
278 * socket buf locked at any time!!! (otherwise you might
279 * sleep() in sblock() w/ a signal pending and cause the
280 * system call to be aborted w/ a locked socketbuf, which
281 * is a problem. So the so_snd buffer lock
282 * (done in sosend()) serves as the lock for Xpd.
283 */
284 if (sb->sb_mb) { /* Anything already in eXpedited data sockbuf? */
285 if (so->so_state & SS_NBIO) {
286 return EWOULDBLOCK;
287 }
288 while (sb->sb_mb) {
289 sbunlock(&so->so_snd); /* already locked by sosend */
290 sbwait(&so->so_snd);
291 sblock(&so->so_snd, M_WAITOK); /* sosend will unlock on return */
292 }
293 }
294
295 if (xdata == (struct mbuf *)0) {
296 /* empty xpd packet */
297 MGETHDR(xdata, M_WAIT, MT_OOBDATA);
298 if (xdata == NULL) {
299 return ENOBUFS;
300 }
301 xdata->m_len = 0;
302 xdata->m_pkthdr.len = 0;
303 }
304 IFDEBUG(D_XPD)
305 printf("tp_sendoob 1:");
306 if (xdata)
307 printf("xdata len 0x%x\n", xdata->m_len);
308 ENDDEBUG
309 xmark = xdata; /* temporary use of variable xmark */
310 while (xmark) {
311 len += xmark->m_len;
312 xmark = xmark->m_next;
313 }
314 if (len > TP_MAX_XPD_DATA) {
315 return EMSGSIZE;
316 }
317 IFDEBUG(D_XPD)
318 printf("tp_sendoob 2:");
319 if (xdata)
320 printf("xdata len 0x%x\n", len);
321 ENDDEBUG
322
323
324 IFTRACE(D_XPD)
325 tptraceTPCB(TPPTmisc, "XPD mark m_next ", xdata->m_next, 0, 0, 0);
326 ENDTRACE
327
328 sbappendrecord(sb, xdata);
329
330 IFDEBUG(D_XPD)
331 printf("tp_sendoob len 0x%x\n", len);
332 dump_mbuf(so->so_snd.sb_mb, "XPD request Regular sndbuf:");
333 dump_mbuf(tpcb->tp_Xsnd.sb_mb, "XPD request Xsndbuf:");
334 ENDDEBUG
335 return DoEvent(T_XPD_req);
336 }
337
338 /*
339 * CALLED FROM:
340 * the socket routines
341 * FUNCTION and ARGUMENTS:
342 * Handles all "user requests" except the [gs]ockopts() requests.
343 * The argument (req) is the request type (PRU*),
344 * (m) is an mbuf chain, generally used for send and
345 * receive type requests only.
346 * (nam) is used for addresses usually, in particular for the bind request.
347 *
348 */
349 /*ARGSUSED*/
350 ProtoHook
tp_usrreq(so,req,m,nam,controlp)351 tp_usrreq(so, req, m, nam, controlp)
352 struct socket *so;
353 u_int req;
354 struct mbuf *m, *nam, *controlp;
355 {
356 register struct tp_pcb *tpcb = sototpcb(so);
357 int s = splnet();
358 int error = 0;
359 int flags, *outflags = &flags;
360 u_long eotsdu = 0;
361 struct tp_event E;
362
363 IFDEBUG(D_REQUEST)
364 printf("usrreq(0x%x,%d,0x%x,0x%x,0x%x)\n",so,req,m,nam,outflags);
365 if (so->so_error)
366 printf("WARNING!!! so->so_error is 0x%x\n", so->so_error);
367 ENDDEBUG
368 IFTRACE(D_REQUEST)
369 tptraceTPCB(TPPTusrreq, "req so m state [", req, so, m,
370 tpcb?tpcb->tp_state:0);
371 ENDTRACE
372
373 if ((u_int)tpcb == 0 && req != PRU_ATTACH) {
374 IFTRACE(D_REQUEST)
375 tptraceTPCB(TPPTusrreq, "req failed NO TPCB[", 0, 0, 0, 0);
376 ENDTRACE
377 splx(s);
378 return ENOTCONN;
379 }
380
381 switch (req) {
382
383 case PRU_ATTACH:
384 if (tpcb) {
385 error = EISCONN;
386 } else if ((error = tp_attach(so, (int)nam)) == 0)
387 tpcb = sototpcb(so);
388 break;
389
390 case PRU_ABORT: /* called from close() */
391 /* called for each incoming connect queued on the
392 * parent (accepting) socket
393 */
394 if (tpcb->tp_state == TP_OPEN || tpcb->tp_state == TP_CONFIRMING) {
395 E.ATTR(T_DISC_req).e_reason = E_TP_NO_SESSION;
396 error = DoEvent(T_DISC_req); /* pretend it was a close() */
397 break;
398 } /* else DROP THROUGH */
399
400 case PRU_DETACH: /* called from close() */
401 /* called only after disconnect was called */
402 error = DoEvent(T_DETACH);
403 if (tpcb->tp_state == TP_CLOSED) {
404 if (tpcb->tp_notdetached) {
405 IFDEBUG(D_CONN)
406 printf("PRU_DETACH: not detached\n");
407 ENDDEBUG
408 tp_detach(tpcb);
409 }
410 free((caddr_t)tpcb, M_PCB);
411 tpcb = 0;
412 }
413 break;
414
415 case PRU_SHUTDOWN:
416 /* recv end may have been released; local credit might be zero */
417 case PRU_DISCONNECT:
418 E.ATTR(T_DISC_req).e_reason = E_TP_NORMAL_DISC;
419 error = DoEvent(T_DISC_req);
420 break;
421
422 case PRU_BIND:
423 error = tp_pcbbind(tpcb, nam);
424 break;
425
426 case PRU_LISTEN:
427 if (tpcb->tp_state != TP_CLOSED || tpcb->tp_lsuffixlen == 0 ||
428 tpcb->tp_next == 0)
429 error = EINVAL;
430 else {
431 register struct tp_pcb **tt;
432 remque(tpcb);
433 tpcb->tp_next = tpcb->tp_prev = tpcb;
434 for (tt = &tp_listeners; *tt; tt = &((*tt)->tp_nextlisten))
435 if ((*tt)->tp_lsuffixlen)
436 break;
437 tpcb->tp_nextlisten = *tt;
438 *tt = tpcb;
439 error = DoEvent(T_LISTEN_req);
440 }
441 break;
442
443 case PRU_CONNECT2:
444 error = EOPNOTSUPP; /* for unix domain sockets */
445 break;
446
447 case PRU_CONNECT:
448 IFTRACE(D_CONN)
449 tptraceTPCB(TPPTmisc,
450 "PRU_CONNECT: so 0x%x *SHORT_LSUFXP(tpcb) 0x%x lsuflen 0x%x, class 0x%x",
451 tpcb->tp_sock, *SHORT_LSUFXP(tpcb), tpcb->tp_lsuffixlen,
452 tpcb->tp_class);
453 ENDTRACE
454 IFDEBUG(D_CONN)
455 printf("PRU_CONNECT: so *SHORT_LSUFXP(tpcb) 0x%x lsuflen 0x%x, class 0x%x",
456 tpcb->tp_sock, *SHORT_LSUFXP(tpcb), tpcb->tp_lsuffixlen,
457 tpcb->tp_class);
458 ENDDEBUG
459 if (tpcb->tp_lsuffixlen == 0) {
460 if (error = tp_pcbbind(tpcb, MNULL)) {
461 IFDEBUG(D_CONN)
462 printf("pcbbind returns error 0x%x\n", error);
463 ENDDEBUG
464 break;
465 }
466 }
467 IFDEBUG(D_CONN)
468 printf("isop 0x%x isop->isop_socket offset 12 :\n", tpcb->tp_npcb);
469 dump_buf(tpcb->tp_npcb, 16);
470 ENDDEBUG
471 if (error = tp_route_to(nam, tpcb, /* channel */0))
472 break;
473 IFDEBUG(D_CONN)
474 printf(
475 "PRU_CONNECT after tpcb 0x%x so 0x%x npcb 0x%x flags 0x%x\n",
476 tpcb, so, tpcb->tp_npcb, tpcb->tp_flags);
477 printf("isop 0x%x isop->isop_socket offset 12 :\n", tpcb->tp_npcb);
478 dump_buf(tpcb->tp_npcb, 16);
479 ENDDEBUG
480 if (tpcb->tp_fsuffixlen == 0) {
481 /* didn't set peer extended suffix */
482 (tpcb->tp_nlproto->nlp_getsufx)(tpcb->tp_npcb, &tpcb->tp_fsuffixlen,
483 tpcb->tp_fsuffix, TP_FOREIGN);
484 }
485 if (tpcb->tp_state == TP_CLOSED) {
486 soisconnecting(so);
487 error = DoEvent(T_CONN_req);
488 } else {
489 (tpcb->tp_nlproto->nlp_pcbdisc)(tpcb->tp_npcb);
490 error = EISCONN;
491 }
492 IFPERF(tpcb)
493 u_int lsufx, fsufx;
494 lsufx = *(u_short *)(tpcb->tp_lsuffix);
495 fsufx = *(u_short *)(tpcb->tp_fsuffix);
496
497 tpmeas(tpcb->tp_lref,
498 TPtime_open | (tpcb->tp_xtd_format << 4),
499 &time, lsufx, fsufx, tpcb->tp_fref);
500 ENDPERF
501 break;
502
503 case PRU_ACCEPT:
504 (tpcb->tp_nlproto->nlp_getnetaddr)(tpcb->tp_npcb, nam, TP_FOREIGN);
505 IFDEBUG(D_REQUEST)
506 printf("ACCEPT PEERADDDR:");
507 dump_buf(mtod(nam, char *), nam->m_len);
508 ENDDEBUG
509 IFPERF(tpcb)
510 u_int lsufx, fsufx;
511 lsufx = *(u_short *)(tpcb->tp_lsuffix);
512 fsufx = *(u_short *)(tpcb->tp_fsuffix);
513
514 tpmeas(tpcb->tp_lref, TPtime_open,
515 &time, lsufx, fsufx, tpcb->tp_fref);
516 ENDPERF
517 break;
518
519 case PRU_RCVD:
520 if (so->so_state & SS_ISCONFIRMING) {
521 if (tpcb->tp_state == TP_CONFIRMING)
522 error = tp_confirm(tpcb);
523 break;
524 }
525 IFTRACE(D_DATA)
526 tptraceTPCB(TPPTmisc,
527 "RCVD BF: lcredit sent_lcdt cc hiwat \n",
528 tpcb->tp_lcredit, tpcb->tp_sent_lcdt,
529 so->so_rcv.sb_cc, so->so_rcv.sb_hiwat);
530 LOCAL_CREDIT(tpcb);
531 tptraceTPCB(TPPTmisc,
532 "PRU_RCVD AF sbspace lcredit hiwat cc",
533 sbspace(&so->so_rcv), tpcb->tp_lcredit,
534 so->so_rcv.sb_cc, so->so_rcv.sb_hiwat);
535 ENDTRACE
536 IFDEBUG(D_REQUEST)
537 printf("RCVD: cc %d space %d hiwat %d\n",
538 so->so_rcv.sb_cc, sbspace(&so->so_rcv),
539 so->so_rcv.sb_hiwat);
540 ENDDEBUG
541 if (((int)nam) & MSG_OOB)
542 error = DoEvent(T_USR_Xrcvd);
543 else
544 error = DoEvent(T_USR_rcvd);
545 break;
546
547 case PRU_RCVOOB:
548 if ((so->so_state & SS_ISCONNECTED) == 0) {
549 error = ENOTCONN;
550 break;
551 }
552 if (! tpcb->tp_xpd_service) {
553 error = EOPNOTSUPP;
554 break;
555 }
556 /* kludge - nam is really flags here */
557 error = tp_rcvoob(tpcb, so, m, outflags, (int)nam);
558 break;
559
560 case PRU_SEND:
561 case PRU_SENDOOB:
562 if (controlp) {
563 error = tp_snd_control(controlp, so, &m);
564 controlp = NULL;
565 if (error)
566 break;
567 }
568 if ((so->so_state & SS_ISCONFIRMING) &&
569 (tpcb->tp_state == TP_CONFIRMING) &&
570 (error = tp_confirm(tpcb)))
571 break;
572 if (req == PRU_SENDOOB) {
573 error = (tpcb->tp_xpd_service == 0) ?
574 EOPNOTSUPP : tp_sendoob(tpcb, so, m, outflags);
575 break;
576 }
577 if (m == 0)
578 break;
579 if (m->m_flags & M_EOR) {
580 eotsdu = 1;
581 m->m_flags &= ~M_EOR;
582 }
583 if (eotsdu == 0 && m->m_pkthdr.len == 0)
584 break;
585 if (tpcb->tp_state != TP_AKWAIT && tpcb->tp_state != TP_OPEN) {
586 error = ENOTCONN;
587 break;
588 }
589 /*
590 * The protocol machine copies mbuf chains,
591 * prepends headers, assigns seq numbers, and
592 * puts the packets on the device.
593 * When they are acked they are removed from the socket buf.
594 *
595 * sosend calls this up until sbspace goes negative.
596 * Sbspace may be made negative by appending this mbuf chain,
597 * possibly by a whole cluster.
598 */
599 {
600 /*
601 * Could have eotsdu and no data.(presently MUST have
602 * an mbuf though, even if its length == 0)
603 */
604 int totlen = m->m_pkthdr.len;
605 struct sockbuf *sb = &so->so_snd;
606 IFPERF(tpcb)
607 PStat(tpcb, Nb_from_sess) += totlen;
608 tpmeas(tpcb->tp_lref, TPtime_from_session, 0, 0,
609 PStat(tpcb, Nb_from_sess), totlen);
610 ENDPERF
611 IFDEBUG(D_SYSCALL)
612 printf(
613 "PRU_SEND: eot %d before sbappend 0x%x len 0x%x to sb @ 0x%x\n",
614 eotsdu, m, totlen, sb);
615 dump_mbuf(sb->sb_mb, "so_snd.sb_mb");
616 dump_mbuf(m, "m : to be added");
617 ENDDEBUG
618 tp_packetize(tpcb, m, eotsdu);
619 IFDEBUG(D_SYSCALL)
620 printf("PRU_SEND: eot %d after sbappend 0x%x\n", eotsdu, m);
621 dump_mbuf(sb->sb_mb, "so_snd.sb_mb");
622 ENDDEBUG
623 if (tpcb->tp_state == TP_OPEN)
624 error = DoEvent(T_DATA_req);
625 IFDEBUG(D_SYSCALL)
626 printf("PRU_SEND: after driver error 0x%x \n",error);
627 printf("so_snd 0x%x cc 0t%d mbcnt 0t%d\n",
628 sb, sb->sb_cc, sb->sb_mbcnt);
629 dump_mbuf(sb->sb_mb, "so_snd.sb_mb after driver");
630 ENDDEBUG
631 }
632 break;
633
634 case PRU_SOCKADDR:
635 (tpcb->tp_nlproto->nlp_getnetaddr)(tpcb->tp_npcb, nam, TP_LOCAL);
636 break;
637
638 case PRU_PEERADDR:
639 (tpcb->tp_nlproto->nlp_getnetaddr)(tpcb->tp_npcb, nam, TP_FOREIGN);
640 break;
641
642 case PRU_CONTROL:
643 error = EOPNOTSUPP;
644 break;
645
646 case PRU_PROTOSEND:
647 case PRU_PROTORCV:
648 case PRU_SENSE:
649 case PRU_SLOWTIMO:
650 case PRU_FASTTIMO:
651 error = EOPNOTSUPP;
652 break;
653
654 default:
655 #ifdef ARGO_DEBUG
656 printf("tp_usrreq UNKNOWN PRU %d\n", req);
657 #endif /* ARGO_DEBUG */
658 error = EOPNOTSUPP;
659 }
660
661 IFDEBUG(D_REQUEST)
662 printf("%s, so 0x%x, tpcb 0x%x, error %d, state %d\n",
663 "returning from tp_usrreq", so, tpcb, error,
664 tpcb ? tpcb->tp_state : 0);
665 ENDDEBUG
666 IFTRACE(D_REQUEST)
667 tptraceTPCB(TPPTusrreq, "END req so m state [", req, so, m,
668 tpcb ? tpcb->tp_state : 0);
669 ENDTRACE
670 if (controlp) {
671 m_freem(controlp);
672 printf("control data unexpectedly retained in tp_usrreq()");
673 }
674 splx(s);
675 return error;
676 }
677 tp_ltrace(so, uio)
678 struct socket *so;
679 struct uio *uio;
680 {
681 IFTRACE(D_DATA)
682 register struct tp_pcb *tpcb = sototpcb(so);
683 if (tpcb) {
684 tptraceTPCB(TPPTmisc, "sosend so resid iovcnt", so,
685 uio->uio_resid, uio->uio_iovcnt, 0);
686 }
687 ENDTRACE
688 }
689
tp_confirm(tpcb)690 tp_confirm(tpcb)
691 register struct tp_pcb *tpcb;
692 {
693 struct tp_event E;
694 if (tpcb->tp_state == TP_CONFIRMING)
695 return DoEvent(T_ACPT_req);
696 printf("Tp confirm called when not confirming; tpcb 0x%x, state 0x%x\n",
697 tpcb, tpcb->tp_state);
698 return 0;
699 }
700
701 /*
702 * Process control data sent with sendmsg()
703 */
704 tp_snd_control(m, so, data)
705 struct mbuf *m;
706 struct socket *so;
707 register struct mbuf **data;
708 {
709 register struct cmsghdr *ch;
710 int error = 0;
711
712 if (m && m->m_len) {
713 ch = mtod(m, struct cmsghdr *);
714 m->m_len -= sizeof (*ch);
715 m->m_data += sizeof (*ch);
716 error = tp_ctloutput(PRCO_SETOPT,
717 so, ch->cmsg_level, ch->cmsg_type, &m);
718 if (ch->cmsg_type == TPOPT_DISC_DATA) {
719 if (data && *data) {
720 m_freem(*data);
721 *data = 0;
722 }
723 error = tp_usrreq(so, PRU_DISCONNECT, (struct mbuf *)0,
724 (caddr_t)0, (struct mbuf *)0);
725 }
726 }
727 if (m)
728 m_freem(m);
729 return error;
730 }
731