📄 llc_subr.c
字号:
/* * Copyright (C) Dirk Husemann, Computer Science Department IV, * University of Erlangen-Nuremberg, Germany, 1990, 1991, 1992 * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Dirk Husemann and the Computer Science Department (IV) of * the University of Erlangen-Nuremberg, Germany. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)llc_subr.c 8.1 (Berkeley) 6/10/93 */#include <sys/param.h>#include <sys/systm.h>#include <sys/mbuf.h>#include <sys/domain.h>#include <sys/socket.h>#include <sys/protosw.h>#include <sys/socketvar.h>#include <sys/errno.h>#include <sys/time.h>#include <sys/kernel.h>#include <net/if.h>#include <net/if_dl.h>#include <net/if_llc.h>#include <net/route.h>#include <netccitt/dll.h>#include <netccitt/llc_var.h>/* * Frame names for diagnostic messages */char *frame_names[] = { "INFO", "RR", "RNR", "REJ", "DM", "SABME", "DISC", "UA", "FRMR", "UI", "XID", "TEST", "ILLEGAL", "TIMER", "N2xT1"};/* * Trace level */int llc_tracelevel = LLCTR_URGENT;/* * Values for accessing various bitfields */struct bitslice llc_bitslice[] = {/* mask, shift value */ { 0x1, 0x0 }, { 0xfe, 0x1 }, { 0x3, 0x0 }, { 0xc, 0x2 }, { 0x10, 0x4 }, { 0xe0, 0x5 }, { 0x1f, 0x0 }};/* * We keep the link control blocks on a doubly linked list - * primarily for checking in llc_time() */struct llccb_q llccb_q = { &llccb_q, &llccb_q };/* * Flag for signalling wether route tree for AF_LINK has been * initialized yet. */int af_link_rts_init_done = 0; /* * Functions dealing with struct sockaddr_dl *//* Compare sdl_a w/ sdl_b */sdl_cmp(struct sockaddr_dl *sdl_a, struct sockaddr_dl *sdl_b){ if (LLADDRLEN(sdl_a) != LLADDRLEN(sdl_b)) return(1); return(bcmp((caddr_t) sdl_a->sdl_data, (caddr_t) sdl_b->sdl_data, LLADDRLEN(sdl_a)));}/* Copy sdl_f to sdl_t */sdl_copy(struct sockaddr_dl *sdl_f, struct sockaddr_dl *sdl_t){ bcopy((caddr_t) sdl_f, (caddr_t) sdl_t, sdl_f->sdl_len);}/* Swap sdl_a w/ sdl_b */sdl_swapaddr(struct sockaddr_dl *sdl_a, struct sockaddr_dl *sdl_b){ struct sockaddr_dl sdl_tmp; sdl_copy(sdl_a, &sdl_tmp); sdl_copy(sdl_b, sdl_a); sdl_copy(&sdl_tmp, sdl_b);}/* Fetch the sdl of the associated if */struct sockaddr_dl * sdl_getaddrif(struct ifnet *ifp){ register struct ifaddr *ifa; for(ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) if (ifa->ifa_addr->sa_family == AF_LINK ) return((struct sockaddr_dl *)(ifa->ifa_addr)); return((struct sockaddr_dl *)0);}/* Check addr of interface with the one given */sdl_checkaddrif(struct ifnet *ifp, struct sockaddr_dl *sdl_c){ register struct ifaddr *ifa; for(ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) if ((ifa->ifa_addr->sa_family == AF_LINK ) && !sdl_cmp((struct sockaddr_dl *)(ifa->ifa_addr), sdl_c)) return(1); return(0);}/* Build an sdl from MAC addr, DLSAP addr, and interface */sdl_setaddrif(struct ifnet *ifp, u_char *mac_addr, u_char dlsap_addr, u_char mac_len, struct sockaddr_dl *sdl_to){ register struct sockaddr_dl *sdl_tmp; if ((sdl_tmp = sdl_getaddrif(ifp)) ) { sdl_copy(sdl_tmp, sdl_to); bcopy((caddr_t) mac_addr, (caddr_t) LLADDR(sdl_to), mac_len); *(LLADDR(sdl_to)+mac_len) = dlsap_addr; sdl_to->sdl_alen = mac_len+1; return(1); } else return(0);}/* Fill out the sdl header aggregate */sdl_sethdrif(struct ifnet *ifp, u_char *mac_src, u_char dlsap_src, u_char *mac_dst, u_char dlsap_dst, u_char mac_len, struct sdl_hdr *sdlhdr_to){ if ( !sdl_setaddrif(ifp, mac_src, dlsap_src, mac_len, &sdlhdr_to->sdlhdr_src) || !sdl_setaddrif(ifp, mac_dst, dlsap_dst, mac_len, &sdlhdr_to->sdlhdr_dst) ) return(0); else return(1);}static struct sockaddr_dl sap_saddr; static struct sockaddr_dl sap_sgate = { sizeof(struct sockaddr_dl), /* _len */ AF_LINK /* _af */};/* * Set sapinfo for SAP address, llcconfig, af, and interface */struct npaidbentry *llc_setsapinfo(struct ifnet *ifp, u_char af, u_char sap, struct dllconfig *llconf){ struct protosw *pp; struct sockaddr_dl *ifdl_addr; struct rtentry *sirt = (struct rtentry *)0; struct npaidbentry *sapinfo; u_char saploc; int size = sizeof(struct npaidbentry); USES_AF_LINK_RTS; /* * We rely/assume that only STREAM protocols will make use of * connection oriented LLC2. If this will one day not be the * case this will obviously fail. */ pp = pffindtype (af, SOCK_STREAM); if (pp == 0 || pp->pr_input == 0 || pp->pr_ctlinput == 0) { printf("network level protosw error"); return 0; } /* * We need a way to jot down the LLC2 configuration for * a certain LSAP address. To do this we enter * a "route" for the SAP. */ ifdl_addr = sdl_getaddrif(ifp); sdl_copy(ifdl_addr, &sap_saddr); sdl_copy(ifdl_addr, &sap_sgate); saploc = LLSAPLOC(&sap_saddr, ifp); sap_saddr.sdl_data[saploc] = sap; sap_saddr.sdl_alen++; /* now enter it */ rtrequest(RTM_ADD, (struct sockaddr *)&sap_saddr, (struct sockaddr *)&sap_sgate, 0, 0, &sirt); if (sirt == 0) return 0; /* Plug in config information in rt->rt_llinfo */ sirt->rt_llinfo = malloc(size , M_PCB, M_WAITOK); sapinfo = (struct npaidbentry *) sirt->rt_llinfo; if (sapinfo) { bzero ((caddr_t)sapinfo, size); /* * For the time being we support LLC CLASS II here * only */ sapinfo->si_class = LLC_CLASS_II; sapinfo->si_window = llconf->dllcfg_window; sapinfo->si_trace = llconf->dllcfg_trace; if (sapinfo->si_trace) llc_tracelevel--; else llc_tracelevel++; sapinfo->si_input = pp->pr_input; sapinfo->si_ctlinput = (caddr_t (*)())pp->pr_ctlinput; return (sapinfo); } return 0;}/* * Get sapinfo for SAP address and interface */struct npaidbentry *llc_getsapinfo(u_char sap, struct ifnet *ifp){ struct sockaddr_dl *ifdl_addr; struct sockaddr_dl si_addr; struct rtentry *sirt; u_char saploc; USES_AF_LINK_RTS; ifdl_addr = sdl_getaddrif(ifp); sdl_copy(ifdl_addr, &si_addr); saploc = LLSAPLOC(&si_addr, ifp); si_addr.sdl_data[saploc] = sap; si_addr.sdl_alen++; if ((sirt = rtalloc1((struct sockaddr *)&si_addr, 0))) sirt->rt_refcnt--; else return(0); return((struct npaidbentry *)sirt->rt_llinfo);}/* * llc_seq2slot() --- We only allocate enough memory to hold the window. This * introduces the necessity to keep track of two ``pointers'' * * o llcl_freeslot the next free slot to be used * this one advances modulo llcl_window * o llcl_projvs the V(S) associated with the next frame * to be set via llcl_freeslot * this one advances modulo LLC_MAX_SEQUENCE * * A new frame is inserted at llcl_output_buffers[llcl_freeslot], after * which both llcl_freeslot and llcl_projvs are incremented. * * The slot sl(sn) for any given sequence number sn is given by * * sl(sn) = (llcl_freeslot + llcl_window - 1 - (llcl_projvs + * LLC_MAX_SEQUENCE- sn) % LLC_MAX_SEQUENCE) % * llcl_window * * i.e. we first calculate the number of frames we need to ``go back'' * from the current one (really the next one, but that doesn't matter as * llcl_projvs is likewise of by plus one) and subtract that from the * pointer to the most recently taken frame (llcl_freeslot - 1). */shortllc_seq2slot(struct llc_linkcb *linkp, short seqn){ register sn = 0; sn = (linkp->llcl_freeslot + linkp->llcl_window - (linkp->llcl_projvs + LLC_MAX_SEQUENCE - seqn) % LLC_MAX_SEQUENCE) % linkp->llcl_window; return sn;}/* * LLC2 link state handler * * There is in most cases one function per LLC2 state. The LLC2 standard * ISO 8802-2 allows in some cases for ambiguities, i.e. we have the choice * to do one thing or the other. Right now I have just chosen one but have also * indicated the spot by "multiple possibilities". One could make the behavior * in those cases configurable, allowing the superuser to enter a profile word * (32/64 bits, whatever is needed) that would suit her needs [I quite like * that idea, perhaps I'll get around to it]. * * [Preceeding each state handler function is the description as taken from * ISO 8802-2, section 7.9.2.1] *//* * ADM --- The connection component is in the asynchronous disconnected mode. * It can accept an SABME PDU from a remote LLC SSAP or, at the request * of the service access point user, can initiate an SABME PDU * transmission to a remote LLC DSAP, to establish a data link * connection. It also responds to a DISC command PDU and to any * command PDU with the P bit set to ``1''. */intllc_state_ADM(struct llc_linkcb *linkp, struct llc *frame, int frame_kind, int cmdrsp, int pollfinal){ int action = 0; switch(frame_kind + cmdrsp) { case NL_CONNECT_REQUEST: llc_send(linkp, LLCFT_SABME, LLC_CMD, pollfinal); LLC_SETFLAG(linkp, P, pollfinal); LLC_SETFLAG(linkp, S, 0); linkp->llcl_retry = 0; LLC_NEWSTATE(linkp, SETUP); break; case LLCFT_SABME + LLC_CMD: /* * ISO 8802-2, table 7-1, ADM state says to set * the P flag, yet this will cause an SABME [P] to be * answered with an UA only, not an UA [F], all * other `disconnected' states set the F flag, so ... */ LLC_SETFLAG(linkp, F, pollfinal); LLC_NEWSTATE(linkp, CONN); action = LLC_CONNECT_INDICATION; break; case LLCFT_DISC + LLC_CMD: llc_send(linkp, LLCFT_DM, LLC_RSP, pollfinal); break; default: if (cmdrsp == LLC_CMD && pollfinal == 1) llc_send(linkp, LLCFT_DM, LLC_RSP, 1); /* remain in ADM state */ } return action;}/* * CONN --- The local connection component has received an SABME PDU from a * remote LLC SSAP, and it is waiting for the local user to accept or * refuse the connection. */intllc_state_CONN(struct llc_linkcb *linkp, struct llc *frame, int frame_kind, int cmdrsp, int pollfinal){ int action = 0; switch(frame_kind + cmdrsp) { case NL_CONNECT_RESPONSE: llc_send(linkp, LLCFT_UA, LLC_RSP, LLC_GETFLAG(linkp, F)); LLC_RESETCOUNTER(linkp); LLC_SETFLAG(linkp, P, 0); LLC_SETFLAG(linkp, REMOTE_BUSY, 0); LLC_NEWSTATE(linkp, NORMAL); break; case NL_DISCONNECT_REQUEST: llc_send(linkp, LLCFT_DM, LLC_RSP, LLC_GETFLAG(linkp, F)); LLC_NEWSTATE(linkp, ADM); break; case LLCFT_SABME + LLC_CMD: LLC_SETFLAG(linkp, F, pollfinal); break; case LLCFT_DM + LLC_RSP: LLC_NEWSTATE(linkp, ADM); action = LLC_DISCONNECT_INDICATION; break; /* all other frames effect nothing here */ } return action;}/* * RESET_WAIT --- The local connection component is waiting for the local user * to indicate a RESET_REQUEST or a DISCONNECT_REQUEST. */intllc_state_RESET_WAIT(struct llc_linkcb *linkp, struct llc *frame, int frame_kind, int cmdrsp, int pollfinal){ int action = 0; switch(frame_kind + cmdrsp) { case NL_RESET_REQUEST: if (LLC_GETFLAG(linkp, S) == 0) { llc_send(linkp, LLCFT_SABME, LLC_CMD, pollfinal); LLC_SETFLAG(linkp, P, pollfinal); LLC_START_ACK_TIMER(linkp); linkp->llcl_retry = 0; LLC_NEWSTATE(linkp, RESET); } else { llc_send(linkp, LLCFT_UA, LLC_RSP, LLC_GETFLAG(linkp, F)); LLC_RESETCOUNTER(linkp); LLC_SETFLAG(linkp, P, 0); LLC_SETFLAG(linkp, REMOTE_BUSY, 0); LLC_NEWSTATE(linkp, NORMAL); action = LLC_RESET_CONFIRM; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -