Linux内核--网络栈实现分析(九)--传输层之UDP协议(下)

本文分析基于Linux Kernel 1.2.13

原创作品,转载请标明http://blog.csdn.net/yming0221/article/details/7549340

更多请查看专栏,地址http://blog.csdn.net/column/details/linux-kernel-net.html

作者:闫明

注:标题中的”(上)“,”(下)“表示分析过程基于数据包的传递方向:”(上)“表示分析是从底层向上分析、”(下)“表示分析是从上向下分析。

上篇分析了应用层经过BSD socket层到INET socket层的函数调用关系和数据的处理流程,INET层会调用具体的传输层协议,还是以UDP协议为例

udp_write()函数

[cpp] view plaincopy

  1. static int udp_write(struct sock *sk, unsigned char *buff, int len, int noblock,
  2. unsigned flags)
  3. {
  4. return(udp_sendto(sk, buff, len, noblock, flags, NULL, 0));
  5. }

在分析udp_sendto()函数之前,先了解一下sockaddr_in结构,这是标准的网络接口地址结构的定义

[cpp] view plaincopy

  1. struct sockaddr_in {
  2. short int     sin_family; /* Address family   地址族 */
  3. unsigned short int    sin_port;   /* Port number  端口号     */
  4. struct in_addr    sin_addr;   /* Internet address 网络地址    */
  5. /* Pad to size of `struct sockaddr‘. */
  6. unsigned char     __pad[__SOCK_SIZE__ - sizeof(short int) -
  7. sizeof(unsigned short int) - sizeof(struct in_addr)];
  8. };
  9. #define sin_zero    __pad       /* for BSD UNIX comp. -FvK  */

udp_sentdto()函数

[cpp] view plaincopy

  1. static int udp_sendto(struct sock *sk, unsigned char *from, int len, int noblock,
  2. unsigned flags, struct sockaddr_in *usin, int addr_len)
  3. {
  4. struct sockaddr_in sin;
  5. int tmp;
  6. /*
  7. *  Check the flags. We support no flags for UDP sending
  8. */
  9. if (flags&~MSG_DONTROUTE)
  10. return(-EINVAL);
  11. /*
  12. *  Get and verify the address.
  13. */
  14. if (usin) //如果usin不是空
  15. {
  16. if (addr_len < sizeof(sin))
  17. return(-EINVAL);
  18. memcpy(&sin,usin,sizeof(sin));
  19. if (sin.sin_family && sin.sin_family != AF_INET)
  20. return(-EINVAL);
  21. if (sin.sin_port == 0)
  22. return(-EINVAL);
  23. }
  24. else //usin为空
  25. {
  26. if (sk->state != TCP_ESTABLISHED)
  27. return(-EINVAL);
  28. sin.sin_family = AF_INET;//协议族
  29. sin.sin_port = sk->dummy_th.dest;//目的端口
  30. sin.sin_addr.s_addr = sk->daddr;//目的地址
  31. }
  32. /*
  33. *  BSD socket semantics. You must set SO_BROADCAST to permit
  34. *  broadcasting of data.
  35. */
  36. if(sin.sin_addr.s_addr==INADDR_ANY)//目的地址是全0地址,对应当前主机
  37. sin.sin_addr.s_addr=ip_my_addr();//将目的地址设为当前主机的网络地址
  38. if(!sk->broadcast && ip_chk_addr(sin.sin_addr.s_addr)==IS_BROADCAST)
  39. return -EACCES;         /* Must turn broadcast on first */
  40. sk->inuse = 1;
  41. /* Send the packet. */
  42. tmp = udp_send(sk, &sin, from, len, flags);//调用udp_send()真正的发送数据
  43. /* The datagram has been sent off.  Release the socket. */
  44. release_sock(sk);
  45. return(tmp);
  46. }

udp_send()函数

[cpp] view plaincopy

  1. static int udp_send(struct sock *sk, //要发送的数据包使用的协议对用的sock结构
  2. struct sockaddr_in *sin,//目的端的标准的网络接口地址
  3. unsigned char *from,//要发送的数据所在地址
  4. int len,//发送数据的长度
  5. int rt)
  6. {
  7. struct sk_buff *skb;
  8. struct device *dev;
  9. struct udphdr *uh;
  10. unsigned char *buff;
  11. unsigned long saddr;
  12. int size, tmp;
  13. int ttl;
  14. /*
  15. *  Allocate an sk_buff copy of the packet.
  16. */
  17. size = sk->prot->max_header + len;//计算大小为UDP最长表头+ 数据长度
  18. skb = sock_alloc_send_skb(sk, size, 0, &tmp);//根据要发送的数据分配sk_buff结构空间并对当前套接字状态检查
  19. if (skb == NULL)
  20. return tmp;
  21. skb->sk       = NULL;    /* to avoid changing sk->saddr */
  22. skb->free     = 1;
  23. skb->localroute = sk->localroute|(rt&MSG_DONTROUTE);
  24. /*
  25. *  Now build the IP and MAC header.
  26. */
  27. buff = skb->data;//将skb中的数据指针赋值给buff指针
  28. saddr = sk->saddr;//本地地址
  29. dev = NULL;
  30. ttl = sk->ip_ttl;//生存时间
  31. #ifdef CONFIG_IP_MULTICAST
  32. if (MULTICAST(sin->sin_addr.s_addr))
  33. ttl = sk->ip_mc_ttl;
  34. #endif
  35. tmp = sk->prot->build_header(skb, saddr, sin->sin_addr.s_addr,
  36. &dev, IPPROTO_UDP, sk->opt, skb->mem_len,sk->ip_tos,ttl);//调用ip_build_header()创建IP报头和调用ip_send()创建MAC首部
  37. skb->sk=sk;  /* So memory is freed correctly */
  38. /*
  39. *  Unable to put a header on the packet.
  40. */
  41. if (tmp < 0 )
  42. {
  43. sk->prot->wfree(sk, skb->mem_addr, skb->mem_len);
  44. return(tmp);
  45. }
  46. buff += tmp;
  47. saddr = skb->saddr; /*dev->pa_addr;*/
  48. skb->len = tmp + sizeof(struct udphdr) + len;    /* len + UDP + IP + MAC */
  49. skb->dev = dev;
  50. /*
  51. *  Fill in the UDP header. 填写UDP的报头
  52. */
  53. uh = (struct udphdr *) buff;
  54. uh->len = htons(len + sizeof(struct udphdr));//数据包长度
  55. uh->source = sk->dummy_th.source;//本地端口
  56. uh->dest = sin->sin_port;//远端端口
  57. buff = (unsigned char *) (uh + 1);
  58. /*
  59. *  Copy the user data.
  60. */
  61. memcpy_fromfs(buff, from, len);//复制用户数据
  62. /*
  63. *  Set up the UDP checksum.
  64. */
  65. udp_send_check(uh, saddr, sin->sin_addr.s_addr, skb->len - tmp, sk);//计算UDP报头的校验和
  66. /*
  67. *  Send the datagram to the interface.
  68. */
  69. udp_statistics.UdpOutDatagrams++;
  70. sk->prot->queue_xmit(sk, dev, skb, 1);//调用IP层函数发送数据
  71. return(len);
  72. }

这样要发送的数据填充的sk_buff结构中之后再对UDP数据包添加IP数据报头和MAC帧的首部。最后调用IP层的发送函数发送数据包。

时间: 2024-09-30 18:55:20

Linux内核--网络栈实现分析(九)--传输层之UDP协议(下)的相关文章

Linux内核--网络栈实现分析(七)--数据包的传递过程(下)

本文分析基于Linux Kernel 1.2.13 原创作品,转载请标明http://blog.csdn.net/yming0221/article/details/7545855 更多请查看专栏,地址http://blog.csdn.net/column/details/linux-kernel-net.html 作者:闫明 注:标题中的”(上)“,”(下)“表示分析过程基于数据包的传递方向:”(上)“表示分析是从底层向上分析.”(下)“表示分析是从上向下分析. 在博文Linux内核--网络栈

Linux内核--网络栈实现分析(十一)--驱动程序层(下)

本文分析基于Linux Kernel 1.2.13 原创作品,转载请标明http://blog.csdn.net/yming0221/article/details/7555870 更多请查看专栏,地址http://blog.csdn.net/column/details/linux-kernel-net.html 作者:闫明 注:标题中的”(上)“,”(下)“表示分析过程基于数据包的传递方向:”(上)“表示分析是从底层向上分析.”(下)“表示分析是从上向下分析. 在博文Linux内核--网络栈

Linux内核--网络栈实现分析(五)--传输层之UDP协议(上)

本文分析基于Linux Kernel 1.2.13 原创作品,转载请标明出处http://blog.csdn.net/yming0221/article/details/7532512 更多请看专栏,地址http://blog.csdn.net/column/details/linux-kernel-net.html 作者:闫明 注:标题中的”(上)“,”(下)“表示分析过程基于数据包的传递方向:”(上)“表示分析是从底层向上分析.”(下)“表示分析是从上向下分析. 这里看看数据包从IP层是如何

Linux内核--网络栈实现分析(一)--网络栈初始化

本文分析基于内核Linux Kernel 1.2.13 原创作品,转载请标明http://blog.csdn.net/yming0221/article/details/7488828 更多请看专栏,地址http://blog.csdn.net/column/details/linux-kernel-net.html 作者:闫明 以后的系列博文将深入分析Linux内核的网络栈实现原理,这里看到曹桂平博士的分析后,也决定选择Linux内核1.2.13版本进行分析. 原因如下: 1.功能和网络栈层次

Linux内核--网络栈实现分析(三)--驱动程序层+链路层(上)

本文分析基于Linux Kernel 1.2.13 原创作品,转载请标明http://blog.csdn.net/yming0221/article/details/7497260 更多请看专栏,地址http://blog.csdn.net/column/details/linux-kernel-net.html 作者:闫明 注:标题中的”(上)“,”(下)“表示分析过程基于数据包的传递方向:”(上)“表示分析是从底层向上分析.”(下)“表示分析是从上向下分析. 经过前面两篇博文的分析,已经对L

Linux内核--网络栈实现分析(六)--应用层获取数据包(上)

本文分析基于内核Linux 1.2.13 原创作品,转载请标明http://blog.csdn.net/yming0221/article/details/7541907 更多请看专栏,地址http://blog.csdn.net/column/details/linux-kernel-net.html 作者:闫明 注:标题中的”(上)“,”(下)“表示分析过程基于数据包的传递方向:”(上)“表示分析是从底层向上分析.”(下)“表示分析是从上向下分析. 上篇博文分析了传输层从网络层获取数据包后将

Linux内核--网络栈实现分析(二)--数据包的传递过程(上)

本文分析基于Linux Kernel 1.2.13 原创作品,转载请标明http://blog.csdn.net/yming0221/article/details/7492423 更多请看专栏,地址http://blog.csdn.net/column/details/linux-kernel-net.html 作者:闫明 注:标题中的”(上)“,”(下)“表示分析过程基于数据包的传递方向:”(上)“表示分析是从底层向上分析.”(下)“表示分析是从上向下分析. 上一篇博文中我们从宏观上分析了L

Linux内核--网络栈实现分析(四)--网络层之IP协议(上)

本文分析基于Linux Kernel 1.2.13 原创作品,转载请标明http://blog.csdn.net/yming0221/article/details/7514017 更多请看专栏,地址http://blog.csdn.net/column/details/linux-kernel-net.html 作者:闫明 注:标题中的”(上)“,”(下)“表示分析过程基于数据包的传递方向:”(上)“表示分析是从底层向上分析.”(下)“表示分析是从上向下分析. 简单分析了链路层之后,上升到网络

Linux内核--网络栈实现分析(十)--网络层之IP协议(下)

本文分析基于Linux Kernel 1.2.13 原创作品,转载请标明http://blog.csdn.net/yming0221/article/details/7552455 更多请查看专栏,地址http://blog.csdn.net/column/details/linux-kernel-net.html 作者:闫明 注:标题中的”(上)“,”(下)“表示分析过程基于数据包的传递方向:”(上)“表示分析是从底层向上分析.”(下)“表示分析是从上向下分析. 上篇博文分析传输层最终会调用函