caraweng
驱动牛犊
驱动牛犊
  • 注册日期2002-11-20
  • 最后登录2003-02-26
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
阅读:1904回复:15

Linux内核代码,哪位高人能懂?

楼主#
更多 发布于:2002-11-20 14:14
我是linux新手,工作要求,读linux内核代码TCP/IP部分,有困难,主要是函数的各种调用比较糊涂,盼高人指点。
ydyuse
驱动老牛
驱动老牛
  • 注册日期2002-07-25
  • 最后登录2005-03-26
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
沙发#
发布于:2002-11-20 14:21
贴点代码看一下?
生命驱动,活力无限!
caraweng
驱动牛犊
驱动牛犊
  • 注册日期2002-11-20
  • 最后登录2003-02-26
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
板凳#
发布于:2002-11-20 15:00
好的,这是网络层接收数据包的代码ip_input.c,为了整体性,都贴在这。我需要在网络层取得对数据包的控制权,需要如何做?

/*
 * Process Router Attention IP option
 */
int ip_call_ra_chain(struct sk_buff *skb)
{
struct ip_ra_chain *ra;
u8 protocol = skb->nh.iph->protocol;
struct sock *last = NULL;

read_lock(&ip_ra_lock);
for (ra = ip_ra_chain; ra; ra = ra->next) {
struct sock *sk = ra->sk;

/* If socket is bound to an interface, only report
* the packet if it came  from that interface.
*/
if (sk && sk->num == protocol
   && ((sk->bound_dev_if == 0)
|| (sk->bound_dev_if == skb->dev->ifindex))) {
if (skb->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) {
skb = ip_defrag(skb);
if (skb == NULL) {
read_unlock(&ip_ra_lock);
return 1;
}
}
if (last) {
struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
if (skb2)
raw_rcv(last, skb2);
}
last = sk;
}
}

if (last) {
raw_rcv(last, skb);
read_unlock(&ip_ra_lock);
return 1;
}
read_unlock(&ip_ra_lock);
return 0;
}

/* Handle this out of line, it is rare. */
static int ip_run_ipprot(struct sk_buff *skb, struct iphdr *iph,
struct inet_protocol *ipprot, int force_copy)
{
int ret = 0;

do {
if (ipprot->protocol == iph->protocol) {
struct sk_buff *skb2 = skb;
if (ipprot->copy || force_copy)
skb2 = skb_clone(skb, GFP_ATOMIC);
if(skb2 != NULL) {
ret = 1;
ipprot->handler(skb2);
}
}
ipprot = (struct inet_protocol *) ipprot->next;
} while(ipprot != NULL);

return ret;
}

static inline int ip_local_deliver_finish(struct sk_buff *skb)
{
int ihl = skb->nh.iph->ihl*4;

#ifdef CONFIG_NETFILTER_DEBUG
nf_debug_ip_local_deliver(skb);
#endif /*CONFIG_NETFILTER_DEBUG*/

/* Pull out additionl 8 bytes to save some space in protocols. */
if (!pskb_may_pull(skb, ihl+8))
goto out;
__skb_pull(skb, ihl);

#ifdef CONFIG_NETFILTER
/* Free reference early: we don\'t need it any more, and it may
           hold ip_conntrack module loaded indefinitely. */
nf_conntrack_put(skb->nfct);
skb->nfct = NULL;
#endif /*CONFIG_NETFILTER*/

        /* Point into the IP datagram, just past the header. */
        skb->h.raw = skb->data;

{
/* Note: See raw.c and net/raw.h, RAWV4_HTABLE_SIZE==MAX_INET_PROTOS */
int protocol = skb->nh.iph->protocol;
int hash = protocol & (MAX_INET_PROTOS - 1);
struct sock *raw_sk = raw_v4_htable[hash];
struct inet_protocol *ipprot;
int flag;

/* If there maybe a raw socket we must check - if not we
* don\'t care less
*/
if(raw_sk != NULL)
raw_sk = raw_v4_input(skb, skb->nh.iph, hash);

ipprot = (struct inet_protocol *) inet_protos[hash];
flag = 0;
if(ipprot != NULL) {
if(raw_sk == NULL &&
  ipprot->next == NULL &&
  ipprot->protocol == protocol) {
int ret;

/* Fast path... */
ret = ipprot->handler(skb);

return ret;
} else {
flag = ip_run_ipprot(skb, skb->nh.iph, ipprot, (raw_sk != NULL));
}
}

/* All protocols checked.
* If this packet was a broadcast, we may *not* reply to it, since that
* causes (proven, grin) ARP storms and a leakage of memory (i.e. all
* ICMP reply messages get queued up for transmission...)
*/
if(raw_sk != NULL) { /* Shift to last raw user */
raw_rcv(raw_sk, skb);
sock_put(raw_sk);
} else if (!flag) { /* Free and report errors */
icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, 0);
out:
kfree_skb(skb);
}
}

return 0;
}

/*
 * Deliver IP Packets to the higher protocol layers.
 */
int ip_local_deliver(struct sk_buff *skb)
{
/*
* Reassemble IP fragments.
*/

if (skb->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) {
skb = ip_defrag(skb);
if (!skb)
return 0;
}

return NF_HOOK(PF_INET, NF_IP_LOCAL_IN, skb, skb->dev, NULL,
      ip_local_deliver_finish);
}

static inline int ip_rcv_finish(struct sk_buff *skb)
{
struct net_device *dev = skb->dev;
struct iphdr *iph = skb->nh.iph;

/*
* Initialise the virtual path cache for the packet. It describes
* how the packet travels inside  Linux networking.
*/
if (skb->dst == NULL) {
if (ip_route_input(skb, iph->daddr, iph->saddr, iph->tos, dev))
goto drop;
}

#ifdef CONFIG_NET_CLS_ROUTE
if (skb->dst->tclassid) {
struct ip_rt_acct *st = ip_rt_acct + 256*smp_processor_id();
u32 idx = skb->dst->tclassid;
st[idx&0xFF].o_packets++;
st[idx&0xFF].o_bytes+=skb->len;
st[(idx>>16)&0xFF].i_packets++;
st[(idx>>16)&0xFF].i_bytes+=skb->len;
}
#endif

if (iph->ihl > 5) {
struct ip_options *opt;

/* It looks as overkill, because not all
  IP options require packet mangling.
  But it is the easiest for now, especially taking
  into account that combination of IP options
  and running sniffer is extremely rare condition.
                                     --ANK (980813)
*/

if (skb_cow(skb, skb_headroom(skb)))
goto drop;
iph = skb->nh.iph;

skb->ip_summed = 0;
if (ip_options_compile(NULL, skb))
goto inhdr_error;

opt = &(IPCB(skb)->opt);
if (opt->srr) {
struct in_device *in_dev = in_dev_get(dev);
if (in_dev) {
if (!IN_DEV_SOURCE_ROUTE(in_dev)) {
if (IN_DEV_LOG_MARTIANS(in_dev) && net_ratelimit())
printk(KERN_INFO \"source route option %u.%u.%u.%u -> %u.%u.%u.%u\\n\",
      NIPQUAD(iph->saddr), NIPQUAD(iph->daddr));
in_dev_put(in_dev);
goto drop;
}
in_dev_put(in_dev);
}
if (ip_options_rcv_srr(skb))
goto drop;
}
}

return skb->dst->input(skb);

inhdr_error:
IP_INC_STATS_BH(IpInHdrErrors);
drop:
        kfree_skb(skb);
        return NET_RX_DROP;
}

/*
 * Main IP Receive routine.
 */
int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt)
{
struct iphdr *iph = skb->nh.iph;

/* When the interface is in promisc. mode, drop all the crap
* that it receives, do not try to analyse it.
*/
if (skb->pkt_type == PACKET_OTHERHOST)
goto drop;

IP_INC_STATS_BH(IpInReceives);

if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL)
goto out;

if (!pskb_may_pull(skb, sizeof(struct iphdr)))
goto inhdr_error;

iph = skb->nh.iph;

/*
* RFC1122: 3.1.2.2 MUST silently discard any IP frame that fails the checksum.
*
* Is the datagram acceptable?
*
* 1. Length at least the size of an ip header
* 2. Version of 4
* 3. Checksums correctly. [Speed optimisation for later, skip loopback checksums]
* 4. Doesn\'t have a bogus length
*/

if (iph->ihl < 5 || iph->version != 4)
goto inhdr_error;

if (!pskb_may_pull(skb, iph->ihl*4))
goto inhdr_error;

if (ip_fast_csum((u8 *)iph, iph->ihl) != 0)
goto inhdr_error;

{
__u32 len = ntohs(iph->tot_len);
if (skb->len < len || len < (iph->ihl<<2))
goto inhdr_error;

/* Our transport medium may have padded the buffer out. Now we know it
* is IP we can trim to the true length of the frame.
* Note this now means skb->len holds ntohs(iph->tot_len).
*/
if (skb->len > len) {
__pskb_trim(skb, len);
if (skb->ip_summed == CHECKSUM_HW)
skb->ip_summed = CHECKSUM_NONE;
}
}

return NF_HOOK(PF_INET, NF_IP_PRE_ROUTING, skb, dev, NULL,
      ip_rcv_finish);

inhdr_error:
IP_INC_STATS_BH(IpInHdrErrors);
drop:
        kfree_skb(skb);
out:
        return NET_RX_DROP;
}
caraweng
驱动牛犊
驱动牛犊
  • 注册日期2002-11-20
  • 最后登录2003-02-26
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
地板#
发布于:2002-11-20 15:05
不好意思,可能代码太多了。刚刚使用论坛,请多关照。
unix1998
驱动老牛
驱动老牛
  • 注册日期2002-05-08
  • 最后登录2016-01-09
  • 粉丝0
  • 关注0
  • 积分6分
  • 威望2点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
地下室#
发布于:2002-11-20 15:40
太长了。具体那个结构不懂?
caraweng
驱动牛犊
驱动牛犊
  • 注册日期2002-11-20
  • 最后登录2003-02-26
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
5楼#
发布于:2002-11-20 15:50
:)就是就是,太长了

我要在截获的数据包前面增加一个包头,就是这个工作,应该怎么做?
读不懂的函数是ip_local_deliver_finish(),我以为需要在这个函数增加我们的工作,对么?
sk_buff这个结构我基本懂了,别的都不行。
caraweng
驱动牛犊
驱动牛犊
  • 注册日期2002-11-20
  • 最后登录2003-02-26
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
6楼#
发布于:2002-11-21 09:40
高人们别弃我而去呀。:(
unix1998
驱动老牛
驱动老牛
  • 注册日期2002-05-08
  • 最后登录2016-01-09
  • 粉丝0
  • 关注0
  • 积分6分
  • 威望2点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
7楼#
发布于:2002-11-21 10:16
ip_local_deliver判断到IP包是本地的数据包,把本地数据包处理函数的地址返回。他完成路由工作,并返回到ip_rcv_finish()函数。ip_rcv_finish()最后调用拉skb->dst->input(skb),也就是调用了ip_local_deliver()函数,而ip_local_deliver()接着就调用了ip_local_deliver_finish()。finish这个函数是往上层传递数据包。你想在这个函数里加自己的包是吧,我想是可以的。
你看看这个文章:
http://www.linuxaid.com.cn/articles/2/0/206856670.shtml
我不是高手。 :(
caraweng
驱动牛犊
驱动牛犊
  • 注册日期2002-11-20
  • 最后登录2003-02-26
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
8楼#
发布于:2002-11-21 11:17
谢谢,这篇文章我看了,有启发。不过,看完之后,对原来认为理解的问题困惑了,请您快帮我!

linux协议栈最重要的数据结构sk_buff中有关数据包处理的四个指针head,data,tail,end中,data到底指向数据包的头,还是纯粹数据的头?还是用户可以自己定义它的位置?
unix1998
驱动老牛
驱动老牛
  • 注册日期2002-05-08
  • 最后登录2016-01-09
  • 粉丝0
  • 关注0
  • 积分6分
  • 威望2点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
9楼#
发布于:2002-11-21 11:49
Data 指向协议数据的当前起始为止。这个指针随着当前拥有这个 sk_buff 的协议层不同而变化。
caraweng
驱动牛犊
驱动牛犊
  • 注册日期2002-11-20
  • 最后登录2003-02-26
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
10楼#
发布于:2002-11-21 12:13
哦。原来我也是这样理解的,协议数据包括数据部分和报头部分,是吧?
然后一位博士说是数据包除了报头的纯粹数据部分,我就糊涂了。谢谢你。

还有,一个IPsec中心的一篇文章说,sk_buff在end的后面,还举出一个函数skb_check(),说是head<=data,tail<=end<=skb条件要满足。可是我看2.4.2函数,好像skb不一定要与数据缓冲区相连吧?是不是以前版本的linux是这样?因为在2.4.2中,没有skb_check()函数呀。
unix1998
驱动老牛
驱动老牛
  • 注册日期2002-05-08
  • 最后登录2016-01-09
  • 粉丝0
  • 关注0
  • 积分6分
  • 威望2点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
11楼#
发布于:2002-11-21 12:41
linux发展很快,2.4.2也许与2.4.18有了很大变化。少了某个函数不奇怪。
不一定要与数据缓冲区相连。我也这么认为。
caraweng
驱动牛犊
驱动牛犊
  • 注册日期2002-11-20
  • 最后登录2003-02-26
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
12楼#
发布于:2002-11-21 13:14
下一个问题,嘻嘻,问题比较多,别扔下我。

数据包的clone没有复制structure,内核中有很多地方clone了数据包,我不懂为什么。copy和clone有什么用呢?
unix1998
驱动老牛
驱动老牛
  • 注册日期2002-05-08
  • 最后登录2016-01-09
  • 粉丝0
  • 关注0
  • 积分6分
  • 威望2点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
13楼#
发布于:2002-11-21 13:36
Clone只复制架构,而不复制所有对象的数据.这是区别。
用处嘛,不知道。
要是有新问题就另发新贴吧,这样估计会更多人看。我水平有限,帮不了你太多。
 :( :(
caraweng
驱动牛犊
驱动牛犊
  • 注册日期2002-11-20
  • 最后登录2003-02-26
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
14楼#
发布于:2002-11-21 13:41
哦,我说反了,学业不精 :)

我会考虑你的建议,不过,好像您教我够了,别谦虚。:)
unix1998
驱动老牛
驱动老牛
  • 注册日期2002-05-08
  • 最后登录2016-01-09
  • 粉丝0
  • 关注0
  • 积分6分
  • 威望2点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
15楼#
发布于:2002-11-21 15:09
不是谦虚,的确不行。 :)
游客

返回顶部