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