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