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

📄 if.c

📁 eCos操作系统源码
💻 C
📖 第 1 页 / 共 3 页
字号:
		} else if (ifr->ifr_flags & IFF_UP &&		    (ifp->if_flags & IFF_UP) == 0) {			int s = splimp();			if_up(ifp);			splx(s);		}		ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) |			(ifr->ifr_flags &~ IFF_CANTCHANGE);		if (ifp->if_ioctl)			(void) (*ifp->if_ioctl)(ifp, cmd, data);		getmicrotime(&ifp->if_lastchange);		break;	case SIOCSIFMETRIC:		ifp->if_metric = ifr->ifr_metric;		getmicrotime(&ifp->if_lastchange);		break;	case SIOCSIFPHYS:		if (!ifp->if_ioctl)		        return EOPNOTSUPP;		error = (*ifp->if_ioctl)(ifp, cmd, data);		if (error == 0)			getmicrotime(&ifp->if_lastchange);		return(error);	case SIOCSIFMTU:	{		u_long oldmtu = ifp->if_mtu;		if (ifp->if_ioctl == NULL)			return (EOPNOTSUPP);		if (ifr->ifr_mtu < IF_MINMTU || ifr->ifr_mtu > IF_MAXMTU)			return (EINVAL);		error = (*ifp->if_ioctl)(ifp, cmd, data);		if (error == 0) {			getmicrotime(&ifp->if_lastchange);			rt_ifmsg(ifp);		}		/*		 * If the link MTU changed, do network layer specific procedure.		 */		if (ifp->if_mtu != oldmtu) {#ifdef INET6			nd6_setmtu(ifp);#endif		}		return (error);	}	case SIOCADDMULTI:	case SIOCDELMULTI:		/* Don't allow group membership on non-multicast interfaces. */		if ((ifp->if_flags & IFF_MULTICAST) == 0)			return EOPNOTSUPP;		/* Don't let users screw up protocols' entries. */		if (ifr->ifr_addr.sa_family != AF_LINK)			return EINVAL;                log(LOG_IOCTL, "%s: %s Multi\n", __FUNCTION__,                     (cmd == SIOCADDMULTI) ? "Add" : "Del");                log_dump(LOG_IOCTL, &ifr->ifr_addr, 32);		if (cmd == SIOCADDMULTI) {			struct ifmultiaddr *ifma;			error = if_addmulti(ifp, &ifr->ifr_addr, &ifma);		} else {			error = if_delmulti(ifp, &ifr->ifr_addr);		}		if (error == 0)			getmicrotime(&ifp->if_lastchange);		return error;	case SIOCSIFPHYADDR:	case SIOCDIFPHYADDR:#ifdef INET6	case SIOCSIFPHYADDR_IN6:#endif	case SIOCSLIFPHYADDR:        case SIOCSIFMEDIA:	case SIOCSIFGENERIC:		if (ifp->if_ioctl == 0)			return (EOPNOTSUPP);		error = (*ifp->if_ioctl)(ifp, cmd, data);		if (error == 0)			getmicrotime(&ifp->if_lastchange);		return error;	case SIOCGIFSTATUS:		ifs = (struct ifstat *)data;		ifs->ascii[0] = '\0';			case SIOCGIFPSRCADDR:	case SIOCGIFPDSTADDR:	case SIOCGLIFPHYADDR:	case SIOCGIFMEDIA:	case SIOCGIFGENERIC:		if (ifp->if_ioctl == 0)			return (EOPNOTSUPP);		return ((*ifp->if_ioctl)(ifp, cmd, data));	case SIOCSIFLLADDR:		return if_setlladdr(ifp,		    ifr->ifr_addr.sa_data, ifr->ifr_addr.sa_len);	default:		oif_flags = ifp->if_flags;		if (so->so_proto == 0)			return (EOPNOTSUPP);#ifndef COMPAT_43		error = ((*so->so_proto->pr_usrreqs->pru_control)(so, cmd,								 data,								 ifp, p));#else	    {		int ocmd = cmd;		switch (cmd) {		case SIOCSIFDSTADDR:		case SIOCSIFADDR:		case SIOCSIFBRDADDR:		case SIOCSIFNETMASK:#if BYTE_ORDER != BIG_ENDIAN			if (ifr->ifr_addr.sa_family == 0 &&			    ifr->ifr_addr.sa_len < 16) {				ifr->ifr_addr.sa_family = ifr->ifr_addr.sa_len;				ifr->ifr_addr.sa_len = 16;			}#else			if (ifr->ifr_addr.sa_len == 0)				ifr->ifr_addr.sa_len = 16;#endif			break;		case OSIOCGIFADDR:			cmd = SIOCGIFADDR;			break;		case OSIOCGIFDSTADDR:			cmd = SIOCGIFDSTADDR;			break;		case OSIOCGIFBRDADDR:			cmd = SIOCGIFBRDADDR;			break;		case OSIOCGIFNETMASK:			cmd = SIOCGIFNETMASK;		}		error =  ((*so->so_proto->pr_usrreqs->pru_control)(so,								   cmd,								   data,								   ifp, p));		switch (ocmd) {		case OSIOCGIFADDR:		case OSIOCGIFDSTADDR:		case OSIOCGIFBRDADDR:		case OSIOCGIFNETMASK:			*(u_short *)&ifr->ifr_addr = ifr->ifr_addr.sa_family;		}	    }#endif /* COMPAT_43 */		if ((oif_flags ^ ifp->if_flags) & IFF_UP) {#ifdef INET6#define DELAY cyg_thread_delay			DELAY(100);/* XXX: temporary workaround for fxp issue*/			if (ifp->if_flags & IFF_UP) {				int s = splimp();				in6_if_up(ifp);				splx(s);			}#endif		}		return (error);	}	return (0);}/* * Set/clear promiscuous mode on interface ifp based on the truth value * of pswitch.  The calls are reference counted so that only the first * "on" request actually has an effect, as does the final "off" request. * Results are undefined if the "off" and "on" requests are not matched. */intifpromisc(ifp, pswitch)	struct ifnet *ifp;	int pswitch;{	struct ifreq ifr;	int error;	int oldflags;	oldflags = ifp->if_flags;	if (pswitch) {		/*		 * If the device is not configured up, we cannot put it in		 * promiscuous mode.		 */		if ((ifp->if_flags & IFF_UP) == 0)			return (ENETDOWN);		if (ifp->if_pcount++ != 0)			return (0);		ifp->if_flags |= IFF_PROMISC;		log(LOG_INFO, "%s%d: promiscuous mode enabled\n",		    ifp->if_name, ifp->if_unit);	} else {		if (--ifp->if_pcount > 0)			return (0);		ifp->if_flags &= ~IFF_PROMISC;		log(LOG_INFO, "%s%d: promiscuous mode disabled\n",		    ifp->if_name, ifp->if_unit);	}	ifr.ifr_flags = ifp->if_flags;	error = (*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, (caddr_t)&ifr);	if (error == 0)		rt_ifmsg(ifp);	else		ifp->if_flags = oldflags;	return error;}/* * Return interface configuration * of system.  List may be used * in later ioctl's (above) to get * other information. *//*ARGSUSED*/static intifconf(cmd, data)	u_long cmd;	caddr_t data;{	register struct ifconf *ifc = (struct ifconf *)data;	register struct ifnet *ifp = ifnet.tqh_first;	register struct ifaddr *ifa;	struct ifreq ifr, *ifrp;	int space = ifc->ifc_len, error = 0;	ifrp = ifc->ifc_req;	for (; space > sizeof (ifr) && ifp; ifp = ifp->if_link.tqe_next) {		char workbuf[64];		int ifnlen, addrs;		ifnlen = snprintf(workbuf, sizeof(workbuf),		    "%s%d", ifp->if_name, ifp->if_unit);		if(ifnlen + 1 > sizeof ifr.ifr_name) {			error = ENAMETOOLONG;			break;		} else {			strcpy(ifr.ifr_name, workbuf);		}		addrs = 0;		ifa = ifp->if_addrhead.tqh_first;		for ( ; space > sizeof (ifr) && ifa;		    ifa = ifa->ifa_link.tqe_next) {			register struct sockaddr *sa = ifa->ifa_addr;			addrs++;#ifdef COMPAT_43			if (cmd == OSIOCGIFCONF) {				struct osockaddr *osa =					 (struct osockaddr *)&ifr.ifr_addr;				ifr.ifr_addr = *sa;				osa->sa_family = sa->sa_family;				error = copyout((caddr_t)&ifr, (caddr_t)ifrp,						sizeof (ifr));				ifrp++;			} else#endif			if (sa->sa_len <= sizeof(*sa)) {				ifr.ifr_addr = *sa;				error = copyout((caddr_t)&ifr, (caddr_t)ifrp,						sizeof (ifr));				ifrp++;			} else {				if (space < sizeof (ifr) + sa->sa_len -					    sizeof(*sa))					break;				space -= sa->sa_len - sizeof(*sa);				error = copyout((caddr_t)&ifr, (caddr_t)ifrp,						sizeof (ifr.ifr_name));				if (error == 0)				    error = copyout((caddr_t)sa,				      (caddr_t)&ifrp->ifr_addr, sa->sa_len);				ifrp = (struct ifreq *)					(sa->sa_len + (caddr_t)&ifrp->ifr_addr);			}			if (error)				break;			space -= sizeof (ifr);		}		if (error)			break;		if (!addrs) {			bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr));			error = copyout((caddr_t)&ifr, (caddr_t)ifrp,			    sizeof (ifr));			if (error)				break;			space -= sizeof (ifr);			ifrp++;		}	}	ifc->ifc_len -= space;	return (error);}/* * Just like if_promisc(), but for all-multicast-reception mode. */intif_allmulti(ifp, onswitch)	struct ifnet *ifp;	int onswitch;{	int error = 0;	int s = splimp();	if (onswitch) {		if (ifp->if_amcount++ == 0) {			ifp->if_flags |= IFF_ALLMULTI;			error = ifp->if_ioctl(ifp, SIOCSIFFLAGS, 0);		}	} else {		if (ifp->if_amcount > 1) {			ifp->if_amcount--;		} else {			ifp->if_amcount = 0;			ifp->if_flags &= ~IFF_ALLMULTI;			error = ifp->if_ioctl(ifp, SIOCSIFFLAGS, 0);		}	}	splx(s);	if (error == 0)		rt_ifmsg(ifp);	return error;}/* * Add a multicast listenership to the interface in question. * The link layer provides a routine which converts */intif_addmulti(ifp, sa, retifma)	struct ifnet *ifp;	/* interface to manipulate */	struct sockaddr *sa;	/* address to add */	struct ifmultiaddr **retifma;{	struct sockaddr *llsa, *dupsa;	int error, s;	struct ifmultiaddr *ifma;	/*	 * If the matching multicast address already exists	 * then don't add a new one, just add a reference	 */	for (ifma = ifp->if_multiaddrs.lh_first; ifma;	     ifma = ifma->ifma_link.le_next) {		if (equal(sa, ifma->ifma_addr)) {			ifma->ifma_refcount++;			if (retifma)				*retifma = ifma;			return 0;		}	}	/*	 * Give the link layer a chance to accept/reject it, and also	 * find out which AF_LINK address this maps to, if it isn't one	 * already.	 */	if (ifp->if_resolvemulti) {		error = ifp->if_resolvemulti(ifp, &llsa, sa);		if (error) return error;	} else {		llsa = 0;	}	MALLOC(ifma, struct ifmultiaddr *, sizeof *ifma, M_IFMADDR, M_WAITOK);	MALLOC(dupsa, struct sockaddr *, sa->sa_len, M_IFMADDR, M_WAITOK);	bcopy(sa, dupsa, sa->sa_len);	ifma->ifma_addr = dupsa;	ifma->ifma_lladdr = llsa;	ifma->ifma_ifp = ifp;	ifma->ifma_refcount = 1;	ifma->ifma_protospec = 0;	rt_newmaddrmsg(RTM_NEWMADDR, ifma);	/*	 * Some network interfaces can scan the address list at	 * interrupt time; lock them out.	 */	s = splimp();	LIST_INSERT_HEAD(&ifp->if_multiaddrs, ifma, ifma_link);	splx(s);	*retifma = ifma;	if (llsa != 0) {		for (ifma = ifp->if_multiaddrs.lh_first; ifma;		     ifma = ifma->ifma_link.le_next) {			if (equal(ifma->ifma_addr, llsa))				break;		}		if (ifma) {			ifma->ifma_refcount++;		} else {			MALLOC(ifma, struct ifmultiaddr *, sizeof *ifma,			       M_IFMADDR, M_WAITOK);			MALLOC(dupsa, struct sockaddr *, llsa->sa_len,			       M_IFMADDR, M_WAITOK);			bcopy(llsa, dupsa, llsa->sa_len);			ifma->ifma_addr = dupsa;			ifma->ifma_ifp = ifp;			ifma->ifma_refcount = 1;			s = splimp();			LIST_INSERT_HEAD(&ifp->if_multiaddrs, ifma, ifma_link);			splx(s);		}	}	/*	 * We are certain we have added something, so call down to the	 * interface to let them know about it.	 */	s = splimp();	ifp->if_ioctl(ifp, SIOCADDMULTI, 0);	splx(s);	return 0;}/* * Remove a reference to a multicast address on this interface.  Yell * if the request does not match an existing membership. */intif_delmulti(ifp, sa)	struct ifnet *ifp;	struct sockaddr *sa;{	struct ifmultiaddr *ifma;	int s;	for (ifma = ifp->if_multiaddrs.lh_first; ifma;	     ifma = ifma->ifma_link.le_next)		if (equal(sa, ifma->ifma_addr))			break;	if (ifma == 0)		return ENOENT;	if (ifma->ifma_refcount > 1) {		ifma->ifma_refcount--;		return 0;	}	rt_newmaddrmsg(RTM_DELMADDR, ifma);	sa = ifma->ifma_lladdr;	s = splimp();	LIST_REMOVE(ifma, ifma_link);	/*	 * Make sure the interface driver is notified	 * in the case of a link layer mcast group being left.	 */	if (ifma->ifma_addr->sa_family == AF_LINK && sa == 0)		ifp->if_ioctl(ifp, SIOCDELMULTI, 0);	splx(s);	free(ifma->ifma_addr, M_IFMADDR);	free(ifma, M_IFMADDR);	if (sa == 0)		return 0;	/*	 * Now look for the link-layer address which corresponds to	 * this network address.  It had been squirreled away in	 * ifma->ifma_lladdr for this purpose (so we don't have	 * to call ifp->if_resolvemulti() again), and we saved that	 * value in sa above.  If some nasty deleted the	 * link-layer address out from underneath us, we can deal because	 * the address we stored was is not the same as the one which was	 * in the record for the link-layer address.  (So we don't complain	 * in that case.)	 */	for (ifma = ifp->if_multiaddrs.lh_first; ifma;	     ifma = ifma->ifma_link.le_next)		if (equal(sa, ifma->ifma_addr))			break;	if (ifma == 0)		return 0;	if (ifma->ifma_refcount > 1) {		ifma->ifma_refcount--;		return 0;	}	s = splimp();	LIST_REMOVE(ifma, ifma_link);	ifp->if_ioctl(ifp, SIOCDELMULTI, 0);	splx(s);	free(ifma->ifma_addr, M_IFMADDR);	free(sa, M_IFMADDR);	free(ifma, M_IFMADDR);	return 0;}/* * Set the link layer address on an interface. * * At this time we only support certain types of interfaces, * and we don't allow the length of the address to change. */intif_setlladdr(struct ifnet *ifp, const u_char *lladdr, int len){	struct sockaddr_dl *sdl;	struct ifaddr *ifa;	ifa = ifnet_addrs[ifp->if_index - 1];	if (ifa == NULL)		return (EINVAL);	sdl = (struct sockaddr_dl *)ifa->ifa_addr;	if (sdl == NULL)		return (EINVAL);	if (len != sdl->sdl_alen)	/* don't allow length to change */		return (EINVAL);	switch (ifp->if_type) {	case IFT_ETHER:			/* these types use struct arpcom */	case IFT_FDDI:	case IFT_XETHER:	case IFT_ISO88025:	case IFT_L2VLAN:		bcopy(lladdr, ((struct arpcom *)ifp->if_softc)->ac_enaddr, len);		bcopy(lladdr, LLADDR(sdl), len);		break;	default:		return (ENODEV);	}	/*	 * If the interface is already up, we need	 * to re-init it in order to reprogram its	 * address filter.	 */	if ((ifp->if_flags & IFF_UP) != 0) {		ifp->if_flags &= ~IFF_UP;		(*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, NULL);		ifp->if_flags |= IFF_UP;		(*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, NULL);	}	return (0);}struct ifmultiaddr *ifmaof_ifpforaddr(sa, ifp)	struct sockaddr *sa;	struct ifnet *ifp;{	struct ifmultiaddr *ifma;		for (ifma = ifp->if_multiaddrs.lh_first; ifma;	     ifma = ifma->ifma_link.le_next)		if (equal(ifma->ifma_addr, sa))			break;	return ifma;}SYSCTL_NODE(_net, PF_LINK, link, CTLFLAG_RW, 0, "Link layers");SYSCTL_NODE(_net_link, 0, generic, CTLFLAG_RW, 0, "Generic link-management");

⌨️ 快捷键说明

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