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