免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2919 | 回复: 3
打印 上一主题 下一主题

ethernet网络层代码详解 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2003-06-11 09:44 |只看该作者 |倒序浏览
/*
*                                                   ethernet网络层代码详解
*                                                   解释ie_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过滤,放火墙等代码.
*/
int
ether_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;
        /*路由结构说明
struct rtentry {
        struct        radix_node rt_nodes[2];        /* 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) {/*如果路由指针为真*/
                if ((rt->;rt_flags & RTF_UP) == 0) {/*如果路由关闭重新取路由*/
                        rt0 = rt = rtalloc1(dst, 1, 0UL);
                        if (rt0)/*路由找到了*/
                                rt->;rt_refcnt--;
                        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);
}

/*以太网链路层输出例程发送一帧数据
*/
int
ether_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等
*/
void
ether_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) {
                (*ng_ether_input_p)(ifp, &m, eh);
                if (m == NULL)
                        return;
        }

/* -------------------------------------------到此为止,这意味着可以加入自己的代码----------------------------------- */
        ether_demux(ifp, eh, m);
}

/*
* 真正处理以太网封包.
*/
void
ether_demux(ifp, eh, m)  /*该三参数和ether_input()函数的参数一样*/
        struct ifnet *ifp;
        struct ether_header *eh;
        struct mbuf *m;
{
        struct ifqueue *inq;  /*
                         * 结构定义了一个网络接口队列.

                        struct        ifqueue {
                                struct        mbuf *ifq_head;         /*封包的队列头指针
                                struct        mbuf *ifq_tail;         /*尾指针
                                int        ifq_len;                    /*队列长度
                                int        ifq_maxlen;                 /*队列的最大长度
                                int        ifq_drops;                  /*丢弃的数量
                        };
            */
        u_short ether_type;
        int s;


        if ((ifp->;if_flags & IFF_PROMISC) != 0       /*不在混杂模式,目的主机硬件地址的第一字节的最后一位是0即非多播地址*/
            && (eh->;ether_dhost[0] & 1) == 0         /*不是本机地址.注意:在XIE_FIREWALL中不能使用之,应调用一函数*/
            && bcmp(eh->;ether_dhost,                 /*该函数功能是先将其转化为IP头部,取目的IP地址(是本地网吗?是),再查*/
              IFP2AC(ifp)->;ac_enaddr, ETHER_ADDR_LEN) != 0) {/*对应的硬件地址,该硬件地址如为空则发出ARP请求*/
                m_freem(m);                                       /*本地网络如下图:*/
                return;
        }
                                       /*   以下是我的一些想发,太可笑了,现在看来
        int duan=3 (即分3个网段)
        SYSCTL_NODE(_net, PF_LINK, xie, CTLFLAG_RW, 0, "Link layers";
        SYSCTL_NODE(_net_xie,OID_AUTO, link, CTLFLAG_RW, 0, "xie link-management";
        SYSCTL_INT(_net_xie_link, OID_AUTO, fr_flags, CTLFLAG_RW, &duan, 0, "";
        SYSCTL_INT(_net_xie_link, OID_AUTO, fr_pass, CTLFLAG_RW, &xie_gateway, 0, "";
        SYSCTL_INT(_net_xie_link, OID_AUTO, fr_active, CTLFLAG_RD, &xie_gatewaymask, 0, "";
        SYSCTL_INT(....);用sysctl可更改为2,4等,看你支持几块卡
        int xie_gateway=...  即210.35.7.1的32位数
        SYSCTL_INT(....);网关地址控制
        int xie_gatewaymask=... 即255.255.255.0
        SYSCTL_INT(....):网关掩码
        struct xie_ipfw {   内网受保护的IP地址及网段
                struct  ifnet   *ifp  ; 所在网卡的ifnet
                int     duan_xie;所在段
                int     area_xie;段的范围标识,0为相等,1为小于,2为在什么之间
                struct in_addr  area_dy; 等于的IP值,
                struct in_addr  area_max;最大的IP
                struct in_addr  area_min;最小的IP
                int    inok_duan; 允许进入的段,
                int    outok_duan;允许出去的段
                struct  in_addr net_address;该段的网络地址,即210.35.7.0
        };
        该结构在启动后进行设置,第一层过滤在ok_duan的规则中,在主机中有几块网卡就有几个该结构,每一个网卡所在的段号不一样
        段的范围标识表示该段中是只有一个IP地址还是中间的一段IP地址或小于那一段IP地址,在其下的结构表示要用到的IP地址.
        在inok_duan中主要是一些常量,0为0段可进入,1为1段可进入,一直到duan,且段的最大值为24,25为所有段,26为同一网络地址
        outok_duan同inok_duan一样,不过是出口.net_address代表是该段的网络地址,他代表在一个段中必须不能有不同的网络地址
        所以我目前只支持C类地址.
       
                      if (INCLASSC(xie_gateway))     B类地址和A类地址不处理
       
        struct xie_ipaddr {   整个网段的IP地址列表,如210.35.7.0网段
                struct        in_addr ip_xie; 对方的IP地址
                struct  xie_ipfw *my_duan;所在段的回指针
                struct  ifnet    *my_ifnet;
                struct  ether_header myhd; 对方的硬件地址
        }
        struct xie_port  {   保护的端口
                int     xie_protocol;   受保护的协议  xie_protocol =0 为TCP,=1 为UDP
                byte    xie_port_in;    受保护的端口号范围(ether_input) xie_prot_in =0 为 ALL,1 为单个端口,2 为大于,3 为小于,4 为大于且小于.
                int     xie_big_in;    大于使用的最大值,
                int     xie_sma_in;  小于使用,等于使用.
                byte    xie_port_out;    ether_output.
                int     xie_big_out;
                int     xie_sma_out;
        }

        在 int ifioctl(so, cmd, data, p) 中加入(此函数在if.c中)
        switch (cmd) {

        case SIOCSIFXIEFIREWALL:
          for(i=1,i=duan,i++)
                为每段分配IP地址;

        ---------------------------------------------------------------------------------------------------------------
        |  网卡 1  (防火墙内主机1)  | 网卡 2 (防火墙内主机2) | 网卡 2 (防火墙内主机3,4,5,6) |  网卡 3 (非军事化区)    |
        ---------------------------------------------------------------------------------------------------------------
        | 210.35.7.2 (ORACLE-8i)    | 210.35.7.3 (NETSERVER) | 210.35.7.10 -50 (现场端)     | 210.35.7.100-200(院校端)|
        ---------------------------------------------------------------------------------------------------------------
       
       
       
       
       
       
        */
        /* 如果接口没启动则放弃包 */
        if ((ifp->;if_flags & IFF_UP) == 0) {
                m_freem(m);
                return;
        }
        ifp->;if_ibytes += m->;m_pkthdr.len + sizeof (*eh); /*接口的接收到的字节数,eh为以太网包头*/
        if (eh->;ether_dhost[0] & 1) {/*以太网的包头的目的地址(硬件)的第一字节不为全0则为广播或多播包*/
                if (bcmp((caddr_t)etherbroadcastaddr, (caddr_t)eh->;ether_dhost,/*是广播还是多播*/
                         sizeof(etherbroadcastaddr)) == 0)
                        m->;m_flags |= M_BCAST;
                else
                        m->;m_flags |= M_MCAST;
        }
        if (m->;m_flags & (M_BCAST|M_MCAST))
                ifp->;if_imcasts++;

        ether_type = ntohs(eh->;ether_type);/*网络到主机方式*/



        switch (ether_type) {
#ifdef INET
        case ETHERTYPE_IP:/*是IP协议吗?*/
                if (ipflow_fastforward(m))
                        return;
                schednetisr(NETISR_IP);/*调用软中断*/
                inq = &amp;/*IP对列*/
                break;

        case ETHERTYPE_ARP:/*是ARP协议吗?*/
                if (ifp->;if_flags & IFF_NOARP) {
                        /* 如果接口不支持ARP方式,释放包 */
                        m_freem(m);
                        return;
                }
                schednetisr(NETISR_ARP);
                inq = &amp;
                break;
#endif

        default:
        }

        s = splimp();/*关网络中断*/
        if (IF_QFULL(inq)) {
      /*#原型是define        IF_QFULL(ifq)                ((ifq)->;ifq_len >;= (ifq)->;ifq_maxlen)  队列满*/

                IF_DROP(inq);
                /*原型是#define        IF_DROP(ifq)                ((ifq)->;ifq_drops++)     丢弃数加1*/

                m_freem(m);
        } else
                IF_ENQUEUE(inq, m);
        /*以下是原型
        #define        IF_ENQUEUE(ifq, m) { \
        (m)->;m_nextpkt = 0; \
        if ((ifq)->;ifq_tail == 0) \  如果队列尾巴为没有,则该队列没初始化
                (ifq)->;ifq_head = m; \   初始化队列头为M
        else \                       有尾巴,即该队列已经有mbuf
                (ifq)->;ifq_tail->;m_nextpkt = m; \  当前的尾巴mbuf的下一mbuf指向m
        (ifq)->;ifq_tail = m; \        队列的尾巴指向m
        (ifq)->;ifq_len++; \           队列长度加1
}
        */
        splx(s); /*开网络中断*/
}

/*
* 当接口链入到接口列表时执行的普通动作
*/
void/*在我的网络设备驱动程序中有描写, 主要是由网卡驱动调用*/
ether_ifattach(ifp, bpf)
        register struct ifnet *ifp;
        int bpf;
{
        register struct ifaddr *ifa;
        register struct sockaddr_dl *sdl;

        if_attach(ifp);/*调用if.c中的过程*/
        ifp->;if_type = IFT_ETHER;
        ifp->;if_addrlen = 6;
        ifp->;if_hdrlen = 14;
        ifp->;if_mtu = ETHERMTU;/*1500*/
        ifp->;if_resolvemulti = ether_resolvemulti;/*解释多播的过程指针*/
        if (ifp->;if_baudrate == 0)           /*初始化波特率*/
            ifp->;if_baudrate = 10000000;
        ifa = ifnet_addrs[ifp->;if_index - 1];
        KASSERT(ifa != NULL, ("%s: no lladdr!\n", __FUNCTION__));
        sdl = (struct sockaddr_dl *)ifa->;ifa_addr;
        sdl->;sdl_type = IFT_ETHER;
        sdl->;sdl_alen = ifp->;if_addrlen;
        bcopy((IFP2AC(ifp))->;ac_enaddr, LLADDR(sdl), ifp->;if_addrlen);
        if (bpf)/*BPF支持*/
                bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header));
        if (ng_ether_attach_p != NULL)/*PPPoE支持即ADSL*/
                (*ng_ether_attach_p)(ifp);
}

void
ether_ifdetach(ifp, bpf)
        struct ifnet *ifp;
        int bpf;
{
        if (ng_ether_detach_p != NULL)
                (*ng_ether_detach_p)(ifp);
        if (bpf)
                bpfdetach(ifp);
        if_detach(ifp);
}

SYSCTL_DECL(_net_link);/*申明从哪个根接上*/
SYSCTL_NODE(_net_link, IFT_ETHER, ether, CTLFLAG_RW, 0, "Ethernet";/*做一个节点*/

int /*inctl控制代码和多播代码我就不写了,太平常了*/
ether_ioctl(ifp, command, data)
        struct ifnet *ifp;
        int command;
        caddr_t data;
{
        struct ifaddr *ifa = (struct ifaddr *) data;
        struct ifreq *ifr = (struct ifreq *) data;
        int error = 0;

        switch (command) {
        case SIOCSIFADDR:
                ifp->;if_flags |= IFF_UP;

                switch (ifa->;ifa_addr->;sa_family) {
#ifdef INET
                case AF_INET:
                        ifp->;if_init(ifp->;if_softc);        /* before arpwhohas */
                        arp_ifinit(IFP2AC(ifp), ifa);
                        break;
#endif

                default:
                        ifp->;if_init(ifp->;if_softc);
                        break;
                }
                break;

        case SIOCGIFADDR:
                {
                        struct sockaddr *sa;

                        sa = (struct sockaddr *) & ifr->;ifr_data;
                        bcopy(IFP2AC(ifp)->;ac_enaddr,
                              (caddr_t) sa->;sa_data, ETHER_ADDR_LEN);
                }
                break;

        case SIOCSIFMTU:
                /*
                 * Set the interface MTU.
                 */
                if (ifr->;ifr_mtu >; ETHERMTU) {
                        error = EINVAL;
                } else {
                        ifp->;if_mtu = ifr->;ifr_mtu;
                }
                break;
        }
        return (error);
}

int
ether_resolvemulti(ifp, llsa, sa)
        struct ifnet *ifp;
        struct sockaddr **llsa;
        struct sockaddr *sa;
{
        struct sockaddr_dl *sdl;
        struct sockaddr_in *sin;

        u_char *e_addr;

        switch(sa->;sa_family) {
        case AF_LINK:
                /*
                 * No mapping needed. Just check that it's a valid MC address.
                 */
                sdl = (struct sockaddr_dl *)sa;
                e_addr = LLADDR(sdl);
                if ((e_addr[0] & 1) != 1)
                        return EADDRNOTAVAIL;
                *llsa = 0;
                return 0;

#ifdef INET
        case AF_INET:
                sin = (struct sockaddr_in *)sa;
                if (!IN_MULTICAST(ntohl(sin->;sin_addr.s_addr)))
                        return EADDRNOTAVAIL;
                MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR,
                       M_WAITOK|M_ZERO);
                sdl->;sdl_len = sizeof *sdl;
                sdl->;sdl_family = AF_LINK;
                sdl->;sdl_index = ifp->;if_index;
                sdl->;sdl_type = IFT_ETHER;
                sdl->;sdl_alen = ETHER_ADDR_LEN;
                e_addr = LLADDR(sdl);
                ETHER_MAP_IP_MULTICAST(&sin->;sin_addr, e_addr);
                *llsa = (struct sockaddr *)sdl;
                return 0;
#endif

        default:
                /*
                 * Well, the text isn't quite right, but it's the name
                 * that counts...
                 */
                return EAFNOSUPPORT;
        }
}

论坛徽章:
0
2 [报告]
发表于 2003-06-11 10:05 |只看该作者

ethernet网络层代码详解

good,另外想问一下大侠,这些都是bsd中的吗?还是....

论坛徽章:
0
3 [报告]
发表于 2003-06-11 10:33 |只看该作者

ethernet网络层代码详解

是的,不好意思, 是4.4的版本(我比较落后了),我比较喜欢稳定一点的版本,当前版本我也在看变化不大,好象核心(kern)变化挺大的特别是PCI网卡的一些调用(机器相关的)我都看不来了,我特别希望有人能分析PCI部分及网络的MII支持,他太重要了,我每次看到和MII相关的我只知道大概的意思,不敢进去.非常希望那位大侠能攻一攻.

论坛徽章:
0
4 [报告]
发表于 2003-06-11 11:24 |只看该作者
提示: 作者被禁止或删除 内容自动屏蔽
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP