1 /*
2 * Copyright (c) University of British Columbia, 1984
3 * Copyright (C) Computer Science Department IV,
4 * University of Erlangen-Nuremberg, Germany, 1992
5 * Copyright (c) 1991, 1992, 1993
6 * The Regents of the University of California. All rights reserved.
7 *
8 * This code is derived from software contributed to Berkeley by the
9 * Laboratory for Computation Vision and the Computer Science Department
10 * of the the University of British Columbia and the Computer Science
11 * Department (IV) of the University of Erlangen-Nuremberg, Germany.
12 *
13 * %sccs.include.redist.c%
14 *
15 * @(#)pk_output.c 8.2 (Berkeley) 09/22/94
16 */
17
18 #include <sys/param.h>
19 #include <sys/systm.h>
20 #include <sys/mbuf.h>
21 #include <sys/socket.h>
22 #include <sys/socketvar.h>
23 #include <sys/protosw.h>
24 #include <sys/errno.h>
25
26 #include <net/if.h>
27
28 #include <netccitt/x25.h>
29 #include <netccitt/pk.h>
30 #include <netccitt/pk_var.h>
31
32 struct mbuf_cache pk_output_cache = {0 }, pk_input_cache;
33 struct mbuf *nextpk ();
34
pk_output(lcp)35 pk_output (lcp)
36 register struct pklcd *lcp;
37 {
38 register struct x25_packet *xp;
39 register struct mbuf *m;
40 register struct pkcb *pkp = lcp -> lcd_pkp;
41
42 if (lcp == 0 || pkp == 0) {
43 printf ("pk_output: zero arg\n");
44 return;
45 }
46
47 while ((m = nextpk (lcp)) != NULL) {
48 xp = mtod (m, struct x25_packet *);
49
50 switch (pk_decode (xp) + lcp -> lcd_state) {
51 /*
52 * All the work is already done - just set the state and
53 * pass to peer.
54 */
55 case CALL + READY:
56 lcp -> lcd_state = SENT_CALL;
57 lcp -> lcd_timer = pk_t21;
58 break;
59
60 /*
61 * Just set the state to allow packet to flow and send the
62 * confirmation.
63 */
64 case CALL_ACCEPTED + RECEIVED_CALL:
65 lcp -> lcd_state = DATA_TRANSFER;
66 break;
67
68 /*
69 * Just set the state. Keep the LCD around till the clear
70 * confirmation is returned.
71 */
72 case CLEAR + RECEIVED_CALL:
73 case CLEAR + SENT_CALL:
74 case CLEAR + DATA_TRANSFER:
75 lcp -> lcd_state = SENT_CLEAR;
76 lcp -> lcd_retry = 0;
77 /* fall through */
78
79 case CLEAR + SENT_CLEAR:
80 lcp -> lcd_timer = pk_t23;
81 lcp -> lcd_retry++;
82 break;
83
84 case CLEAR_CONF + RECEIVED_CLEAR:
85 case CLEAR_CONF + SENT_CLEAR:
86 case CLEAR_CONF + READY:
87 lcp -> lcd_state = READY;
88 break;
89
90 case DATA + DATA_TRANSFER:
91 SPS(xp, lcp -> lcd_ssn);
92 lcp -> lcd_input_window =
93 (lcp -> lcd_rsn + 1) % MODULUS;
94 SPR(xp, lcp -> lcd_input_window);
95 lcp -> lcd_last_transmitted_pr = lcp -> lcd_input_window;
96 lcp -> lcd_ssn = (lcp -> lcd_ssn + 1) % MODULUS;
97 if (lcp -> lcd_ssn == ((lcp -> lcd_output_window + lcp -> lcd_windowsize) % MODULUS))
98 lcp -> lcd_window_condition = TRUE;
99 break;
100
101 case INTERRUPT + DATA_TRANSFER:
102 #ifdef ancient_history
103 xp -> packet_data = 0;
104 #endif
105 lcp -> lcd_intrconf_pending = TRUE;
106 break;
107
108 case INTERRUPT_CONF + DATA_TRANSFER:
109 break;
110
111 case RR + DATA_TRANSFER:
112 case RNR + DATA_TRANSFER:
113 lcp -> lcd_input_window =
114 (lcp -> lcd_rsn + 1) % MODULUS;
115 SPR(xp, lcp -> lcd_input_window);
116 lcp -> lcd_last_transmitted_pr = lcp -> lcd_input_window;
117 break;
118
119 case RESET + DATA_TRANSFER:
120 lcp -> lcd_reset_condition = TRUE;
121 break;
122
123 case RESET_CONF + DATA_TRANSFER:
124 lcp -> lcd_reset_condition = FALSE;
125 break;
126
127 /*
128 * A restart should be only generated internally. Therefore
129 * all logic for restart is in the pk_restart routine.
130 */
131 case RESTART + READY:
132 lcp -> lcd_timer = pk_t20;
133 break;
134
135 /*
136 * Restarts are all handled internally. Therefore all the
137 * logic for the incoming restart packet is handled in the
138 * pk_input routine.
139 */
140 case RESTART_CONF + READY:
141 break;
142
143 default:
144 m_freem (m);
145 return;
146 }
147
148 /* Trace the packet. */
149 pk_trace (pkp -> pk_xcp, m, "P-Out");
150
151 /* Pass the packet on down to the link layer */
152 if (pk_input_cache.mbc_size || pk_input_cache.mbc_oldsize) {
153 m->m_flags |= 0x08;
154 mbuf_cache(&pk_input_cache, m);
155 }
156 (*pkp -> pk_lloutput) (pkp -> pk_llnext, m, pkp -> pk_rt);
157 }
158 }
159
160 /*
161 * This procedure returns the next packet to send or null. A
162 * packet is composed of one or more mbufs.
163 */
164
165 struct mbuf *
nextpk(lcp)166 nextpk (lcp)
167 struct pklcd *lcp;
168 {
169 register struct mbuf *m, *n;
170 struct socket *so = lcp -> lcd_so;
171 register struct sockbuf *sb = (so ? &so -> so_snd : &lcp -> lcd_sb);
172
173 if (lcp -> lcd_template) {
174 m = lcp -> lcd_template;
175 lcp -> lcd_template = NULL;
176 } else {
177 if (lcp -> lcd_rnr_condition || lcp -> lcd_window_condition ||
178 lcp -> lcd_reset_condition)
179 return (NULL);
180
181 if ((m = sb -> sb_mb) == 0)
182 return (NULL);
183
184 sb -> sb_mb = m -> m_nextpkt;
185 m->m_act = 0;
186 for (n = m; n; n = n -> m_next)
187 sbfree (sb, n);
188 }
189 return (m);
190 }
191