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.9 (Berkeley) 05/09/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 }; 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 PR(xp) = lcp -> lcd_input_window; 90 lcp -> lcd_last_transmitted_pr = lcp -> lcd_input_window; 91 lcp -> lcd_ssn = (lcp -> lcd_ssn + 1) % MODULUS; 92 if (lcp -> lcd_ssn == ((lcp -> lcd_output_window + lcp -> lcd_windowsize) % MODULUS)) 93 lcp -> lcd_window_condition = TRUE; 94 break; 95 96 case INTERRUPT + DATA_TRANSFER: 97 #ifdef ancient_history 98 xp -> packet_data = 0; 99 #endif 100 lcp -> lcd_intrconf_pending = TRUE; 101 break; 102 103 case INTERRUPT_CONF + DATA_TRANSFER: 104 break; 105 106 case RR + DATA_TRANSFER: 107 lcp -> lcd_input_window = (lcp -> lcd_input_window + 1) % MODULUS; 108 PR(xp) = lcp -> lcd_input_window; 109 lcp -> lcd_last_transmitted_pr = lcp -> lcd_input_window; 110 break; 111 112 case RNR + DATA_TRANSFER: 113 PR(xp) = lcp -> lcd_input_window; 114 lcp -> lcd_last_transmitted_pr = lcp -> lcd_input_window; 115 break; 116 117 case RESET + DATA_TRANSFER: 118 lcp -> lcd_reset_condition = TRUE; 119 break; 120 121 case RESET_CONF + DATA_TRANSFER: 122 lcp -> lcd_reset_condition = FALSE; 123 break; 124 125 /* 126 * A restart should be only generated internally. Therefore 127 * all logic for restart is in the pk_restart routine. 128 */ 129 case RESTART + READY: 130 lcp -> lcd_timer = pk_t20; 131 break; 132 133 /* 134 * Restarts are all handled internally. Therefore all the 135 * logic for the incoming restart packet is handled in the 136 * pk_input routine. 137 */ 138 case RESTART_CONF + READY: 139 break; 140 141 default: 142 m_freem (m); 143 return; 144 } 145 146 /* Trace the packet. */ 147 pk_trace (pkp -> pk_xcp, m, "P-Out"); 148 149 /* Pass the packet on down to the link layer */ 150 if (pk_output_cache.mbc_size || pk_output_cache.mbc_oldsize) 151 mbuf_cache(&pk_output_cache, m); 152 (*pkp -> pk_lloutput) (pkp -> pk_llnext, m); 153 } 154 } 155 156 /* 157 * This procedure returns the next packet to send or null. A 158 * packet is composed of one or more mbufs. 159 */ 160 161 struct mbuf * 162 nextpk (lcp) 163 struct pklcd *lcp; 164 { 165 register struct mbuf *m, *n; 166 struct socket *so = lcp -> lcd_so; 167 register struct sockbuf *sb = & (so ? so -> so_snd : lcp -> lcd_sb); 168 169 if (lcp -> lcd_template) { 170 m = lcp -> lcd_template; 171 lcp -> lcd_template = NULL; 172 } else { 173 if (lcp -> lcd_rnr_condition || lcp -> lcd_window_condition || 174 lcp -> lcd_reset_condition) 175 return (NULL); 176 177 if ((m = sb -> sb_mb) == 0) 178 return (NULL); 179 180 sb -> sb_mb = m -> m_nextpkt; 181 m->m_act = 0; 182 for (n = m; n; n = n -> m_next) 183 sbfree (sb, n); 184 } 185 return (m); 186 } 187