Commit | Line | Data |
---|---|---|
4a61b6ff KS |
1 | /*********************************************************** |
2 | Copyright IBM Corporation 1987 | |
3 | ||
4 | All Rights Reserved | |
5 | ||
6 | Permission to use, copy, modify, and distribute this software and its | |
7 | documentation for any purpose and without fee is hereby granted, | |
8 | provided that the above copyright notice appear in all copies and that | |
9 | both that copyright notice and this permission notice appear in | |
10 | supporting documentation, and that the name of IBM not be | |
11 | used in advertising or publicity pertaining to distribution of the | |
12 | software without specific, written prior permission. | |
13 | ||
14 | IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING | |
15 | ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL | |
16 | IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR | |
17 | ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, | |
18 | WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, | |
19 | ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS | |
20 | SOFTWARE. | |
21 | ||
22 | ******************************************************************/ | |
23 | ||
24 | /* | |
25 | * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison | |
26 | */ | |
27 | /* | |
28 | * ARGO TP | |
29 | * | |
30 | * $Header: tp_usrreq.c,v 5.4 88/11/18 17:29:18 nhall Exp $ | |
31 | * $Source: /usr/argo/sys/netiso/RCS/tp_usrreq.c,v $ | |
32 | * | |
33 | * tp_usrreq(), the fellow that gets called from most of the socket code. | |
34 | * Pretty straighforward. | |
35 | * THe only really awful stuff here is the OOB processing, which is done | |
36 | * wholly here. | |
37 | * tp_rcvoob() and tp_sendoob() are contained here and called by tp_usrreq(). | |
38 | */ | |
39 | ||
40 | #ifndef lint | |
41 | static char *rcsid = "$Header: tp_usrreq.c,v 5.4 88/11/18 17:29:18 nhall Exp $"; | |
42 | #endif lint | |
43 | ||
44 | #include "param.h" | |
45 | #include "systm.h" | |
46 | #include "dir.h" | |
47 | #include "user.h" | |
48 | #include "mbuf.h" | |
49 | #include "socket.h" | |
50 | #include "socketvar.h" | |
51 | #include "domain.h" | |
52 | #include "protosw.h" | |
53 | #include "errno.h" | |
54 | ||
55 | #include "../netiso/tp_param.h" | |
56 | #include "../netiso/tp_timer.h" | |
57 | #include "../netiso/tp_stat.h" | |
58 | #include "../netiso/tp_seq.h" | |
59 | #include "../netiso/tp_ip.h" | |
60 | #include "../netiso/tp_pcb.h" | |
61 | #include "../netiso/argo_debug.h" | |
62 | #include "../netiso/tp_trace.h" | |
63 | #include "../netiso/tp_meas.h" | |
64 | #include "../netiso/iso.h" | |
65 | #include "../netiso/iso_errno.h" | |
66 | ||
67 | int tp_attach(), tp_driver(); | |
68 | ||
69 | #ifdef ARGO_DEBUG | |
70 | /* | |
71 | * CALLED FROM: | |
72 | * anywhere you want to debug... | |
73 | * FUNCTION and ARGUMENTS: | |
74 | * print (str) followed by the control info in the mbufs of an mbuf chain (n) | |
75 | */ | |
76 | void | |
77 | dump_mbuf(n, str) | |
78 | struct mbuf *n; | |
79 | char *str; | |
80 | { | |
81 | struct mbuf *nextrecord; | |
82 | ||
83 | printf("dump %s\n", str); | |
84 | ||
85 | if( n == MNULL) { | |
86 | printf("EMPTY:\n"); | |
87 | return; | |
88 | } | |
89 | ||
90 | for(;n;) { | |
91 | nextrecord = n->m_act; | |
92 | printf("RECORD:\n"); | |
93 | while (n) { | |
94 | printf("%x : Len %x Of %x A %x Nx %x Tp %x\n", | |
95 | n, n->m_len, n->m_off, n->m_act, n->m_next, n->m_type); | |
96 | #ifdef notdef | |
97 | { | |
98 | register char *p = mtod(n, char *); | |
99 | register int i; | |
100 | ||
101 | printf("data: "); | |
102 | for(i=0; i < n->m_len; i++ ) { | |
103 | if(i%8 == 0) | |
104 | printf("\n"); | |
105 | printf("0x%x ", *(p+i)); | |
106 | } | |
107 | printf("\n"); | |
108 | } | |
109 | #endif notdef | |
110 | if( n->m_next == n ) { | |
111 | printf("LOOP!\n"); | |
112 | return; | |
113 | } | |
114 | n = n->m_next; | |
115 | } | |
116 | n = nextrecord; | |
117 | } | |
118 | printf("\n"); | |
119 | } | |
120 | ||
121 | #endif ARGO_DEBUG | |
122 | ||
123 | /* | |
124 | * CALLED FROM: | |
125 | * tp_usrreq(), PRU_RCVOOB | |
126 | * FUNCTION and ARGUMENTS: | |
127 | * Copy data from the expedited data socket buffer into | |
128 | * the pre-allocated mbuf m. | |
129 | * There is an isomorphism between XPD TPDUs and expedited data TSDUs. | |
130 | * XPD tpdus are limited to 16 bytes of data so they fit in one mbuf. | |
131 | * RETURN VALUE: | |
132 | * EINVAL if debugging is on and a disaster has occurred | |
133 | * ENOTCONN if the socket isn't connected | |
134 | * EWOULDBLOCK if the socket is in non-blocking mode and there's no | |
135 | * xpd data in the buffer | |
136 | * E* whatever is returned from the fsm. | |
137 | */ | |
138 | static int | |
139 | tp_rcvoob(tpcb, so, m, outflags, inflags) | |
140 | struct tp_pcb *tpcb; | |
141 | register struct socket *so; | |
142 | register struct mbuf *m; | |
143 | int *outflags; | |
144 | int inflags; | |
145 | { | |
146 | register struct mbuf *n; | |
147 | register struct sockbuf *sb = &tpcb->tp_Xrcv; | |
148 | struct tp_event E; | |
149 | int error = 0; | |
150 | ||
151 | IFDEBUG(D_XPD) | |
152 | printf("PRU_RCVOOB, sostate 0x%x\n", so->so_state); | |
153 | ENDDEBUG | |
154 | ||
155 | /* if you use soreceive */ | |
156 | if (m==MNULL) | |
157 | return ENOBUFS; | |
158 | ||
159 | restart: | |
160 | sblock(sb); | |
161 | ||
162 | if ((((so->so_state & SS_ISCONNECTED) == 0) | |
163 | || (so->so_state & SS_ISDISCONNECTING) != 0) && | |
164 | (so->so_proto->pr_flags & PR_CONNREQUIRED)) { | |
165 | return ENOTCONN; | |
166 | } | |
167 | ||
168 | if ( sb->sb_cc == 0) { | |
169 | ASSERT( (tpcb->tp_flags & TPF_DISC_DATA_IN) == 0 ); | |
170 | IFDEBUG(D_XPD) | |
171 | printf("RCVOOB: empty queue!\n"); | |
172 | ENDDEBUG | |
173 | if (so->so_state & SS_NBIO) { | |
174 | return EWOULDBLOCK; | |
175 | } | |
176 | sbunlock(sb); | |
177 | sbwait(sb); | |
178 | goto restart; | |
179 | } | |
180 | /* Take the first mbuf off the chain. | |
181 | * Each XPD TPDU gives you a complete TSDU so the chains don't get | |
182 | * coalesced, but one TSDU may span several mbufs. | |
183 | * Nevertheless, since n should have a most 16 bytes, it | |
184 | * will fit into m. (size was checked in tp_input() ) | |
185 | */ | |
186 | ||
187 | n = sb->sb_mb; | |
188 | ASSERT((n->m_type == TPMT_DATA) || | |
189 | n->m_type == TPMT_IPHDR || n->m_type == TPMT_TPHDR); | |
190 | ||
191 | /* | |
192 | * mtod doesn't work for cluster-type mbufs, hence this disaster check: | |
193 | */ | |
194 | if( n->m_off > MMAXOFF ) | |
195 | panic("tp_rcvoob: unexpected cluster "); | |
196 | ||
197 | m->m_next = MNULL; | |
198 | m->m_act = MNULL; | |
199 | m->m_off = MMINOFF; | |
200 | m->m_len = 0; | |
201 | ||
202 | /* Assuming at most one xpd tpdu is in the buffer at once */ | |
203 | while ( n != MNULL ) { | |
204 | m->m_len += n->m_len; | |
205 | bcopy(mtod(n, caddr_t), mtod(m, caddr_t), n->m_len); | |
206 | m->m_off += n->m_len; /* so mtod() in bcopy() above gives right addr */ | |
207 | n = n->m_next; | |
208 | } | |
209 | m->m_off = MMINOFF; /* restore it to its proper value */ | |
210 | ||
211 | IFDEBUG(D_XPD) | |
212 | printf("tp_rcvoob: xpdlen 0x%x\n", m->m_len); | |
213 | dump_mbuf(so->so_rcv.sb_mb, "RCVOOB: Rcv socketbuf"); | |
214 | dump_mbuf(sb->sb_mb, "RCVOOB: Xrcv socketbuf"); | |
215 | ENDDEBUG | |
216 | ||
217 | if( (inflags & MSG_PEEK) == 0 ) | |
218 | sbdrop(sb, m->m_len); | |
219 | ||
220 | release: | |
221 | sbunlock(sb); | |
222 | ||
223 | IFTRACE(D_XPD) | |
224 | tptraceTPCB(TPPTmisc, "PRU_RCVOOB @ release sb_cc m_len", | |
225 | tpcb->tp_Xrcv.sb_cc, m->m_len,0,0 ); | |
226 | ENDTRACE | |
227 | if(outflags) | |
228 | *outflags = MSG_OOB | MSG_EOTSDU | inflags; /* always on xpd recv */ | |
229 | if (error == 0) | |
230 | error = DoEvent(T_USR_Xrcvd); | |
231 | return error; | |
232 | } | |
233 | ||
234 | /* | |
235 | * CALLED FROM: | |
236 | * tp_usrreq(), PRU_SENDOOB | |
237 | * FUNCTION and ARGUMENTS: | |
238 | * Send what's in the mbuf chain (m) as an XPD TPDU. | |
239 | * The mbuf may not contain more then 16 bytes of data. | |
240 | * XPD TSDUs aren't segmented, so they translate into | |
241 | * exactly one XPD TPDU, with EOT bit set. | |
242 | * RETURN VALUE: | |
243 | * EWOULDBLOCK if socket is in non-blocking mode and the previous | |
244 | * xpd data haven't been acked yet. | |
245 | * EMSGSIZE if trying to send > max-xpd bytes (16) | |
246 | * ENOBUFS if ran out of mbufs | |
247 | */ | |
248 | static int | |
249 | tp_sendoob(tpcb, so, xdata, outflags) | |
250 | struct tp_pcb *tpcb; | |
251 | register struct socket *so; | |
252 | register struct mbuf *xdata; | |
253 | int *outflags; /* not used */ | |
254 | { | |
255 | /* | |
256 | * Each mbuf chain represents a sequence # in the XPD seq space. | |
257 | * The first one in the queue has sequence # tp_Xuna. | |
258 | * When we add to the XPD queue, we stuff a zero-length | |
259 | * mbuf (mark) into the DATA queue, with its sequence number in m_next | |
260 | * to be assigned to this XPD tpdu, so data xfer can stop | |
261 | * when it reaches the zero-length mbuf if this XPD TPDU hasn't | |
262 | * yet been acknowledged. | |
263 | */ | |
264 | register struct sockbuf *sb = &(tpcb->tp_Xsnd); | |
265 | register struct mbuf *xmark; | |
266 | register int len=0; | |
267 | struct tp_event E; | |
268 | ||
269 | IFDEBUG(D_XPD) | |
270 | printf("tp_sendoob:"); | |
271 | if(xdata) | |
272 | printf("xdata len 0x%x\n", xdata->m_len); | |
273 | ENDDEBUG | |
274 | oob_again: | |
275 | /* DO NOT LOCK the Xsnd buffer!!!! You can have at MOST one | |
276 | * socket buf locked at any time!!! (otherwise you might | |
277 | * sleep() in sblock() w/ a signal pending and cause the | |
278 | * system call to be aborted w/ a locked socketbuf, which | |
279 | * is a problem. So the so_snd buffer lock | |
280 | * (done in sosend()) serves as the lock for Xpd. | |
281 | */ | |
282 | if (sb->sb_mb) { /* anything already in this sockbuf? */ | |
283 | if (so->so_state & SS_NBIO) { | |
284 | return EWOULDBLOCK; | |
285 | } | |
286 | sbunlock(&so->so_snd); | |
287 | sbwait(&so->so_snd); | |
288 | sblock(&so->so_snd); | |
289 | goto oob_again; | |
290 | } | |
291 | ||
292 | if (xdata == (struct mbuf *)0) { | |
293 | /* empty xpd packet */ | |
294 | MGET(xdata, M_WAIT, TPMT_DATA); | |
295 | if (xdata == NULL) { | |
296 | return ENOBUFS; | |
297 | } | |
298 | xdata->m_len = 0; | |
299 | xdata->m_act = MNULL; | |
300 | } | |
301 | IFDEBUG(D_XPD) | |
302 | printf("tp_sendoob 1:"); | |
303 | if(xdata) | |
304 | printf("xdata len 0x%x\n", xdata->m_len); | |
305 | ENDDEBUG | |
306 | xmark = xdata; /* temporary use of variable xmark */ | |
307 | while (xmark) { | |
308 | len += xmark->m_len; | |
309 | xmark = xmark->m_next; | |
310 | } | |
311 | if (len > TP_MAX_XPD_DATA) { | |
312 | return EMSGSIZE; | |
313 | } | |
314 | IFDEBUG(D_XPD) | |
315 | printf("tp_sendoob 2:"); | |
316 | if(xdata) | |
317 | printf("xdata len 0x%x\n", len); | |
318 | ENDDEBUG | |
319 | ||
320 | /* stick an xpd mark in the normal data queue | |
321 | * make sure we have enough mbufs before we stick anything into any queues | |
322 | */ | |
323 | MGET(xmark,M_WAIT, TPMT_XPD); | |
324 | if (xmark == MNULL) { | |
325 | return ENOBUFS; | |
326 | } | |
327 | xmark->m_len = 0; | |
328 | xmark->m_act = MNULL; | |
329 | ||
330 | { /* stash the xpd sequence number in the mark */ | |
331 | SeqNum *Xuna = mtod(xmark, SeqNum *); | |
332 | *Xuna = tpcb->tp_Xuna; | |
333 | } | |
334 | ||
335 | IFTRACE(D_XPD) | |
336 | tptraceTPCB(TPPTmisc, "XPD mark m_next ", xmark->m_next, 0, 0, 0); | |
337 | ENDTRACE | |
338 | ||
339 | sbappendrecord(&so->so_snd, xmark); /* the mark */ | |
340 | sbappendrecord(sb, xdata); | |
341 | ||
342 | IFDEBUG(D_XPD) | |
343 | printf("tp_sendoob len 0x%x\n", len); | |
344 | dump_mbuf(so->so_snd.sb_mb, "XPD request Regular sndbuf:"); | |
345 | dump_mbuf(tpcb->tp_Xsnd.sb_mb, "XPD request Xsndbuf:"); | |
346 | ENDDEBUG | |
347 | u.u_r.r_val1 += len; | |
348 | return DoEvent(T_XPD_req); | |
349 | ||
350 | } | |
351 | ||
352 | /* | |
353 | * CALLED FROM: | |
354 | * the socket routines | |
355 | * FUNCTION and ARGUMENTS: | |
356 | * Handles all "user requests" except the [gs]ockopts() requests. | |
357 | * The argument (req) is the request type (PRU*), | |
358 | * (m) is an mbuf chain, generally used for send and | |
359 | * receive type requests only. | |
360 | * (nam) is used for addresses usually, in particular for the bind request. | |
361 | * | |
362 | * The last argument (rights in most usrreq()s) has been stolen for | |
363 | * returning flags values. Since rights can't be passed around w/ tp, | |
364 | * this field is used only for RCVOOB user requests, and is assumed | |
365 | * to be either 0 (as soreceive() would have it) or a ptr to the int flags | |
366 | * (as recvv()'s version of soreceive() would have it | |
367 | */ | |
368 | /*ARGSUSED*/ | |
369 | ProtoHook | |
370 | tp_usrreq(so, req, m, nam, rightsp, outflags) | |
371 | struct socket *so; | |
372 | u_int req; | |
373 | struct mbuf *m, *nam, *rightsp /* not used */; | |
374 | int *outflags; | |
375 | { | |
376 | register struct tp_pcb *tpcb = sototpcb(so); | |
377 | int s = splnet(); | |
378 | int error = 0; | |
379 | u_long eotsdu = 0; | |
380 | struct tp_event E; | |
381 | ||
382 | IFDEBUG(D_REQUEST) | |
383 | printf("usrreq(0x%x,%d,0x%x,0x%x,0x%x)\n",so,req,m,nam,outflags); | |
384 | if(so->so_error) | |
385 | printf("WARNING!!! so->so_error is 0x%x\n", so->so_error); | |
386 | ENDDEBUG | |
387 | IFTRACE(D_REQUEST) | |
388 | tptraceTPCB(TPPTusrreq, "req so m state [", req, so, m, | |
389 | tpcb?tpcb->tp_state:0); | |
390 | ENDTRACE | |
391 | ||
392 | if ((u_int)tpcb == 0 && req != PRU_ATTACH) { | |
393 | IFTRACE(D_REQUEST) | |
394 | tptraceTPCB(TPPTusrreq, "req failed NO TPCB[", 0, 0, 0, 0); | |
395 | ENDTRACE | |
396 | splx(s); | |
397 | return ENOTCONN; | |
398 | } | |
399 | ||
400 | ||
401 | IFDEBUG(D_XPD) | |
402 | extern struct mbuf *mfree; | |
403 | struct mbuf *m = mfree, *n=MNULL; | |
404 | ||
405 | if ( (u_int) tpcb != 0 ) { | |
406 | n = tpcb->tp_Xrcv.sb_mb; | |
407 | if(n) while(m) { | |
408 | if(m == n) { | |
409 | printf("enter usrreq %d Xrcv sb_mb 0x%x is on freelist!\n", | |
410 | req, n); | |
411 | } | |
412 | m = m->m_next; | |
413 | } | |
414 | } | |
415 | ENDDEBUG | |
416 | ||
417 | switch (req) { | |
418 | ||
419 | case PRU_ATTACH: | |
420 | if (tpcb) { | |
421 | error = EISCONN; | |
422 | break; | |
423 | } | |
424 | if( error = tp_attach(so, so->so_proto->pr_domain->dom_family ) ) | |
425 | break; | |
426 | tpcb = sototpcb(so); | |
427 | break; | |
428 | ||
429 | case PRU_ABORT: /* called from close() */ | |
430 | /* called for each incoming connect queued on the | |
431 | * parent (accepting) socket | |
432 | */ | |
433 | if( tpcb->tp_state == TP_OPEN ) { | |
434 | E.ATTR(T_DISC_req).e_reason = E_TP_NO_SESSION; | |
435 | error = DoEvent(T_DISC_req); /* pretend it was a close() */ | |
436 | break; | |
437 | } /* else DROP THROUGH */ | |
438 | ||
439 | case PRU_DETACH: /* called from close() */ | |
440 | /* called only after disconnect was called */ | |
441 | error = DoEvent(T_DETACH); | |
442 | break; | |
443 | ||
444 | case PRU_SHUTDOWN: | |
445 | /* recv end may have been released; local credit might be zero */ | |
446 | case PRU_DISCONNECT: | |
447 | E.ATTR(T_DISC_req).e_reason = E_TP_NORMAL_DISC; | |
448 | error = DoEvent(T_DISC_req); | |
449 | break; | |
450 | ||
451 | case PRU_BIND: | |
452 | error = (tpcb->tp_nlproto->nlp_pcbbind)( so->so_pcb, nam ); | |
453 | if (error == 0) { | |
454 | tpcb->tp_lsuffixlen = sizeof(short); /* default */ | |
455 | *(u_short *)(tpcb->tp_lsuffix) = (u_short) | |
456 | (tpcb->tp_nlproto->nlp_getsufx)( so->so_pcb, TP_LOCAL ); | |
457 | } | |
458 | break; | |
459 | ||
460 | case PRU_LISTEN: | |
461 | if ( *SHORT_LSUFXP(tpcb) == (short)0 ) { | |
462 | /* note: this suffix is independent of the extended suffix */ | |
463 | if( error = (tpcb->tp_nlproto->nlp_pcbbind)(so->so_pcb, MNULL) ) | |
464 | break; | |
465 | } | |
466 | if( tpcb->tp_lsuffixlen == 0) { | |
467 | tpcb->tp_lsuffixlen = sizeof(short); /* default */ | |
468 | *SHORT_LSUFXP(tpcb) = (short) | |
469 | (tpcb->tp_nlproto->nlp_getsufx)( so->so_pcb, TP_LOCAL ); | |
470 | } | |
471 | IFDEBUG(D_TPISO) | |
472 | if(tpcb->tp_state != TP_CLOSED) | |
473 | printf("LISTEN ERROR: state 0x%x\n", tpcb->tp_state); | |
474 | ENDDEBUG | |
475 | error = DoEvent(T_LISTEN_req); | |
476 | break; | |
477 | ||
478 | case PRU_CONNECT2: | |
479 | error = EOPNOTSUPP; /* for unix domain sockets */ | |
480 | break; | |
481 | ||
482 | case PRU_CONNECT: | |
483 | IFTRACE(D_CONN) | |
484 | tptraceTPCB(TPPTmisc, | |
485 | "PRU_CONNECT: so *SHORT_LSUFXP(tpcb) 0x%x lsuflen 0x%x, class 0x%x", | |
486 | tpcb->tp_sock, *SHORT_LSUFXP(tpcb), tpcb->tp_lsuffixlen, | |
487 | tpcb->tp_class); | |
488 | ENDTRACE | |
489 | IFDEBUG(D_CONN) | |
490 | printf("PRU_CONNECT: so *SHORT_LSUFXP(tpcb) 0x%x lsuflen 0x%x, class 0x%x", | |
491 | tpcb->tp_sock, *SHORT_LSUFXP(tpcb), tpcb->tp_lsuffixlen, | |
492 | tpcb->tp_class); | |
493 | ENDDEBUG | |
494 | if (*SHORT_LSUFXP(tpcb) == (short)0) { | |
495 | /* no bind was done */ | |
496 | /* note: this suffix is independent of the extended suffix */ | |
497 | if( error = (tpcb->tp_nlproto->nlp_pcbbind)(so->so_pcb, MNULL) ) { | |
498 | IFDEBUG(D_CONN) | |
499 | printf("pcbbind returns error 0x%x\n", error ); | |
500 | ENDDEBUG | |
501 | break; | |
502 | } | |
503 | } | |
504 | if (tpcb->tp_lsuffixlen == 0) { | |
505 | /* didn't set an extended suffix */ | |
506 | tpcb->tp_lsuffixlen = sizeof(short); | |
507 | *SHORT_LSUFXP(tpcb) = (short) | |
508 | (tpcb->tp_nlproto->nlp_getsufx)( so->so_pcb, TP_LOCAL ); | |
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_fsuffixlen = sizeof(short); | |
527 | *SHORT_FSUFXP(tpcb) = (short) | |
528 | (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, TP_FOREIGN); | |
529 | } | |
530 | (void) (tpcb->tp_nlproto->nlp_mtu)(so, so->so_pcb, | |
531 | &tpcb->tp_l_tpdusize, &tpcb->tp_tpdusize, 0); | |
532 | if( tpcb->tp_state == TP_CLOSED) { | |
533 | soisconnecting(so); | |
534 | error = DoEvent(T_CONN_req); | |
535 | } else { | |
536 | (tpcb->tp_nlproto->nlp_pcbdisc)(so->so_pcb); | |
537 | error = EISCONN; | |
538 | } | |
539 | IFPERF(tpcb) | |
540 | u_int lsufx, fsufx; | |
541 | lsufx = *(u_int *)(tpcb->tp_lsuffix); | |
542 | fsufx = *(u_int *)(tpcb->tp_fsuffix); | |
543 | ||
544 | tpmeas( tpcb->tp_lref, | |
545 | TPtime_open | (tpcb->tp_xtd_format <<4 ), | |
546 | &time, lsufx, fsufx, tpcb->tp_fref); | |
547 | ENDPERF | |
548 | break; | |
549 | ||
550 | case PRU_ACCEPT: | |
551 | /* all this garbage is to keep accept from returning | |
552 | * before the 3-way handshake is done in class 4. | |
553 | * it'll have to be modified for other classes | |
554 | */ | |
555 | IFDEBUG(D_REQUEST) | |
556 | printf("PRU_ACCEPT so_error 0x%x\n", so->so_error); | |
557 | ENDDEBUG | |
558 | so->so_error = 0; | |
559 | if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTED)== 0) { | |
560 | error = EWOULDBLOCK; | |
561 | break; | |
562 | } | |
563 | while ((so->so_state & SS_ISCONNECTED) == 0 && so->so_error == 0) { | |
564 | sleep((caddr_t)&so->so_timeo, PZERO+1); | |
565 | } | |
566 | if (so->so_error) { | |
567 | error = so->so_error; | |
568 | } else { | |
569 | struct sockaddr *sa = mtod(nam, struct sockaddr *); | |
570 | ||
571 | nam->m_len = sizeof (struct sockaddr); | |
572 | (tpcb->tp_nlproto->nlp_getnetaddr)(so->so_pcb, sa, TP_FOREIGN); | |
573 | ||
574 | switch(sa->sa_family = sototpcb(so)->tp_domain) { | |
575 | case AF_INET: | |
576 | satosin(sa)->sin_port = | |
577 | (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, TP_FOREIGN); | |
578 | break; | |
579 | case AF_ISO: | |
580 | satosiso(sa)->siso_tsuffix = | |
581 | (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, TP_FOREIGN); | |
582 | /* doesn't cover the case where the suffix is extended - | |
583 | * grotesque - the user *has* to do the getsockopt */ | |
584 | break; | |
585 | } | |
586 | IFDEBUG(D_REQUEST) | |
587 | printf("ACCEPT PEERADDDR:"); | |
588 | dump_buf(sa, sizeof(struct sockaddr)); | |
589 | ENDDEBUG | |
590 | } | |
591 | IFPERF(tpcb) | |
592 | u_int lsufx, fsufx; | |
593 | lsufx = *(u_int *)(tpcb->tp_lsuffix); | |
594 | fsufx = *(u_int *)(tpcb->tp_fsuffix); | |
595 | ||
596 | tpmeas( tpcb->tp_lref, TPtime_open, | |
597 | &time, lsufx, fsufx, tpcb->tp_fref); | |
598 | ENDPERF | |
599 | break; | |
600 | ||
601 | case PRU_RCVD: | |
602 | IFTRACE(D_DATA) | |
603 | tptraceTPCB(TPPTmisc, | |
604 | "RCVD BF: lcredit sent_lcdt cc hiwat \n", | |
605 | tpcb->tp_lcredit, tpcb->tp_sent_lcdt, | |
606 | so->so_rcv.sb_cc, so->so_rcv.sb_hiwat); | |
607 | LOCAL_CREDIT(tpcb); | |
608 | tptraceTPCB(TPPTmisc, | |
609 | "PRU_RCVD AF sbspace lcredit hiwat cc", | |
610 | sbspace(&so->so_rcv), tpcb->tp_lcredit, | |
611 | so->so_rcv.sb_cc, so->so_rcv.sb_hiwat); | |
612 | ENDTRACE | |
613 | error = DoEvent(T_USR_rcvd); | |
614 | break; | |
615 | ||
616 | case PRU_RCVOOB: | |
617 | if ((so->so_state & SS_ISCONNECTED) == 0) { | |
618 | error = ENOTCONN; | |
619 | break; | |
620 | } | |
621 | if( ! tpcb->tp_xpd_service ) { | |
622 | error = EOPNOTSUPP; | |
623 | break; | |
624 | } | |
625 | /* kludge - nam is really flags here */ | |
626 | error = tp_rcvoob(tpcb, so, m, outflags, (int)nam); | |
627 | break; | |
628 | ||
629 | case PRU_SENDOOB: | |
630 | if ((so->so_state & SS_ISCONNECTED) == 0) { | |
631 | error = ENOTCONN; | |
632 | break; | |
633 | } | |
634 | if( ! tpcb->tp_xpd_service ) { | |
635 | error = EOPNOTSUPP; | |
636 | break; | |
637 | } | |
638 | error = tp_sendoob(tpcb, so, m, outflags); | |
639 | break; | |
640 | ||
641 | case PRU_SENDEOT: | |
642 | eotsdu = 1; | |
643 | /* fall through */ | |
644 | case PRU_SEND: | |
645 | /* | |
646 | * The protocol machine copies mbuf chains, | |
647 | * prepends headers, assigns seq numbers, and | |
648 | * puts the packets on the device. | |
649 | * When they are acked they are removed from the socket buf. | |
650 | * | |
651 | * sosend calls this up until sbspace goes negative. | |
652 | * Sbspace may be made negative by appending this mbuf chain, | |
653 | * possibly by a whole cluster. | |
654 | */ | |
655 | if ((so->so_state & SS_ISCONNECTED) == 0) { | |
656 | error = ENOTCONN; | |
657 | break; | |
658 | } | |
659 | { | |
660 | register struct mbuf *n; | |
661 | register int len=0; | |
662 | register struct sockbuf *sb = &so->so_snd; | |
663 | ||
664 | n = m; | |
665 | while (n) { /* Could have eotsdu and no data.(presently MUST have | |
666 | * an mbuf though, even if its length == 0) | |
667 | */ | |
668 | len += n->m_len; | |
669 | if( n->m_next == MNULL && eotsdu ) { | |
670 | CHANGE_MTYPE(n, TPMT_EOT); | |
671 | } | |
672 | n = n->m_next; | |
673 | } | |
674 | IFPERF(tpcb) | |
675 | PStat(tpcb, Nb_from_sess) += len; | |
676 | tpmeas(tpcb->tp_lref, TPtime_from_session, 0, 0, | |
677 | PStat(tpcb, Nb_from_sess), len); | |
678 | ENDPERF | |
679 | IFDEBUG(D_SYSCALL) | |
680 | printf( | |
681 | "PRU_SEND: eot %d before sbappend 0x%x len 0x%x to sb @ 0x%x\n", | |
682 | eotsdu, m,len, &sb->sb_mb); | |
683 | dump_mbuf(sb->sb_mb, "so_snd.sb_mb"); | |
684 | dump_mbuf(m, "m : to be added"); | |
685 | ENDDEBUG | |
686 | /* The last mbuf has type TPMT_EOT so it will never be compressed | |
687 | * with TPMT_DATA mbufs, but if this was an EOTSDU request w/o | |
688 | * any data, the only way to keep this mbuf from being thrown | |
689 | * away is to link it through the m_act field | |
690 | * We are ASSUMING that if there are any data at all with this | |
691 | * request, the last mbuf will be non-empty!!! | |
692 | */ | |
693 | if( m->m_type == TPMT_EOT ) /* first mbuf in chain is EOT? */ | |
694 | sbappendrecord(sb, m); /* to keep 2 TPMT_EOTs from being | |
695 | compressed */ | |
696 | else | |
697 | sbappend(sb, m); | |
698 | IFDEBUG(D_SYSCALL) | |
699 | printf("PRU_SEND: eot %d after sbappend 0x%x len 0x%x\n", | |
700 | eotsdu, m,len); | |
701 | dump_mbuf(sb->sb_mb, "so_snd.sb_mb"); | |
702 | ENDDEBUG | |
703 | u.u_r.r_val1 += len; | |
704 | error = DoEvent(T_DATA_req); | |
705 | IFDEBUG(D_SYSCALL) | |
706 | printf("PRU_SEND: after driver error 0x%x \n",error); | |
707 | ENDDEBUG | |
708 | } | |
709 | break; | |
710 | ||
711 | case PRU_SOCKADDR: { | |
712 | struct sockaddr *sa = mtod(nam, struct sockaddr *); | |
713 | ||
714 | nam->m_len = sizeof (struct sockaddr); | |
715 | (tpcb->tp_nlproto->nlp_getnetaddr)(so->so_pcb, sa, TP_LOCAL); | |
716 | switch ( sa->sa_family = sototpcb(so)->tp_domain ) { | |
717 | case AF_INET: | |
718 | satosin(sa)->sin_port = | |
719 | (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, TP_LOCAL); | |
720 | break; | |
721 | case AF_ISO: | |
722 | satosiso(sa)->siso_tsuffix = | |
723 | (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, TP_LOCAL); | |
724 | break; | |
725 | } | |
726 | } | |
727 | break; | |
728 | ||
729 | case PRU_PEERADDR: | |
730 | if( (so->so_state & SS_ISCONNECTED) && | |
731 | (so->so_state & SS_ISDISCONNECTING) == 0) { | |
732 | struct sockaddr *sa = mtod(nam, struct sockaddr *); | |
733 | ||
734 | nam->m_len = sizeof (struct sockaddr); | |
735 | ||
736 | (tpcb->tp_nlproto->nlp_getnetaddr)(so->so_pcb, sa, TP_FOREIGN); | |
737 | ||
738 | switch ( sa->sa_family = sototpcb(so)->tp_domain ) { | |
739 | case AF_INET: | |
740 | satosin(sa)->sin_port = | |
741 | (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, TP_FOREIGN); | |
742 | break; | |
743 | case AF_ISO: | |
744 | satosiso(sa)->siso_tsuffix = | |
745 | (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, TP_FOREIGN); | |
746 | break; | |
747 | } | |
748 | IFDEBUG(D_REQUEST) | |
749 | printf("PEERADDDR:"); | |
750 | dump_buf(sa, sizeof(struct sockaddr)); | |
751 | ENDDEBUG | |
752 | } else | |
753 | error = ENOTCONN; | |
754 | break; | |
755 | ||
756 | case PRU_CONTROL: | |
757 | error = EOPNOTSUPP; | |
758 | break; | |
759 | ||
760 | case PRU_PROTOSEND: | |
761 | case PRU_PROTORCV: | |
762 | case PRU_SENSE: | |
763 | case PRU_SLOWTIMO: | |
764 | case PRU_FASTTIMO: | |
765 | error = EOPNOTSUPP; | |
766 | break; | |
767 | ||
768 | default: | |
769 | #ifdef ARGO_DEBUG | |
770 | printf("tp_usrreq UNKNOWN PRU %d\n", req); | |
771 | #endif ARGO_DEBUG | |
772 | error = EOPNOTSUPP; | |
773 | } | |
774 | ||
775 | IFDEBUG(D_REQUEST) | |
776 | printf("returning from tp_usrreq(so 0x%x) error 0x%x\n", so, error); | |
777 | ENDDEBUG | |
778 | IFTRACE(D_REQUEST) | |
779 | tptraceTPCB(TPPTusrreq, "END req so m state [", req, so, m, | |
780 | tpcb?0:tpcb->tp_state); | |
781 | ENDTRACE | |
782 | splx(s); | |
783 | return error; | |
784 | } |