Commit | Line | Data |
---|---|---|
4a61b6ff | 1 | /*********************************************************** |
7b25382f | 2 | Copyright IBM Corporation 1987 |
4a61b6ff KS |
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 $ | |
03733bb1 | 32 | * @(#)tp_usrreq.c 7.6 (Berkeley) %G% |
4a61b6ff KS |
33 | * |
34 | * tp_usrreq(), the fellow that gets called from most of the socket code. | |
35 | * Pretty straighforward. | |
36 | * THe only really awful stuff here is the OOB processing, which is done | |
37 | * wholly here. | |
38 | * tp_rcvoob() and tp_sendoob() are contained here and called by tp_usrreq(). | |
39 | */ | |
40 | ||
41 | #ifndef lint | |
42 | static char *rcsid = "$Header: tp_usrreq.c,v 5.4 88/11/18 17:29:18 nhall Exp $"; | |
43 | #endif lint | |
44 | ||
45 | #include "param.h" | |
46 | #include "systm.h" | |
4a61b6ff KS |
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 | ||
a50e2bc0 KS |
55 | #include "tp_param.h" |
56 | #include "tp_timer.h" | |
57 | #include "tp_stat.h" | |
58 | #include "tp_seq.h" | |
59 | #include "tp_ip.h" | |
60 | #include "tp_pcb.h" | |
61 | #include "argo_debug.h" | |
62 | #include "tp_trace.h" | |
63 | #include "tp_meas.h" | |
64 | #include "iso.h" | |
65 | #include "iso_errno.h" | |
4a61b6ff KS |
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) { | |
a50e2bc0 KS |
94 | printf("%x : Len %x Data %x A %x Nx %x Tp %x\n", |
95 | n, n->m_len, n->m_data, n->m_act, n->m_next, n->m_type); | |
4a61b6ff KS |
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 | */ | |
4a61b6ff KS |
138 | tp_rcvoob(tpcb, so, m, outflags, inflags) |
139 | struct tp_pcb *tpcb; | |
140 | register struct socket *so; | |
141 | register struct mbuf *m; | |
142 | int *outflags; | |
143 | int inflags; | |
144 | { | |
145 | register struct mbuf *n; | |
a50e2bc0 | 146 | register struct sockbuf *sb = &so->so_rcv; |
4a61b6ff KS |
147 | struct tp_event E; |
148 | int error = 0; | |
a50e2bc0 | 149 | register struct mbuf **nn; |
4a61b6ff KS |
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: | |
4a61b6ff KS |
160 | if ((((so->so_state & SS_ISCONNECTED) == 0) |
161 | || (so->so_state & SS_ISDISCONNECTING) != 0) && | |
162 | (so->so_proto->pr_flags & PR_CONNREQUIRED)) { | |
163 | return ENOTCONN; | |
164 | } | |
165 | ||
a50e2bc0 KS |
166 | /* Take the first mbuf off the chain. |
167 | * Each XPD TPDU gives you a complete TSDU so the chains don't get | |
168 | * coalesced, but one TSDU may span several mbufs. | |
169 | * Nevertheless, since n should have a most 16 bytes, it | |
170 | * will fit into m. (size was checked in tp_input() ) | |
171 | */ | |
172 | ||
173 | /* | |
174 | * Code for excision of OOB data should be added to | |
175 | * uipc_socket2.c (like sbappend). | |
176 | */ | |
177 | ||
44f52ea5 | 178 | sblock(sb); |
a50e2bc0 KS |
179 | for (nn = &sb->sb_mb; n = *nn; nn = &n->m_act) |
180 | if (n->m_type == MT_OOBDATA) | |
181 | break; | |
182 | ||
183 | if (n == 0) { | |
4a61b6ff KS |
184 | ASSERT( (tpcb->tp_flags & TPF_DISC_DATA_IN) == 0 ); |
185 | IFDEBUG(D_XPD) | |
186 | printf("RCVOOB: empty queue!\n"); | |
187 | ENDDEBUG | |
44f52ea5 | 188 | sbunlock(sb); |
4a61b6ff KS |
189 | if (so->so_state & SS_NBIO) { |
190 | return EWOULDBLOCK; | |
191 | } | |
4a61b6ff KS |
192 | sbwait(sb); |
193 | goto restart; | |
194 | } | |
4a61b6ff KS |
195 | m->m_len = 0; |
196 | ||
197 | /* Assuming at most one xpd tpdu is in the buffer at once */ | |
198 | while ( n != MNULL ) { | |
199 | m->m_len += n->m_len; | |
a50e2bc0 KS |
200 | bcopy(mtod(n, caddr_t), mtod(m, caddr_t), (unsigned)n->m_len); |
201 | m->m_data += n->m_len; /* so mtod() in bcopy() above gives right addr */ | |
4a61b6ff KS |
202 | n = n->m_next; |
203 | } | |
a50e2bc0 KS |
204 | m->m_data = m->m_dat; |
205 | m->m_flags |= M_EOR; | |
4a61b6ff KS |
206 | |
207 | IFDEBUG(D_XPD) | |
208 | printf("tp_rcvoob: xpdlen 0x%x\n", m->m_len); | |
209 | dump_mbuf(so->so_rcv.sb_mb, "RCVOOB: Rcv socketbuf"); | |
210 | dump_mbuf(sb->sb_mb, "RCVOOB: Xrcv socketbuf"); | |
211 | ENDDEBUG | |
212 | ||
a50e2bc0 KS |
213 | if( (inflags & MSG_PEEK) == 0 ) { |
214 | n = *nn; | |
215 | *nn = n->m_act; | |
216 | sb->sb_cc -= m->m_len; | |
217 | } | |
4a61b6ff KS |
218 | |
219 | release: | |
220 | sbunlock(sb); | |
221 | ||
222 | IFTRACE(D_XPD) | |
223 | tptraceTPCB(TPPTmisc, "PRU_RCVOOB @ release sb_cc m_len", | |
224 | tpcb->tp_Xrcv.sb_cc, m->m_len,0,0 ); | |
225 | ENDTRACE | |
4a61b6ff KS |
226 | if (error == 0) |
227 | error = DoEvent(T_USR_Xrcvd); | |
228 | return error; | |
229 | } | |
230 | ||
231 | /* | |
232 | * CALLED FROM: | |
233 | * tp_usrreq(), PRU_SENDOOB | |
234 | * FUNCTION and ARGUMENTS: | |
235 | * Send what's in the mbuf chain (m) as an XPD TPDU. | |
236 | * The mbuf may not contain more then 16 bytes of data. | |
237 | * XPD TSDUs aren't segmented, so they translate into | |
238 | * exactly one XPD TPDU, with EOT bit set. | |
239 | * RETURN VALUE: | |
240 | * EWOULDBLOCK if socket is in non-blocking mode and the previous | |
241 | * xpd data haven't been acked yet. | |
242 | * EMSGSIZE if trying to send > max-xpd bytes (16) | |
243 | * ENOBUFS if ran out of mbufs | |
244 | */ | |
4a61b6ff KS |
245 | tp_sendoob(tpcb, so, xdata, outflags) |
246 | struct tp_pcb *tpcb; | |
247 | register struct socket *so; | |
248 | register struct mbuf *xdata; | |
249 | int *outflags; /* not used */ | |
250 | { | |
251 | /* | |
252 | * Each mbuf chain represents a sequence # in the XPD seq space. | |
253 | * The first one in the queue has sequence # tp_Xuna. | |
254 | * When we add to the XPD queue, we stuff a zero-length | |
255 | * mbuf (mark) into the DATA queue, with its sequence number in m_next | |
256 | * to be assigned to this XPD tpdu, so data xfer can stop | |
257 | * when it reaches the zero-length mbuf if this XPD TPDU hasn't | |
258 | * yet been acknowledged. | |
259 | */ | |
260 | register struct sockbuf *sb = &(tpcb->tp_Xsnd); | |
261 | register struct mbuf *xmark; | |
262 | register int len=0; | |
263 | struct tp_event E; | |
264 | ||
265 | IFDEBUG(D_XPD) | |
266 | printf("tp_sendoob:"); | |
267 | if(xdata) | |
268 | printf("xdata len 0x%x\n", xdata->m_len); | |
269 | ENDDEBUG | |
4a61b6ff KS |
270 | /* DO NOT LOCK the Xsnd buffer!!!! You can have at MOST one |
271 | * socket buf locked at any time!!! (otherwise you might | |
272 | * sleep() in sblock() w/ a signal pending and cause the | |
273 | * system call to be aborted w/ a locked socketbuf, which | |
274 | * is a problem. So the so_snd buffer lock | |
275 | * (done in sosend()) serves as the lock for Xpd. | |
276 | */ | |
44f52ea5 | 277 | if (sb->sb_mb) { /* Anything already in eXpedited data sockbuf? */ |
4a61b6ff KS |
278 | if (so->so_state & SS_NBIO) { |
279 | return EWOULDBLOCK; | |
280 | } | |
44f52ea5 KS |
281 | while (sb->sb_mb) { |
282 | sbunlock(&so->so_snd); /* already locked by sosend */ | |
283 | sbwait(&so->so_snd); | |
284 | sblock(&so->so_snd); /* sosend will unlock on return */ | |
285 | } | |
4a61b6ff KS |
286 | } |
287 | ||
288 | if (xdata == (struct mbuf *)0) { | |
289 | /* empty xpd packet */ | |
a50e2bc0 | 290 | MGETHDR(xdata, M_WAIT, MT_OOBDATA); |
4a61b6ff KS |
291 | if (xdata == NULL) { |
292 | return ENOBUFS; | |
293 | } | |
294 | xdata->m_len = 0; | |
a50e2bc0 | 295 | xdata->m_pkthdr.len = 0; |
4a61b6ff KS |
296 | } |
297 | IFDEBUG(D_XPD) | |
298 | printf("tp_sendoob 1:"); | |
299 | if(xdata) | |
300 | printf("xdata len 0x%x\n", xdata->m_len); | |
301 | ENDDEBUG | |
302 | xmark = xdata; /* temporary use of variable xmark */ | |
303 | while (xmark) { | |
304 | len += xmark->m_len; | |
305 | xmark = xmark->m_next; | |
306 | } | |
307 | if (len > TP_MAX_XPD_DATA) { | |
308 | return EMSGSIZE; | |
309 | } | |
310 | IFDEBUG(D_XPD) | |
311 | printf("tp_sendoob 2:"); | |
312 | if(xdata) | |
313 | printf("xdata len 0x%x\n", len); | |
314 | ENDDEBUG | |
315 | ||
4a61b6ff KS |
316 | |
317 | IFTRACE(D_XPD) | |
44f52ea5 | 318 | tptraceTPCB(TPPTmisc, "XPD mark m_next ", xdata->m_next, 0, 0, 0); |
4a61b6ff KS |
319 | ENDTRACE |
320 | ||
4a61b6ff KS |
321 | sbappendrecord(sb, xdata); |
322 | ||
323 | IFDEBUG(D_XPD) | |
324 | printf("tp_sendoob len 0x%x\n", len); | |
325 | dump_mbuf(so->so_snd.sb_mb, "XPD request Regular sndbuf:"); | |
326 | dump_mbuf(tpcb->tp_Xsnd.sb_mb, "XPD request Xsndbuf:"); | |
327 | ENDDEBUG | |
4a61b6ff | 328 | return DoEvent(T_XPD_req); |
4a61b6ff KS |
329 | } |
330 | ||
331 | /* | |
332 | * CALLED FROM: | |
333 | * the socket routines | |
334 | * FUNCTION and ARGUMENTS: | |
335 | * Handles all "user requests" except the [gs]ockopts() requests. | |
336 | * The argument (req) is the request type (PRU*), | |
337 | * (m) is an mbuf chain, generally used for send and | |
338 | * receive type requests only. | |
339 | * (nam) is used for addresses usually, in particular for the bind request. | |
340 | * | |
4a61b6ff KS |
341 | */ |
342 | /*ARGSUSED*/ | |
343 | ProtoHook | |
a50e2bc0 | 344 | tp_usrreq(so, req, m, nam, rightsp, controlp) |
4a61b6ff KS |
345 | struct socket *so; |
346 | u_int req; | |
a50e2bc0 | 347 | struct mbuf *m, *nam, *rightsp, *controlp; |
4a61b6ff KS |
348 | { |
349 | register struct tp_pcb *tpcb = sototpcb(so); | |
350 | int s = splnet(); | |
351 | int error = 0; | |
a50e2bc0 | 352 | int flags, *outflags = &flags; |
4a61b6ff KS |
353 | u_long eotsdu = 0; |
354 | struct tp_event E; | |
355 | ||
356 | IFDEBUG(D_REQUEST) | |
357 | printf("usrreq(0x%x,%d,0x%x,0x%x,0x%x)\n",so,req,m,nam,outflags); | |
358 | if(so->so_error) | |
359 | printf("WARNING!!! so->so_error is 0x%x\n", so->so_error); | |
360 | ENDDEBUG | |
361 | IFTRACE(D_REQUEST) | |
362 | tptraceTPCB(TPPTusrreq, "req so m state [", req, so, m, | |
363 | tpcb?tpcb->tp_state:0); | |
364 | ENDTRACE | |
365 | ||
366 | if ((u_int)tpcb == 0 && req != PRU_ATTACH) { | |
367 | IFTRACE(D_REQUEST) | |
368 | tptraceTPCB(TPPTusrreq, "req failed NO TPCB[", 0, 0, 0, 0); | |
369 | ENDTRACE | |
370 | splx(s); | |
371 | return ENOTCONN; | |
372 | } | |
373 | ||
4a61b6ff KS |
374 | switch (req) { |
375 | ||
376 | case PRU_ATTACH: | |
377 | if (tpcb) { | |
378 | error = EISCONN; | |
379 | break; | |
380 | } | |
381 | if( error = tp_attach(so, so->so_proto->pr_domain->dom_family ) ) | |
382 | break; | |
383 | tpcb = sototpcb(so); | |
384 | break; | |
385 | ||
386 | case PRU_ABORT: /* called from close() */ | |
387 | /* called for each incoming connect queued on the | |
388 | * parent (accepting) socket | |
389 | */ | |
390 | if( tpcb->tp_state == TP_OPEN ) { | |
391 | E.ATTR(T_DISC_req).e_reason = E_TP_NO_SESSION; | |
392 | error = DoEvent(T_DISC_req); /* pretend it was a close() */ | |
393 | break; | |
394 | } /* else DROP THROUGH */ | |
395 | ||
396 | case PRU_DETACH: /* called from close() */ | |
397 | /* called only after disconnect was called */ | |
398 | error = DoEvent(T_DETACH); | |
a50e2bc0 KS |
399 | if (tpcb->tp_state == TP_CLOSED) { |
400 | free((caddr_t)tpcb, M_PCB); | |
401 | tpcb = 0; | |
402 | } | |
4a61b6ff KS |
403 | break; |
404 | ||
405 | case PRU_SHUTDOWN: | |
406 | /* recv end may have been released; local credit might be zero */ | |
407 | case PRU_DISCONNECT: | |
408 | E.ATTR(T_DISC_req).e_reason = E_TP_NORMAL_DISC; | |
409 | error = DoEvent(T_DISC_req); | |
410 | break; | |
411 | ||
412 | case PRU_BIND: | |
413 | error = (tpcb->tp_nlproto->nlp_pcbbind)( so->so_pcb, nam ); | |
414 | if (error == 0) { | |
a50e2bc0 KS |
415 | (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_lsuffixlen, |
416 | tpcb->tp_lsuffix, TP_LOCAL ); | |
4a61b6ff KS |
417 | } |
418 | break; | |
419 | ||
420 | case PRU_LISTEN: | |
44f52ea5 | 421 | if( tpcb->tp_lsuffixlen == 0) { |
4a61b6ff KS |
422 | if( error = (tpcb->tp_nlproto->nlp_pcbbind)(so->so_pcb, MNULL) ) |
423 | break; | |
a50e2bc0 KS |
424 | (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_lsuffixlen, |
425 | tpcb->tp_lsuffix, TP_LOCAL ); | |
4a61b6ff KS |
426 | } |
427 | IFDEBUG(D_TPISO) | |
428 | if(tpcb->tp_state != TP_CLOSED) | |
429 | printf("LISTEN ERROR: state 0x%x\n", tpcb->tp_state); | |
430 | ENDDEBUG | |
431 | error = DoEvent(T_LISTEN_req); | |
432 | break; | |
433 | ||
434 | case PRU_CONNECT2: | |
435 | error = EOPNOTSUPP; /* for unix domain sockets */ | |
436 | break; | |
437 | ||
438 | case PRU_CONNECT: | |
439 | IFTRACE(D_CONN) | |
440 | tptraceTPCB(TPPTmisc, | |
a50e2bc0 | 441 | "PRU_CONNECT: so 0x%x *SHORT_LSUFXP(tpcb) 0x%x lsuflen 0x%x, class 0x%x", |
4a61b6ff KS |
442 | tpcb->tp_sock, *SHORT_LSUFXP(tpcb), tpcb->tp_lsuffixlen, |
443 | tpcb->tp_class); | |
444 | ENDTRACE | |
445 | IFDEBUG(D_CONN) | |
446 | printf("PRU_CONNECT: so *SHORT_LSUFXP(tpcb) 0x%x lsuflen 0x%x, class 0x%x", | |
447 | tpcb->tp_sock, *SHORT_LSUFXP(tpcb), tpcb->tp_lsuffixlen, | |
448 | tpcb->tp_class); | |
449 | ENDDEBUG | |
44f52ea5 | 450 | if( tpcb->tp_lsuffixlen == 0) { |
4a61b6ff KS |
451 | if( error = (tpcb->tp_nlproto->nlp_pcbbind)(so->so_pcb, MNULL) ) { |
452 | IFDEBUG(D_CONN) | |
453 | printf("pcbbind returns error 0x%x\n", error ); | |
454 | ENDDEBUG | |
455 | break; | |
456 | } | |
a50e2bc0 KS |
457 | (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_lsuffixlen, |
458 | tpcb->tp_lsuffix, TP_LOCAL ); | |
459 | } | |
4a61b6ff KS |
460 | |
461 | IFDEBUG(D_CONN) | |
462 | printf("isop 0x%x isop->isop_socket offset 12 :\n", tpcb->tp_npcb); | |
463 | dump_buf( tpcb->tp_npcb, 16); | |
464 | ENDDEBUG | |
465 | if( error = tp_route_to( nam, tpcb, /* channel */0) ) | |
466 | break; | |
467 | IFDEBUG(D_CONN) | |
468 | printf( | |
469 | "PRU_CONNECT after tpcb 0x%x so 0x%x npcb 0x%x flags 0x%x\n", | |
470 | tpcb, so, tpcb->tp_npcb, tpcb->tp_flags); | |
471 | printf("isop 0x%x isop->isop_socket offset 12 :\n", tpcb->tp_npcb); | |
472 | dump_buf( tpcb->tp_npcb, 16); | |
473 | ENDDEBUG | |
a50e2bc0 | 474 | if( tpcb->tp_fsuffixlen == 0) { |
4a61b6ff | 475 | /* didn't set peer extended suffix */ |
a50e2bc0 KS |
476 | (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_fsuffixlen, |
477 | tpcb->tp_fsuffix, TP_FOREIGN ); | |
4a61b6ff KS |
478 | } |
479 | (void) (tpcb->tp_nlproto->nlp_mtu)(so, so->so_pcb, | |
480 | &tpcb->tp_l_tpdusize, &tpcb->tp_tpdusize, 0); | |
481 | if( tpcb->tp_state == TP_CLOSED) { | |
482 | soisconnecting(so); | |
483 | error = DoEvent(T_CONN_req); | |
484 | } else { | |
485 | (tpcb->tp_nlproto->nlp_pcbdisc)(so->so_pcb); | |
486 | error = EISCONN; | |
487 | } | |
488 | IFPERF(tpcb) | |
489 | u_int lsufx, fsufx; | |
7b25382f KS |
490 | lsufx = *(u_short *)(tpcb->tp_lsuffix); |
491 | fsufx = *(u_short *)(tpcb->tp_fsuffix); | |
4a61b6ff KS |
492 | |
493 | tpmeas( tpcb->tp_lref, | |
494 | TPtime_open | (tpcb->tp_xtd_format <<4 ), | |
495 | &time, lsufx, fsufx, tpcb->tp_fref); | |
496 | ENDPERF | |
497 | break; | |
498 | ||
499 | case PRU_ACCEPT: | |
44f52ea5 | 500 | (tpcb->tp_nlproto->nlp_getnetaddr)(so->so_pcb, nam, TP_FOREIGN); |
4a61b6ff | 501 | IFDEBUG(D_REQUEST) |
44f52ea5 KS |
502 | printf("ACCEPT PEERADDDR:"); |
503 | dump_buf(mtod(nam, char *), nam->m_len); | |
4a61b6ff | 504 | ENDDEBUG |
4a61b6ff KS |
505 | IFPERF(tpcb) |
506 | u_int lsufx, fsufx; | |
7b25382f KS |
507 | lsufx = *(u_short *)(tpcb->tp_lsuffix); |
508 | fsufx = *(u_short *)(tpcb->tp_fsuffix); | |
4a61b6ff KS |
509 | |
510 | tpmeas( tpcb->tp_lref, TPtime_open, | |
511 | &time, lsufx, fsufx, tpcb->tp_fref); | |
512 | ENDPERF | |
513 | break; | |
514 | ||
515 | case PRU_RCVD: | |
44f52ea5 KS |
516 | if (so->so_state & SS_ISCONFIRMING) { |
517 | if (tpcb->tp_state == TP_CONFIRMING) | |
518 | error = tp_confirm(tpcb); | |
519 | break; | |
520 | } | |
4a61b6ff KS |
521 | IFTRACE(D_DATA) |
522 | tptraceTPCB(TPPTmisc, | |
523 | "RCVD BF: lcredit sent_lcdt cc hiwat \n", | |
524 | tpcb->tp_lcredit, tpcb->tp_sent_lcdt, | |
525 | so->so_rcv.sb_cc, so->so_rcv.sb_hiwat); | |
526 | LOCAL_CREDIT(tpcb); | |
527 | tptraceTPCB(TPPTmisc, | |
528 | "PRU_RCVD AF sbspace lcredit hiwat cc", | |
529 | sbspace(&so->so_rcv), tpcb->tp_lcredit, | |
530 | so->so_rcv.sb_cc, so->so_rcv.sb_hiwat); | |
531 | ENDTRACE | |
a50e2bc0 KS |
532 | IFDEBUG(D_REQUEST) |
533 | printf("RCVD: cc %d space %d hiwat %d\n", | |
534 | so->so_rcv.sb_cc, sbspace(&so->so_rcv), | |
535 | so->so_rcv.sb_hiwat); | |
536 | ENDDEBUG | |
537 | if (((int)nam) & MSG_OOB) | |
538 | error = DoEvent(T_USR_Xrcvd); | |
539 | else | |
540 | error = DoEvent(T_USR_rcvd); | |
4a61b6ff KS |
541 | break; |
542 | ||
543 | case PRU_RCVOOB: | |
544 | if ((so->so_state & SS_ISCONNECTED) == 0) { | |
545 | error = ENOTCONN; | |
546 | break; | |
547 | } | |
548 | if( ! tpcb->tp_xpd_service ) { | |
549 | error = EOPNOTSUPP; | |
550 | break; | |
551 | } | |
552 | /* kludge - nam is really flags here */ | |
553 | error = tp_rcvoob(tpcb, so, m, outflags, (int)nam); | |
554 | break; | |
555 | ||
44f52ea5 | 556 | case PRU_SEND: |
4a61b6ff | 557 | case PRU_SENDOOB: |
a50e2bc0 | 558 | if (controlp && (error = tp_snd_control(controlp, so, &m))) |
4a61b6ff | 559 | break; |
44f52ea5 KS |
560 | if (so->so_state & SS_ISCONFIRMING) { |
561 | if (tpcb->tp_state == TP_CONFIRMING) | |
562 | error = tp_confirm(tpcb); | |
563 | if (m) { | |
564 | if (error == 0 && m->m_len != 0) | |
565 | error = ENOTCONN; | |
566 | m_freem(m); | |
567 | m = 0; | |
568 | } | |
569 | break; | |
570 | } | |
a50e2bc0 KS |
571 | if (m == 0) |
572 | break; | |
44f52ea5 KS |
573 | |
574 | if (req == PRU_SENDOOB) { | |
575 | if (tpcb->tp_xpd_service == 0) { | |
576 | error = EOPNOTSUPP; | |
577 | break; | |
578 | } | |
579 | error = tp_sendoob(tpcb, so, m, outflags); | |
4a61b6ff KS |
580 | break; |
581 | } | |
4a61b6ff KS |
582 | /* |
583 | * The protocol machine copies mbuf chains, | |
584 | * prepends headers, assigns seq numbers, and | |
585 | * puts the packets on the device. | |
586 | * When they are acked they are removed from the socket buf. | |
587 | * | |
588 | * sosend calls this up until sbspace goes negative. | |
589 | * Sbspace may be made negative by appending this mbuf chain, | |
590 | * possibly by a whole cluster. | |
591 | */ | |
4a61b6ff | 592 | { |
a50e2bc0 | 593 | register struct mbuf *n = m; |
4a61b6ff KS |
594 | register int len=0; |
595 | register struct sockbuf *sb = &so->so_snd; | |
a50e2bc0 KS |
596 | int maxsize = tpcb->tp_l_tpdusize |
597 | - tp_headersize(DT_TPDU_type, tpcb) | |
598 | - (tpcb->tp_use_checksum?4:0) ; | |
599 | int totlen = n->m_pkthdr.len; | |
7b25382f | 600 | struct mbuf *nn; |
a50e2bc0 KS |
601 | |
602 | /* | |
603 | * Could have eotsdu and no data.(presently MUST have | |
604 | * an mbuf though, even if its length == 0) | |
605 | */ | |
44f52ea5 | 606 | if (n->m_flags & M_EOR) { |
a50e2bc0 | 607 | eotsdu = 1; |
44f52ea5 KS |
608 | n->m_flags &= ~M_EOR; |
609 | } | |
4a61b6ff | 610 | IFPERF(tpcb) |
a50e2bc0 | 611 | PStat(tpcb, Nb_from_sess) += totlen; |
4a61b6ff | 612 | tpmeas(tpcb->tp_lref, TPtime_from_session, 0, 0, |
a50e2bc0 | 613 | PStat(tpcb, Nb_from_sess), totlen); |
4a61b6ff KS |
614 | ENDPERF |
615 | IFDEBUG(D_SYSCALL) | |
616 | printf( | |
617 | "PRU_SEND: eot %d before sbappend 0x%x len 0x%x to sb @ 0x%x\n", | |
a50e2bc0 | 618 | eotsdu, m,len, sb); |
4a61b6ff KS |
619 | dump_mbuf(sb->sb_mb, "so_snd.sb_mb"); |
620 | dump_mbuf(m, "m : to be added"); | |
621 | ENDDEBUG | |
a50e2bc0 KS |
622 | /* |
623 | * Pre-packetize the data in the sockbuf | |
624 | * according to negotiated mtu. Do it here | |
625 | * where we can safely wait for mbufs. | |
7b25382f KS |
626 | * |
627 | * This presumes knowledge of sockbuf conventions. | |
4a61b6ff | 628 | */ |
7b25382f KS |
629 | len = 0; |
630 | if (n = sb->sb_mb) | |
631 | while (n->m_act) | |
632 | n = n->m_act; | |
03733bb1 | 633 | if ((nn = n) && n->m_pkthdr.len < maxsize) { |
7b25382f | 634 | int space = maxsize - n->m_pkthdr.len; |
03733bb1 KS |
635 | |
636 | do { | |
637 | if (n->m_flags & M_EOR) | |
638 | goto on1; | |
639 | } while (n->m_next && (n = n->m_next)); | |
640 | nn->m_pkthdr.len += space; | |
7b25382f KS |
641 | if (m->m_pkthdr.len <= space) { |
642 | n->m_next = m; | |
03733bb1 | 643 | sballoc(sb, m); |
7b25382f KS |
644 | if (eotsdu) |
645 | nn->m_flags |= M_EOR; | |
646 | goto on2; | |
647 | } else { | |
03733bb1 KS |
648 | nn->m_next = m_copym(m, 0, space, M_WAIT); |
649 | sballoc(sb, nn->m_next); | |
650 | m_adj(m, space); | |
7b25382f KS |
651 | } |
652 | } | |
653 | on1: len++; | |
654 | for (n = m; n->m_pkthdr.len > maxsize;) { | |
655 | nn = m_copym(n, 0, len, M_WAIT); | |
a50e2bc0 KS |
656 | sbappendrecord(sb, nn); |
657 | m_adj(n, maxsize); | |
7b25382f | 658 | len++; |
a50e2bc0 | 659 | } |
7b25382f | 660 | if (eotsdu) |
44f52ea5 | 661 | n->m_flags |= M_EOR; |
7b25382f KS |
662 | sbappendrecord(sb, n); |
663 | on2: | |
664 | IFTRACE(D_DATA) | |
665 | tptraceTPCB(TPPTmisc, | |
666 | "SEND BF: maxsize totlen frags eotsdu", | |
667 | maxsize, totlen, len, eotsdu); | |
668 | ENDTRACE | |
4a61b6ff KS |
669 | IFDEBUG(D_SYSCALL) |
670 | printf("PRU_SEND: eot %d after sbappend 0x%x len 0x%x\n", | |
a50e2bc0 | 671 | eotsdu, n, len); |
4a61b6ff KS |
672 | dump_mbuf(sb->sb_mb, "so_snd.sb_mb"); |
673 | ENDDEBUG | |
4a61b6ff KS |
674 | error = DoEvent(T_DATA_req); |
675 | IFDEBUG(D_SYSCALL) | |
676 | printf("PRU_SEND: after driver error 0x%x \n",error); | |
a50e2bc0 KS |
677 | printf("so_snd 0x%x cc 0t%d mbcnt 0t%d\n", |
678 | sb, sb->sb_cc, sb->sb_mbcnt); | |
679 | dump_mbuf(sb->sb_mb, "so_snd.sb_mb after driver"); | |
4a61b6ff KS |
680 | ENDDEBUG |
681 | } | |
682 | break; | |
683 | ||
a50e2bc0 KS |
684 | case PRU_SOCKADDR: |
685 | (tpcb->tp_nlproto->nlp_getnetaddr)(so->so_pcb, nam, TP_LOCAL); | |
4a61b6ff KS |
686 | break; |
687 | ||
688 | case PRU_PEERADDR: | |
44f52ea5 | 689 | (tpcb->tp_nlproto->nlp_getnetaddr)(so->so_pcb, nam, TP_FOREIGN); |
4a61b6ff KS |
690 | break; |
691 | ||
692 | case PRU_CONTROL: | |
693 | error = EOPNOTSUPP; | |
694 | break; | |
695 | ||
696 | case PRU_PROTOSEND: | |
697 | case PRU_PROTORCV: | |
698 | case PRU_SENSE: | |
699 | case PRU_SLOWTIMO: | |
700 | case PRU_FASTTIMO: | |
701 | error = EOPNOTSUPP; | |
702 | break; | |
703 | ||
704 | default: | |
705 | #ifdef ARGO_DEBUG | |
706 | printf("tp_usrreq UNKNOWN PRU %d\n", req); | |
707 | #endif ARGO_DEBUG | |
708 | error = EOPNOTSUPP; | |
709 | } | |
710 | ||
711 | IFDEBUG(D_REQUEST) | |
44f52ea5 KS |
712 | printf("%s, so 0x%x, tpcb 0x%x, error %d, state %d\n", |
713 | "returning from tp_usrreq", so, tpcb, error, | |
714 | tpcb ? 0 : tpcb->tp_state); | |
4a61b6ff KS |
715 | ENDDEBUG |
716 | IFTRACE(D_REQUEST) | |
717 | tptraceTPCB(TPPTusrreq, "END req so m state [", req, so, m, | |
718 | tpcb?0:tpcb->tp_state); | |
719 | ENDTRACE | |
720 | splx(s); | |
721 | return error; | |
722 | } | |
7b25382f KS |
723 | tp_ltrace(so, uio) |
724 | struct socket *so; | |
725 | struct uio *uio; | |
726 | { | |
727 | IFTRACE(D_DATA) | |
728 | register struct tp_pcb *tpcb = sototpcb(so); | |
729 | if (tpcb) { | |
730 | tptraceTPCB(TPPTmisc, "sosend so resid iovcnt", so, | |
731 | uio->uio_resid, uio->uio_iovcnt, 0); | |
732 | } | |
733 | ENDTRACE | |
734 | } | |
a50e2bc0 | 735 | |
44f52ea5 KS |
736 | tp_confirm(tpcb) |
737 | register struct tp_pcb *tpcb; | |
a50e2bc0 | 738 | { |
44f52ea5 KS |
739 | struct tp_event E; |
740 | if (tpcb->tp_state == TP_CONFIRMING) | |
741 | return DoEvent(T_ACPT_req); | |
742 | printf("Tp confirm called when not confirming; tpcb 0x%x, state 0x%x\n", | |
743 | tpcb, tpcb->tp_state); | |
744 | return 0; | |
a50e2bc0 KS |
745 | } |
746 | ||
747 | /* | |
748 | * Process control data sent with sendmsg() | |
749 | */ | |
750 | tp_snd_control(m0, so, data) | |
751 | register struct mbuf *m0; | |
752 | struct socket *so; | |
753 | register struct mbuf **data; | |
754 | { | |
755 | register struct tp_control_hdr *ch; | |
756 | struct mbuf *m; | |
757 | int error = 0; | |
758 | ||
759 | if (m0 && m0->m_len) { | |
760 | ch = mtod(m0, struct tp_control_hdr *); | |
761 | m0->m_len -= sizeof (*ch); | |
762 | m0->m_data += sizeof (*ch); | |
763 | m = m_copym(m0, 0, M_COPYALL, M_WAIT); | |
764 | error = tp_ctloutput(PRCO_SETOPT, | |
765 | so, ch->cmsg_level, ch->cmsg_type, &m); | |
766 | if (m) | |
767 | m_freem(m); | |
768 | if (ch->cmsg_type == TPOPT_DISC_DATA) { | |
769 | if (data && *data) { | |
770 | m_freem(*data); | |
771 | *data = 0; | |
772 | } | |
773 | m0 = 0; | |
774 | error = tp_usrreq(so, PRU_DISCONNECT, m0, (caddr_t)0, m0, m0); | |
775 | } | |
776 | } | |
777 | return error; | |
778 | } |