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