PF_PACKET 设备层编程接口

转载地址:http://waret.iteye.com/blog/743983

定义:

Cpp代码   收藏代码
  1. #include "/usr/include/sys/socket. h"  
  2. #include "/usr/includ/sys/if_packet. h"  
  3. packet_socket = socket(PF_PACKET,  socket_type,  protocol);  

 

描述: 
packet socket用于从设备驱动层接收或发送原始数据包, 可用于用户在物理层以上构建自己的通信协议. 

socket_type 可为:SOCK_RAW或SOCK_DGRAM.

其中SOCK_RAW可用于发送原始数据包, 此时可自定义数据链路层头部; SOCK_DGRAM可用于在数据链路层以上构建包. 结构sockaddr_ll中会用到链路层头部信息. 协议为IEEE 802. 3 协议号的网络序列. 所有到达的属于已定义物理层协议的包先通过packet socket到达已在内核实现的链路层协议处理层. 

仅有特权进程或有CAP_NET_RAW属性的进程才能打开packet套接口. 

如果用SOCK_RAW, 则数据包将直接通过设备驱动程序不加任何改变地发送出去. 这就要求用户程序必须了解物理层头部结构, 并适当地构建包, 此时地址解析将用到标准sockaddr_ll结构. SOCK_RAW很象用于2. 0版核心老的SOCK_PACKET, 但他们并不完全一致. 

SOCK_DGRAM建立在更高层. 在接受包时, 物理头将在到达用户前被去掉; 而在发包时, 物理头部将在发送前被自动添加. 

默认地所有的包都从packet socket层接收. 当仅接收从特定界面来的包时将使用bind来绑定由sockaddr_ll地址结构指定的接口. 

为发送SOCK_RAW包, 用户必须提供空间并构建包括物理头部在内的完整的数据包. 此包将不加任何改变地加入网卡驱动程序发送队列, 而网卡将由目的地址确认. 对于SOCK_DGRAM包, 其头部将在包被加入发送队列前由系统根据地址结构(sockaddr_ll)信息自动填写. 

地址结构: 
sockaddr_ll为设备无关的物理层地址结构.

Cpp代码   收藏代码
  1. struct sockaddr_ll  
  2. {  
  3.     unsigned short sll_family; /* 总填 AF_PACKET */  
  4.     unsigned short sll_protocol;/* 网络序列的物理层协议号 */  
  5.     int sll_ifindex; /* 接口编号 */  
  6.     unsigned short sll_hatype; /* 头部类型 */  
  7.     unsigned char sll_pkttype; /* 包类型 */  
  8.     unsigned char sll_halen; /* 地址长度 */  
  9.     unsigned char sll_addr[8]; /* 物理地址 */  
  10. };  

 

sll_protocol为在sys/if_ether. h中定义的标准以太协议好的网络序列.

sll_pkttype为包类型. 可用的有:
    PACKET_HOST类型用于本机地址的包;
    PACKET_BROADCAST类型用于物理广播;
    PACKET_MULTICAST类型用于物理组播;
    PACKET_OTHERHOST用于在网卡混杂模式下从别的主机通信上接收包;
    PACKET_OUTGOING类型用于从本机packet socket发出的包. 
sll_halen和sll_addr为物理地址及其长度. 

组播和混杂模式的支持: 
Linux2. 2支持一种建立在packet socket上的新方法来配置组播和混杂模式. 它调用setsockopt来工作, 其工作建立在SOL_PACKET packet socket之上, 其选项为PACKET_ADD_MEMBERSHIP或PACKET_DROP_MEMBERSHIP. 底层结构为:

Cpp代码   收藏代码
  1. struct packet_mreq  
  2. {  
  3.     intmr_ifindex; /* 接口编号 */  
  4.     unsigned shortmr_type; /* mreq 类型 */  
  5.     unsigned shortmr_alen; /* 地址长度 */  
  6.     unsigned charmr_address[8]; /* 物理地址 */  
  7. };  

 

mr_interfac包含接口索引, 它指出了谁将要被改变.

mr_type有:
    PACKET_MR_MULTICAST用于绑定套接口和由mr_address指定的物理组播地址;
    PACKET_MR_PROMISC 用于激活混杂模式以接受所有网络包;
    PACKET_DROP_MEMBERSHIP用于撤销绑订或重置. 

输入输出控制: 
输入输出控制可调用ioct:

Cpp代码   收藏代码
  1. ioctl(tcp_socket,  ioctl_type,  value_ptr);  

 

SIOCGSTAMP 返回一个标准timeval结构, 则在须精确时间记录时很有用.

FIOCSETOWN 和 SIOCSPGRP 用于在进程异步通信结束时发送SIGIO信号, 其参数为pid_t类型. 
FIOCGETOWN 和 SIOCGPGRP 用于得到当前接收到SIGIO信号的进程组, 当没有设置时返回0, 参数类型为pid_t.

 

出错处理: 
无出错处理机制. 

兼容性: 
Linux 2. 0仅支持SOCK_RAW, 它使用老的结构:

Cpp代码   收藏代码
  1. struct sockaddr_pkt  
  2. {  
  3.     unsigned short spkt_family;  
  4.     unsigned char spkt_device[14];  
  5.     unsigned short spkt_protocol;  
  6. };  

 

spkt_family包含设备类型.

spkt_protocol为IEEE 802. 3标准协议. 
spkt_device为设备名, 如"eth0";

出错类型: 
ENETDOWN 接口未工作. 
ENOTCONN 没有接口地址. 
ENODEV 未知的设备或接口名. 
EMSGSIZE 包太大. 
ENOBUFS 没有足够的内存来存放接收的包. 
EFAULT 错误的内存地址. 
EINVAL 参数错. 
ENXIO 接口地址包含不合法接口索引. 
EPERM 无打开packet socket接口权用户. 
EADDRNOTAVAIL 未知组播地址. oup address passed. 
ENOENT 未接收到包.


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值