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