📄 dli_input.c
字号:
#ifndef lintstatic char *sccsid = "@(#)dli_input.c 4.3 (DECnet-ULTRIX) 4/30/91";#endif lint/* * Program dli_input.c, Module DLI * * Copyright (C) 1985, 1988 by * Digital Equipment Corporation, Maynard, Mass. * * This software is furnished under a license and may be used and copied * only in accordance with the terms of such license and with the * inclusion of the above copyright notice. This software or any other * copies thereof may not be provided or otherwise made available to any * other person. No title to and ownership of the software is hereby * transferred. * * The information in this software is subject to change without notice * and should not be construed as a commitment by Digital Equipment * Corporation. * * Digital assumes no responsibility for the use or reliability of its * software on equipment which is not supplied by Digital. * * * Networks & Communications Software Engineering * * IDENT HISTORY: * * 1.00 10-Jul-1985 * DECnet-ULTRIX V1.0 * * 2.00 18-Apr-1986 * DECnet-Ultrix V2.0 * * Added sysid and point-to-point support * * 2.01 18-Mar-1988 * DECnet-ULTRIX V2.4 * - Allowed use of reserved bit in individual and group SAPs * - Fixed request counters and request sysid processing code * to examine packet count. * * 2.02 02-Jun-1988 * DECnet-Ultrix V2.4 * Added support for ln driver. * * 2.03 25-Jul-1988 * DECnet-Ultrix V3.0 * Restore sysid destination to Console Carrier multicast * after transmitting to specific node. * * 19-Dec-1988 Matt Thomas * Fix unaligned accesses for PMAX (for sysid and rqctrs). * * 29-Apr-1991 Matt Thomas * Add code so that dliintrq is emptied by one cpu at a time. * */#include "../../h/param.h"#include "../../h/systm.h"#include "../../h/mbuf.h"#include "../../h/protosw.h"#include "../../h/socket.h"#include "../../h/socketvar.h"#include "../../h/domain.h"#include "../../h/errno.h"#include "../../h/ioctl.h"#include "../../h/user.h"#include "../../h/buf.h"#include "../../h/conf.h"#include "../../h/proc.h"#include "../../h/smp_lock.h"#include "../../h/cpudata.h"#include "../../net/net/if.h"#include "../../net/netinet/in.h"#include "../../net/netinet/if_ether.h"#include "../../net/netdnet/evl.h"#include "../../net/netdnet/dn.h"#include "../../net/netdnet/decnet_types.h"#include "../../net/netdnet/dli_var.h"extern struct ifqueue dli_intrq;extern struct sockaddr_dl sysid_dst;extern struct ether_header no_enet_header;extern struct domain dlidomain;extern struct protosw dlisw[];extern u_char sysid_mcast[];extern u_char loopback_mcast[];extern struct dli_sysid_dev mop_dev_code[];extern struct dli_sysid_to sysid_to[];extern u_short nqna;extern struct lock_t lk_dli;/* * DLI domain received message processing. */ /* * d l i i n t r * * DLI domain input routine. This routine is 'called' from the network software * ISR routine to process incoming packets. The first MBUF in any chain * contains a DLI receive descriptor containing the received ethernet header * and a pointer to the interface structure. * * Outputs: None. * * Inputs: None. */dliintr(){ register struct mbuf *m; register struct dli_recv *recv; register struct protosw *pr; struct mbuf *loopback_enet_msg(), *loopback_ptop_msg(); int s, owner = 0; static int dliintrq_owned = 0;next: /* * Try to pull an input message (MBUF chain) from the DLI input queue. */ s = splimp(); m = NULL; smp_lock(&lk_dliintrq, LK_RETRY); if (owner || !dliintrq_owned) { IF_DEQUEUE(&dli_intrq, m); owner = dliintrq_owned = (m != NULL); } smp_unlock(&lk_dliintrq); splx(s); if (m) { recv = mtod(m, struct dli_recv *); /* * Pass to destined protocol module. Probe DLPROTO_DLI * last since it is lower priority. */ pr = &dlisw[0]; while ( ++pr != dlidomain.dom_protoswNPROTOSW ) { if ( pr->pr_protocol == recv->rcv_protocol && pr->pr_input ) { m = (struct mbuf *) (*pr->pr_input)(m); break; } } if ( m && recv->rcv_protocol == DLPROTO_CSMACD ) dli_input(m); else { if ( m ) m_freem(m); } goto next; }}/* * d l i _ i n p u t * * DLPROTO_DLI input routine. This routine is 'called' from dliintr() * to process incoming packets. The first MBUF in any chain * contains a DLI receive descriptor containing the received ethernet header * and a pointer to the interface structure. This routine makes sure all * mbufs are disposed properly. * * Outputs: None. * * Inputs: None. */dli_input(m)struct mbuf *m;{ register struct dli_recv *recv; struct dli_recv rcv; struct mbuf *loopback_enet_msg(), *loopback_ptop_msg(); int s; recv = mtod(m, struct dli_recv *); bcopy(recv, &rcv, sizeof(rcv)); /* * If there is no data link header, * process as point to point. * else * process as ethernet. */ if ( bcmp(&(recv->rcv_hdr.rcv_ether), &no_enet_header, sizeof(recv->rcv_hdr.rcv_ether)) == 0 ) { if ( m = loopback_ptop_msg(m, (recv->rcv_ifp->if_flags & IFF_MOP), &rcv) ) { forward_to_user(m, &rcv); } } else { /* * if ethernet protocol is < 0x5dc * process 802.3 packet * else if message is request sysid * send sysid message * else if message is request for mop counters * send counters. * else if loopback response requested * send loopback response * else * attempt to pass ethernet message to user. */ if(recv->rcv_hdr.rcv_ether.ether_type <= OSI802) { osi_802input(m, &rcv); } else if( (recv->rcv_hdr.rcv_ether.ether_type == SYSIDPROTO) && (*(mtod(m->m_next, u_char *) + sizeof(u_short)) == REQSYSID) ) { dli_proc_reqsysid(m, &rcv); } else if( (recv->rcv_hdr.rcv_ether.ether_type == CCRPROTO) && (*(mtod(m->m_next, u_char *) + sizeof(u_short)) == DLI_REQCTRS) ) { dli_proc_reqctrs(m, &rcv); } else if ( (recv->rcv_hdr.rcv_ether.ether_type != DLI_LBACK) || (m = loopback_enet_msg(m, &rcv)) ) { forward_to_user(m, &rcv); } }}/* * f o r w a r d _ t o _ u s e r * * This routine attempts to find the user to whom the current * packet belongs. If successful, the message is placed on * the user's socket receive queue. Otherwise, the packet is * dropped. * * Outputs: mbuf chain (possibly) place on user's rcv queue. * * Inputs: m = mbuf chain containing packet. Note that the * first mbuf contains junk at this point. * rcv = pointer to data link header structure. */extern struct dli_line dli_ltable[];forward_to_user( m, rcv )register struct mbuf *m;register struct dli_recv *rcv;{ register struct sockaddr_edl *eaddr; register struct sockaddr_802 *oaddr; register struct sockaddr_pdl *paddr; register int i; register int save_i = -1; struct socket *dliso, *save_so = NULL; struct lock_t *dlisolk; for ( i = 0; i < dli_maxline; i++ ) { smp_lock(&dli_ltable[i].dli_lk, LK_RETRY); if ( rcv->rcv_ifp != dli_ltable[i].dli_if ) { smp_unlock(&dli_ltable[i].dli_lk); continue; } switch ( dli_ltable[i].dli_lineid.dli_substructype ) { case DLI_802: /* * the only valid way to get here * is from the 802 input routine * for snap saps. * all other saps have either been * handled by the responder, or gone * directly to found_user */ if(rcv->rcv_hdr.osi_header.dsap != SNAP_SAP) break; oaddr = &dli_ltable[i].dli_lineid.choose_addr.dli_802addr; switch ( oaddr->ioctl ) { case DLI_EXCLUSIVE: if(bcmp(rcv->rcv_hdr.osi_header.osi_pi, oaddr->eh_802.osi_pi, 5) == NULL) { smp_lock((dlisolk = &(dli_ltable[i].dli_so->lk_socket)), LK_RETRY); found_user(m, dli_ltable[i].dli_so, DLI_802, rcv); smp_unlock(dlisolk); smp_unlock(&dli_ltable[i].dli_lk); return; } break; case DLI_NORMAL: if( (bcmp(rcv->rcv_hdr.osi_header.osi_pi, oaddr->eh_802.osi_pi, 5) == NULL) && match_targets(oaddr->eh_802.dst, rcv->rcv_hdr.osi_header.src) && match_mcast(dli_ltable[i].dli_sockopt.dli_mcast, rcv->rcv_hdr.osi_header.dst)) { smp_lock((dlisolk = &(dli_ltable[i].dli_so->lk_socket)), LK_RETRY); found_user(m, dli_ltable[i].dli_so, DLI_802, rcv); smp_unlock(dlisolk); smp_unlock(&dli_ltable[i].dli_lk); return; } break; case DLI_DEFAULT: if(bcmp(rcv->rcv_hdr.osi_header.osi_pi, oaddr->eh_802.osi_pi, 5) == NULL) { save_i = i; save_so = dli_ltable[i].dli_so; } break; default: break; } break; case DLI_ETHERNET: eaddr = &dli_ltable[i].dli_lineid.choose_addr.dli_eaddr; switch ( eaddr->dli_ioctlflg ) { case DLI_EXCLUSIVE: if (rcv->rcv_hdr.rcv_ether.ether_type == eaddr->dli_protype) { smp_lock((dlisolk = &(dli_ltable[i].dli_so->lk_socket)), LK_RETRY); found_user(m, dli_ltable[i].dli_so, DLI_ETHERNET, rcv); smp_unlock(dlisolk); smp_unlock(&dli_ltable[i].dli_lk); return; } break; case DLI_NORMAL: if ( (rcv->rcv_hdr.rcv_ether.ether_type == eaddr->dli_protype) && match_targets(eaddr->dli_target, rcv->rcv_hdr.rcv_ether.ether_shost) && match_mcast(dli_ltable[i].dli_sockopt.dli_mcast, rcv->rcv_hdr.rcv_ether.ether_dhost)) { smp_lock((dlisolk = &(dli_ltable[i].dli_so->lk_socket)), LK_RETRY); found_user(m, dli_ltable[i].dli_so, DLI_ETHERNET, rcv); smp_unlock(dlisolk); smp_unlock(&dli_ltable[i].dli_lk); return; } break; case DLI_DEFAULT: if (rcv->rcv_hdr.rcv_ether.ether_type == eaddr->dli_protype) { save_i = i; save_so = dli_ltable[i].dli_so; } break; default: break; } break; case DLI_POINTOPOINT: smp_lock((dlisolk = &(dli_ltable[i].dli_so->lk_socket)), LK_RETRY); found_user(m, dli_ltable[i].dli_so, DLI_POINTOPOINT, rcv); smp_unlock(dlisolk); smp_unlock(&dli_ltable[i].dli_lk); return; break; default: panic( "dli_input: forward_to_user" ); break; } smp_unlock(&dli_ltable[i].dli_lk); } if ( save_so ) { smp_lock(&dli_ltable[save_i].dli_lk, LK_RETRY); if (dli_ltable[save_i].dli_so == save_so) { smp_lock((dlisolk = &(dli_ltable[save_i].dli_so->lk_socket)), LK_RETRY); found_user(m, dli_ltable[save_i].dli_so, dli_ltable[save_i].dli_lineid.dli_substructype, rcv); smp_unlock(dlisolk); } else m_freem(m); smp_unlock(&dli_ltable[save_i].dli_lk); return; } m_freem(m); return;}/* * f o u n d _ u s e r * * This routine places an mbuf chain on a user's receive queue. * * Note: Both line table entry and socket must be locked * before this routine called. * * Outputs: None. * * Inputs: m = Pointer to mbuf chain; first mbuf is * garbage. * so = Pointer to user's socket structure. * link_type = type of link ( ethernet, point to point ) * rcv = pointer to data link header structure. */found_user( m, so, link_type, rcv )register struct mbuf *m;register struct socket *so;u_char link_type;register struct dli_recv *rcv;{ register struct sockaddr_dl *so_dl; register struct mbuf *temp; u_short len; if ( so == NULL ) { panic( "dli_input: found_user1" ); } if ( so == (struct socket *) -1 ) { panic( "dli_input, found_user2: bad socket" ); } /* * Make sure there's enough room on Rx Q */ if ( sbspace(&so->so_rcv) < 0 ) { m_freem(m); return; } /* * Allocate some memory for the socket address structure * needed by sbappendaddr(). * clear out memory and place address info in it. */ KM_ALLOC(so_dl, struct sockaddr_dl *, sizeof(struct sockaddr_dl), KM_SONAME, KM_NOW_CL); if ( so_dl == NULL ) { m_freem(m); return; } so_dl->dli_family = AF_DLI; switch ( so_dl->dli_substructype = link_type ) { case DLI_802: /* * only individual saps should be coming through here */ so_dl->choose_addr.dli_802addr.eh_802.len = rcv->rcv_hdr.osi_header.len; *(struct ether_pa *) so_dl->choose_addr.dli_802addr.eh_802.dst = *(struct ether_pa *) rcv->rcv_hdr.rcv_ether.ether_shost; *(struct ether_pa *) so_dl->choose_addr.dli_802addr.eh_802.src = *(struct ether_pa *) rcv->rcv_hdr.rcv_ether.ether_dhost; /* this is who enabled the sap */ so_dl->choose_addr.dli_802addr.eh_802.ssap = rcv->rcv_hdr.osi_header.dsap; /* this is who it came from */ so_dl->choose_addr.dli_802addr.eh_802.dsap = rcv->rcv_hdr.osi_header.ssap; if (so_dl->choose_addr.dli_802addr.eh_802.dsap == SNAP_SAP) bcopy(rcv->rcv_hdr.osi_header.osi_pi, so_dl->choose_addr.dli_802addr.eh_802.osi_pi, sizeof(so_dl->choose_addr.dli_802addr.eh_802.osi_pi)); if( (rcv->rcv_hdr.osi_header.ctl.U_fmt & 3) == 3) { so_dl->choose_addr.dli_802addr.eh_802.ctl.U_fmt = rcv->rcv_hdr.osi_header.ctl.U_fmt; } else { so_dl->choose_addr.dli_802addr.eh_802.ctl.I_S_fmt = rcv->rcv_hdr.osi_header.ctl.I_S_fmt; } break; case DLI_ETHERNET: so_dl->choose_addr.dli_eaddr.dli_protype = rcv->rcv_hdr.rcv_ether.ether_type; *(struct ether_pa *) so_dl->choose_addr.dli_eaddr.dli_target = *(struct ether_pa *) rcv->rcv_hdr.rcv_ether.ether_shost; *(struct ether_pa *) so_dl->choose_addr.dli_eaddr.dli_dest = *(struct ether_pa *) rcv->rcv_hdr.rcv_ether.ether_dhost; break; case DLI_POINTOPOINT: break; default: panic( "dli, found_user2" ); break; } so_dl->dli_device.dli_devnumber = rcv->rcv_ifp->if_unit; bcopy(rcv->rcv_ifp->if_name, so_dl->dli_device.dli_devname, strlen(rcv->rcv_ifp->if_name)); if ( sbappendanyaddr(&so->so_rcv, (u_char *) so_dl, sizeof(struct sockaddr_dl), m->m_next, NULL) == 0 ) { KM_FREE(so_dl, KM_SONAME); m_freem(m); return; } KM_FREE(so_dl, KM_SONAME); MFREE(m, temp); sorwakeup(so); return;}extern struct dli_timers lback_timers[];/* * l o o p b a c k _ e n e t _ m s g * * This routine processes Ethernet loopback messages. If the * function code is "forward data," then the message * is forwarded to its next destination. Otherwise, * nothing is done. * * Outputs: mbuf chain given to driver if message to be forwared. * returns NULL if message looped, otherwise mbuf pointer returned. * * Inputs: m = mbuf chain containing packet. * rcv = pointer to data link header structure. */struct mbuf *loopback_enet_msg( m, rcv )register struct mbuf *m;register struct dli_recv *rcv;{ int saveaffinity; /* for nonsymm drivers. 8.18.88.us */ int error; struct sockaddr_dl dst_addr; u_char *loop_msg; u_short loop_sc, timer_active, i; struct ifdevea ifd; /* * If to multicast, make sure its the correct one. */ if ( rcv->rcv_hdr.rcv_ether.ether_dhost[0] & MCASTADDR ) if (bcmp( rcv->rcv_hdr.rcv_ether.ether_dhost, loopback_mcast, DLI_EADDRSIZE) != 0) { m_freem(m); return(NULL); } /* * pull up header into second mbuf */ if ( ! pull_header(m, 30) ) { return(NULL); } /* * determine if message should be looped back */ if ( (loop_sc = EXT16(mtod(m->m_next, u_short *)) + sizeof(loop_sc)) > 28 ) { return(m); } loop_msg = mtod(m->m_next, u_char *);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -