2016-09-08 15:55:25 zjli321 阅读数 2859
  • 玩转Linux:常用命令实例指南

    本课程以简洁易懂的语言手把手教你系统掌握日常所需的Linux知识,每个知识点都会配合案例实战让你融汇贯通 。课程通俗易懂,简洁流畅,适合0基础以及对Linux掌握不熟练的人学习; 注意: 1、本课程本月原价99元,截止2月23日前仅需29元!购课就送5门价值300元的编程课! 2、课程内容不仅是大纲上这些,2月底前老师会继续增加10余节课程,届时会恢复原件!现在购买最划算! 3、购课后登陆csdn学院官网,在课程目录页面即可下载课件。 学完即可轻松应对工作中 85% 以上的 Linux 使用场景 【限时福利】 1)购课后按提示添加小助手,进答疑群,还可获得价值300元的编程大礼包! 2)本课程【现在享受早鸟价29元】,3月恢复原价! 3)本月购买此套餐加入老师答疑交流群,可参加老师的免费分享活动,学习最新技术项目经验。 注意: 1)现在购买至少享受80元优惠; 2)购课后添加微信itxy06,发送订单截图领取300元编程礼包。 --------------------------------------------------------------- 这门课程,绝对不会让你觉得亏! 29元=掌握Linux必修知识+社群答疑+讲师社群分享会+300元编程礼包。   人工智能、物联网、大数据时代,Linux正有着一统天下的趋势,几乎每个程序员岗位,都要求掌握Linux。本课程零基础也能轻松入门。   在这门课中,我们保证你能收获到这些 1)快速掌握 Linux 常用命令及配置 2)Linux核心知识点 3) 文件、进程、磁盘、用户管理,以及网络工具命令、文件传输等 4)Vi/Vim编辑器用法  

    4531 人正在学习 去看看 严宇

简介

 Android中无线网络的软件涉及linux内核、supplicant、

framework、wifi service,代码从c、c++、java都有,这一篇主
要介绍linux内核中的无线网络。要了解linux的无线网络,首先要
了解linux的网络架构,接着介绍无线网络的架构,然后分析网络数
据包的收、发流程。

1 Linux的网络架构

首先看一下linux的网络架构
这里写图片描述

 系统调用接口
系统调用接口可以从两个角度进行描述。用户发起网络调用时,通过系统调用接口进入内核的过程应该是多路的。最后调用 ./net/socket.c 中的 sys_socketcall 结束该过程,然后进一步将调用分路发送到指定目标。系统调用接口的另一种描述是使用普通文件操作作为网络 I/O。例如,典型的读写操作可以在网络 socket 上执行(socket 使用一个文件描述符表示,与一个普通文件一样)。因此,尽管有很多操作是网络专用的(使用 socket 调用创建一个 socket,使用 connect 调用连接一个收信方,等等),但是也有一些标准的文件操作可以应用于网络对象,就像操作普通文件一样。最后,系统调用接口提供了在用户空间应用程序和内核之间转移控制的方法。

 协议无关接口
socket 层是一个协议无关接口,它提供了一组通用函数来支持各种不同协议。socket 层不但可以支持典型的 TCP 和 UDP 协议,而且还可以支持 IP、裸以太网和其他传输协议,例如 SCTP(Stream Control Transmission Protocol)。
通过网络栈进行的通信都需要对 socket 进行操作。Linux 中的 socket 结构是 struct sock,这个结构是在 linux/include/net/sock.h 中定义的。这个巨大的结构中包含了特定 socket 所需要的所有状态信息,其中包括 socket 所使用的特定协议和在 socket 上可以执行的一些操作。
网络子系统可以通过一个定义了自己功能的特殊结构来了解可用协议。每个协议都维护了一个名为 proto 的结构(可以在 linux/include/net/sock.h 中找到)。这个结构定义了可以在从 socket 层到传输层中执行特定的 socket 操作(例如,如何创建一个 socket,如何使用 socket 建立一个连接,如何关闭一个 socket 等等)。

 网络协议
网络协议这一节对一些可用的特定网络协议作出了定义(例如 TCP、UDP 等)。它们都是在 linux/net/ipv4/af_inet.c 文件中一个名为 inet_init 的函数中进行初始化的(因为 TCP 和 UDP 都是 inet 簇协议的一部分)。 inet_init 函数使用 proto_register 函数来注册每个内嵌协议。这个函数是在 linux/net/core/sock.c 中定义的,除了可以将这个协议添加到活动协议列表中之外,如果需要,该函数还可以选择分配一到多个 slab 缓存。
通过 linux/net/ipv4/ 目录中 udp.c 和 raw.c 文件中的 proto 接口,您可以了解各个协议是如何标识自己的。这些协议接口每个都按照类型和协议映射到 inetsw_array,该数组将内嵌协议与操作映射到一起。inetsw_array 结构及其关系如图所示。最初,会调用 inet_init 中的 inet_register_protosw 将这个数组中的每个协议都初始化为 inetsw。函数 inet_init 也会对各个 inet 模块进行初始化,例如 ARP、ICMP 和 IP 模块,以及 TCP 和 UDP 模块。
这里写图片描述

 设备无关接口
协议层下面是另外一个无关接口层,它将协议与具有很多各种不同功能的硬件设备连接在一起。这一层提供了一组通用函数供底层网络设备驱动程序使用,让它们可以对高层协议栈进行操作。
首先,设备驱动程序可能会通过调用 register_netdevice 或 unregister_netdevice 在内核中进行注册或注销。调用者首先填写 net_device 结构,然后传递这个结构进行注册。内核调用它的 init 函数(如果定义了这种函数),然后执行一组健全性检查,并创建一个 sysfs 条目,然后将新设备添加到设备列表中(内核中的活动设备链表)。在 linux/include/linux/netdevice.h 中可以找到这个 net_device 结构。这些函数都是在 linux/net/core/dev.c 中实现的。
要从协议层向设备中发送 sk_buff,就需要使用 dev_queue_xmit 函数。这个函数可以对 sk_buff 进行排队,从而由底层设备驱动程序进行最终传输(使用 sk_buff 中引用的 net_device 或 sk_buff->dev 所定义的网络设备)。dev 结构中包含了一个名为 hard_start_xmit 的方法,其中保存有发起 sk_buff 传输所使用的驱动程序函数。
报文的接收通常是使用 netif_rx 执行的。当底层设备驱动程序接收一个报文(包含在所分配的 sk_buff 中)时,就会通过调用 netif_rx 将 sk_buff 上传至网络层。然后,这个函数通过 netif_rx_schedule 将 sk_buff 在上层协议队列中进行排队,供以后进行处理。可以在 linux/net/core/dev.c 中找到 dev_queue_xmit 和 netif_rx 函数。

 设备驱动程序
网络栈底部是负责管理物理网络设备的设备驱动程序。例如,包串口使用的 SLIP 驱动程序以及以太网设备使用的以太网驱动程序都是这一层的设备。
在进行初始化时,设备驱动程序会分配一个 net_device 结构,然后使用必须的程序对其进行初始化。这些程序中有一个是 dev->hard_start_xmit,它定义了上层应该如何对 sk_buff 排队进行传输。这个程序的参数为 sk_buff。这个函数的操作取决于底层硬件,但是通常 sk_buff 所描述的报文都会被移动到硬件环或队列中。

 网络接口的注册
一个网卡,要能够被内核使用,必须通过register_netdev接口注册进内核。register_netdev的参数为net_device结构体,其中net_device结构中的netdev_ops成员涉及数据发送,网络操作的接口。下面给出了register_netdev和netdev_ops的结构体及boardcom的netdev_ops的定义。对于网络数据包接收,是直接调用内核接口netif_rx把数据包传给内核,在下面的章节在介绍。

kernel\include\linux\netdevice.h
struct net_device {

    /*
     * This is the first field of the "visible" part of this structure
     * (i.e. as seen by users in the "Space.c" file).  It is the name
     * of the interface.
     */
……..  /* 省略中间代码  */

    /* Management operations */
    const struct net_device_ops *netdev_ops;
    const struct ethtool_ops *ethtool_ops;
kernel\include\linux\netdevice.h
struct net_device_ops {
    int         (*ndo_init)(struct net_device *dev);
    void            (*ndo_uninit)(struct net_device *dev);
    int         (*ndo_open)(struct net_device *dev);
    int         (*ndo_stop)(struct net_device *dev);
    netdev_tx_t     (*ndo_start_xmit) (struct sk_buff *skb,
                           struct net_device *dev);
    u16         (*ndo_select_queue)(struct net_device *dev,
                            struct sk_buff *skb);
    void            (*ndo_change_rx_flags)(struct net_device *dev,
                               int flags);
    void            (*ndo_set_rx_mode)(struct net_device *dev);
    int         (*ndo_set_mac_address)(struct net_device *dev,
                               void *addr);
    int         (*ndo_validate_addr)(struct net_device *dev);
    int         (*ndo_do_ioctl)(struct net_device *dev,
                            struct ifreq *ifr, int cmd);
    int         (*ndo_set_config)(struct net_device *dev,
                              struct ifmap *map);
    int         (*ndo_change_mtu)(struct net_device *dev,
                          int new_mtu);
    int         (*ndo_neigh_setup)(struct net_device *dev,
                           struct neigh_parms *);
    void            (*ndo_tx_timeout) (struct net_device *dev);
kernel\drivers\net\wireless\actions\bcmdhd\dhd_linux.c
static struct net_device_ops dhd_ops_pri = {
    .ndo_open = dhd_open,
    .ndo_stop = dhd_stop,
    .ndo_get_stats = dhd_get_stats,
    .ndo_do_ioctl = dhd_ioctl_entry,
    .ndo_start_xmit = dhd_start_xmit,
    .ndo_set_mac_address = dhd_set_mac_address,
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0))
    .ndo_set_rx_mode = dhd_set_multicast_list,
#else
    .ndo_set_multicast_list = dhd_set_multicast_list,
#endif
};
kernel\drivers\net\wireless\actions\bcmdhd\dhd_linux.c
int
dhd_register_if(dhd_pub_t *dhdp, int ifidx, bool need_rtnl_lock)
{
    dhd_info_t *dhd = (dhd_info_t *)dhdp->info;

……..  /* 省略中间代码  */

    if (ifidx == 0) {
        /*
         * device functions for the primary interface only
         */
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31))
        net->open = dhd_open;
        net->stop = dhd_stop;
#else
        net->netdev_ops = &dhd_ops_pri;
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) */
        if (!ETHER_ISNULLADDR(dhd->pub.mac.octet))
            memcpy(temp_addr, dhd->pub.mac.octet, ETHER_ADDR_LEN);
    } 

……..  /* 省略中间代码  */

    if (need_rtnl_lock)
        err = register_netdev(net);
    else
        err = register_netdevice(net);

2 Linux的无线架构

对于Linux的无线架构,可以分成两部分来学习,第一部分为数据包的收发过程,这部分与1节所说的一样。第二部分为无线网络的控制部分,包括无线网络的扫描、连接、断开及无线网络的各种设置及查询。下图为一个较完整的无线架构。
这里写图片描述
上面的图看起来涉及比较多的内容,而且各种架构都存在,总的来说可以分成2大部分,无线网络控制部分及无线网络数据传输部分,数据传输部分与2.1节介绍的一样。控制部分中,应用层Wext方式的通道已经不使用,现在大部分都是使用libnl方式。对于驱动架构的方式,内核中3种使用方式都有使用。当从我们现在使用的驱动代码看,都是使用方式3的驱动架构。在这只介绍方式3的驱动架构,在方式3的驱动架构的代码中,mac80211已经看不到痕迹了,在这主要介绍一下nl80211及cfg80211。
 nl80211
无线网络在应用层使用libnl(Netlink Library)对命令进行了一层封装,应用层对无线网络的操作全部是通过libnl提供的接口,而libnl与内核的交互最终会走到nl80211(nl80211.c)。nl80211的核心结构如下,包含了所有的无线网络操作命令。

\kernel\include\net\genetlink.h
/**
 * struct genl_ops - generic netlink operations
 * @cmd: command identifier
 * @internal_flags: flags used by the family
 * @flags: flags
 * @policy: attribute validation policy
 * @doit: standard command callback
 * @dumpit: callback for dumpers
 * @done: completion callback for dumps
 * @ops_list: operations list
 */
struct genl_ops {
    u8          cmd;
    u8          internal_flags;
    unsigned int        flags;
    const struct nla_policy *policy;
    int            (*doit)(struct sk_buff *skb,
                       struct genl_info *info);
    int            (*dumpit)(struct sk_buff *skb,
                     struct netlink_callback *cb);
    int            (*done)(struct netlink_callback *cb);
    struct list_head    ops_list;
};
kernel\net\wireless\nl80211.c
static struct genl_ops nl80211_ops[] = {
    {
        .cmd = NL80211_CMD_GET_WIPHY,
        .doit = nl80211_get_wiphy,
        .dumpit = nl80211_dump_wiphy,
        .policy = nl80211_policy,
        /* can be retrieved by unprivileged users */
        .internal_flags = NL80211_FLAG_NEED_WIPHY,
    },
    {
        .cmd = NL80211_CMD_SET_WIPHY,
        .doit = nl80211_set_wiphy,
        .policy = nl80211_policy,
        .flags = GENL_ADMIN_PERM,
        .internal_flags = NL80211_FLAG_NEED_RTNL,
    },
     ……        /* 省略中间部分代码 */
     {
        .cmd = NL80211_CMD_VENDOR,
        .doit = nl80211_vendor_cmd,
        .policy = nl80211_policy,
        .flags = GENL_ADMIN_PERM,
        .internal_flags = NL80211_FLAG_NEED_WIPHY |
                  NL80211_FLAG_NEED_RTNL,
    },
};

 cfg80211_ops
cfg80211是Linux 802.11配置API, 用于对无线设备进行配置管理,用于连接nl80211和硬件的操作,每一个不同的wifi驱动都有自己的一份cfg80211_ops代码,在初始化时通过wiphy_register注册进内核。下面为boardcom的cfg80211_ops代码:

kernel\drivers\net\wireless\actions\bcmdhd\ wl_cfg80211.c
static struct cfg80211_ops wl_cfg80211_ops = {
    .add_virtual_intf = wl_cfg80211_add_virtual_iface,
    .del_virtual_intf = wl_cfg80211_del_virtual_iface,
    .change_virtual_intf = wl_cfg80211_change_virtual_iface,
#if defined(WL_CFG80211_P2P_DEV_IF)
    .start_p2p_device = wl_cfgp2p_start_p2p_device,
    .stop_p2p_device = wl_cfgp2p_stop_p2p_device,
#endif /* WL_CFG80211_P2P_DEV_IF */
    .scan = wl_cfg80211_scan,
    .set_wiphy_params = wl_cfg80211_set_wiphy_params,
    .join_ibss = wl_cfg80211_join_ibss,
    .leave_ibss = wl_cfg80211_leave_ibss,
    .get_station = wl_cfg80211_get_station,
    .set_tx_power = wl_cfg80211_set_tx_power,
    .get_tx_power = wl_cfg80211_get_tx_power,
    .add_key = wl_cfg80211_add_key,
    .del_key = wl_cfg80211_del_key,
    .get_key = wl_cfg80211_get_key,
    .set_default_key = wl_cfg80211_config_default_key,
    .set_default_mgmt_key = wl_cfg80211_config_default_mgmt_key,
    .set_power_mgmt = wl_cfg80211_set_power_mgmt,
    .connect = wl_cfg80211_connect,
    .disconnect = wl_cfg80211_disconnect,
    .suspend = wl_cfg80211_suspend,
    .resume = wl_cfg80211_resume,
    .set_pmksa = wl_cfg80211_set_pmksa,
    .del_pmksa = wl_cfg80211_del_pmksa,
    .flush_pmksa = wl_cfg80211_flush_pmksa,
    .remain_on_channel = wl_cfg80211_remain_on_channel,
    .cancel_remain_on_channel = wl_cfg80211_cancel_remain_on_channel,
    .mgmt_tx = wl_cfg80211_mgmt_tx,
    .mgmt_frame_register = wl_cfg80211_mgmt_frame_register,
    .change_bss = wl_cfg80211_change_bss,
#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)) || defined(WL_COMPAT_WIRELESS)
    .set_channel = wl_cfg80211_set_channel,
#endif /* ((LINUX_VERSION < VERSION(3, 6, 0)) || WL_COMPAT_WIRELESS */
#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0)) && !defined(WL_COMPAT_WIRELESS)
    .set_beacon = wl_cfg80211_add_set_beacon,
    .add_beacon = wl_cfg80211_add_set_beacon,
#else
    .change_beacon = wl_cfg80211_change_beacon,
    .start_ap = wl_cfg80211_start_ap,
    .stop_ap = wl_cfg80211_stop_ap,
#endif /* LINUX_VERSION < KERNEL_VERSION(3,4,0) && !WL_COMPAT_WIRELESS */
#ifdef WL_SCHED_SCAN
    .sched_scan_start = wl_cfg80211_sched_scan_start,
    .sched_scan_stop = wl_cfg80211_sched_scan_stop,
#endif /* WL_SCHED_SCAN */
#if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0))
    .del_station = wl_cfg80211_del_station,
    .change_station = wl_cfg80211_change_station,
    .mgmt_tx_cancel_wait = wl_cfg80211_mgmt_tx_cancel_wait,
#endif /* WL_SUPPORT_BACKPORTED_KPATCHES || KERNEL_VERSION >= (3,2,0) */
#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0)) || defined(WL_COMPAT_WIRELESS)
    .tdls_oper = wl_cfg80211_tdls_oper,
#endif /* LINUX_VERSION > VERSION(3, 2, 0) || WL_COMPAT_WIRELESS */
#ifdef WL_SUPPORT_ACS
    .dump_survey = wl_cfg80211_dump_survey,
#endif /* WL_SUPPORT_ACS */
#ifdef WL_CFG80211_ACL
    .set_mac_acl = wl_cfg80211_set_mac_acl,
#endif /* WL_CFG80211_ACL */
};

3 Linux内核网络数据发送流程

网络协议繁多,但大体框架相同,下面以发送一个ipv4 tcp数据包为例,说明网络数据包的发送流程,下图为Linux tcp数据包的发送流程。
这里写图片描述

各层主要函数以及位置功能说明:
1) SYSCALL_DEFINE4(send):kernel/net/socket.c;socket发送数据包系统调用接口;
2) SYSCALL_DEFINE6(sendto):kernel/net/socket.c;send调用sendto(sendto也是系统调用),填充struct msghdr结构体;
3) sock_sendmsg: kernel/net/socket.c;
4) __sock_sendmsg: kernel/net/socket.c;
5) __sock_sendmsg_nosec:kernel/net/socket.c;选择tcp、udp、raw data协议发送数据包。

kernel/net/socket.c
static inline int __sock_sendmsg_nosec(struct kiocb *iocb, struct socket *sock,
                       struct msghdr *msg, size_t size)
{
    struct sock_iocb *si = kiocb_to_siocb(iocb);

    si->sock = sock;
    si->scm = NULL;
    si->msg = msg;
    si->size = size;

    return sock->ops->sendmsg(iocb, sock, msg, size);
}

const struct proto_ops inet_stream_ops = {   /* tcp数据包处理 */
    .family        = PF_INET,
    .owner         = THIS_MODULE,
    .release       = inet_release,
    .bind          = inet_bind,
    .connect       = inet_stream_connect,
    .socketpair    = sock_no_socketpair,
    .accept        = inet_accept,
    .getname       = inet_getname,
    .poll          = tcp_poll,
    .ioctl         = inet_ioctl,
    .listen        = inet_listen,
    .shutdown      = inet_shutdown,
    .setsockopt    = sock_common_setsockopt,
    .getsockopt    = sock_common_getsockopt,
    .sendmsg       = inet_sendmsg,
    .recvmsg       = inet_recvmsg,

const struct proto_ops inet_dgram_ops = {    /* udp数据包处理 */
    .family        = PF_INET,
    .owner         = THIS_MODULE,
    .release       = inet_release,
    .bind          = inet_bind,
    .connect       = inet_dgram_connect,
    .socketpair    = sock_no_socketpair,
    .accept        = sock_no_accept,
    .getname       = inet_getname,
    .poll          = udp_poll,
    .ioctl         = inet_ioctl,
    .listen        = sock_no_listen,
    .shutdown      = inet_shutdown,
    .setsockopt    = sock_common_setsockopt,
    .getsockopt    = sock_common_getsockopt,
    .sendmsg       = inet_sendmsg,
    .recvmsg       = inet_recvmsg,

static const struct proto_ops inet_sockraw_ops = {   /* raw数据包处理 */
    .family        = PF_INET,
    .owner         = THIS_MODULE,
    .release       = inet_release,
    .bind          = inet_bind,
    .connect       = inet_dgram_connect,
    .socketpair    = sock_no_socketpair,
    .accept        = sock_no_accept,
    .getname       = inet_getname,
    .poll          = datagram_poll,
    .ioctl         = inet_ioctl,
    .listen        = sock_no_listen,
    .shutdown      = inet_shutdown,
    .setsockopt    = sock_common_setsockopt,
    .getsockopt    = sock_common_getsockopt,
    .sendmsg       = inet_sendmsg,
    .recvmsg       = inet_recvmsg,

6) inet_sendmsg:kernel\net\ipv4\ af_inet.c;选择ipv4处理数据发送

kernel\net\ipv4\ af_inet.c
int inet_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
         size_t size)
{
    struct sock *sk = sock->sk;

    sock_rps_record_flow(sk);

    /* We may need to bind the socket. */
    if (!inet_sk(sk)->inet_num && !sk->sk_prot->no_autobind &&
        inet_autobind(sk))
        return -EAGAIN;

    return sk->sk_prot->sendmsg(iocb, sk, msg, size);
}
kernel\net\ipv4\tcp_ipv4.c
struct proto tcp_prot = {
    .name           = "TCP",
    .owner          = THIS_MODULE,
    .close          = tcp_close,
    .connect        = tcp_v4_connect,
    .disconnect     = tcp_disconnect,
    .accept         = inet_csk_accept,
    .ioctl          = tcp_ioctl,
    .init           = tcp_v4_init_sock,
    .destroy        = tcp_v4_destroy_sock,
    .shutdown       = tcp_shutdown,
    .setsockopt     = tcp_setsockopt,
    .getsockopt     = tcp_getsockopt,
    .recvmsg        = tcp_recvmsg,
    .sendmsg        = tcp_sendmsg,

7) tcp_sendmsg:kernel\net\ipv4\tcp.c;申请sk_buff{}结构的空间,把msghdr{}结构中的数据填入sk_buff空间;
8) tcp_push_one:kernel\net\ipv4\ tcp_output.c;
9) tcp_write_xmit:kernel\net\ipv4\ tcp_output.c;
10) tcp_transmit_skb:kernel\net\ipv4\ tcp_output.c;进行tcp封包,传给ip层;

kernel\net\ipv4\ tcp_output.c
static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it,
                gfp_t gfp_mask)
{
    const struct inet_connection_sock *icsk = inet_csk(sk);
    struct inet_sock *inet;

    ……        /* 省略中间部分代码 */

    err = icsk->icsk_af_ops->queue_xmit(skb, &inet->cork.fl);
kernel\net\ipv4\tcp_ipv4.c
const struct inet_connection_sock_af_ops ipv4_specific = {
    .queue_xmit    = ip_queue_xmit,
    .send_check    = tcp_v4_send_check,
    .rebuild_header    = inet_sk_rebuild_header,
    .sk_rx_dst_set     = inet_sk_rx_dst_set,
    .conn_request      = tcp_v4_conn_request,
    .syn_recv_sock     = tcp_v4_syn_recv_sock,
    .net_header_len    = sizeof(struct iphdr),
    .setsockopt    = ip_setsockopt,
    .getsockopt    = ip_getsockopt,
    .addr2sockaddr     = inet_csk_addr2sockaddr,
    .sockaddr_len      = sizeof(struct sockaddr_in),
    .bind_conflict     = inet_csk_bind_conflict,
#ifdef CONFIG_COMPAT
    .compat_setsockopt = compat_ip_setsockopt,
    .compat_getsockopt = compat_ip_getsockopt,
#endif
};

11) ip_queue_xmit:kernel\net\ipv4\ ip_output.c;ip层封包;
12) ip_local_out:kernel\net\ipv4\ ip_output.c;
13) __ip_local_out:kernel\net\ipv4\ ip_output.c;调用netfilter进行处理;
14) dst_output:kernel\include\net\dst.h;
15) ip_output:kernel\net\ipv4\ ip_output.c;
16) ip_finish_output:kernel\net\ipv4\ ip_output.c;
17) ip_finish_output2:kernel\net\ipv4\ ip_output.c;
18) dst_neigh_output:kernel\include\net\ neighbour.h;
19) neigh_hh_output或neigh_resolve_output; kernel\include\net\ neighbour.h 或kernel\net\core\neighbour.c;
20) dev_queue_xm it:kernel\net\core\dev.c;
21) dev_hard_start_xmit:kernel\net\core\dev.c;
22) ndo_start_xmit:网卡驱动注册的发送接口。

4 Linux内核网络数据接收流程

Linux的网络数据包接收流程以接收一个ipv4 tcp数据包为例,接收流程如下图所示:
这里写图片描述

各层主要函数以及位置功能说明:
 从上往下调用接口如下:
1) SYSCALL_DEFINE6(recvfrom):kernel/net/socket.c;socket接收数据包系统调用接口;
2) sock_recvmsg:kernel/net/socket.c;
3) __sock_recvmsg:kernel/net/socket.c;
4) __sock_recvmsg_nosec::kernel/net/socket.c;调用函数指针sock->ops->recvmsg完成在INET Socket层的数据接收过程,其中sock->ops被初始化为inet_stream_ops。
5) inet_recvmsg:kernel\net\ipv4\ af_inet.c;调用函数指针sk->sk_prot->recvmsg,recvmsg被初始化为tcp_recvmsg;
6) tcp_recvmsg:kernel\net\ipv4\tcp.c;从网络协议栈接收数据的动作,自上而下的触发动作一直到这个函数为止,出现了一次等待的过程。函数tcp_recvmsg可能会被动地等待在sk的接收数据队列上,也就是说,系统中肯定有其他地方会去修改这个队列使得tcp_recvmsg可以进行下去,入口参数sk是这个网络连接对应的sock{}指针,msg用于存放接收到的数据。当有数据时,直接返回获取的数据,若没有数据时,则在sk_receive_queue上等待,等待底层收到数据后唤醒。

 下层接收到数据包后通知上层接口如下:
1) netif_rx:kernel\net\core\dev.c; wifi驱动接收到数据包后调用接口把数据包传给内核,同时该函数调用enqueue_to_backlog 把数据包放入input_pkt_queue队列,同时ip_rcv函数从input_pkt_queue取出数据包,再推送给上层;
2) ip_rcv:kernel\net\ipv4\ip_input.c;
3) ip_rcv_finish:kernel\net\ipv4\ip_input.c;ip_rcv和ip_rcv_finish从以太网接收数据,放到skb里,作ip层的一些数据及选项检查,调用ip_route_input() 做路由处理,判断是进行ip转发还是将数据传递到高一层的协议。调用skb->dst->input函数指针,这个指针的实现可能有多种情况,如果路由得到的结果说明这个数据包应该转发到其他主机,这里的input便是ip_forward;如果数据包是给本机的,那么input指针初始化为ip_local_deliver;
4) dst_input:kernel\include\net\dst.h;dst_input 函数调用skb_dst(skb)->input(skb),input函数指针被初始化为ip_local_deliver;
5) ip_local_deliver:kernel\net\ipv4\ ip_input.c;
6) ip_local_deliver_finish:kernel\net\ipv4\ ip_input.c; ip_local_deliver、ip_local_deliver_finish入口参数skb存放需要传送到上层协议的数据,从ip头中获取是否已经分拆的信息,如果已经分拆,则调用函数ip_defrag将数据包重组。然后通过调用ip_prot->handler指针调用 tcp_v4_rcv(tcp)。ip_prot是inet_protocol结构指针,是用来ip层登记协议的,比如由udp,tcp,icmp等协议;
7) tcp_v4_rcv:kernel\net\ipv4\tcp_ipv4.c;
8) tcp_v4_do_rcv:kernel\net\ipv4\tcp_ipv4.c;
9) tcp_rcv_established:kernel\net\ipv4\tcp_ipv4.c;
10) tcp_queue_rcv:kernel\net\ipv4\tcp_ipv4.c;tcp_v4_rcv被ip_local_deliver函数调用,是从IP层协议向INET Socket层提交的“数据到”请求,入口参数skb存放接收到的数据,len是接收的数据的长度,这个函数首先移动skb->data指针,让它指向tcp头,然后更新tcp层的一些数据统计,然后进行tcp的一些值的校验,再从INET Socket层中已经建立的sock{}结构变量中查找正在等待当前到达数据的哪一项,可能这个sock{}结构已经建立,或者还处于监听端口、等待数据连接的状态。返回的sock结构指针存放在sk中。然后根据其他进程对sk的操作情况,将skb发送到合适的位置,调用如下:TCP包接收器(tcp_v4_rcv)将TCP包投递到目的套接字进行接收处理。当套接字正被用户锁定,TCP包将暂时排入该套接字的后备队列(sk_add_backlog),这时如果某一用户线程企图锁定该套接字(lock_sock),该线程被排入套接字的后备处理等待队列(sk->lock.wq),当用户释放上锁的套接字时 (release_sock在tcp_recvmsg中调用),后备队列中的TCP包被立即注入TCP包处理器(tcp_v4_do_rcv)进行处理,然后唤醒等待队列中最先的一个用户来获得其锁定权。如果套接字未被上锁,当用户正在读取该套接字时,TCP包将被排入套接字的预备队列(tcp_prequeue),将其传递到该用户线程上下文中进行处理,如果添加到sk->prequeue不成功,便可以添加到sk_receive_queue队列中。

2015-01-30 10:11:55 u014621518 阅读数 2717
  • 玩转Linux:常用命令实例指南

    本课程以简洁易懂的语言手把手教你系统掌握日常所需的Linux知识,每个知识点都会配合案例实战让你融汇贯通 。课程通俗易懂,简洁流畅,适合0基础以及对Linux掌握不熟练的人学习; 注意: 1、本课程本月原价99元,截止2月23日前仅需29元!购课就送5门价值300元的编程课! 2、课程内容不仅是大纲上这些,2月底前老师会继续增加10余节课程,届时会恢复原件!现在购买最划算! 3、购课后登陆csdn学院官网,在课程目录页面即可下载课件。 学完即可轻松应对工作中 85% 以上的 Linux 使用场景 【限时福利】 1)购课后按提示添加小助手,进答疑群,还可获得价值300元的编程大礼包! 2)本课程【现在享受早鸟价29元】,3月恢复原价! 3)本月购买此套餐加入老师答疑交流群,可参加老师的免费分享活动,学习最新技术项目经验。 注意: 1)现在购买至少享受80元优惠; 2)购课后添加微信itxy06,发送订单截图领取300元编程礼包。 --------------------------------------------------------------- 这门课程,绝对不会让你觉得亏! 29元=掌握Linux必修知识+社群答疑+讲师社群分享会+300元编程礼包。   人工智能、物联网、大数据时代,Linux正有着一统天下的趋势,几乎每个程序员岗位,都要求掌握Linux。本课程零基础也能轻松入门。   在这门课中,我们保证你能收获到这些 1)快速掌握 Linux 常用命令及配置 2)Linux核心知识点 3) 文件、进程、磁盘、用户管理,以及网络工具命令、文件传输等 4)Vi/Vim编辑器用法  

    4531 人正在学习 去看看 严宇

安装Kali Linux操作系统Kali Linux无线网络渗透

Kali Linux是一个基于Debian的Linux发行版,它的前身是BackTrack Linux发行版。在该操作系统中,自带了大量安全和取证方面的相关工具。为了方便用户进行渗透测试,本书选择使用Kali Linux操作系统。用户可以将Kali Linux操作系统安装在,物理机、虚拟机、树莓派、U盘、手机等设备。本节将介绍Kali Linux操作系统的安装方法本文选自Kali Linux无线网络渗透测试教程大学霸。

1.2.1  在物理机上安装Kali Linux

在物理机上安装Kali Linux操作系统之前,需要做一些准备工作,如磁盘空间大小、内存等。为了方便用户的使用,建议磁盘空间至少25GB、内存最好为512MB以上。接下来,就是将Kali Linux系统的ISO文件刻录到一张DVD光盘上。如果用户没有光驱的话,可以将Kali Linux系统的ISO文件写入到U盘上。然后使用U盘,引导启动系统。下面将分别介绍这两种安装方法本文选自Kali Linux无线网络渗透测试教程大学霸。

当用户确认所安装该操作系统的计算机,硬件没问题的话,接下来需要下载Kali Linux的ISO文件。Kali Linux的官方下载地址为http://www.kali.org/downloads/,目前最新版本为1.0.9a。下载界面如图1.1所示本文选自Kali Linux无线网络渗透测试教程大学霸。


图1.1  Kali Linux ISO文件下载界面

从该界面可以看到,Kali Linux目前最新的版本是1.0.9a,并且在该网站提供了32位和64位ISO文件。由于本书主要介绍对无线网络进行渗透测试,Aircrack-ng工具是专门用于无线渗透测试的工具。但是,该工具只有在Kali Linux1.0.5的内核中才支持。为了使用户更好的使用该工具,本书将介绍安装Kali Linux1.0.5操作系统。然后,升级到最新版1.0.9a。这样可以保留1.0.5操作系统的内核,也就可以很好的使用Aircrack-ng工具。目前官方网站已经不提供1.0.5的下载,需要到http://cdimage.kali.org/网站下载,如图1.2所示本文选自Kali Linux无线网络渗透测试教程大学霸。


图1.2  Kali操作系统的下载页面

从该界面可以看到,在该网站提供了Kali Linux操作系统所有版本的下载。这里选择kali-1.0.5,将打开如图1.3所示的界面。


图1.3  下载kali linux 1.0.5

从该界面可以看到提供了Kali Linux1.0.5各种平台的种子。本书以64位操作系统为例,讲解Kali Linux的安装和使用。所以,选择使用迅雷下载kali-linux-1.0.5-amd64.torrent种子的ISO文件。用户可以根据自己的硬件配置,选择相应的种子下载本文选自Kali Linux无线网络渗透测试教程大学霸。

2011-02-22 10:20:00 liranke 阅读数 1238
  • 玩转Linux:常用命令实例指南

    本课程以简洁易懂的语言手把手教你系统掌握日常所需的Linux知识,每个知识点都会配合案例实战让你融汇贯通 。课程通俗易懂,简洁流畅,适合0基础以及对Linux掌握不熟练的人学习; 注意: 1、本课程本月原价99元,截止2月23日前仅需29元!购课就送5门价值300元的编程课! 2、课程内容不仅是大纲上这些,2月底前老师会继续增加10余节课程,届时会恢复原件!现在购买最划算! 3、购课后登陆csdn学院官网,在课程目录页面即可下载课件。 学完即可轻松应对工作中 85% 以上的 Linux 使用场景 【限时福利】 1)购课后按提示添加小助手,进答疑群,还可获得价值300元的编程大礼包! 2)本课程【现在享受早鸟价29元】,3月恢复原价! 3)本月购买此套餐加入老师答疑交流群,可参加老师的免费分享活动,学习最新技术项目经验。 注意: 1)现在购买至少享受80元优惠; 2)购课后添加微信itxy06,发送订单截图领取300元编程礼包。 --------------------------------------------------------------- 这门课程,绝对不会让你觉得亏! 29元=掌握Linux必修知识+社群答疑+讲师社群分享会+300元编程礼包。   人工智能、物联网、大数据时代,Linux正有着一统天下的趋势,几乎每个程序员岗位,都要求掌握Linux。本课程零基础也能轻松入门。   在这门课中,我们保证你能收获到这些 1)快速掌握 Linux 常用命令及配置 2)Linux核心知识点 3) 文件、进程、磁盘、用户管理,以及网络工具命令、文件传输等 4)Vi/Vim编辑器用法  

    4531 人正在学习 去看看 严宇

我的系统:ubuntu.

1. 用无线:
   首先,与无线网建立链接,然后,做如下设置:
   1). 系统->首选项->网络代理,选择“直接链接到internet”;
   2). 在FireFox浏览器中,编辑->首选项->设置,选择“无代理“。
  

2. 用一般网络:
   首先,与本地网建立链接,然后,做如下设置:
   1). 系统->首选项->网络代理,选择“使用代理”,填写好相应的项;
   2). 在FireFox浏览器中,编辑->首选项->设置,选择“手动代理“,填写好相应的项。

如果设置完了,还不能登录,就是网络的问题。

2015-07-08 19:42:54 xiaobo_Linux 阅读数 3570
  • 玩转Linux:常用命令实例指南

    本课程以简洁易懂的语言手把手教你系统掌握日常所需的Linux知识,每个知识点都会配合案例实战让你融汇贯通 。课程通俗易懂,简洁流畅,适合0基础以及对Linux掌握不熟练的人学习; 注意: 1、本课程本月原价99元,截止2月23日前仅需29元!购课就送5门价值300元的编程课! 2、课程内容不仅是大纲上这些,2月底前老师会继续增加10余节课程,届时会恢复原件!现在购买最划算! 3、购课后登陆csdn学院官网,在课程目录页面即可下载课件。 学完即可轻松应对工作中 85% 以上的 Linux 使用场景 【限时福利】 1)购课后按提示添加小助手,进答疑群,还可获得价值300元的编程大礼包! 2)本课程【现在享受早鸟价29元】,3月恢复原价! 3)本月购买此套餐加入老师答疑交流群,可参加老师的免费分享活动,学习最新技术项目经验。 注意: 1)现在购买至少享受80元优惠; 2)购课后添加微信itxy06,发送订单截图领取300元编程礼包。 --------------------------------------------------------------- 这门课程,绝对不会让你觉得亏! 29元=掌握Linux必修知识+社群答疑+讲师社群分享会+300元编程礼包。   人工智能、物联网、大数据时代,Linux正有着一统天下的趋势,几乎每个程序员岗位,都要求掌握Linux。本课程零基础也能轻松入门。   在这门课中,我们保证你能收获到这些 1)快速掌握 Linux 常用命令及配置 2)Linux核心知识点 3) 文件、进程、磁盘、用户管理,以及网络工具命令、文件传输等 4)Vi/Vim编辑器用法  

    4531 人正在学习 去看看 严宇

       1、右击无线网络图标的“编辑连接”。

  2、在“无线”选项卡里,选择“编辑”。

  3、在“无线安全性”选项卡里,输入无线密匙,并选中左下角的“对所有用户可      用”的选项点击应用,会提示输入用        户密码以授权。

  4、然后点击无线网络图标,点击无线网络的名字,即可自动连接至无线网络。

  以后每次开机,都不会再提示输入密匙才能连接无线网络了。

2009-09-24 22:35:00 woods2001 阅读数 865
  • 玩转Linux:常用命令实例指南

    本课程以简洁易懂的语言手把手教你系统掌握日常所需的Linux知识,每个知识点都会配合案例实战让你融汇贯通 。课程通俗易懂,简洁流畅,适合0基础以及对Linux掌握不熟练的人学习; 注意: 1、本课程本月原价99元,截止2月23日前仅需29元!购课就送5门价值300元的编程课! 2、课程内容不仅是大纲上这些,2月底前老师会继续增加10余节课程,届时会恢复原件!现在购买最划算! 3、购课后登陆csdn学院官网,在课程目录页面即可下载课件。 学完即可轻松应对工作中 85% 以上的 Linux 使用场景 【限时福利】 1)购课后按提示添加小助手,进答疑群,还可获得价值300元的编程大礼包! 2)本课程【现在享受早鸟价29元】,3月恢复原价! 3)本月购买此套餐加入老师答疑交流群,可参加老师的免费分享活动,学习最新技术项目经验。 注意: 1)现在购买至少享受80元优惠; 2)购课后添加微信itxy06,发送订单截图领取300元编程礼包。 --------------------------------------------------------------- 这门课程,绝对不会让你觉得亏! 29元=掌握Linux必修知识+社群答疑+讲师社群分享会+300元编程礼包。   人工智能、物联网、大数据时代,Linux正有着一统天下的趋势,几乎每个程序员岗位,都要求掌握Linux。本课程零基础也能轻松入门。   在这门课中,我们保证你能收获到这些 1)快速掌握 Linux 常用命令及配置 2)Linux核心知识点 3) 文件、进程、磁盘、用户管理,以及网络工具命令、文件传输等 4)Vi/Vim编辑器用法  

    4531 人正在学习 去看看 严宇

当今,不考虑 Linux 和无线网络技术的话,就无法谈到计算机和网络。在这篇文章中,Sreekrishnan Venkateswaran 用 Linux 观点阐释了通过 WLAN、Bluetooth、GPRS、GSM 以及 IrDA 实现无线联网。他使用各种不同的无线设备和相应的内核层,以及用户空间工具来示范它们在 Linux 下如何工作。

无线技术,例如 WLAN (Wireless Local Area Network)、Bluetooth、GPRS (General Packet Radio Service)、GSM (Global System for Mobile communications) 以及 IrDa (Infrared Data),在不同的环境下提供服务。虽然 WLAN 支持比 Bluetooth 更高的速度和更长的传播距离,但是它也需要更多的费用并且耗电量更大。GPRS 虽然比 Bluetooth 和 WLAN 慢,但是可用于移动技术。尽管它们存在差异,或者是其他原因,但是具有多种无线功能的设备可以综合利用它们。例如,根据 GPS 模块的定位输入,设备可以透明地将网络连接从路上的 GPRS 切换到网吧中更便宜的 WLAN。移动电话可以通过 Bluetooth 与心律监视器通信,当病人心律超出某个极限时,就可以通过 GSM 向医生发送警报。

目前,无线技术已经以 PCMCIA、Compact Flash (CF) 卡的形式广泛应用,或者用于 USB 设备。大多数计算机系统,包括嵌入式设备,都有 PCMCIA、CF 或者 USB 接口,即使不含对无线技术的内置支持,也能够立刻使用这些技术。这篇文章分析了无线设备的一些示例,并且研究了设备驱动程序的 Linux 实现、总线技术以及各种协议。

首先,通过跟踪 WLAN 样卡的代码流,您将了解到 WLAN 设备是如何在 Linux 下工作的,然后还可以看到几个 Bluetooth 设备如何与 Linux Bluetooth 栈和其他内核层连接。接下来,您将了解到如何使 GPRS 和 GSM 设备在 Linux 下工作。文章最后分析了 Linux 上的 IrDa 支持并简要介绍了有关无线网络设备的性能问题。

注意:本文涉及到的内核数据结构和文件名是当前 Linux 版本中所使用的。文件名相对于 Linux 内核源程序树的根。

Linux 802.11 WLAN

WLAN 通信系统作为有线 LAN 以外的另一种选择一般用在同一座建筑内。WLAN 使用 ISM (Industrial、Scientific、Medical) 无线电广播频段通信。WLAN 的 802.11a 标准使用 5 GHz 频段,支持的最大速度为 54 Mbps,而 802.11b 和 802.11g 标准使用 2.4 GHz 频段,分别支持最大 11 Mbps 和 54 Mbps 的速度。

WLAN 类似于有线以太网,它们都是从同一地址池分配 MAC (Media Access Control) 地址,并且都是作为以太网设备出现在操作系统的网络设备层。例如,ARP(Address Resolution Protocol) 表是用 WLAN MAC 地址和以太网 MAC 地址填充的。

然而 WLAN 与有线以太网在链路层有很大的区别。例如,802.11 标准使用冲突避免(CSMA/CA)代替有线以太网的冲突检测(CSMA/CD)。而且,与以太网帧不同的是,WLAN 帧是被确认的。

由 于 WLAN 工作站之间的模糊边界,WLAN 链路层拥有在传送前清除一个区域的协议。出于安全性考虑,WLAN 的 Wired Equivalent Privacy (WEP) 加密机制提供与有线网络相同的安全级别。WEP 将 40 比特或 104 比特密钥与随机的 24 比特初始向量组合用以加解密数据。WLAN 支持两种通信模式:Ad Hoc 模式 用于小群组工作站之间不必使用访问点的短时间内通信,而 Infrastructure 模式 的所有通信必须通过访问点。访问点周期性地广播一个服务集标识符(SSID),SSID 用于将一个 WLAN 网络与其他网络区别开来。

大多数可用的 WLAN 卡是基于 Intersil Prism 或 Lucent Hermes 芯片组的。Compaq、Nokia、Linksys 和 D-Link 卡使用 Prism 芯片组,而 Lucent Orinoco 卡和 Apple Airport 使用 Hermes 芯片组。

Linux WLAN 支持

Linux WLAN 支持由 WLAN API 实现和 WLAN 设备驱动程序组成。我将依次研究它们。

有 两个 Linux 项目定义一般的 WLAN API,并且提供工具让用户空间应用程序配置参数和存取来自 WLAN 设备驱动程序的信息。Wireless Extensions 项目为不同的无线网卡提供公共的 Linux 用户空间接口。这个项目的工具包括 iwconfig 用以配置参数(比如 WLAN 驱动程序中的 WEP 关键字及 SSID)。linux-wlan 项目作为 Wireless Extensions 项目一部分,也支持一系列用于从用户空间与 WLAN 设备驱动程序交互的工具。与基于 Wireless Extensions 的工具不同,这些工具使用类似于 SNMP (Simple Network Management Protocol) MIB (Management Information Base) 的语法,该语法反映 IEEE 802.11 规范。

继续讨论设备驱动程序,支持流行的 WLAN 卡的 Linux 设备驱动程序包括:

Orinoco WLAN 驱动程序:是 Linux 内核源代码的一部分,支持基于 Hermes 的卡和基于 Intersil Prism 的卡。orinoco_cs 模块提供了 PCMCIA 和 CF 卡所必需的 PCMCIA 卡服务支持。
linux-wlan 项目的 linux-wlan-ng 驱动程序:支持多种基于 Prism 芯片组的卡。这个驱动程序支持 linux-wlan API 并部分支持 Wireless Extensions。
Host AP 设备驱动程序:支持 Prism 芯片组的 AP 模式,可以使 WLAN 主机起访问点的作用。
Linux Symbol Spectrum 设备驱动程序:支持 Symbol PCMCIA 卡。不同于 PCMCIA 卡,Symbol CF 卡缺乏板载固件,它依靠设备驱动程序来下载固件。该驱动程序的一个单独版本适用于 CF 卡。Intel 将 Symbol PCMCIA 卡重新打包为 Intel PRO/Wireless 卡,而 Socket 通信重新打包了 Symbol CF 卡。
Atmel USB WLAN 驱动程序:利用 Atmel 芯片组支持许多 USB WLAN 设备。

Intersil Prism2 WLAN CF 卡

我将讨论 Intersil Prism2 802.11b WLAN CF 卡来展示它如何与 Linux PCMCIA、网络设备及协议层一起工作。

Linux PCMCIA/CF 层由 PCMCIA 主机控制器的设备驱动程序、不同卡的客户机驱动程序、用户模式程序、有助于热拔的后台进程和与以上各部分交互并为它们提供服务的内核卡服务中枢组成。 PCMCIA 控制器将卡连接到系统总线,将卡内存映射到主机 I/O 和内存窗口,并将卡产生的中断路由到自由处理器中断线。CF 卡较小,但与 PCMCIA 兼容,并且经常应用于手持设备。PCMCIA/CF 卡拥有两个存储空间:属性内存(attribute memory)和 公共内存(common memory)。属性内存类似于 Card Information Structure (CIS),用来保存配置注册和描述符信息。Linux 卡服务核心与主机控制器设备驱动程序、卡设备驱动程序及用户模式 cardmgr 后台进程交互。它在一些事件(比如卡插入、卡移出以及低电量)发生时调用卡驱动程序的事件处理程序例程。尽管卡服务从卡的 CIS 向上传送信息到 cardmgr,但是 cardmgr 将为分配内存窗口和中断级别而在用户空间(/etc/pcmcia/config.opts)中定义的资源分配策略向下传送到卡服务。查看 drivers/pcmcia/ds.c 可以了解与 cardmgr 交互的内核代码,查阅 /etc/pcmcia/config.opts 可以了解用户空间资源分配策略。

插入 Intersil WLAN CF 卡时,卡服务调用 orinoco_cs 模块的 PCMCIA 事件处理程序。卡服务解析卡属性内存中的 CIS 元组(tuples)并向上传送信息到 cardmgr,这将从 /etc/pcmcia/config 文件(参阅清单 1)加载适当的设备驱动程序。由于卡的 CIS 中的 manfid 元组匹配 /etc/pcmcia/config 中的条目,所以 cardmgr 绑定带有 orinoco_cs 驱动程序的卡。清单 1 中的设备条目规定 orinoco_cs 驱动程序由三个内核模块组成:orinoco、orinoco_cs 和 hermes。此外,由于设备属于无线的(wireless)一类,所以当启动和停止设备时,cardmgr 执行脚本 /etc/wireless/wireless。这个脚本使用 WLAN 工具和实用程序来配置设备驱动程序参数,例如 WEP 关键字和 SSID。它还可以启动 WLAN 上的网络协议,例如 DHCP(Dynamic Host Configuration Protocol,动态主机配置通讯协议)。清单 1 中的示例使用 Wireless Extensions 工具来执行设备配置。

注意: PCMCIA 配置文件的确切位置取决于所用的 Linux 分布。

清单 1. Intersil WLAN CF 卡的 PCMCIA 设备条目

card "Intersil PRISM2 11 Mbps Wireless Adapter" 
manfid 0x0156, 0x0002
bind "orinoco_cs"

device "orinoco_cs"
class "wireless" module "orinoco","orinoco_cs","hermes"



用 /etc/pcmcia/wireless 和 /etc/pcmcia/wireless.opts 脚本来配置 WEP 关键字和 SSID 这样的参数。

清单 2. 配置 WLAN 特定参数

iwconfig ethX essid <wlan_name>  
key AAAA-AAAA-AA [1] key BBBB-BBBB-BB [2] key CCCC-CCCC-CC [3] key DDDD-DDDD-DD [4]
: Set 64-bit WEP Keys and ESSID in the driver
iwconfig ethX : Display WLAN parameters
iwpriv : Get nongeneric, driver-specific parameters
iwlist : List Information and statistics from an interface
iwspy : Read quality of link for a set of addresses
/proc/net/wireless : Wireless Statistics from the device driver



在 插入卡时,orinoco_cs 像传统的网络设备驱动程序一样,调用 register_netdev 来获得分配给 WLAN 接口的 ethX 网络接口名。它还会注册一个中断服务例程的地址以服务收发无线数据时产生的中断。中断处理程序是 orinoco 模块的一部分,并与 Linux 网络栈交互。Linux 网络栈使用主要的数据结构是 sk_buff 结构(定义在 include/linux/skbuff.h 中,该文件包括关于附加在它上的一个内存块的控制信息)。sk_buffs 为所有网络层提供有效的缓冲器处理和流控制机制。网络设备驱动程序执行一个 dev_alloc_skb 和一个 skb_put,以用 IP 数据填充一个 sk_buff,然后通过调用 netif_rx 将这个sk_buff 传送到 TCP/IP 栈。orinoco 中断服务例程用从 WLAN 接收的数据填充 sk_buffs,并经由 netif_rx 将它传送到 IP 栈。

Linux TCP/IP 应用程序可以在前面谈到的内核模块为 Intersil WLAN CF 卡提供的网络接口上不加更改地运行。

关于作者

Sreekrishnan Venkateswaran 拥有印度坎普尔市印度科技学院的计算机科学硕士学位。他从 1996 年 2 月开始为 IBM India 工作。 他的兴趣包括设计设备驱动程序和网络协议。可以通过 s_krishna@in.ibm.com 与 Sreekrishnan 联系。

全文出自 : IBM developerWorks 中国网站

没有更多推荐了,返回首页