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.7 (Berkeley) 01/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 *nextpk (); 30 31 pk_output (lcp) 32 register struct pklcd *lcp; 33 { 34 register struct x25_packet *xp; 35 register struct mbuf *m; 36 register struct pkcb *pkp = lcp -> lcd_pkp; 37 38 if (lcp == 0 || pkp == 0) { 39 printf ("pk_output: zero arg\n"); 40 return; 41 } 42 43 while ((m = nextpk (lcp)) != NULL) { 44 xp = mtod (m, struct x25_packet *); 45 46 switch (pk_decode (xp) + lcp -> lcd_state) { 47 /* 48 * All the work is already done - just set the state and 49 * pass to peer. 50 */ 51 case CALL + READY: 52 lcp -> lcd_state = SENT_CALL; 53 lcp -> lcd_timer = pk_t21; 54 break; 55 56 /* 57 * Just set the state to allow packet to flow and send the 58 * confirmation. 59 */ 60 case CALL_ACCEPTED + RECEIVED_CALL: 61 lcp -> lcd_state = DATA_TRANSFER; 62 break; 63 64 /* 65 * Just set the state. Keep the LCD around till the clear 66 * confirmation is returned. 67 */ 68 case CLEAR + RECEIVED_CALL: 69 case CLEAR + SENT_CALL: 70 case CLEAR + DATA_TRANSFER: 71 lcp -> lcd_state = SENT_CLEAR; 72 lcp -> lcd_retry = 0; 73 /* fall through */ 74 75 case CLEAR + SENT_CLEAR: 76 lcp -> lcd_timer = pk_t23; 77 lcp -> lcd_retry++; 78 break; 79 80 case CLEAR_CONF + RECEIVED_CLEAR: 81 case CLEAR_CONF + SENT_CLEAR: 82 case CLEAR_CONF + READY: 83 lcp -> lcd_state = READY; 84 break; 85 86 case DATA + DATA_TRANSFER: 87 PS(xp) = lcp -> lcd_ssn; 88 PR(xp) = lcp -> lcd_input_window; 89 lcp -> lcd_last_transmitted_pr = lcp -> lcd_input_window; 90 lcp -> lcd_ssn = (lcp -> lcd_ssn + 1) % MODULUS; 91 if (lcp -> lcd_ssn == ((lcp -> lcd_output_window + pkp->pk_xcp->xc_pwsize) % MODULUS)) 92 lcp -> lcd_window_condition = TRUE; 93 break; 94 95 case INTERRUPT + DATA_TRANSFER: 96 #ifdef ancient_history 97 xp -> packet_data = 0; 98 #endif 99 lcp -> lcd_intrconf_pending = TRUE; 100 break; 101 102 case INTERRUPT_CONF + DATA_TRANSFER: 103 break; 104 105 case RR + DATA_TRANSFER: 106 lcp -> lcd_input_window = (lcp -> lcd_input_window + 1) % MODULUS; 107 PR(xp) = lcp -> lcd_input_window; 108 lcp -> lcd_last_transmitted_pr = lcp -> lcd_input_window; 109 break; 110 111 case RNR + DATA_TRANSFER: 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 (*pkp -> pk_lloutput) (pkp -> pk_llnext, m); 150 } 151 } 152 153 /* 154 * This procedure returns the next packet to send or null. A 155 * packet is composed of one or more mbufs. 156 */ 157 158 struct mbuf * 159 nextpk (lcp) 160 struct pklcd *lcp; 161 { 162 register struct mbuf *m, *n; 163 struct socket *so = lcp -> lcd_so; 164 register struct sockbuf *sb = & (so ? so -> so_snd : lcp -> lcd_sb); 165 166 if (lcp -> lcd_template) { 167 m = lcp -> lcd_template; 168 lcp -> lcd_template = NULL; 169 } else { 170 if (lcp -> lcd_rnr_condition || lcp -> lcd_window_condition || 171 lcp -> lcd_reset_condition) 172 return (NULL); 173 174 if ((m = sb -> sb_mb) == 0) 175 return (NULL); 176 177 sb -> sb_mb = m -> m_nextpkt; 178 m->m_act = 0; 179 for (n = m; n; n = n -> m_next) 180 sbfree (sb, n); 181 } 182 return (m); 183 } 184