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