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