1 /* 2 * Copyright (C) Dirk Husemann, Computer Science Department IV, 3 * University of Erlangen-Nuremberg, Germany, 1990, 1991, 1992 4 * Copyright (c) 1992, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Dirk Husemann and the Computer Science Department (IV) of 9 * the University of Erlangen-Nuremberg, Germany. 10 * 11 * %sccs.include.redist.c% 12 * 13 * @(#)llc_output.c 8.1 (Berkeley) 06/10/93 14 */ 15 16 #include <sys/param.h> 17 #include <sys/systm.h> 18 #include <sys/mbuf.h> 19 #include <sys/domain.h> 20 #include <sys/socket.h> 21 #include <sys/protosw.h> 22 #include <sys/errno.h> 23 #include <sys/time.h> 24 #include <sys/kernel.h> 25 26 #include <net/if.h> 27 #include <net/if_dl.h> 28 #include <net/if_llc.h> 29 #include <net/route.h> 30 31 #include <netccitt/dll.h> 32 #include <netccitt/llc_var.h> 33 34 /* 35 * llc_output() --- called by an upper layer (network layer) entity whenever 36 * there is an INFO frame to be transmitted. We enqueue the 37 * info frame and call llc_start() to do the actual sending. 38 */ 39 40 llc_output(struct llc_linkcb *linkp, struct mbuf *m) 41 { 42 register int i; 43 44 i = splimp(); 45 LLC_ENQUEUE(linkp, m); 46 llc_start(linkp); 47 splx(i); 48 49 } 50 51 52 /* 53 * llc_start() --- We try to subsequently dequeue all the frames available and 54 * send them out. 55 */ 56 void 57 llc_start(struct llc_linkcb *linkp) 58 { 59 register int i; 60 register struct mbuf *m; 61 int action; 62 63 while ((LLC_STATEEQ(linkp, NORMAL) || LLC_STATEEQ(linkp, BUSY) || 64 LLC_STATEEQ(linkp, REJECT)) && 65 (linkp->llcl_slotsfree > 0) && 66 (LLC_GETFLAG(linkp, REMOTE_BUSY) == 0)) { 67 LLC_DEQUEUE(linkp, m); 68 if (m == NULL) 69 break; 70 LLC_SETFRAME(linkp, m); 71 (void)llc_statehandler(linkp, (struct llc *) 0, NL_DATA_REQUEST, 72 0, 0); 73 } 74 } 75 76 77 /* 78 * llc_send() --- Handles single frames. If dealing with INFO frames we need to 79 * prepend the LLC header, otherwise we just allocate an mbuf. 80 * In both cases the actual send is done by llc_rawsend(). 81 */ 82 llc_send(struct llc_linkcb *linkp, int frame_kind, int cmdrsp, int pollfinal) 83 { 84 register struct mbuf *m = (struct mbuf *)0; 85 register struct llc *frame; 86 87 if (frame_kind == LLCFT_INFO) 88 m = linkp->llcl_output_buffers[llc_seq2slot(linkp, 89 linkp->llcl_vs)]; 90 LLC_GETHDR(frame, m); 91 92 /* pass it on to llc_rawsend() */ 93 llc_rawsend(linkp, m, frame, frame_kind, linkp->llcl_vs, cmdrsp, pollfinal); 94 95 if (frame_kind == LLCFT_INFO) 96 LLC_INC(linkp->llcl_vs); 97 98 return 0; 99 } 100 101 /* 102 * llc_resend() --- llc_resend() retransmits all unacknowledged INFO frames. 103 */ 104 llc_resend(struct llc_linkcb *linkp, int cmdrsp, int pollfinal) 105 { 106 register struct llc *frame; 107 register struct mbuf *m; 108 register int seq, slot; 109 110 if (linkp->llcl_slotsfree < linkp->llcl_window) 111 /* assert lock between nr_received & V(S) */ 112 if (linkp->llcl_nr_received != linkp->llcl_vs) 113 panic("llc: V(S) != N(R) received\n"); 114 115 for (slot = llc_seq2slot(linkp, linkp->llcl_vs); 116 slot != linkp->llcl_freeslot; 117 LLC_INC(linkp->llcl_vs), 118 slot = llc_seq2slot(linkp, linkp->llcl_vs)) { 119 m = linkp->llcl_output_buffers[slot]; 120 LLC_GETHDR(frame, m); 121 llc_rawsend(linkp, m, frame, LLCFT_INFO, linkp->llcl_vs, 122 cmdrsp, pollfinal); 123 pollfinal = 0; 124 } 125 126 return 0; 127 } 128 129 /* 130 * llc_rawsend() --- constructs an LLC frame and sends it out via the 131 * associated interface of the link control block. 132 * 133 * We need to make sure that outgoing frames have the correct length, 134 * in particular the 4 byte ones (RR, RNR, REJ) as LLC_GETHDR() will 135 * set the mbuf len to 3 as default len for non INFO frames ... 136 * 137 * Frame kind Length (w/o MAC header, {D,S}SAP incl.) 138 * -------------------------------------------------------------- 139 * DISC, SABME, UA, DM 3 bytes ({D,S}SAP + CONTROL) 140 * RR, RNR, REJ 4 bytes ({D,S}SAP + CONTROL0 + CONTROL1) 141 * XID 6 bytes ({D,S}SAP + CONTROL0 + FI,CLASS,WINDOW) 142 * FRMR 7 bytes ({D,S}SAP + CONTROL0 + REJ CONTROL,V(S),V(R),CAUSE) 143 * INFO 4 -- MTU 144 * UI, TEST 3 -- MTU 145 * 146 */ 147 #define LLC_SETLEN(m, l) (m)->m_pkthdr.len = (m)->m_len = (l) 148 149 llc_rawsend(struct llc_linkcb *linkp, struct mbuf *m, struct llc *frame, 150 int frame_kind, int vs, int cmdrsp, int pollfinal) 151 { 152 register short adjust = LLC_UFRAMELEN; 153 struct ifnet *ifp; 154 155 switch (frame_kind) { 156 /* supervisory and information frames */ 157 case LLCFT_INFO: 158 frame->llc_control = LLC_INFO; 159 LLCSBITS(frame->llc_control, i_ns, vs); 160 LLCSBITS(frame->llc_control_ext, i_nr, linkp->llcl_vr); 161 adjust = LLC_ISFRAMELEN; 162 break; 163 case LLCFT_RR: 164 frame->llc_control = LLC_RR; 165 LLC_SETLEN(m, LLC_ISFRAMELEN); 166 LLCSBITS(frame->llc_control_ext, s_nr, linkp->llcl_vr); 167 adjust = LLC_ISFRAMELEN; 168 break; 169 case LLCFT_RNR: 170 frame->llc_control = LLC_RNR; 171 LLC_SETLEN(m, LLC_ISFRAMELEN); 172 LLCSBITS(frame->llc_control_ext, s_nr, linkp->llcl_vr); 173 adjust = LLC_ISFRAMELEN; 174 break; 175 case LLCFT_REJ: 176 frame->llc_control = LLC_REJ; 177 LLC_SETLEN(m, LLC_ISFRAMELEN); 178 LLCSBITS(frame->llc_control_ext, s_nr, linkp->llcl_vr); 179 adjust = LLC_ISFRAMELEN; 180 break; 181 /* unnumbered frames */ 182 case LLCFT_DM: 183 frame->llc_control = LLC_DM; 184 break; 185 case LLCFT_SABME: 186 frame->llc_control = LLC_SABME; 187 break; 188 case LLCFT_DISC: 189 frame->llc_control = LLC_DISC; 190 break; 191 case LLCFT_UA: 192 frame->llc_control = LLC_UA; 193 break; 194 case LLCFT_UI: 195 frame->llc_control = LLC_UI; 196 break; 197 case LLCFT_FRMR: 198 frame->llc_control = LLC_FRMR; 199 /* get more space --- FRMR frame are longer then usual */ 200 LLC_SETLEN(m, LLC_FRMRLEN); 201 bcopy((caddr_t) &linkp->llcl_frmrinfo, 202 (caddr_t) &frame->llc_frmrinfo, 203 sizeof(struct frmrinfo)); 204 break; 205 default: 206 /* 207 * We don't send {XID, TEST} frames 208 */ 209 if (m) 210 m_freem(m); 211 return; 212 } 213 214 /* 215 * Fill in DSAP/SSAP 216 */ 217 frame->llc_dsap = frame->llc_ssap = LLSAPADDR(&linkp->llcl_addr); 218 frame->llc_ssap |= cmdrsp; 219 220 /* 221 * Check for delayed action pending. ISO 8802-2, 7.9.2 (5) 222 * and ISO 8802-2, 7.9.2.3 (32), (34), (36) pertain to this 223 * piece of code --- hopefully we got it right here (i.e. 224 * in the spirit of (32), (34), and (36) ... 225 */ 226 switch (frame_kind) { 227 case LLCFT_RR: 228 case LLCFT_RNR: 229 case LLCFT_REJ: 230 case LLCFT_INFO: 231 switch (LLC_GETFLAG(linkp, DACTION)) { 232 case LLC_DACKCMD: 233 case LLC_DACKRSP: 234 LLC_STOPTIMER(linkp, DACTION); 235 break; 236 case LLC_DACKCMDPOLL: 237 if (cmdrsp == LLC_CMD) { 238 pollfinal = 1; 239 LLC_STOPTIMER(linkp, DACTION); 240 } 241 break; 242 case LLC_DACKRSPFINAL: 243 if (cmdrsp == LLC_RSP) { 244 pollfinal = 1; 245 LLC_STOPTIMER(linkp, DACTION); 246 } 247 break; 248 } 249 break; 250 } 251 252 if (adjust == LLC_UFRAMELEN) 253 LLCSBITS(frame->llc_control, u_pf, pollfinal); 254 else LLCSBITS(frame->llc_control_ext, s_pf, pollfinal); 255 256 /* 257 * Get interface to send frame onto 258 */ 259 ifp = linkp->llcl_if; 260 if (frame_kind == LLCFT_INFO) { 261 /* 262 * send out a copy of the frame, retain the 263 * original 264 */ 265 (*ifp->if_output)(ifp, m_copy(m, 0, (int)M_COPYALL), 266 rt_key(linkp->llcl_nlrt), 267 linkp->llcl_nlrt); 268 /* 269 * Account for the LLC header and let it ``disappear'' 270 * as the raw info frame payload is what we hold in 271 * the output_buffers of the link. 272 */ 273 m_adj(m, LLC_ISFRAMELEN); 274 } else (*ifp->if_output)(ifp, m, 275 rt_key(linkp->llcl_nlrt), 276 linkp->llcl_nlrt); 277 } 278 279