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 * @(#)hd_subr.c 7.5 (Berkeley) 10/04/90 13 */ 14 15 #include "param.h" 16 #include "systm.h" 17 #include "mbuf.h" 18 #include "domain.h" 19 #include "socket.h" 20 #include "protosw.h" 21 #include "errno.h" 22 #include "time.h" 23 #include "kernel.h" 24 25 #include "../net/if.h" 26 27 #include "hdlc.h" 28 #include "hd_var.h" 29 #include "x25.h" 30 31 hd_init () 32 { 33 34 hdintrq.ifq_maxlen = IFQ_MAXLEN; 35 } 36 37 hd_ctlinput (prc, addr) 38 struct sockaddr *addr; 39 { 40 register struct x25config *xcp = (struct x25config *)addr; 41 register struct hdcb *hdp; 42 register struct ifaddr *ifa; 43 struct ifnet *ifp; 44 45 if (addr->sa_family != AF_CCITT) 46 return (EAFNOSUPPORT); 47 if (xcp->xc_lptype != HDLCPROTO_LAPB) 48 return (EPROTONOSUPPORT); 49 ifa = ifa_ifwithaddr(addr); 50 if (ifa == 0 || ifa->ifa_addr->sa_family != AF_CCITT || 51 (ifp = ifa->ifa_ifp) == 0) 52 panic ("hd_ctlinput"); 53 for (hdp = hdcbhead; hdp; hdp = hdp->hd_next) 54 if (hdp->hd_ifp == ifp) 55 break; 56 57 if (hdp == 0) { /* new interface */ 58 int error, hd_ifoutput(), hd_output(); 59 60 /* an hdcb is now too big to fit in an mbuf */ 61 MALLOC(hdp, struct hdcb *, sizeof (*hdp), M_PCB, M_DONTWAIT); 62 if (hdp == 0) 63 return (ENOBUFS); 64 bzero((caddr_t)hdp, sizeof(*hdp)); 65 if (error = pk_ctlinput (PRC_LINKDOWN, xcp)) { 66 free((caddr_t)hdp, M_PCB); 67 return (error); 68 } 69 hdp->hd_next = hdcbhead; 70 hdcbhead = hdp; 71 hdp->hd_ifp = ifp; 72 hdp->hd_ifa = ifa; 73 hdp->hd_xcp = xcp; 74 hdp->hd_state = INIT; 75 hdp->hd_output = hd_ifoutput; 76 pk_ifattach((struct x25_ifaddr *)ifa, hd_output, (caddr_t)hdp); 77 } 78 79 switch (prc) { 80 case PRC_IFUP: 81 if (xcp->xc_lwsize == 0 || 82 xcp->xc_lwsize > MAX_WINDOW_SIZE) 83 xcp->xc_lwsize = MAX_WINDOW_SIZE; 84 if (hdp->hd_state == INIT) 85 SET_TIMER (hdp); 86 break; 87 88 case PRC_IFDOWN: 89 if (hdp->hd_state == ABM) 90 hd_message (hdp, "Operator shutdown: link closed"); 91 (void) pk_ctlinput (PRC_LINKDOWN, xcp); 92 hd_writeinternal (hdp, DISC, POLLON); 93 hdp->hd_state = DISC_SENT; 94 SET_TIMER (hdp); 95 } 96 return (0); 97 } 98 99 hd_initvars (hdp) 100 register struct hdcb *hdp; 101 { 102 register struct mbuf *m; 103 register int i; 104 105 /* Clear Transmit queue. */ 106 while ((m = hd_remove (&hdp->hd_txq)) != NULL) 107 m_freem (m); 108 109 /* Clear Retransmit queue. */ 110 i = hdp->hd_lastrxnr; 111 while (i != hdp->hd_retxqi) { 112 m_freem (hdp->hd_retxq[i]); 113 i = (i + 1) % MODULUS; 114 } 115 hdp->hd_retxqi = 0; 116 117 hdp->hd_vs = hdp->hd_vr = 0; 118 hdp->hd_lasttxnr = hdp->hd_lastrxnr = 0; 119 hdp->hd_rrtimer = 0; 120 KILL_TIMER(hdp); 121 hdp->hd_retxcnt = 0; 122 hdp->hd_condition = 0; 123 } 124 125 hd_decode (hdp, frame) 126 register struct hdcb *hdp; 127 struct Hdlc_frame *frame; 128 { 129 register int frametype = ILLEGAL; 130 register struct Hdlc_iframe *iframe = (struct Hdlc_iframe *) frame; 131 register struct Hdlc_sframe *sframe = (struct Hdlc_sframe *) frame; 132 register struct Hdlc_uframe *uframe = (struct Hdlc_uframe *) frame; 133 134 if (iframe -> hdlc_0 == 0) { 135 frametype = IFRAME; 136 hdp->hd_iframes_in++; 137 } 138 139 else if (sframe -> hdlc_01 == 1) { 140 /* Supervisory format. */ 141 switch (sframe -> s2) { 142 case 0: 143 frametype = RR; 144 hdp->hd_rrs_in++; 145 break; 146 147 case 1: 148 frametype = RNR; 149 hdp->hd_rnrs_in++; 150 break; 151 152 case 2: 153 frametype = REJ; 154 hdp->hd_rejs_in++; 155 } 156 } 157 else if (uframe -> hdlc_11 == 3) { 158 /* Unnumbered format. */ 159 switch (uframe -> m3) { 160 case 0: 161 frametype = DM; 162 break; 163 164 case 1: 165 frametype = SABM; 166 break; 167 168 case 2: 169 frametype = DISC; 170 break; 171 172 case 3: 173 frametype = UA; 174 break; 175 176 case 4: 177 frametype = FRMR; 178 hdp->hd_frmrs_in++; 179 } 180 } 181 return (frametype); 182 } 183 184 /* 185 * This routine is called when the HDLC layer internally generates a 186 * command or response for the remote machine ( eg. RR, UA etc. ). 187 * Only supervisory or unnumbered frames are processed. 188 */ 189 190 hd_writeinternal (hdp, frametype, pf) 191 register struct hdcb *hdp; 192 register int frametype, pf; 193 { 194 register struct mbuf *buf; 195 struct Hdlc_frame *frame; 196 register struct Hdlc_sframe *sframe; 197 register struct Hdlc_uframe *uframe; 198 199 MGETHDR (buf, M_DONTWAIT, MT_HEADER); 200 if (buf == 0) 201 return; 202 frame = mtod (buf, struct Hdlc_frame *); 203 sframe = mtod (buf, struct Hdlc_sframe *); 204 uframe = mtod (buf, struct Hdlc_uframe *); 205 206 /* Assume a response - address structure for DTE */ 207 frame -> address = ADDRESS_A; 208 buf -> m_len = 2; 209 buf -> m_act = buf -> m_next = NULL; 210 211 switch (frametype) { 212 case RR: 213 frame -> control = RR_CONTROL; 214 hdp->hd_rrs_out++; 215 break; 216 217 case RNR: 218 frame -> control = RNR_CONTROL; 219 hdp->hd_rnrs_out++; 220 break; 221 222 case REJ: 223 frame -> control = REJ_CONTROL; 224 hdp->hd_rejs_out++; 225 break; 226 227 case SABM: 228 frame -> control = SABM_CONTROL; 229 frame -> address = ADDRESS_B; 230 break; 231 232 case DISC: 233 if ((hdp->hd_ifp->if_flags & IFF_UP) == 0) { 234 hdp->hd_state = DISCONNECTED; 235 (void) m_freem (buf); 236 hd_flush (hdp->hd_ifp); 237 return; 238 } 239 frame -> control = DISC_CONTROL; 240 frame -> address = ADDRESS_B; 241 break; 242 243 case DM: 244 frame -> control = DM_CONTROL; 245 break; 246 247 case UA: 248 frame -> control = UA_CONTROL; 249 break; 250 251 case FRMR: 252 frame -> control = FRMR_CONTROL; 253 bcopy ((caddr_t)&hd_frmr, (caddr_t)frame -> info, 3); 254 buf -> m_len = 5; 255 hdp->hd_frmrs_out++; 256 257 } 258 259 if (sframe -> hdlc_01 == 1) { 260 /* Supervisory format - RR, REJ, or RNR. */ 261 sframe -> nr = hdp->hd_vr; 262 sframe -> pf = pf; 263 hdp->hd_lasttxnr = hdp->hd_vr; 264 hdp->hd_rrtimer = 0; 265 } 266 else 267 uframe -> pf = pf; 268 269 hd_trace (hdp, TX, frame); 270 buf -> m_pkthdr.len = buf -> m_len; 271 (*hdp->hd_output) (hdp, buf); 272 } 273 274 struct mbuf * 275 hd_remove (q) 276 struct hdtxq *q; 277 { 278 register struct mbuf *m; 279 280 m = q -> head; 281 if (m) { 282 if ((q -> head = m -> m_act) == NULL) 283 q -> tail = NULL; 284 m -> m_act = 0; 285 } 286 return (m); 287 } 288 289 hd_append (q, m) 290 register struct hdtxq *q; 291 register struct mbuf *m; 292 { 293 294 m -> m_act = NULL; 295 if (q -> tail == NULL) 296 q -> head = m; 297 else 298 q -> tail -> m_act = m; 299 q -> tail = m; 300 } 301 302 hd_flush (ifp) 303 struct ifnet *ifp; 304 { 305 register struct mbuf *m; 306 register int s; 307 308 while (1) { 309 s = splimp (); 310 IF_DEQUEUE (&ifp->if_snd, m); 311 splx (s); 312 if (m == 0) 313 break; 314 m_freem (m); 315 } 316 } 317 318 hd_message (hdp, msg) 319 struct hdcb *hdp; 320 char *msg; 321 { 322 char *format_ntn (); 323 324 if (hdcbhead -> hd_next) 325 printf ("HDLC(%s): %s\n", format_ntn (hdp->hd_xcp), msg); 326 else 327 printf ("HDLC: %s\n", msg); 328 } 329 330 #ifdef HDLCDEBUG 331 hd_status (hdp) 332 struct hdcb *hdp; 333 { 334 printf ("HDLC STATUS:\n V(S)=%d, V(R)=%d, retxqi=%d,\n", 335 hdp->hd_vs, hdp->hd_vr, hdp->hd_retxqi); 336 337 printf ("Last_rx_nr=%d, Last_tx_nr=%d,\n Condition=%d, Xx=%d\n", 338 hdp->hd_lastrxnr, hdp->hd_lasttxnr, hdp->hd_condition, hdp->hd_xx); 339 } 340 #endif 341