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