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.4 (Berkeley) 06/21/90 13 */ 14 15 #include "../h/param.h" 16 #include "../h/systm.h" 17 #include "../h/mbuf.h" 18 #include "../h/socket.h" 19 #include "../h/socketvar.h" 20 #include "../h/protosw.h" 21 #include "../h/errno.h" 22 23 #include "../net/if.h" 24 25 #include "../netccitt/pk.h" 26 #include "../netccitt/pk_var.h" 27 #include "../netccitt/x25.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 xp -> packet_data = 0; 97 lcp -> lcd_intrconf_pending = TRUE; 98 break; 99 100 case INTERRUPT_CONF + DATA_TRANSFER: 101 break; 102 103 case RR + DATA_TRANSFER: 104 lcp -> lcd_input_window = (lcp -> lcd_input_window + 1) % MODULUS; 105 PR(xp) = lcp -> lcd_input_window; 106 lcp -> lcd_last_transmitted_pr = lcp -> lcd_input_window; 107 break; 108 109 case RNR + DATA_TRANSFER: 110 PR(xp) = lcp -> lcd_input_window; 111 lcp -> lcd_last_transmitted_pr = lcp -> lcd_input_window; 112 break; 113 114 case RESET + DATA_TRANSFER: 115 lcp -> lcd_reset_condition = TRUE; 116 break; 117 118 case RESET_CONF + DATA_TRANSFER: 119 lcp -> lcd_reset_condition = FALSE; 120 break; 121 122 /* 123 * A restart should be only generated internally. Therefore 124 * all logic for restart is in the pk_restart routine. 125 */ 126 case RESTART + READY: 127 lcp -> lcd_timer = pk_t20; 128 break; 129 130 /* 131 * Restarts are all handled internally. Therefore all the 132 * logic for the incoming restart packet is handled in the 133 * pk_input routine. 134 */ 135 case RESTART_CONF + READY: 136 break; 137 138 default: 139 m_freem (m); 140 return; 141 } 142 143 /* Trace the packet. */ 144 pk_trace (pkp -> pk_xcp, xp, "P-Out"); 145 146 /* Pass the packet on down to the link layer */ 147 (*pkp -> pk_lloutput) (m, pkp -> llnext); 148 } 149 } 150 151 /* 152 * This procedure returns the next packet to send or null. A 153 * packet is composed of one or more mbufs. 154 */ 155 156 struct mbuf * 157 nextpk (lcp) 158 struct pklcd *lcp; 159 { 160 register struct mbuf *m, *n; 161 struct socket *so = lcp -> lcd_so; 162 register struct sockbuf *sb = & (so ? so -> so_snd : lcp -> lcd_sb); 163 164 if (lcp -> lcd_template) { 165 m = dtom (lcp -> lcd_template); 166 lcp -> lcd_template = NULL; 167 } else { 168 if (lcp -> lcd_rnr_condition || lcp -> lcd_window_condition || 169 lcp -> lcd_reset_condition) 170 return (NULL); 171 172 if ((m = sb -> sb_mb) == 0) 173 return (NULL); 174 175 sb -> sb_mb = m -> m_nextpkt; 176 m->m_act = 0; 177 for (n = m; n; n = n -> m_next) 178 sbfree (sb, n); 179 } 180 return (m); 181 } 182