1 /*
2 * Copyright (c) 1995, Mike Mitchell
3 * Copyright (c) 1984, 1985, 1986, 1987, 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 * This product includes software developed by the University of
17 * California, Berkeley and its contributors.
18 * 4. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 *
34 * @(#)spx_usrreq.h
35 */
36
37 #include <sys/cdefs.h>
38 __FBSDID("$FreeBSD: releng/5.3/sys/netipx/spx_usrreq.c 136588 2004-10-16 08:43:07Z cvs2svn $");
39
40 #include <sys/param.h>
41 #include <sys/lock.h>
42 #include <sys/malloc.h>
43 #include <sys/mbuf.h>
44 #include <sys/mutex.h>
45 #include <sys/proc.h>
46 #include <sys/protosw.h>
47 #include <sys/signalvar.h>
48 #include <sys/socket.h>
49 #include <sys/socketvar.h>
50 #include <sys/sx.h>
51 #include <sys/systm.h>
52
53 #include <net/route.h>
54 #include <netinet/tcp_fsm.h>
55
56 #include <netipx/ipx.h>
57 #include <netipx/ipx_pcb.h>
58 #include <netipx/ipx_var.h>
59 #include <netipx/spx.h>
60 #include <netipx/spx_debug.h>
61 #include <netipx/spx_timer.h>
62 #include <netipx/spx_var.h>
63
64 /*
65 * SPX protocol implementation.
66 */
67 static u_short spx_iss;
68 static u_short spx_newchecks[50];
69 static int spx_hardnosed;
70 static int spx_use_delack = 0;
71 static int traceallspxs = 0;
72 static struct spx spx_savesi;
73 static struct spx_istat spx_istat;
74
75 /* Following was struct spxstat spxstat; */
76 #ifndef spxstat
77 #define spxstat spx_istat.newstats
78 #endif
79
80 static const int spx_backoff[SPX_MAXRXTSHIFT+1] =
81 { 1, 2, 4, 8, 16, 32, 64, 64, 64, 64, 64, 64, 64 };
82
83 static struct spxpcb *spx_close(struct spxpcb *cb);
84 static struct spxpcb *spx_disconnect(struct spxpcb *cb);
85 static struct spxpcb *spx_drop(struct spxpcb *cb, int errno);
86 static int spx_output(struct spxpcb *cb, struct mbuf *m0);
87 static int spx_reass(struct spxpcb *cb, struct spx *si);
88 static void spx_setpersist(struct spxpcb *cb);
89 static void spx_template(struct spxpcb *cb);
90 static struct spxpcb *spx_timers(struct spxpcb *cb, int timer);
91 static struct spxpcb *spx_usrclosed(struct spxpcb *cb);
92
93 static int spx_usr_abort(struct socket *so);
94 static int spx_accept(struct socket *so, struct sockaddr **nam);
95 static int spx_attach(struct socket *so, int proto, struct thread *td);
96 static int spx_bind(struct socket *so, struct sockaddr *nam, struct thread *td);
97 static int spx_connect(struct socket *so, struct sockaddr *nam,
98 struct thread *td);
99 static int spx_detach(struct socket *so);
100 static int spx_usr_disconnect(struct socket *so);
101 static int spx_listen(struct socket *so, struct thread *td);
102 static int spx_rcvd(struct socket *so, int flags);
103 static int spx_rcvoob(struct socket *so, struct mbuf *m, int flags);
104 static int spx_send(struct socket *so, int flags, struct mbuf *m,
105 struct sockaddr *addr, struct mbuf *control,
106 struct thread *td);
107 static int spx_shutdown(struct socket *so);
108 static int spx_sp_attach(struct socket *so, int proto, struct thread *td);
109
110 struct pr_usrreqs spx_usrreqs = {
111 spx_usr_abort, spx_accept, spx_attach, spx_bind,
112 spx_connect, pru_connect2_notsupp, ipx_control, spx_detach,
113 spx_usr_disconnect, spx_listen, ipx_peeraddr, spx_rcvd,
114 spx_rcvoob, spx_send, pru_sense_null, spx_shutdown,
115 ipx_sockaddr, sosend, soreceive, sopoll, pru_sosetlabel_null
116 };
117
118 struct pr_usrreqs spx_usrreq_sps = {
119 spx_usr_abort, spx_accept, spx_sp_attach, spx_bind,
120 spx_connect, pru_connect2_notsupp, ipx_control, spx_detach,
121 spx_usr_disconnect, spx_listen, ipx_peeraddr, spx_rcvd,
122 spx_rcvoob, spx_send, pru_sense_null, spx_shutdown,
123 ipx_sockaddr, sosend, soreceive, sopoll, pru_sosetlabel_null
124 };
125
126 void
127 spx_init()
128 {
129
130 spx_iss = 1; /* WRONG !! should fish it out of TODR */
131 }
132
133 void
134 spx_input(m, ipxp)
135 register struct mbuf *m;
136 register struct ipxpcb *ipxp;
137 {
138 register struct spxpcb *cb;
139 register struct spx *si = mtod(m, struct spx *);
140 register struct socket *so;
141 int dropsocket = 0;
142 short ostate = 0;
143
144 spxstat.spxs_rcvtotal++;
145 if (ipxp == NULL) {
146 panic("No ipxpcb in spx_input\n");
147 return;
148 }
149
150 cb = ipxtospxpcb(ipxp);
151 if (cb == NULL)
152 goto bad;
153
154 if (m->m_len < sizeof(*si)) {
155 if ((m = m_pullup(m, sizeof(*si))) == NULL) {
156 spxstat.spxs_rcvshort++;
157 return;
158 }
159 si = mtod(m, struct spx *);
160 }
161 si->si_seq = ntohs(si->si_seq);
162 si->si_ack = ntohs(si->si_ack);
163 si->si_alo = ntohs(si->si_alo);
164
165 so = ipxp->ipxp_socket;
166
167 if (so->so_options & SO_DEBUG || traceallspxs) {
168 ostate = cb->s_state;
169 spx_savesi = *si;
170 }
171 if (so->so_options & SO_ACCEPTCONN) {
172 struct spxpcb *ocb = cb;
173
174 so = sonewconn(so, 0);
175 if (so == NULL) {
176 goto drop;
177 }
178 /*
179 * This is ugly, but ....
180 *
181 * Mark socket as temporary until we're
182 * committed to keeping it. The code at
183 * ``drop'' and ``dropwithreset'' check the
184 * flag dropsocket to see if the temporary
185 * socket created here should be discarded.
186 * We mark the socket as discardable until
187 * we're committed to it below in TCPS_LISTEN.
188 */
189 dropsocket++;
190 ipxp = (struct ipxpcb *)so->so_pcb;
191 ipxp->ipxp_laddr = si->si_dna;
192 cb = ipxtospxpcb(ipxp);
193 cb->s_mtu = ocb->s_mtu; /* preserve sockopts */
194 cb->s_flags = ocb->s_flags; /* preserve sockopts */
195 cb->s_flags2 = ocb->s_flags2; /* preserve sockopts */
196 cb->s_state = TCPS_LISTEN;
197 }
198
199 /*
200 * Packet received on connection.
201 * reset idle time and keep-alive timer;
202 */
203 cb->s_idle = 0;
204 cb->s_timer[SPXT_KEEP] = SPXTV_KEEP;
205
206 switch (cb->s_state) {
207
208 case TCPS_LISTEN:{
209 struct sockaddr_ipx *sipx, ssipx;
210 struct ipx_addr laddr;
211
212 /*
213 * If somebody here was carying on a conversation
214 * and went away, and his pen pal thinks he can
215 * still talk, we get the misdirected packet.
216 */
217 if (spx_hardnosed && (si->si_did != 0 || si->si_seq != 0)) {
218 spx_istat.gonawy++;
219 goto dropwithreset;
220 }
221 sipx = &ssipx;
222 bzero(sipx, sizeof *sipx);
223 sipx->sipx_len = sizeof(*sipx);
224 sipx->sipx_family = AF_IPX;
225 sipx->sipx_addr = si->si_sna;
226 laddr = ipxp->ipxp_laddr;
227 if (ipx_nullhost(laddr))
228 ipxp->ipxp_laddr = si->si_dna;
229 if (ipx_pcbconnect(ipxp, (struct sockaddr *)sipx, &thread0)) {
230 ipxp->ipxp_laddr = laddr;
231 spx_istat.noconn++;
232 goto drop;
233 }
234 spx_template(cb);
235 dropsocket = 0; /* committed to socket */
236 cb->s_did = si->si_sid;
237 cb->s_rack = si->si_ack;
238 cb->s_ralo = si->si_alo;
239 #define THREEWAYSHAKE
240 #ifdef THREEWAYSHAKE
241 cb->s_state = TCPS_SYN_RECEIVED;
242 cb->s_force = 1 + SPXT_KEEP;
243 spxstat.spxs_accepts++;
244 cb->s_timer[SPXT_KEEP] = SPXTV_KEEP;
245 }
246 break;
247 /*
248 * This state means that we have heard a response
249 * to our acceptance of their connection
250 * It is probably logically unnecessary in this
251 * implementation.
252 */
253 case TCPS_SYN_RECEIVED: {
254 if (si->si_did != cb->s_sid) {
255 spx_istat.wrncon++;
256 goto drop;
257 }
258 #endif
259 ipxp->ipxp_fport = si->si_sport;
260 cb->s_timer[SPXT_REXMT] = 0;
261 cb->s_timer[SPXT_KEEP] = SPXTV_KEEP;
262 soisconnected(so);
263 cb->s_state = TCPS_ESTABLISHED;
264 spxstat.spxs_accepts++;
265 }
266 break;
267
268 /*
269 * This state means that we have gotten a response
270 * to our attempt to establish a connection.
271 * We fill in the data from the other side,
272 * telling us which port to respond to, instead of the well-
273 * known one we might have sent to in the first place.
274 * We also require that this is a response to our
275 * connection id.
276 */
277 case TCPS_SYN_SENT:
278 if (si->si_did != cb->s_sid) {
279 spx_istat.notme++;
280 goto drop;
281 }
282 spxstat.spxs_connects++;
283 cb->s_did = si->si_sid;
284 cb->s_rack = si->si_ack;
285 cb->s_ralo = si->si_alo;
286 cb->s_dport = ipxp->ipxp_fport = si->si_sport;
287 cb->s_timer[SPXT_REXMT] = 0;
288 cb->s_flags |= SF_ACKNOW;
289 soisconnected(so);
290 cb->s_state = TCPS_ESTABLISHED;
291 /* Use roundtrip time of connection request for initial rtt */
292 if (cb->s_rtt) {
293 cb->s_srtt = cb->s_rtt << 3;
294 cb->s_rttvar = cb->s_rtt << 1;
295 SPXT_RANGESET(cb->s_rxtcur,
296 ((cb->s_srtt >> 2) + cb->s_rttvar) >> 1,
297 SPXTV_MIN, SPXTV_REXMTMAX);
298 cb->s_rtt = 0;
299 }
300 }
301 if (so->so_options & SO_DEBUG || traceallspxs)
302 spx_trace(SA_INPUT, (u_char)ostate, cb, &spx_savesi, 0);
303
304 m->m_len -= sizeof(struct ipx);
305 m->m_pkthdr.len -= sizeof(struct ipx);
306 m->m_data += sizeof(struct ipx);
307
308 if (spx_reass(cb, si)) {
309 m_freem(m);
310 }
311 if (cb->s_force || (cb->s_flags & (SF_ACKNOW|SF_WIN|SF_RXT)))
312 spx_output(cb, (struct mbuf *)NULL);
313 cb->s_flags &= ~(SF_WIN|SF_RXT);
314 return;
315
316 dropwithreset:
317 if (dropsocket) {
318 struct socket *head;
319 ACCEPT_LOCK();
320 KASSERT((so->so_qstate & SQ_INCOMP) != 0,
321 ("spx_input: nascent socket not SQ_INCOMP on soabort()"));
322 head = so->so_head;
323 TAILQ_REMOVE(&head->so_incomp, so, so_list);
324 head->so_incqlen--;
325 so->so_qstate &= ~SQ_INCOMP;
326 so->so_head = NULL;
327 ACCEPT_UNLOCK();
328 soabort(so);
329 }
330 si->si_seq = ntohs(si->si_seq);
331 si->si_ack = ntohs(si->si_ack);
332 si->si_alo = ntohs(si->si_alo);
333 m_freem(dtom(si));
334 if (cb->s_ipxpcb->ipxp_socket->so_options & SO_DEBUG || traceallspxs)
335 spx_trace(SA_DROP, (u_char)ostate, cb, &spx_savesi, 0);
336 return;
337
338 drop:
339 bad:
340 if (cb == 0 || cb->s_ipxpcb->ipxp_socket->so_options & SO_DEBUG ||
341 traceallspxs)
342 spx_trace(SA_DROP, (u_char)ostate, cb, &spx_savesi, 0);
343 m_freem(m);
344 }
345
346 static int spxrexmtthresh = 3;
347
348 /*
349 * This is structurally similar to the tcp reassembly routine
350 * but its function is somewhat different: It merely queues
351 * packets up, and suppresses duplicates.
352 */
353 static int
354 spx_reass(cb, si)
355 register struct spxpcb *cb;
356 register struct spx *si;
357 {
358 register struct spx_q *q;
359 register struct mbuf *m;
360 register struct socket *so = cb->s_ipxpcb->ipxp_socket;
361 char packetp = cb->s_flags & SF_HI;
362 int incr;
363 char wakeup = 0;
364
365 if (si == SI(0))
366 goto present;
367 /*
368 * Update our news from them.
369 */
370 if (si->si_cc & SPX_SA)
371 cb->s_flags |= (spx_use_delack ? SF_DELACK : SF_ACKNOW);
372 if (SSEQ_GT(si->si_alo, cb->s_ralo))
373 cb->s_flags |= SF_WIN;
374 if (SSEQ_LEQ(si->si_ack, cb->s_rack)) {
375 if ((si->si_cc & SPX_SP) && cb->s_rack != (cb->s_smax + 1)) {
376 spxstat.spxs_rcvdupack++;
377 /*
378 * If this is a completely duplicate ack
379 * and other conditions hold, we assume
380 * a packet has been dropped and retransmit
381 * it exactly as in tcp_input().
382 */
383 if (si->si_ack != cb->s_rack ||
384 si->si_alo != cb->s_ralo)
385 cb->s_dupacks = 0;
386 else if (++cb->s_dupacks == spxrexmtthresh) {
387 u_short onxt = cb->s_snxt;
388 int cwnd = cb->s_cwnd;
389
390 cb->s_snxt = si->si_ack;
391 cb->s_cwnd = CUNIT;
392 cb->s_force = 1 + SPXT_REXMT;
393 spx_output(cb, (struct mbuf *)NULL);
394 cb->s_timer[SPXT_REXMT] = cb->s_rxtcur;
395 cb->s_rtt = 0;
396 if (cwnd >= 4 * CUNIT)
397 cb->s_cwnd = cwnd / 2;
398 if (SSEQ_GT(onxt, cb->s_snxt))
399 cb->s_snxt = onxt;
400 return (1);
401 }
402 } else
403 cb->s_dupacks = 0;
404 goto update_window;
405 }
406 cb->s_dupacks = 0;
407 /*
408 * If our correspondent acknowledges data we haven't sent
409 * TCP would drop the packet after acking. We'll be a little
410 * more permissive
411 */
412 if (SSEQ_GT(si->si_ack, (cb->s_smax + 1))) {
413 spxstat.spxs_rcvacktoomuch++;
414 si->si_ack = cb->s_smax + 1;
415 }
416 spxstat.spxs_rcvackpack++;
417 /*
418 * If transmit timer is running and timed sequence
419 * number was acked, update smoothed round trip time.
420 * See discussion of algorithm in tcp_input.c
421 */
422 if (cb->s_rtt && SSEQ_GT(si->si_ack, cb->s_rtseq)) {
423 spxstat.spxs_rttupdated++;
424 if (cb->s_srtt != 0) {
425 register short delta;
426 delta = cb->s_rtt - (cb->s_srtt >> 3);
427 if ((cb->s_srtt += delta) <= 0)
428 cb->s_srtt = 1;
429 if (delta < 0)
430 delta = -delta;
431 delta -= (cb->s_rttvar >> 2);
432 if ((cb->s_rttvar += delta) <= 0)
433 cb->s_rttvar = 1;
434 } else {
435 /*
436 * No rtt measurement yet
437 */
438 cb->s_srtt = cb->s_rtt << 3;
439 cb->s_rttvar = cb->s_rtt << 1;
440 }
441 cb->s_rtt = 0;
442 cb->s_rxtshift = 0;
443 SPXT_RANGESET(cb->s_rxtcur,
444 ((cb->s_srtt >> 2) + cb->s_rttvar) >> 1,
445 SPXTV_MIN, SPXTV_REXMTMAX);
446 }
447 /*
448 * If all outstanding data is acked, stop retransmit
449 * timer and remember to restart (more output or persist).
450 * If there is more data to be acked, restart retransmit
451 * timer, using current (possibly backed-off) value;
452 */
453 if (si->si_ack == cb->s_smax + 1) {
454 cb->s_timer[SPXT_REXMT] = 0;
455 cb->s_flags |= SF_RXT;
456 } else if (cb->s_timer[SPXT_PERSIST] == 0)
457 cb->s_timer[SPXT_REXMT] = cb->s_rxtcur;
458 /*
459 * When new data is acked, open the congestion window.
460 * If the window gives us less than ssthresh packets
461 * in flight, open exponentially (maxseg at a time).
462 * Otherwise open linearly (maxseg^2 / cwnd at a time).
463 */
464 incr = CUNIT;
465 if (cb->s_cwnd > cb->s_ssthresh)
466 incr = max(incr * incr / cb->s_cwnd, 1);
467 cb->s_cwnd = min(cb->s_cwnd + incr, cb->s_cwmx);
468 /*
469 * Trim Acked data from output queue.
470 */
471 while ((m = so->so_snd.sb_mb) != NULL) {
472 if (SSEQ_LT((mtod(m, struct spx *))->si_seq, si->si_ack))
473 sbdroprecord(&so->so_snd);
474 else
475 break;
476 }
477 sowwakeup(so);
478 cb->s_rack = si->si_ack;
479 update_window:
480 if (SSEQ_LT(cb->s_snxt, cb->s_rack))
481 cb->s_snxt = cb->s_rack;
482 if (SSEQ_LT(cb->s_swl1, si->si_seq) || ((cb->s_swl1 == si->si_seq &&
483 (SSEQ_LT(cb->s_swl2, si->si_ack))) ||
484 (cb->s_swl2 == si->si_ack && SSEQ_LT(cb->s_ralo, si->si_alo)))) {
485 /* keep track of pure window updates */
486 if ((si->si_cc & SPX_SP) && cb->s_swl2 == si->si_ack
487 && SSEQ_LT(cb->s_ralo, si->si_alo)) {
488 spxstat.spxs_rcvwinupd++;
489 spxstat.spxs_rcvdupack--;
490 }
491 cb->s_ralo = si->si_alo;
492 cb->s_swl1 = si->si_seq;
493 cb->s_swl2 = si->si_ack;
494 cb->s_swnd = (1 + si->si_alo - si->si_ack);
495 if (cb->s_swnd > cb->s_smxw)
496 cb->s_smxw = cb->s_swnd;
497 cb->s_flags |= SF_WIN;
498 }
499 /*
500 * If this packet number is higher than that which
501 * we have allocated refuse it, unless urgent
502 */
503 if (SSEQ_GT(si->si_seq, cb->s_alo)) {
504 if (si->si_cc & SPX_SP) {
505 spxstat.spxs_rcvwinprobe++;
506 return (1);
507 } else
508 spxstat.spxs_rcvpackafterwin++;
509 if (si->si_cc & SPX_OB) {
510 if (SSEQ_GT(si->si_seq, cb->s_alo + 60)) {
511 m_freem(dtom(si));
512 return (0);
513 } /* else queue this packet; */
514 } else {
515 /*register struct socket *so = cb->s_ipxpcb->ipxp_socket;
516 if (so->so_state && SS_NOFDREF) {
517 spx_close(cb);
518 } else
519 would crash system*/
520 spx_istat.notyet++;
521 m_freem(dtom(si));
522 return (0);
523 }
524 }
525 /*
526 * If this is a system packet, we don't need to
527 * queue it up, and won't update acknowledge #
528 */
529 if (si->si_cc & SPX_SP) {
530 return (1);
531 }
532 /*
533 * We have already seen this packet, so drop.
534 */
535 if (SSEQ_LT(si->si_seq, cb->s_ack)) {
536 spx_istat.bdreas++;
537 spxstat.spxs_rcvduppack++;
538 if (si->si_seq == cb->s_ack - 1)
539 spx_istat.lstdup++;
540 return (1);
541 }
542 /*
543 * Loop through all packets queued up to insert in
544 * appropriate sequence.
545 */
546 for (q = cb->s_q.si_next; q != &cb->s_q; q = q->si_next) {
547 if (si->si_seq == SI(q)->si_seq) {
548 spxstat.spxs_rcvduppack++;
549 return (1);
550 }
551 if (SSEQ_LT(si->si_seq, SI(q)->si_seq)) {
552 spxstat.spxs_rcvoopack++;
553 break;
554 }
555 }
556 insque(si, q->si_prev);
557 /*
558 * If this packet is urgent, inform process
559 */
560 if (si->si_cc & SPX_OB) {
561 cb->s_iobc = ((char *)si)[1 + sizeof(*si)];
562 sohasoutofband(so);
563 cb->s_oobflags |= SF_IOOB;
564 }
565 present:
566 #define SPINC sizeof(struct spxhdr)
567 /*
568 * Loop through all packets queued up to update acknowledge
569 * number, and present all acknowledged data to user;
570 * If in packet interface mode, show packet headers.
571 */
572 for (q = cb->s_q.si_next; q != &cb->s_q; q = q->si_next) {
573 if (SI(q)->si_seq == cb->s_ack) {
574 cb->s_ack++;
575 m = dtom(q);
576 if (SI(q)->si_cc & SPX_OB) {
577 cb->s_oobflags &= ~SF_IOOB;
578 SOCKBUF_LOCK(&so->so_rcv);
579 if (so->so_rcv.sb_cc)
580 so->so_oobmark = so->so_rcv.sb_cc;
581 else
582 so->so_rcv.sb_state |= SBS_RCVATMARK;
583 SOCKBUF_UNLOCK(&so->so_rcv);
584 }
585 q = q->si_prev;
586 remque(q->si_next);
587 wakeup = 1;
588 spxstat.spxs_rcvpack++;
589 #ifdef SF_NEWCALL
590 if (cb->s_flags2 & SF_NEWCALL) {
591 struct spxhdr *sp = mtod(m, struct spxhdr *);
592 u_char dt = sp->spx_dt;
593 spx_newchecks[4]++;
594 if (dt != cb->s_rhdr.spx_dt) {
595 struct mbuf *mm =
596 m_getclr(M_DONTWAIT, MT_CONTROL);
597 spx_newchecks[0]++;
598 if (mm != NULL) {
599 u_short *s =
600 mtod(mm, u_short *);
601 cb->s_rhdr.spx_dt = dt;
602 mm->m_len = 5; /*XXX*/
603 s[0] = 5;
604 s[1] = 1;
605 *(u_char *)(&s[2]) = dt;
606 sbappend(&so->so_rcv, mm);
607 }
608 }
609 if (sp->spx_cc & SPX_OB) {
610 MCHTYPE(m, MT_OOBDATA);
611 spx_newchecks[1]++;
612 SOCKBUF_LOCK(&so->so_rcv);
613 so->so_oobmark = 0;
614 so->so_rcv.sb_state &= ~SBS_RCVATMARK;
615 SOCKBUF_UNLOCK(&so->so_rcv);
616 }
617 if (packetp == 0) {
618 m->m_data += SPINC;
619 m->m_len -= SPINC;
620 m->m_pkthdr.len -= SPINC;
621 }
622 if ((sp->spx_cc & SPX_EM) || packetp) {
623 sbappendrecord(&so->so_rcv, m);
624 spx_newchecks[9]++;
625 } else
626 sbappend(&so->so_rcv, m);
627 } else
628 #endif
629 if (packetp) {
630 sbappendrecord(&so->so_rcv, m);
631 } else {
632 cb->s_rhdr = *mtod(m, struct spxhdr *);
633 m->m_data += SPINC;
634 m->m_len -= SPINC;
635 m->m_pkthdr.len -= SPINC;
636 sbappend(&so->so_rcv, m);
637 }
638 } else
639 break;
640 }
641 if (wakeup)
642 sorwakeup(so);
643 return (0);
644 }
645
646 void
647 spx_ctlinput(cmd, arg_as_sa, dummy)
648 int cmd;
649 struct sockaddr *arg_as_sa; /* XXX should be swapped with dummy */
650 void *dummy;
651 {
652 caddr_t arg = (/* XXX */ caddr_t)arg_as_sa;
653 struct ipx_addr *na;
654 struct sockaddr_ipx *sipx;
655
656 if (cmd < 0 || cmd >= PRC_NCMDS)
657 return;
658
659 switch (cmd) {
660
661 case PRC_ROUTEDEAD:
662 return;
663
664 case PRC_IFDOWN:
665 case PRC_HOSTDEAD:
666 case PRC_HOSTUNREACH:
667 sipx = (struct sockaddr_ipx *)arg;
668 if (sipx->sipx_family != AF_IPX)
669 return;
670 na = &sipx->sipx_addr;
671 break;
672
673 default:
674 break;
675 }
676 }
677
678 #ifdef notdef
679 int
680 spx_fixmtu(ipxp)
681 register struct ipxpcb *ipxp;
682 {
683 register struct spxpcb *cb = (struct spxpcb *)(ipxp->ipxp_pcb);
684 register struct mbuf *m;
685 register struct spx *si;
686 struct ipx_errp *ep;
687 struct sockbuf *sb;
688 int badseq, len;
689 struct mbuf *firstbad, *m0;
690
691 if (cb != NULL) {
692 /*
693 * The notification that we have sent
694 * too much is bad news -- we will
695 * have to go through queued up so far
696 * splitting ones which are too big and
697 * reassigning sequence numbers and checksums.
698 * we should then retransmit all packets from
699 * one above the offending packet to the last one
700 * we had sent (or our allocation)
701 * then the offending one so that the any queued
702 * data at our destination will be discarded.
703 */
704 ep = (struct ipx_errp *)ipxp->ipxp_notify_param;
705 sb = &ipxp->ipxp_socket->so_snd;
706 cb->s_mtu = ep->ipx_err_param;
707 badseq = SI(&ep->ipx_err_ipx)->si_seq;
708 for (m = sb->sb_mb; m != NULL; m = m->m_act) {
709 si = mtod(m, struct spx *);
710 if (si->si_seq == badseq)
711 break;
712 }
713 if (m == NULL)
714 return;
715 firstbad = m;
716 /*for (;;) {*/
717 /* calculate length */
718 for (m0 = m, len = 0; m != NULL; m = m->m_next)
719 len += m->m_len;
720 if (len > cb->s_mtu) {
721 }
722 /* FINISH THIS
723 } */
724 }
725 }
726 #endif
727
728 static int
729 spx_output(cb, m0)
730 register struct spxpcb *cb;
731 struct mbuf *m0;
732 {
733 struct socket *so = cb->s_ipxpcb->ipxp_socket;
734 register struct mbuf *m;
735 register struct spx *si = (struct spx *)NULL;
736 register struct sockbuf *sb = &so->so_snd;
737 int len = 0, win, rcv_win;
738 short span, off, recordp = 0;
739 u_short alo;
740 int error = 0, sendalot;
741 #ifdef notdef
742 int idle;
743 #endif
744 struct mbuf *mprev;
745
746 if (m0 != NULL) {
747 int mtu = cb->s_mtu;
748 int datalen;
749 /*
750 * Make sure that packet isn't too big.
751 */
752 for (m = m0; m != NULL; m = m->m_next) {
753 mprev = m;
754 len += m->m_len;
755 if (m->m_flags & M_EOR)
756 recordp = 1;
757 }
758 datalen = (cb->s_flags & SF_HO) ?
759 len - sizeof(struct spxhdr) : len;
760 if (datalen > mtu) {
761 if (cb->s_flags & SF_PI) {
762 m_freem(m0);
763 return (EMSGSIZE);
764 } else {
765 int oldEM = cb->s_cc & SPX_EM;
766
767 cb->s_cc &= ~SPX_EM;
768 while (len > mtu) {
769 /*
770 * Here we are only being called
771 * from usrreq(), so it is OK to
772 * block.
773 */
774 m = m_copym(m0, 0, mtu, M_TRYWAIT);
775 if (cb->s_flags & SF_NEWCALL) {
776 struct mbuf *mm = m;
777 spx_newchecks[7]++;
778 while (mm != NULL) {
779 mm->m_flags &= ~M_EOR;
780 mm = mm->m_next;
781 }
782 }
783 error = spx_output(cb, m);
784 if (error) {
785 cb->s_cc |= oldEM;
786 m_freem(m0);
787 return (error);
788 }
789 m_adj(m0, mtu);
790 len -= mtu;
791 }
792 cb->s_cc |= oldEM;
793 }
794 }
795 /*
796 * Force length even, by adding a "garbage byte" if
797 * necessary.
798 */
799 if (len & 1) {
800 m = mprev;
801 if (M_TRAILINGSPACE(m) >= 1)
802 m->m_len++;
803 else {
804 struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA);
805
806 if (m1 == NULL) {
807 m_freem(m0);
808 return (ENOBUFS);
809 }
810 m1->m_len = 1;
811 *(mtod(m1, u_char *)) = 0;
812 m->m_next = m1;
813 }
814 }
815 m = m_gethdr(M_DONTWAIT, MT_HEADER);
816 if (m == NULL) {
817 m_freem(m0);
818 return (ENOBUFS);
819 }
820 /*
821 * Fill in mbuf with extended SP header
822 * and addresses and length put into network format.
823 */
824 MH_ALIGN(m, sizeof(struct spx));
825 m->m_len = sizeof(struct spx);
826 m->m_next = m0;
827 si = mtod(m, struct spx *);
828 si->si_i = *cb->s_ipx;
829 si->si_s = cb->s_shdr;
830 if ((cb->s_flags & SF_PI) && (cb->s_flags & SF_HO)) {
831 register struct spxhdr *sh;
832 if (m0->m_len < sizeof(*sh)) {
833 if((m0 = m_pullup(m0, sizeof(*sh))) == NULL) {
834 m_free(m);
835 m_freem(m0);
836 return (EINVAL);
837 }
838 m->m_next = m0;
839 }
840 sh = mtod(m0, struct spxhdr *);
841 si->si_dt = sh->spx_dt;
842 si->si_cc |= sh->spx_cc & SPX_EM;
843 m0->m_len -= sizeof(*sh);
844 m0->m_data += sizeof(*sh);
845 len -= sizeof(*sh);
846 }
847 len += sizeof(*si);
848 if ((cb->s_flags2 & SF_NEWCALL) && recordp) {
849 si->si_cc |= SPX_EM;
850 spx_newchecks[8]++;
851 }
852 if (cb->s_oobflags & SF_SOOB) {
853 /*
854 * Per jqj@cornell:
855 * make sure OB packets convey exactly 1 byte.
856 * If the packet is 1 byte or larger, we
857 * have already guaranted there to be at least
858 * one garbage byte for the checksum, and
859 * extra bytes shouldn't hurt!
860 */
861 if (len > sizeof(*si)) {
862 si->si_cc |= SPX_OB;
863 len = (1 + sizeof(*si));
864 }
865 }
866 si->si_len = htons((u_short)len);
867 m->m_pkthdr.len = ((len - 1) | 1) + 1;
868 /*
869 * queue stuff up for output
870 */
871 sbappendrecord(sb, m);
872 cb->s_seq++;
873 }
874 #ifdef notdef
875 idle = (cb->s_smax == (cb->s_rack - 1));
876 #endif
877 again:
878 sendalot = 0;
879 off = cb->s_snxt - cb->s_rack;
880 win = min(cb->s_swnd, (cb->s_cwnd / CUNIT));
881
882 /*
883 * If in persist timeout with window of 0, send a probe.
884 * Otherwise, if window is small but nonzero
885 * and timer expired, send what we can and go into
886 * transmit state.
887 */
888 if (cb->s_force == 1 + SPXT_PERSIST) {
889 if (win != 0) {
890 cb->s_timer[SPXT_PERSIST] = 0;
891 cb->s_rxtshift = 0;
892 }
893 }
894 span = cb->s_seq - cb->s_rack;
895 len = min(span, win) - off;
896
897 if (len < 0) {
898 /*
899 * Window shrank after we went into it.
900 * If window shrank to 0, cancel pending
901 * restransmission and pull s_snxt back
902 * to (closed) window. We will enter persist
903 * state below. If the widndow didn't close completely,
904 * just wait for an ACK.
905 */
906 len = 0;
907 if (win == 0) {
908 cb->s_timer[SPXT_REXMT] = 0;
909 cb->s_snxt = cb->s_rack;
910 }
911 }
912 if (len > 1)
913 sendalot = 1;
914 rcv_win = sbspace(&so->so_rcv);
915
916 /*
917 * Send if we owe peer an ACK.
918 */
919 if (cb->s_oobflags & SF_SOOB) {
920 /*
921 * must transmit this out of band packet
922 */
923 cb->s_oobflags &= ~ SF_SOOB;
924 sendalot = 1;
925 spxstat.spxs_sndurg++;
926 goto found;
927 }
928 if (cb->s_flags & SF_ACKNOW)
929 goto send;
930 if (cb->s_state < TCPS_ESTABLISHED)
931 goto send;
932 /*
933 * Silly window can't happen in spx.
934 * Code from tcp deleted.
935 */
936 if (len)
937 goto send;
938 /*
939 * Compare available window to amount of window
940 * known to peer (as advertised window less
941 * next expected input.) If the difference is at least two
942 * packets or at least 35% of the mximum possible window,
943 * then want to send a window update to peer.
944 */
945 if (rcv_win > 0) {
946 u_short delta = 1 + cb->s_alo - cb->s_ack;
947 int adv = rcv_win - (delta * cb->s_mtu);
948
949 if ((so->so_rcv.sb_cc == 0 && adv >= (2 * cb->s_mtu)) ||
950 (100 * adv / so->so_rcv.sb_hiwat >= 35)) {
951 spxstat.spxs_sndwinup++;
952 cb->s_flags |= SF_ACKNOW;
953 goto send;
954 }
955
956 }
957 /*
958 * Many comments from tcp_output.c are appropriate here
959 * including . . .
960 * If send window is too small, there is data to transmit, and no
961 * retransmit or persist is pending, then go to persist state.
962 * If nothing happens soon, send when timer expires:
963 * if window is nonzero, transmit what we can,
964 * otherwise send a probe.
965 */
966 if (so->so_snd.sb_cc && cb->s_timer[SPXT_REXMT] == 0 &&
967 cb->s_timer[SPXT_PERSIST] == 0) {
968 cb->s_rxtshift = 0;
969 spx_setpersist(cb);
970 }
971 /*
972 * No reason to send a packet, just return.
973 */
974 cb->s_outx = 1;
975 return (0);
976
977 send:
978 /*
979 * Find requested packet.
980 */
981 si = 0;
982 if (len > 0) {
983 cb->s_want = cb->s_snxt;
984 for (m = sb->sb_mb; m != NULL; m = m->m_act) {
985 si = mtod(m, struct spx *);
986 if (SSEQ_LEQ(cb->s_snxt, si->si_seq))
987 break;
988 }
989 found:
990 if (si != NULL) {
991 if (si->si_seq == cb->s_snxt)
992 cb->s_snxt++;
993 else
994 spxstat.spxs_sndvoid++, si = 0;
995 }
996 }
997 /*
998 * update window
999 */
1000 if (rcv_win < 0)
1001 rcv_win = 0;
1002 alo = cb->s_ack - 1 + (rcv_win / ((short)cb->s_mtu));
1003 if (SSEQ_LT(alo, cb->s_alo))
1004 alo = cb->s_alo;
1005
1006 if (si != NULL) {
1007 /*
1008 * must make a copy of this packet for
1009 * ipx_output to monkey with
1010 */
1011 m = m_copy(dtom(si), 0, (int)M_COPYALL);
1012 if (m == NULL) {
1013 return (ENOBUFS);
1014 }
1015 si = mtod(m, struct spx *);
1016 if (SSEQ_LT(si->si_seq, cb->s_smax))
1017 spxstat.spxs_sndrexmitpack++;
1018 else
1019 spxstat.spxs_sndpack++;
1020 } else if (cb->s_force || cb->s_flags & SF_ACKNOW) {
1021 /*
1022 * Must send an acknowledgement or a probe
1023 */
1024 if (cb->s_force)
1025 spxstat.spxs_sndprobe++;
1026 if (cb->s_flags & SF_ACKNOW)
1027 spxstat.spxs_sndacks++;
1028 m = m_gethdr(M_DONTWAIT, MT_HEADER);
1029 if (m == NULL)
1030 return (ENOBUFS);
1031 /*
1032 * Fill in mbuf with extended SP header
1033 * and addresses and length put into network format.
1034 */
1035 MH_ALIGN(m, sizeof(struct spx));
1036 m->m_len = sizeof(*si);
1037 m->m_pkthdr.len = sizeof(*si);
1038 si = mtod(m, struct spx *);
1039 si->si_i = *cb->s_ipx;
1040 si->si_s = cb->s_shdr;
1041 si->si_seq = cb->s_smax + 1;
1042 si->si_len = htons(sizeof(*si));
1043 si->si_cc |= SPX_SP;
1044 } else {
1045 cb->s_outx = 3;
1046 if (so->so_options & SO_DEBUG || traceallspxs)
1047 spx_trace(SA_OUTPUT, cb->s_state, cb, si, 0);
1048 return (0);
1049 }
1050 /*
1051 * Stuff checksum and output datagram.
1052 */
1053 if ((si->si_cc & SPX_SP) == 0) {
1054 if (cb->s_force != (1 + SPXT_PERSIST) ||
1055 cb->s_timer[SPXT_PERSIST] == 0) {
1056 /*
1057 * If this is a new packet and we are not currently
1058 * timing anything, time this one.
1059 */
1060 if (SSEQ_LT(cb->s_smax, si->si_seq)) {
1061 cb->s_smax = si->si_seq;
1062 if (cb->s_rtt == 0) {
1063 spxstat.spxs_segstimed++;
1064 cb->s_rtseq = si->si_seq;
1065 cb->s_rtt = 1;
1066 }
1067 }
1068 /*
1069 * Set rexmt timer if not currently set,
1070 * Initial value for retransmit timer is smoothed
1071 * round-trip time + 2 * round-trip time variance.
1072 * Initialize shift counter which is used for backoff
1073 * of retransmit time.
1074 */
1075 if (cb->s_timer[SPXT_REXMT] == 0 &&
1076 cb->s_snxt != cb->s_rack) {
1077 cb->s_timer[SPXT_REXMT] = cb->s_rxtcur;
1078 if (cb->s_timer[SPXT_PERSIST]) {
1079 cb->s_timer[SPXT_PERSIST] = 0;
1080 cb->s_rxtshift = 0;
1081 }
1082 }
1083 } else if (SSEQ_LT(cb->s_smax, si->si_seq)) {
1084 cb->s_smax = si->si_seq;
1085 }
1086 } else if (cb->s_state < TCPS_ESTABLISHED) {
1087 if (cb->s_rtt == 0)
1088 cb->s_rtt = 1; /* Time initial handshake */
1089 if (cb->s_timer[SPXT_REXMT] == 0)
1090 cb->s_timer[SPXT_REXMT] = cb->s_rxtcur;
1091 }
1092 {
1093 /*
1094 * Do not request acks when we ack their data packets or
1095 * when we do a gratuitous window update.
1096 */
1097 if (((si->si_cc & SPX_SP) == 0) || cb->s_force)
1098 si->si_cc |= SPX_SA;
1099 si->si_seq = htons(si->si_seq);
1100 si->si_alo = htons(alo);
1101 si->si_ack = htons(cb->s_ack);
1102
1103 if (ipxcksum) {
1104 si->si_sum = ipx_cksum(m, ntohs(si->si_len));
1105 } else
1106 si->si_sum = 0xffff;
1107
1108 cb->s_outx = 4;
1109 if (so->so_options & SO_DEBUG || traceallspxs)
1110 spx_trace(SA_OUTPUT, cb->s_state, cb, si, 0);
1111
1112 if (so->so_options & SO_DONTROUTE)
1113 error = ipx_outputfl(m, (struct route *)NULL, IPX_ROUTETOIF);
1114 else
1115 error = ipx_outputfl(m, &cb->s_ipxpcb->ipxp_route, 0);
1116 }
1117 if (error) {
1118 return (error);
1119 }
1120 spxstat.spxs_sndtotal++;
1121 /*
1122 * Data sent (as far as we can tell).
1123 * If this advertises a larger window than any other segment,
1124 * then remember the size of the advertized window.
1125 * Any pending ACK has now been sent.
1126 */
1127 cb->s_force = 0;
1128 cb->s_flags &= ~(SF_ACKNOW|SF_DELACK);
1129 if (SSEQ_GT(alo, cb->s_alo))
1130 cb->s_alo = alo;
1131 if (sendalot)
1132 goto again;
1133 cb->s_outx = 5;
1134 return (0);
1135 }
1136
1137 static int spx_do_persist_panics = 0;
1138
1139 static void
1140 spx_setpersist(cb)
1141 register struct spxpcb *cb;
1142 {
1143 register int t = ((cb->s_srtt >> 2) + cb->s_rttvar) >> 1;
1144
1145 if (cb->s_timer[SPXT_REXMT] && spx_do_persist_panics)
1146 panic("spx_output REXMT");
1147 /*
1148 * Start/restart persistance timer.
1149 */
1150 SPXT_RANGESET(cb->s_timer[SPXT_PERSIST],
1151 t*spx_backoff[cb->s_rxtshift],
1152 SPXTV_PERSMIN, SPXTV_PERSMAX);
1153 if (cb->s_rxtshift < SPX_MAXRXTSHIFT)
1154 cb->s_rxtshift++;
1155 }
1156
1157 int
1158 spx_ctloutput(so, sopt)
1159 struct socket *so;
1160 struct sockopt *sopt;
1161 {
1162 struct ipxpcb *ipxp = sotoipxpcb(so);
1163 register struct spxpcb *cb;
1164 int mask, error;
1165 short soptval;
1166 u_short usoptval;
1167 int optval;
1168
1169 error = 0;
1170
1171 if (sopt->sopt_level != IPXPROTO_SPX) {
1172 /* This will have to be changed when we do more general
1173 stacking of protocols */
1174 return (ipx_ctloutput(so, sopt));
1175 }
1176 if (ipxp == NULL)
1177 return (EINVAL);
1178 else
1179 cb = ipxtospxpcb(ipxp);
1180
1181 switch (sopt->sopt_dir) {
1182 case SOPT_GET:
1183 switch (sopt->sopt_name) {
1184 case SO_HEADERS_ON_INPUT:
1185 mask = SF_HI;
1186 goto get_flags;
1187
1188 case SO_HEADERS_ON_OUTPUT:
1189 mask = SF_HO;
1190 get_flags:
1191 soptval = cb->s_flags & mask;
1192 error = sooptcopyout(sopt, &soptval, sizeof soptval);
1193 break;
1194
1195 case SO_MTU:
1196 usoptval = cb->s_mtu;
1197 error = sooptcopyout(sopt, &usoptval, sizeof usoptval);
1198 break;
1199
1200 case SO_LAST_HEADER:
1201 error = sooptcopyout(sopt, &cb->s_rhdr,
1202 sizeof cb->s_rhdr);
1203 break;
1204
1205 case SO_DEFAULT_HEADERS:
1206 error = sooptcopyout(sopt, &cb->s_shdr,
1207 sizeof cb->s_shdr);
1208 break;
1209
1210 default:
1211 error = ENOPROTOOPT;
1212 }
1213 break;
1214
1215 case SOPT_SET:
1216 switch (sopt->sopt_name) {
1217 /* XXX why are these shorts on get and ints on set?
1218 that doesn't make any sense... */
1219 case SO_HEADERS_ON_INPUT:
1220 mask = SF_HI;
1221 goto set_head;
1222
1223 case SO_HEADERS_ON_OUTPUT:
1224 mask = SF_HO;
1225 set_head:
1226 error = sooptcopyin(sopt, &optval, sizeof optval,
1227 sizeof optval);
1228 if (error)
1229 break;
1230
1231 if (cb->s_flags & SF_PI) {
1232 if (optval)
1233 cb->s_flags |= mask;
1234 else
1235 cb->s_flags &= ~mask;
1236 } else error = EINVAL;
1237 break;
1238
1239 case SO_MTU:
1240 error = sooptcopyin(sopt, &usoptval, sizeof usoptval,
1241 sizeof usoptval);
1242 if (error)
1243 break;
1244 cb->s_mtu = usoptval;
1245 break;
1246
1247 #ifdef SF_NEWCALL
1248 case SO_NEWCALL:
1249 error = sooptcopyin(sopt, &optval, sizeof optval,
1250 sizeof optval);
1251 if (error)
1252 break;
1253 if (optval) {
1254 cb->s_flags2 |= SF_NEWCALL;
1255 spx_newchecks[5]++;
1256 } else {
1257 cb->s_flags2 &= ~SF_NEWCALL;
1258 spx_newchecks[6]++;
1259 }
1260 break;
1261 #endif
1262
1263 case SO_DEFAULT_HEADERS:
1264 {
1265 struct spxhdr sp;
1266
1267 error = sooptcopyin(sopt, &sp, sizeof sp,
1268 sizeof sp);
1269 if (error)
1270 break;
1271 cb->s_dt = sp.spx_dt;
1272 cb->s_cc = sp.spx_cc & SPX_EM;
1273 }
1274 break;
1275
1276 default:
1277 error = ENOPROTOOPT;
1278 }
1279 break;
1280 }
1281 return (error);
1282 }
1283
1284 static int
1285 spx_usr_abort(so)
1286 struct socket *so;
1287 {
1288 int s;
1289 struct ipxpcb *ipxp;
1290 struct spxpcb *cb;
1291
1292 ipxp = sotoipxpcb(so);
1293 cb = ipxtospxpcb(ipxp);
1294
1295 s = splnet();
1296 spx_drop(cb, ECONNABORTED);
1297 splx(s);
1298 return (0);
1299 }
1300
1301 /*
1302 * Accept a connection. Essentially all the work is
1303 * done at higher levels; just return the address
1304 * of the peer, storing through addr.
1305 */
1306 static int
1307 spx_accept(so, nam)
1308 struct socket *so;
1309 struct sockaddr **nam;
1310 {
1311 struct ipxpcb *ipxp;
1312 struct sockaddr_ipx *sipx, ssipx;
1313
1314 ipxp = sotoipxpcb(so);
1315 sipx = &ssipx;
1316 bzero(sipx, sizeof *sipx);
1317 sipx->sipx_len = sizeof *sipx;
1318 sipx->sipx_family = AF_IPX;
1319 sipx->sipx_addr = ipxp->ipxp_faddr;
1320 *nam = sodupsockaddr((struct sockaddr *)sipx, M_NOWAIT);
1321 return (0);
1322 }
1323
1324 static int
1325 spx_attach(so, proto, td)
1326 struct socket *so;
1327 int proto;
1328 struct thread *td;
1329 {
1330 int error;
1331 int s;
1332 struct ipxpcb *ipxp;
1333 struct spxpcb *cb;
1334 struct mbuf *mm;
1335 struct sockbuf *sb;
1336
1337 ipxp = sotoipxpcb(so);
1338 cb = ipxtospxpcb(ipxp);
1339
1340 if (ipxp != NULL)
1341 return (EISCONN);
1342 s = splnet();
1343 error = ipx_pcballoc(so, &ipxpcb, td);
1344 if (error)
1345 goto spx_attach_end;
1346 if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
1347 error = soreserve(so, (u_long) 3072, (u_long) 3072);
1348 if (error)
1349 goto spx_attach_end;
1350 }
1351 ipxp = sotoipxpcb(so);
1352
1353 MALLOC(cb, struct spxpcb *, sizeof *cb, M_PCB, M_NOWAIT | M_ZERO);
1354
1355 if (cb == NULL) {
1356 error = ENOBUFS;
1357 goto spx_attach_end;
1358 }
1359 sb = &so->so_snd;
1360
1361 mm = m_getclr(M_DONTWAIT, MT_HEADER);
1362 if (mm == NULL) {
1363 FREE(cb, M_PCB);
1364 error = ENOBUFS;
1365 goto spx_attach_end;
1366 }
1367 cb->s_ipx = mtod(mm, struct ipx *);
1368 cb->s_state = TCPS_LISTEN;
1369 cb->s_smax = -1;
1370 cb->s_swl1 = -1;
1371 cb->s_q.si_next = cb->s_q.si_prev = &cb->s_q;
1372 cb->s_ipxpcb = ipxp;
1373 cb->s_mtu = 576 - sizeof(struct spx);
1374 cb->s_cwnd = sbspace(sb) * CUNIT / cb->s_mtu;
1375 cb->s_ssthresh = cb->s_cwnd;
1376 cb->s_cwmx = sbspace(sb) * CUNIT / (2 * sizeof(struct spx));
1377 /* Above is recomputed when connecting to account
1378 for changed buffering or mtu's */
1379 cb->s_rtt = SPXTV_SRTTBASE;
1380 cb->s_rttvar = SPXTV_SRTTDFLT << 2;
1381 SPXT_RANGESET(cb->s_rxtcur,
1382 ((SPXTV_SRTTBASE >> 2) + (SPXTV_SRTTDFLT << 2)) >> 1,
1383 SPXTV_MIN, SPXTV_REXMTMAX);
1384 ipxp->ipxp_pcb = (caddr_t)cb;
1385 spx_attach_end:
1386 splx(s);
1387 return (error);
1388 }
1389
1390 static int
1391 spx_bind(so, nam, td)
1392 struct socket *so;
1393 struct sockaddr *nam;
1394 struct thread *td;
1395 {
1396 struct ipxpcb *ipxp;
1397
1398 ipxp = sotoipxpcb(so);
1399
1400 return (ipx_pcbbind(ipxp, nam, td));
1401 }
1402
1403 /*
1404 * Initiate connection to peer.
1405 * Enter SYN_SENT state, and mark socket as connecting.
1406 * Start keep-alive timer, setup prototype header,
1407 * Send initial system packet requesting connection.
1408 */
1409 static int
1410 spx_connect(so, nam, td)
1411 struct socket *so;
1412 struct sockaddr *nam;
1413 struct thread *td;
1414 {
1415 int error;
1416 int s;
1417 struct ipxpcb *ipxp;
1418 struct spxpcb *cb;
1419
1420 ipxp = sotoipxpcb(so);
1421 cb = ipxtospxpcb(ipxp);
1422
1423 s = splnet();
1424 if (ipxp->ipxp_lport == 0) {
1425 error = ipx_pcbbind(ipxp, (struct sockaddr *)NULL, td);
1426 if (error)
1427 goto spx_connect_end;
1428 }
1429 error = ipx_pcbconnect(ipxp, nam, td);
1430 if (error)
1431 goto spx_connect_end;
1432 soisconnecting(so);
1433 spxstat.spxs_connattempt++;
1434 cb->s_state = TCPS_SYN_SENT;
1435 cb->s_did = 0;
1436 spx_template(cb);
1437 cb->s_timer[SPXT_KEEP] = SPXTV_KEEP;
1438 cb->s_force = 1 + SPXTV_KEEP;
1439 /*
1440 * Other party is required to respond to
1441 * the port I send from, but he is not
1442 * required to answer from where I am sending to,
1443 * so allow wildcarding.
1444 * original port I am sending to is still saved in
1445 * cb->s_dport.
1446 */
1447 ipxp->ipxp_fport = 0;
1448 error = spx_output(cb, (struct mbuf *)NULL);
1449 spx_connect_end:
1450 splx(s);
1451 return (error);
1452 }
1453
1454 static int
1455 spx_detach(so)
1456 struct socket *so;
1457 {
1458 int s;
1459 struct ipxpcb *ipxp;
1460 struct spxpcb *cb;
1461
1462 ipxp = sotoipxpcb(so);
1463 cb = ipxtospxpcb(ipxp);
1464
1465 if (ipxp == NULL)
1466 return (ENOTCONN);
1467 s = splnet();
1468 if (cb->s_state > TCPS_LISTEN)
1469 spx_disconnect(cb);
1470 else
1471 spx_close(cb);
1472 splx(s);
1473 return (0);
1474 }
1475
1476 /*
1477 * We may decide later to implement connection closing
1478 * handshaking at the spx level optionally.
1479 * here is the hook to do it:
1480 */
1481 static int
1482 spx_usr_disconnect(so)
1483 struct socket *so;
1484 {
1485 int s;
1486 struct ipxpcb *ipxp;
1487 struct spxpcb *cb;
1488
1489 ipxp = sotoipxpcb(so);
1490 cb = ipxtospxpcb(ipxp);
1491
1492 s = splnet();
1493 spx_disconnect(cb);
1494 splx(s);
1495 return (0);
1496 }
1497
1498 static int
1499 spx_listen(so, td)
1500 struct socket *so;
1501 struct thread *td;
1502 {
1503 int error;
1504 struct ipxpcb *ipxp;
1505 struct spxpcb *cb;
1506
1507 error = 0;
1508 ipxp = sotoipxpcb(so);
1509 cb = ipxtospxpcb(ipxp);
1510
1511 if (ipxp->ipxp_lport == 0)
1512 error = ipx_pcbbind(ipxp, (struct sockaddr *)NULL, td);
1513 if (error == 0)
1514 cb->s_state = TCPS_LISTEN;
1515 return (error);
1516 }
1517
1518 /*
1519 * After a receive, possibly send acknowledgment
1520 * updating allocation.
1521 */
1522 static int
1523 spx_rcvd(so, flags)
1524 struct socket *so;
1525 int flags;
1526 {
1527 int s;
1528 struct ipxpcb *ipxp;
1529 struct spxpcb *cb;
1530
1531 ipxp = sotoipxpcb(so);
1532 cb = ipxtospxpcb(ipxp);
1533
1534 s = splnet();
1535 cb->s_flags |= SF_RVD;
1536 spx_output(cb, (struct mbuf *)NULL);
1537 cb->s_flags &= ~SF_RVD;
1538 splx(s);
1539 return (0);
1540 }
1541
1542 static int
1543 spx_rcvoob(so, m, flags)
1544 struct socket *so;
1545 struct mbuf *m;
1546 int flags;
1547 {
1548 struct ipxpcb *ipxp;
1549 struct spxpcb *cb;
1550
1551 ipxp = sotoipxpcb(so);
1552 cb = ipxtospxpcb(ipxp);
1553
1554 if ((cb->s_oobflags & SF_IOOB) || so->so_oobmark ||
1555 (so->so_rcv.sb_state & SBS_RCVATMARK)) {
1556 m->m_len = 1;
1557 *mtod(m, caddr_t) = cb->s_iobc;
1558 return (0);
1559 }
1560 return (EINVAL);
1561 }
1562
1563 static int
1564 spx_send(so, flags, m, addr, controlp, td)
1565 struct socket *so;
1566 int flags;
1567 struct mbuf *m;
1568 struct sockaddr *addr;
1569 struct mbuf *controlp;
1570 struct thread *td;
1571 {
1572 int error;
1573 int s;
1574 struct ipxpcb *ipxp;
1575 struct spxpcb *cb;
1576
1577 error = 0;
1578 ipxp = sotoipxpcb(so);
1579 cb = ipxtospxpcb(ipxp);
1580
1581 s = splnet();
1582 if (flags & PRUS_OOB) {
1583 if (sbspace(&so->so_snd) < -512) {
1584 error = ENOBUFS;
1585 goto spx_send_end;
1586 }
1587 cb->s_oobflags |= SF_SOOB;
1588 }
1589 if (controlp != NULL) {
1590 u_short *p = mtod(controlp, u_short *);
1591 spx_newchecks[2]++;
1592 if ((p[0] == 5) && (p[1] == 1)) { /* XXXX, for testing */
1593 cb->s_shdr.spx_dt = *(u_char *)(&p[2]);
1594 spx_newchecks[3]++;
1595 }
1596 m_freem(controlp);
1597 }
1598 controlp = NULL;
1599 error = spx_output(cb, m);
1600 m = NULL;
1601 spx_send_end:
1602 if (controlp != NULL)
1603 m_freem(controlp);
1604 if (m != NULL)
1605 m_freem(m);
1606 splx(s);
1607 return (error);
1608 }
1609
1610 static int
1611 spx_shutdown(so)
1612 struct socket *so;
1613 {
1614 int error;
1615 int s;
1616 struct ipxpcb *ipxp;
1617 struct spxpcb *cb;
1618
1619 error = 0;
1620 ipxp = sotoipxpcb(so);
1621 cb = ipxtospxpcb(ipxp);
1622
1623 s = splnet();
1624 socantsendmore(so);
1625 cb = spx_usrclosed(cb);
1626 if (cb != NULL)
1627 error = spx_output(cb, (struct mbuf *)NULL);
1628 splx(s);
1629 return (error);
1630 }
1631
1632 static int
1633 spx_sp_attach(so, proto, td)
1634 struct socket *so;
1635 int proto;
1636 struct thread *td;
1637 {
1638 int error;
1639 struct ipxpcb *ipxp;
1640
1641 error = spx_attach(so, proto, td);
1642 if (error == 0) {
1643 ipxp = sotoipxpcb(so);
1644 ((struct spxpcb *)ipxp->ipxp_pcb)->s_flags |=
1645 (SF_HI | SF_HO | SF_PI);
1646 }
1647 return (error);
1648 }
1649
1650 /*
1651 * Create template to be used to send spx packets on a connection.
1652 * Called after host entry created, fills
1653 * in a skeletal spx header (choosing connection id),
1654 * minimizing the amount of work necessary when the connection is used.
1655 */
1656 static void
1657 spx_template(cb)
1658 register struct spxpcb *cb;
1659 {
1660 register struct ipxpcb *ipxp = cb->s_ipxpcb;
1661 register struct ipx *ipx = cb->s_ipx;
1662 register struct sockbuf *sb = &(ipxp->ipxp_socket->so_snd);
1663
1664 ipx->ipx_pt = IPXPROTO_SPX;
1665 ipx->ipx_sna = ipxp->ipxp_laddr;
1666 ipx->ipx_dna = ipxp->ipxp_faddr;
1667 cb->s_sid = htons(spx_iss);
1668 spx_iss += SPX_ISSINCR/2;
1669 cb->s_alo = 1;
1670 cb->s_cwnd = (sbspace(sb) * CUNIT) / cb->s_mtu;
1671 cb->s_ssthresh = cb->s_cwnd; /* Try to expand fast to full complement
1672 of large packets */
1673 cb->s_cwmx = (sbspace(sb) * CUNIT) / (2 * sizeof(struct spx));
1674 cb->s_cwmx = max(cb->s_cwmx, cb->s_cwnd);
1675 /* But allow for lots of little packets as well */
1676 }
1677
1678 /*
1679 * Close a SPIP control block:
1680 * discard spx control block itself
1681 * discard ipx protocol control block
1682 * wake up any sleepers
1683 */
1684 static struct spxpcb *
1685 spx_close(cb)
1686 register struct spxpcb *cb;
1687 {
1688 register struct spx_q *s;
1689 struct ipxpcb *ipxp = cb->s_ipxpcb;
1690 struct socket *so = ipxp->ipxp_socket;
1691 register struct mbuf *m;
1692
1693 s = cb->s_q.si_next;
1694 while (s != &(cb->s_q)) {
1695 s = s->si_next;
1696 m = dtom(s->si_prev);
1697 remque(s->si_prev);
1698 m_freem(m);
1699 }
1700 m_free(dtom(cb->s_ipx));
1701 FREE(cb, M_PCB);
1702 ipxp->ipxp_pcb = 0;
1703 soisdisconnected(so);
1704 ipx_pcbdetach(ipxp);
1705 spxstat.spxs_closed++;
1706 return ((struct spxpcb *)NULL);
1707 }
1708
1709 /*
1710 * Someday we may do level 3 handshaking
1711 * to close a connection or send a xerox style error.
1712 * For now, just close.
1713 */
1714 static struct spxpcb *
1715 spx_usrclosed(cb)
1716 register struct spxpcb *cb;
1717 {
1718 return (spx_close(cb));
1719 }
1720
1721 static struct spxpcb *
1722 spx_disconnect(cb)
1723 register struct spxpcb *cb;
1724 {
1725 return (spx_close(cb));
1726 }
1727
1728 /*
1729 * Drop connection, reporting
1730 * the specified error.
1731 */
1732 static struct spxpcb *
1733 spx_drop(cb, errno)
1734 register struct spxpcb *cb;
1735 int errno;
1736 {
1737 struct socket *so = cb->s_ipxpcb->ipxp_socket;
1738
1739 /*
1740 * someday, in the xerox world
1741 * we will generate error protocol packets
1742 * announcing that the socket has gone away.
1743 */
1744 if (TCPS_HAVERCVDSYN(cb->s_state)) {
1745 spxstat.spxs_drops++;
1746 cb->s_state = TCPS_CLOSED;
1747 /*tcp_output(cb);*/
1748 } else
1749 spxstat.spxs_conndrops++;
1750 so->so_error = errno;
1751 return (spx_close(cb));
1752 }
1753
1754 /*
1755 * Fast timeout routine for processing delayed acks
1756 */
1757 void
1758 spx_fasttimo()
1759 {
1760 register struct ipxpcb *ipxp;
1761 register struct spxpcb *cb;
1762 int s = splnet();
1763
1764 ipxp = ipxpcb.ipxp_next;
1765 if (ipxp != NULL)
1766 for (; ipxp != &ipxpcb; ipxp = ipxp->ipxp_next)
1767 if ((cb = (struct spxpcb *)ipxp->ipxp_pcb) != NULL &&
1768 (cb->s_flags & SF_DELACK)) {
1769 cb->s_flags &= ~SF_DELACK;
1770 cb->s_flags |= SF_ACKNOW;
1771 spxstat.spxs_delack++;
1772 spx_output(cb, (struct mbuf *)NULL);
1773 }
1774 splx(s);
1775 }
1776
1777 /*
1778 * spx protocol timeout routine called every 500 ms.
1779 * Updates the timers in all active pcb's and
1780 * causes finite state machine actions if timers expire.
1781 */
1782 void
1783 spx_slowtimo()
1784 {
1785 register struct ipxpcb *ip, *ipnxt;
1786 register struct spxpcb *cb;
1787 int s = splnet();
1788 register int i;
1789
1790 /*
1791 * Search through tcb's and update active timers.
1792 */
1793 ip = ipxpcb.ipxp_next;
1794 if (ip == NULL) {
1795 splx(s);
1796 return;
1797 }
1798 while (ip != &ipxpcb) {
1799 cb = ipxtospxpcb(ip);
1800 ipnxt = ip->ipxp_next;
1801 if (cb == NULL)
1802 goto tpgone;
1803 for (i = 0; i < SPXT_NTIMERS; i++) {
1804 if (cb->s_timer[i] && --cb->s_timer[i] == 0) {
1805 spx_timers(cb, i);
1806 if (ipnxt->ipxp_prev != ip)
1807 goto tpgone;
1808 }
1809 }
1810 cb->s_idle++;
1811 if (cb->s_rtt)
1812 cb->s_rtt++;
1813 tpgone:
1814 ip = ipnxt;
1815 }
1816 spx_iss += SPX_ISSINCR/PR_SLOWHZ; /* increment iss */
1817 splx(s);
1818 }
1819
1820 /*
1821 * SPX timer processing.
1822 */
1823 static struct spxpcb *
1824 spx_timers(cb, timer)
1825 register struct spxpcb *cb;
1826 int timer;
1827 {
1828 long rexmt;
1829 int win;
1830
1831 cb->s_force = 1 + timer;
1832 switch (timer) {
1833
1834 /*
1835 * 2 MSL timeout in shutdown went off. TCP deletes connection
1836 * control block.
1837 */
1838 case SPXT_2MSL:
1839 printf("spx: SPXT_2MSL went off for no reason\n");
1840 cb->s_timer[timer] = 0;
1841 break;
1842
1843 /*
1844 * Retransmission timer went off. Message has not
1845 * been acked within retransmit interval. Back off
1846 * to a longer retransmit interval and retransmit one packet.
1847 */
1848 case SPXT_REXMT:
1849 if (++cb->s_rxtshift > SPX_MAXRXTSHIFT) {
1850 cb->s_rxtshift = SPX_MAXRXTSHIFT;
1851 spxstat.spxs_timeoutdrop++;
1852 cb = spx_drop(cb, ETIMEDOUT);
1853 break;
1854 }
1855 spxstat.spxs_rexmttimeo++;
1856 rexmt = ((cb->s_srtt >> 2) + cb->s_rttvar) >> 1;
1857 rexmt *= spx_backoff[cb->s_rxtshift];
1858 SPXT_RANGESET(cb->s_rxtcur, rexmt, SPXTV_MIN, SPXTV_REXMTMAX);
1859 cb->s_timer[SPXT_REXMT] = cb->s_rxtcur;
1860 /*
1861 * If we have backed off fairly far, our srtt
1862 * estimate is probably bogus. Clobber it
1863 * so we'll take the next rtt measurement as our srtt;
1864 * move the current srtt into rttvar to keep the current
1865 * retransmit times until then.
1866 */
1867 if (cb->s_rxtshift > SPX_MAXRXTSHIFT / 4 ) {
1868 cb->s_rttvar += (cb->s_srtt >> 2);
1869 cb->s_srtt = 0;
1870 }
1871 cb->s_snxt = cb->s_rack;
1872 /*
1873 * If timing a packet, stop the timer.
1874 */
1875 cb->s_rtt = 0;
1876 /*
1877 * See very long discussion in tcp_timer.c about congestion
1878 * window and sstrhesh
1879 */
1880 win = min(cb->s_swnd, (cb->s_cwnd/CUNIT)) / 2;
1881 if (win < 2)
1882 win = 2;
1883 cb->s_cwnd = CUNIT;
1884 cb->s_ssthresh = win * CUNIT;
1885 spx_output(cb, (struct mbuf *)NULL);
1886 break;
1887
1888 /*
1889 * Persistance timer into zero window.
1890 * Force a probe to be sent.
1891 */
1892 case SPXT_PERSIST:
1893 spxstat.spxs_persisttimeo++;
1894 spx_setpersist(cb);
1895 spx_output(cb, (struct mbuf *)NULL);
1896 break;
1897
1898 /*
1899 * Keep-alive timer went off; send something
1900 * or drop connection if idle for too long.
1901 */
1902 case SPXT_KEEP:
1903 spxstat.spxs_keeptimeo++;
1904 if (cb->s_state < TCPS_ESTABLISHED)
1905 goto dropit;
1906 if (cb->s_ipxpcb->ipxp_socket->so_options & SO_KEEPALIVE) {
1907 if (cb->s_idle >= SPXTV_MAXIDLE)
1908 goto dropit;
1909 spxstat.spxs_keepprobe++;
1910 spx_output(cb, (struct mbuf *)NULL);
1911 } else
1912 cb->s_idle = 0;
1913 cb->s_timer[SPXT_KEEP] = SPXTV_KEEP;
1914 break;
1915 dropit:
1916 spxstat.spxs_keepdrops++;
1917 cb = spx_drop(cb, ETIMEDOUT);
1918 break;
1919 }
1920 return (cb);
1921 }
Cache object: 2e2014123f1434713dfc27a9c60b786c
|