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