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

📄 if_ethersubr.c

📁 Details description of Free BSD network source code.Those documents have explained each line of code
💻 C
📖 第 1 页 / 共 2 页
字号:
/*略过BSD版权说明: *                                   ethernet网络层代码详解 *                                       解释:xie_minix */#include "opt_atalk.h"                      -------#include "opt_inet.h"                         ^#include "opt_inet6.h"                       此段由编译器编译时候产生,用于一些开关的设置#include "opt_ipx.h"                          |#include "opt_bdg.h"                          |#include "opt_netgraph.h"                   --------#include <sys/param.h>#include <sys/systm.h>#include <sys/kernel.h>#include <sys/malloc.h>#include <sys/mbuf.h>#include <sys/socket.h>#include <sys/sockio.h>#include <sys/sysctl.h>#include <net/if.h>#include <net/netisr.h>#include <net/route.h>#include <net/if_llc.h>#include <net/if_dl.h>#include <net/if_types.h>#include <net/bpf.h>#include <net/ethernet.h>#if defined(INET) || defined(INET6)#include <netinet/in.h>#include <netinet/in_var.h>#include <netinet/if_ether.h>#endif/*vlan的代码我也去掉了,因为我不打算分析他*/#include "vlan.h"#if NVLAN > 0#include <net/if_vlan_var.h>#endif /* NVLAN > 0 *//* netgraph 相关函数用于PPPoE协议即ADSL,对不起大家,我去掉了这些函数的说明,如果那位感兴趣,可以加上 */void	(*ng_ether_input_p)(struct ifnet *ifp,		struct mbuf **mp, struct ether_header *eh);void	(*ng_ether_input_orphan_p)(struct ifnet *ifp,		struct mbuf *m, struct ether_header *eh);int	(*ng_ether_output_p)(struct ifnet *ifp, struct mbuf **mp);void	(*ng_ether_attach_p)(struct ifnet *ifp);void	(*ng_ether_detach_p)(struct ifnet *ifp);static	int ether_resolvemulti __P((struct ifnet *, struct sockaddr **,				    struct sockaddr *));u_char	etherbroadcastaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };#define senderr(e) do { error = (e); goto bad;} while (0)#define IFP2AC(IFP) ((struct arpcom *)IFP)/* * 以太网输出子程序.在此程序中,我省去了很多对我们没有很大用处的东西,如IPX协议,APPLETALK协议,IPV6等,还有 * 一些BPF过滤,防火墙等代码. */intether_output(ifp, m, dst, rt0)	register struct ifnet *ifp;	struct mbuf *m;	struct sockaddr *dst;	/* * 该结构来自于sys/socket.h 核心用于存储大多数地址. *struct sockaddr {	u_char		sa_len;		/* 总长度 	sa_family_t	sa_family;	/* 地址族 	char		sa_data[14];	/* 地址值 };*/	struct rtentry *rt0;	/*路由结构说明,以下结构在我写的"路由基树(radix)代码头文件及原理分析"中有详细说明struct rtentry {	struct	radix_node rt_nodes[2];	/* radix树节点结构,详见"路由基树(radix)代码头文件及原理分析" /#define	rt_key(r)	((struct sockaddr *)((r)->rt_nodes->rn_key))#define	rt_mask(r)	((struct sockaddr *)((r)->rt_nodes->rn_mask))	struct	sockaddr *rt_gateway;	/* 网关 *	long	rt_refcnt;		/* # 保留参考 *	u_long	rt_flags;		/* 已经启动up/或接口已经关闭down?, 是主机路由还是网络路由 *	struct	ifnet *rt_ifp;		/* 使用的接口 /	struct	ifaddr *rt_ifa;		/* 接口的硬件地址 *	struct	sockaddr *rt_genmask;	/* 克窿路由产生的 *	caddr_t	rt_llinfo;		/* 指向链路层信息 *	struct	rt_metrics rt_rmx;	/* metrics used by rx'ing protocols *	struct	rtentry *rt_gwroute;	/* 网关路由入口 /	int	(*rt_output) __P((struct ifnet *, struct mbuf *,				  struct sockaddr *, struct rtentry *));					/* 输出程序 *	struct	rtentry *rt_parent; 	/* 该路由的克隆父路由 /	void	*rt_filler2;		};*/{	short type;	int error = 0, hdrcmplt = 0; 	u_char esrc[6], edst[6];	register struct rtentry *rt;	register struct ether_header *eh;	int off, loop_copy = 0;	int hlen;	/* 链路层头长度 */	struct arpcom *ac = IFP2AC(ifp);/*强制结构类型转换*/	/*接口打开了吗*/	if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))/*接口启动了吗?*/		senderr(ENETDOWN);	rt = rt0;/*rt也指向路由表*/	if (rt) {/*如果路由指针为真,也就是说TCP连接时保留了对方的路由*/		if ((rt->rt_flags & RTF_UP) == 0) {/*如果路由关闭重新取路由*/			rt0 = rt = rtalloc1(dst, 1, 0UL);/*在路由选路中有(route.c中),作用是查询该地址的路由*/			if (rt0)/*路由找到了*/				rt->rt_refcnt--;/*参考记数减1,到0时该路由将被删除*/			else				senderr(EHOSTUNREACH);/*否则发送主机没找到*/		}		if (rt->rt_flags & RTF_GATEWAY) {/*路由标识中有网关,既该地址是间接路由,发到网关即可*/			if (rt->rt_gwroute == 0)/*该网关硬件地址没有,找吧*/				goto lookup;			if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) {/*网关没启动*/				rtfree(rt); rt = rt0;			lookup: rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1,							  0UL);/*查找网关硬件地址*/				if ((rt = rt->rt_gwroute) == 0)/*还没找到硬件地址*/					senderr(EHOSTUNREACH);			}		}		if (rt->rt_flags & RTF_REJECT)			if (rt->rt_rmx.rmx_expire == 0 ||			    time_second < rt->rt_rmx.rmx_expire)				senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH);	}	hlen = ETHER_HDR_LEN;/*=14*/	switch (dst->sa_family) {/*查看地址族*/#ifdef INET	case AF_INET:/*是IP协议*/		if (!arpresolve(ac, rt, m, dst, edst, rt0))/*调用ARP的地址解释例程*/			return (0);	/* 还是解释不了 */		off = m->m_pkthdr.len - m->m_len;/*总长度=包的长度-目前mbuf的长度*/		type = htons(ETHERTYPE_IP);/*主机到网络方式*/		break;#endif	case pseudo_AF_HDRCMPLT:		hdrcmplt = 1;		eh = (struct ether_header *)dst->sa_data;		(void)memcpy(esrc, eh->ether_shost, sizeof (esrc));		/*上面这一段比较有意思,是以太网的头部的源地址和目的地址对调,一般用于ARP的代理*/	case AF_UNSPEC:/*一般由ARP的ARP请求发送例程调用*/		loop_copy = -1; 		eh = (struct ether_header *)dst->sa_data;/*构造发送的以太网头部*/ 		(void)memcpy(edst, eh->ether_dhost, sizeof (edst));		type = eh->ether_type;		break;	default:/*如果到了这,那肯定出错了*/		printf("%s%d: can't handle af%d\n", ifp->if_name, ifp->if_unit,			dst->sa_family);		senderr(EAFNOSUPPORT);	}	/*	 * 加上局域网头部. 如果在第一个mbuf中没有空间,那么再分配另外一个mbuf	 */	M_PREPEND(m, sizeof (struct ether_header), M_DONTWAIT);/*分配一mbuf,前面保留以太网头部的长度空间*/	if (m == 0)		senderr(ENOBUFS);	eh = mtod(m, struct ether_header *);/*定位以太网头*/	(void)memcpy(&eh->ether_type, &type,		sizeof(eh->ether_type)); 	(void)memcpy(eh->ether_dhost, edst, sizeof (edst));/*拷贝目的地址*/	if (hdrcmplt)		(void)memcpy(eh->ether_shost, esrc,			sizeof(eh->ether_shost));	else		(void)memcpy(eh->ether_shost, ac->ac_enaddr,/*拷贝源地址,在xie_ipfw中要从ether_input中的源地址拷贝过来*/			sizeof(eh->ether_shost));	/*	 * 如果一个单工接口, 并且有一包到达地址是本卡的地址或广播地址,或环回.	 * XXX 为了使一个单工设备做起来象一双工设备	 */	if ((ifp->if_flags & IFF_SIMPLEX) && (loop_copy != -1)) {		if ((m->m_flags & M_BCAST) || (loop_copy > 0)) {			struct mbuf *n = m_copy(m, 0, (int)M_COPYALL);			(void) if_simloop(ifp, n, dst->sa_family, hlen);		} else if (bcmp(eh->ether_dhost,		    eh->ether_shost, ETHER_ADDR_LEN) == 0) {			(void) if_simloop(ifp, m, dst->sa_family, hlen);			return (0);	/* XXX */		}	}	/* PPPoe协议,我们可不管他 */	if (ng_ether_output_p != NULL) {		if ((error = (*ng_ether_output_p)(ifp, &m)) != 0) {bad:			if (m != NULL)				m_freem(m);			return (error);		}		if (m == NULL)			return (0);	}	/* 以太网头准备完毕,调用以太网祯输出*/	return ether_output_frame(ifp, m);}/*以太网链路层输出例程发送一帧数据 */intether_output_frame(ifp, m)	struct ifnet *ifp;	struct mbuf *m;{	int s, error = 0;	s = splimp();/*在对队列和输出开始操作前屏蔽网络中断*/	if (IF_QFULL(&ifp->if_snd)) {/*发送队列满了吗?*/		IF_DROP(&ifp->if_snd);		splx(s);		m_freem(m);		return (ENOBUFS);	}	ifp->if_obytes += m->m_pkthdr.len;	if (m->m_flags & M_MCAST)		ifp->if_omcasts++;	IF_ENQUEUE(&ifp->if_snd, m);/*把mbuf编入队列*/	if ((ifp->if_flags & IFF_OACTIVE) == 0)/*接口正在输出吗?*/		(*ifp->if_start)(ifp);	splx(s);	return (error);}/* 处理一收到的以太网包,此包在一个无以太网头部的mbuf链中 * (其实在此过程中并没处理封包,而是传导到ether_demux中处理,在这可以安排自己的代码) * 调用是由网卡驱动程序调用,可参考我的网卡驱动程序详解,在这我去掉了一些不相关的代码 * 如:IPX, APPALTALK,IPV6,IPFW,DUMMYNET等 */voidether_input(ifp, eh, m)	struct ifnet *ifp;   /*接收到以太网封包的网络适配器的ifnet*/	struct ether_header *eh; /*以太网头部,成员为*/	                         /* 10M以太网络头部结构. 								struct	ether_header {									u_char	ether_dhost[ETHER_ADDR_LEN];    目的主机地址									u_char	ether_shost[ETHER_ADDR_LEN];    源主机地址									u_short	ether_type;                     以太网络类型								};   */	struct mbuf *m;{/*---------------------------------------从这到下面都是过滤用的---------------------------------------------*/	/* PPPoE支持(ADSL) */	if (ng_ether_input_p != NULL) {

⌨️ 快捷键说明

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