⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dli_bind.c

📁 <B>Digital的Unix操作系统VAX 4.2源码</B>
💻 C
字号:
#ifndef	lintstatic char *sccsid = "@(#)dli_bind.c	4.2	ULTRIX	9/4/90";#endif	lint/* * Program dli_bind.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 * * */#include "../../h/param.h"#include "../../h/systm.h"#include "../../h/mbuf.h"#include "../../h/socket.h"#include "../../h/socketvar.h"#include "../../h/protosw.h"#include "../../h/errno.h"#include "../../h/smp_lock.h"#include "../../h/cpudata.h"#include "../../net/net/if.h"#include "../../net/net/if_to_proto.h"#include "../../net/netinet/in.h"#include "../../net/netinet/if_ether.h"#include "../../net/netdnet/dli_var.h"#include "../../net/dli/csmacd_if.h"/* *		d l i _ b i n d * * Process a DLI bind request by binding to a particular device and * optionally to an address. * * Returns:		Error code if error occurs, otherwise NULL. * * Inputs: *	uentry		= Pointer to the user's line table entry for this request. *	so_addr		= Pointer to structure containing address. */dli_bind( uentry, so_addr )register struct dli_line *uentry;register struct sockaddr_dl *so_addr;{	extern struct dli_line dli_ltable[];	register int error = NULL;	register struct ifnet *ifp;	struct ifnet *match_device();	struct sockaddr_802 *so_802;	u_char sap, dmy_pi[5];	int s;	if(so_addr->dli_family != AF_DLI)	{		return(EINVAL);	}	if ( uentry->dli_if )	{		return(EADDRINUSE);	}	if( ! (ifp = match_device(&so_addr->dli_device)))	{		return(ENODEV);	}	switch (so_addr->dli_substructype)	{		case DLI_802:			so_802 = &so_addr->choose_addr.dli_802addr;			/*			 *  dest addr must be physical			 */			if( so_802->eh_802.dst[0] & 1 )			{					return(EINVAL);			}			/* 			 * source sap validation, set bit 1 for user 			 * also, can't have a pi if ssap != SNAP SAP			 */			bzero(dmy_pi, 5);			sap = so_802->eh_802.ssap;			if( (sap != SNAP_SAP ) && 			( (bcmp(so_802->eh_802.osi_pi, dmy_pi, 5) != 0) || 			(sap & VSAP) || sap == 0) ) {				return(EINVAL);			}			/* 			 * class 1 users only allowed these types of ctl formats			 */			if(so_802->svc == TYPE1)			{				switch(so_802->eh_802.ctl.U_fmt)				{					case UI_NPCMD:					case TEST_PCMD:					case TEST_NPCMD:					case XID_PCMD:					case XID_NPCMD:						break;					default:						return(EINVAL);				}			}			/*			 * for SNAP SAP, validate service (class 1 this release)			 * and enable protocol			 * this is the same as enabling an ethernet protocol,			 * except the protocol field is 5 bytes			 */			if(sap == SNAP_SAP)			{				if((so_802->svc != TYPE1) || (so_802->eh_802.ctl.U_fmt != UI_NPCMD))				{					return(EINVAL);				}				smp_unlock(&uentry->dli_so->lk_socket);				if(error = osi_ena_802pi(so_802, ifp, uentry))				{					smp_lock(&uentry->dli_so->lk_socket, LK_RETRY);					return(error);				}				smp_lock(&uentry->dli_so->lk_socket, LK_RETRY);			}			/* validate & enable other individual saps */			else if(error = osi_ena_802isap(ifp, so_802, uentry->dli_so))			{				return(error);			}			uentry->dli_sockopt.dli_state = DLS_ON;			bcopy((u_char *)so_802, (u_char *)&uentry->dli_lineid.choose_addr.dli_802addr, sizeof(struct sockaddr_802));			break;		case DLI_ETHERNET:			if( error = proto_reserved(so_addr->choose_addr.dli_eaddr.dli_protype) )			{				return(error);			}			if( error = eaddr_reserved(&so_addr->choose_addr.dli_eaddr, ifp, uentry) )			{				return(error);			}			uentry->dli_sockopt.dli_state = DLS_ON;			bcopy((u_char *) &so_addr->choose_addr.dli_eaddr, 				(u_char *) &uentry->dli_lineid.choose_addr.dli_eaddr,				 sizeof(struct sockaddr_edl));			break;		case DLI_POINTOPOINT:			if ( ! so_addr->choose_addr.dli_paddr.dev_cstate.if_next_family )			{				so_addr->choose_addr.dli_paddr.dev_cstate.if_next_family = AF_DLI;			}			if ( error = change_dlistate(ifp,				&so_addr->choose_addr.dli_paddr.dev_cstate,				&uentry->dli_lineid.choose_addr.dli_paddr.dev_cstate,				&uentry->dli_lineid.choose_addr.dli_paddr.dev_pstate) )			{				return(error);			}			/*			 * NOTE: the lineid entry must be fully set up before			 * going to sleep.			 */			uentry->dli_lineid.dli_substructype = so_addr->dli_substructype;			uentry->dli_lineid.dli_family = so_addr->dli_family;			bcopy((u_char *) &so_addr->dli_device, 				(u_char *) &uentry->dli_lineid.dli_device,				 sizeof(struct dli_devid));			uentry->dli_if = ifp;			/*			 * need to lock out device interrupts when making 			 * decision to go to sleep.			 */			s = splimp();			if ( ifp->if_flags & IFF_UP )				uentry->dli_sockopt.dli_state = DLS_ON;			else {				uentry->dli_sockopt.dli_state = DLS_SLEEP;				while ( uentry->dli_sockopt.dli_state == DLS_SLEEP )				{					smp_unlock(&uentry->dli_so->lk_socket);					smp_unlock(&uentry->dli_lk);					sleep((caddr_t) ifp, PZERO+1);					smp_lock(&uentry->dli_lk, LK_RETRY);					if (uentry->dli_so == NULL )						panic("dli_bind: socket gone!");					smp_lock(&uentry->dli_so->lk_socket, LK_RETRY);				}			}			splx(s);			break;		default:			return(EOPNOTSUPP);			break;	}	uentry->dli_lineid.dli_substructype = so_addr->dli_substructype;	uentry->dli_lineid.dli_family = so_addr->dli_family;	uentry->dli_if = ifp;	uentry->dli_portid = dli_openport(ifp, &uentry->dli_lineid, uentry->dli_sockopt.dli_mcast, &uentry->dli_proto);	return(0);}/* *		m a t c h _ d e v i c e * * Find the ifnet interface for the selected device. * * Returns:		= Pointer to ifnet structure if found, *			  otherwise, NULL. * * Inputs: *	device		= Pointer to the structure containing the device id. */struct ifnet *match_device( device )register struct dli_devid  *device;{	register struct ifnet *ifp = ifnet;	register int i, nlen;	u_char *c;	/*	 * validate device name.	 */	if( (nlen = strlen(device->dli_devname)) > DLI_DEVSIZE )	{		return(NULL);	}	for ( c = device->dli_devname, i = 0; i < nlen; i++)	{		if ( ! ((*c >='a' && *c <='z') || (*c >='A' && *c <='Z')) )		{			return(NULL);		}	} 	/*	 * search ifnet linked list for device.	 */	while (ifp)	{		if ( (i = strlen(ifp->if_name)) == nlen			&& bcmp(ifp->if_name, device->dli_devname, nlen) == NULL			&& ifp->if_unit == device->dli_devnumber )		{			if ( ifp->if_flags &  IFF_RUNNING )			{				return(ifp);			}			else			{				return(NULL);			}		}		ifp = ifp->if_next;	}	return(NULL);}/* *		e a d d r _ r e s e r v e d * * make sure address is not reserved. * * Returns:		Error code if error occurs, otherwise NULL. * * Inputs: *	eaddr		= Pointer to structure containing Ethernet addr info. *	ifp		= Pointer to devices ifnet structure. *	ue		= Pointer to user's dli line table entry. */eaddr_reserved( eaddr, ifp, ue )register struct sockaddr_edl *eaddr;struct ifnet *ifp;struct dli_line *ue;{	extern struct dli_line dli_ltable[];	register int i, error;	register struct sockaddr_edl *search_eaddr;	u_char	flags = eaddr->dli_ioctlflg;	/*	 * Target address should be physical	 */	if ( eaddr->dli_target[0] & 1 )	{		return(EINVAL);	}	/*	 * Only one control flag should be set.	 */	switch (flags)	{		case DLI_EXCLUSIVE:		case DLI_NORMAL:		case DLI_DEFAULT:			break;		default:			return(EINVAL);			break;	}	/*	 * Make sure address structure is unique per device.	 */	smp_unlock(&ue->dli_so->lk_socket);	for ( i = 0; i < dli_maxline; i++ )	{		if ( &dli_ltable[i] == ue )			continue;		smp_lock(&dli_ltable[i].dli_lk, LK_RETRY);		if (dli_ltable[i].dli_lineid.dli_substructype != DLI_ETHERNET ||			dli_ltable[i].dli_so == NULL ||			ifp != dli_ltable[i].dli_if )		{			smp_unlock(&dli_ltable[i].dli_lk);			continue;		}		search_eaddr = &dli_ltable[i].dli_lineid.choose_addr.dli_eaddr;		error = NULL;		switch (search_eaddr->dli_ioctlflg)		{			case NULL:				break;			case DLI_EXCLUSIVE:				error = search_eaddr->dli_protype == eaddr->dli_protype ? EADDRINUSE : NULL;				break;			case DLI_NORMAL:				switch (flags)				{					case DLI_EXCLUSIVE:						error = search_eaddr->dli_protype == eaddr->dli_protype ? EADDRINUSE : NULL;						break;					case DLI_NORMAL:						error = search_eaddr->dli_protype == eaddr->dli_protype ? EADDRINUSE : NULL;						if (error)						{							error = match_targets(search_eaddr->dli_target, eaddr->dli_target);						}						break;					default:						break;				}				break;			case DLI_DEFAULT:				switch (flags)				{					case DLI_EXCLUSIVE:					case DLI_DEFAULT:						error = search_eaddr->dli_protype == eaddr->dli_protype ? EADDRINUSE : NULL;						break;					default:						break;				}				break;			default:				panic( "dli_bind: eaddr_reserved:" );				break;		}		if (error != NULL)		{			smp_unlock(&dli_ltable[i].dli_lk);			smp_lock(&ue->dli_so->lk_socket, LK_RETRY);			return(error);		}		smp_unlock(&dli_ltable[i].dli_lk);	}	smp_lock(&ue->dli_so->lk_socket, LK_RETRY);	return(NULL);}/* *		p r o t o _ r e s e r v e d * * make sure protocol type is not reserved. * * Returns:		Error code if error occurs, otherwise NULL. * * Inputs: *	ptype		= protocol type to be checked. */extern struct if_family if_family[];proto_reserved( ptype )u_short ptype;{	register int i;	/*	 * Protocol types hardwired in QE and DE drivers.	 */	switch ( ptype )	{		case ETHERTYPE_IP:		case ETHERTYPE_ARP:			return(EACCES);			break;		default:			if(ptype <= OSI802)				{				return(EACCES);			}			else if( ptype >= ETHERTYPE_TRAIL && ptype < (ETHERTYPE_TRAIL + ETHERTYPE_NTRAILER) )			{				return(EACCES);			}			break;	}	/*	 * Protocol types enabled in if_family array.	 */	i = -1;	while ( if_family[++i].if_type != -1 )	{		if ( ptype == if_family[i].if_type )		{			return(EACCES);		}	}	return(NULL);}/* *		d l i _ o p e n p o r t * * Open a port to correct data link module for network mgt purposes. * * Returns:		portid or zero if no port. * * Inputs: */dli_openport(ifp, soaddr, mcast, protoptr)struct ifnet *ifp;struct sockaddr_dl *soaddr;u_char *mcast;struct protosw **protoptr;{    int i, j, portid = 0;    struct dli_ifop op;    extern struct dli_line dli_ltable[];    struct protosw *pr;    switch ( soaddr->dli_substructype )    {	case DLI_ETHERNET:	case DLI_802:#ifdef IFT_FDDI    	    if (ifp->if_type == IFT_FDDI)		pr = pffindproto(AF_DLI, DLPROTO_FDDI, 0);    	    else#endif        	pr = pffindproto(AF_DLI, DLPROTO_CSMACD, 0);	    break;	case DLI_POINTOPOINT:        	pr = pffindproto(AF_DLI, DLPROTO_DDCMP, 0);		break;	default:		return(0);		break;    }    if ( pr == NULL )	return(0);    /*     * Initialize Open Port structure.  Note that     * DLI sockets don't set up client name and station name,     * and they don't make use of port name.     */    bzero(&op, sizeof(op));    op.ifp = ifp;    op.protosw = NULL;    for ( i = 0, j = 0; i < MAXMCAST && j < MCAST_MAXNUM*MCAST_SIZE; j += MCAST_SIZE )	if ( mcast[j] & 1 )	    bcopy(&mcast[j], op.dldef.type3.mcast[i++], DLI_EADDRSIZE);    switch ( soaddr->dli_substructype )    {	case DLI_ETHERNET:            op.dldef.type3.llc = USER_SUPPLIED;	    for ( i = 0, j = 0; i < dli_maxline; i++ )	    {		if ( dli_ltable[i].dli_lineid.choose_addr.dli_eaddr.dli_protype 		     == soaddr->choose_addr.dli_eaddr.dli_protype )		{			if ( dli_ltable[i].dli_portid != 0 )			{			    pr = dli_ltable[i].dli_proto;			    portid = dli_ltable[i].dli_portid;			}			j++;		}	    }	    if ( j > 1 )	    {		*protoptr = pr;		return(portid);	/* a port has already been opened */	    }    	    op.dldef.type3.ptype = soaddr->choose_addr.dli_eaddr.dli_protype;    	    op.dltype = DLI_ETHERNET;	    break;			case DLI_802:    	    if ( soaddr->choose_addr.dli_802addr.svc == USER )        	op.dldef.type3.llc = USER_SUPPLIED;    	    else        	op.dldef.type3.llc = CLASS1_TYPE1;	    for ( i = 0, j = 0; i < dli_maxline; i++ )	    {		if ( soaddr->choose_addr.dli_802addr.eh_802.ssap != SNAP_SAP )		{		    if ( dli_ltable[i].dli_lineid.choose_addr.dli_802addr.eh_802.ssap		     	== soaddr->choose_addr.dli_802addr.eh_802.ssap )		    {			if ( dli_ltable[i].dli_portid != 0 )			{			    pr = dli_ltable[i].dli_proto;			    portid = dli_ltable[i].dli_portid;			}			j++;		    }		}		else		{		    if ( bcmp( dli_ltable[i].dli_lineid.choose_addr.dli_802addr.eh_802.osi_pi,			      soaddr->choose_addr.dli_802addr.eh_802.osi_pi,			      sizeof(soaddr->choose_addr.dli_802addr.eh_802.osi_pi))			      == 0 )		    {			if ( dli_ltable[i].dli_portid != 0 )			{			    pr = dli_ltable[i].dli_proto;			    portid = dli_ltable[i].dli_portid;	    		}			j++;		    }		}	    }	    if ( j > 1 )	    {		*protoptr = pr;		return(portid);	/* a port has already been opened */	    }    	    op.dldef.type3.selector = soaddr->choose_addr.dli_802addr.eh_802.ssap;	    bcopy(soaddr->choose_addr.dli_802addr.eh_802.osi_pi, 		op.dldef.type3.pid, sizeof(op.dldef.type3.pid));    	    op.dltype = DLI_802;	    break;			case DLI_POINTOPOINT:    	    op.dltype = DLI_POINTOPOINT;	    break;			default:	    return(EOPNOTSUPP);	    break;    }    if ( (*pr->pr_ctloutput)(PRCO_PIF, NULL, 0, DLIPIF_OPENPORT, &op) == 0 )	portid = (u_int) op.port;    if ( portid )	*protoptr = pr;    return(portid);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -