【Linux 内核网络协议栈源码剖析】connect 函数剖析(二)
来源:互联网 发布:ip开放端口查询 编辑:程序博客网 时间:2024/06/15 01:02
网络层——ip_build_header 函数
前篇(跳跃有点大,记得理清思路找到被调用位置,参见connect(一))介绍的 tcp_connect 函数内部调用了 build_header函数,实则是ip层的 ip_build_header 函数,该函数的主要功能是创建合适的 mac和ip头部
-
-
-
-
-
-
-
- int ip_build_header(struct sk_buff *skb, unsigned long saddr, unsigned long daddr,
- struct device **dev, int type, struct options *opt, int len, int tos, int ttl)
- {
- static struct options optmem;
- struct iphdr *iph;
- struct rtable *rt;
- unsigned char *buff;
- unsigned long raddr;
- int tmp;
- unsigned long src;
-
- buff = skb->data;
-
-
-
-
-
- #ifdef CONFIG_INET_MULTICAST
-
- if(MULTICAST(daddr) && *dev==NULL && skb->sk && *skb->sk->ip_mc_name)
- *dev=dev_get(skb->sk->ip_mc_name);
- #endif
-
- if (*dev == NULL)
- {
- if(skb->localroute)
-
-
- rt = ip_rt_local(daddr, &optmem, &src);
- else
- rt = ip_rt_route(daddr, &optmem, &src);
- if (rt == NULL)
- {
- ip_statistics.IpOutNoRoutes++;
- return(-ENETUNREACH);
- }
-
- *dev = rt->rt_dev;
-
-
-
-
- if (LOOPBACK(saddr) && !LOOPBACK(daddr))
- saddr = src;
- raddr = rt->rt_gateway;
-
- opt = &optmem;
- }
- else
- {
-
-
-
- if(skb->localroute)
- rt = ip_rt_local(daddr, &optmem, &src);
- else
- rt = ip_rt_route(daddr, &optmem, &src);
-
-
-
-
- if (LOOPBACK(saddr) && !LOOPBACK(daddr))
- saddr = src;
-
- raddr = (rt == NULL) ? 0 : rt->rt_gateway;
- }
-
-
-
-
-
- if (saddr == 0)
- saddr = src;
-
-
-
-
-
- if (raddr == 0)
- raddr = daddr;
-
-
-
-
-
- tmp = ip_send(skb, raddr, len, *dev, saddr);
-
- buff += tmp;
- len -= tmp;
-
-
-
-
-
- skb->dev = *dev;
- skb->saddr = saddr;
- if (skb->sk)
- skb->sk->saddr = saddr;
-
-
-
-
-
-
-
-
-
-
- if(type == IPPROTO_RAW)
- return (tmp);
-
- iph = (struct iphdr *)buff;
- iph->version = 4;
- iph->tos = tos;
- iph->frag_off = 0;
- iph->ttl = ttl;
- iph->daddr = daddr;
- iph->saddr = saddr;
- iph->protocol = type;
- iph->ihl = 5;
- skb->ip_hdr = iph;
-
-
- #ifdef Not_Yet_Avail
- build_options(iph, opt);
- #endif
-
- return(20 + tmp);
- }
内部调用了一个ip_send函数,用于创建填充MAC头部(这函数名取得。。)-
-
-
-
- static int ip_send(struct sk_buff *skb, unsigned long daddr, int len, struct device *dev, unsigned long saddr)
- {
- int mac = 0;
-
- skb->dev = dev;
- skb->arp = 1;
- if (dev->hard_header)
- {
-
-
-
-
-
- mac = dev->hard_header(skb->data, dev, ETH_P_IP, NULL, NULL, len, skb);
- if (mac < 0)
- {
- mac = -mac;
- skb->arp = 0;
- skb->raddr = daddr;
- }
- }
- return mac;
- }
6、链路层——eth_header 函数承接上面函数,完成创建MAC首部工作
-
-
-
-
-
-
-
- int eth_header(unsigned char *buff, struct device *dev, unsigned short type,
- void *daddr, void *saddr, unsigned len,
- struct sk_buff *skb)
- {
- struct ethhdr *eth = (struct ethhdr *)buff;
-
-
-
-
-
-
- if(type!=ETH_P_802_3)
- eth->h_proto = htons(type);
- else
- eth->h_proto = htons(len);
-
-
-
-
-
- if(saddr)
- memcpy(eth->h_source,saddr,dev->addr_len);
- else
- memcpy(eth->h_source,dev->dev_addr,dev->addr_len);
-
-
-
-
-
- if (dev->flags & IFF_LOOPBACK)
- {
- memset(eth->h_dest, 0, dev->addr_len);
- return(dev->hard_header_len);
- }
-
- if(daddr)
- {
- memcpy(eth->h_dest,daddr,dev->addr_len);
- return dev->hard_header_len;
- }
-
- return -dev->hard_header_len;
- }
至此,connect 函数基本上算是分析完了,中间涉及到数据包的发送与接收我们另外剖析。
来源:http://user.qzone.qq.com/3029454660
参考书籍:《Linux内核网络栈源代码情景分析》、Linux kernel 1.2.13
0 0