SG最主要的一个函数是NdisMAllocateNetBufferSGList(); 其定义可以参看WDK文档。

这里先简单介绍下windows网络发包的流程(限802.11):

1.Driver先注册好相应的callback function,。DriverEntry就不提了,另外需要注意的是InitializeHandlerEx里面需要调用NdisMRegisterScatterGatherDma注册DMA的callback.

2.NDIS发NetBufferList(NBL)给Driver,Driver会先对802.11的头部做一些必要的调整。Call NdisMAllocateNetBufferSGList请求NDIS准备SG List。DMA根据SGlist中带的信息做DMA传输。

Ok,之所以叫SG是因为这个技术支持DMA同时传多块物理地址不连续的memory。其实理解起来也很容易,只要告诉DMA这些不连续的Memory,它们各自的物理地址,以及大小就可以了,然后enable DMA, hardware就自动会工作了。Driver要做的这部分就是提取这些信息。在OS跟Hardware之间搭个桥梁。

今天遇到了一个问题就是64Win8机器上,发现,StartDMA之前,Driver修改Memory里面的数据,但是sniffer到的包却没有没变。后来发现是因为在64bit机器上call NdisMAllocateNetBufferSGList,OS会重新分配一块memory来存之前的数据,这样就有两块Memory存放了同样的数据,Mem1,Mem2。Driver尝试去修改Mem1,但是DMA的时候取的却是Mem2里的数据。导致修改Mem1不能改变包的内容。

但是这个问题貌似在32bit的机器上却不存在。

据我理解,Windows下想修改包的内容必须要在call NdisMAllocateNetBufferSGList之前。不过总感觉Windows分配两块内同去存一样的数据这点比较奇怪,觉得MS的人不会这么笨吧,所以这点待考证。