kk Blog —— 通用基础

date [-d @int|str] [+%s|"+%F %T"]

基于82599网卡的二层网络数据包发送

https://tqr.ink/2017/05/01/intel-82599-transmit-packet/

这篇文档主要介绍了网络数据包在二层的发送流程。网络数据包在二层的发送主要包括了网络设备层和驱动层两个部分,所以下面将会从这两个方面讲述报文在二层的发送流程。

网络设备层在报文发送时的处理流程

  当网络协议栈上层准备好了待发送的报文,即构造了一个管理着待发送报文数据的skb对象之后,便会调用网络设备层的主入口函数dev_queue_xmit()进行后续的发送处理。

  当上层已经准备好的skb对象达到网络设备层之后,一般来说并不是直接交给网卡驱动的(在没有设置TCQ_F_CAN_BYPASS的情况下),而是会用类型为struct netdev_queue的发送队列先将skb对象缓存起来,接着依次处理发送队列中的skb对象,将其中的报文数据交给网卡发送出去。而在类型为struct netdev_queue的发送队列中,真正用来缓存skb对象的则是类型为struct Qdisc的实例,该类型的实例通常会实现一组出入队列的回调函数,来实现skb的缓存,重传和移除等操作。当发送队列中struct Qdisc的实例设置了TCQ_F_CAN_BYPASS标志的时候,会将上层下发的skb对象直接通过网卡驱动交给网卡进行发送。

  下图是网络设备层的报文发送主要流程:

图1 网络设备层报文发送流程图

  从上图中我们可以看到在网络设备层用struct Qdisc队列实例来缓存skb对象时,会调用函数 __qdisc_run() 来处理struct Qdisc队列实例中的skb对象,其实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
void __qdisc_run(struct Qdisc *q)
{
  int quota = weight_p;
  int packets;

  /*
   * 循环发送qdisc队列中的报文,直到达到了发送阈值,或者队列中的报文发送完毕,
   * 或者时间片到了,其他进程需要使用cpu
   */
  while (qdisc_restart(q, &packets)) {
      /*
       * Ordered by possible occurrence: Postpone processing if
       * 1. we've exceeded packet quota
       * 2. another process needs the CPU;
       */
      quota -= packets;

      /*
       * 如果quota <= 0,说明qdisc队列中仍然有报文没有发送完,这个时候需要触发
       * 软中断,在软中断处理函数中发送剩余报文
       */
      if (quota <= 0 || need_resched()) {
          __netif_schedule(q);
          break;
      }
  }

  qdisc_run_end(q);
}

  从 __qdisc_run() 函数的实现我们可以看到会有如下两种情况发生:

  1) 一次性将struct Qdisc队列实例中所有的skb对象通过网卡驱动交给网卡发送出去。

  2) 在某次处理struct Qdisc队列实例中的skb对象时,由于某些原因中途停止了,队列实例中可能还有skb对象没有处理完。

  当struct Qdisc队列实例中还有skb对象没有处理完时,就会调用netif_schedule()函数触发一次发送软中断(NET_TX_SOFTIRQ),并将struct Qdisc队列实例加入到cpu私有数据对象softnet_data的output_queue链表成员中,在软中断中会遍历output_queue,继续处理其中的struct Qdisc队列实例剩余的skb对象。发送软中断处理函数实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
static __latent_entropy void net_tx_action(struct softirq_action *h)
{
	struct softnet_data *sd = this_cpu_ptr(&softnet_data);

	……
	/*
	 * softnet_data->output_queue链表不为空,说明其中存有数据没有发送完毕的qdisc
	 * 队列,那么这个时候需要调用qdisc_run()尝试将队列中的报文发送出去
	 */
	if (sd->output_queue) {
		struct Qdisc *head;

		local_irq_disable();
		head = sd->output_queue;
		sd->output_queue = NULL;
		sd->output_queue_tailp = &sd->output_queue;
		local_irq_enable();

		while (head) {
			struct Qdisc *q = head;
			spinlock_t *root_lock;

			head = head->next_sched;

			root_lock = qdisc_lock(q);
			spin_lock(root_lock);
			/* We need to make sure head->next_sched is read
			 * before clearing __QDISC_STATE_SCHED
			 */
			smp_mb__before_atomic();
			clear_bit(__QDISC_STATE_SCHED, &q->state);
			qdisc_run(q);
			spin_unlock(root_lock);
		}
	}
}

  在net_tx_action()函数的实现中可以看到,其间接又调用了 __qdisc_run() 函数,这说明只要struct Qdisc队列实例中有skb对象没有处理完,就会继续触发发送软中断直到所有的队列中所有的skb对象都被处理完。

ixgbe驱动中和数据发送相关的内容

  在二层网络报文接收流程中,接收报文描述符承载了报文从网卡到主存的过程,与之相对应的,发送报文描述符则承载了报文从主存到网卡的过程。对于网卡驱动而言,当收到来自协议栈上层下发的网络报文时,网卡驱动会将存放着报文数据的地址写入到报文发送描述符中,并将填充了报文地址信息的描述符传递给网卡,而网卡则从报文发送描述符中存放的地址中读取报文数据。

报文发送描述符

  对于82599网卡而言,其支持两种格式的报文发送描述符,即传统格式和高级格式。虽然有两种不同格式的报文发送描述符,但是两种格式的报文发送描述符所占用的内存大小是一样的(目前为16字节),只是对这块内存使用有所不同。对于两种不同格式的报文发送描述符,可以通过设置报文发送描述符中的TDESC.DEXT位进行区分,当该位设置为0的时候,表明使用的是传统格式;当该位设置为1的时候,表明使用的是高级格式。下面介绍高级格式的报文发送描述符。

  相比于传统格式,高级格式的报文发送描述符可以用来支持更多的功能特性。高级格式的报文描述符由于需要支持更多的功能特性,所以分为了读格式和回写格式。

  先来看下82599网卡中读格式的定义,如下图:

图2 高级格式报文发送描述符-读格式

  从图中可以看到,读格式的报文发送描述符中主要包含了报文数据所在的内存地址和一些报文元信息,如报文长度等。这里不再详述,详细可以参考82599网卡的datasheet。

  再来看下82599网卡中回写格式的定义:

图3 高级格式报文发送描述符-回写格式

  从图中可以看到,回写格式的报文发送描述符中有效的域很少,只有STA,而STA中有效位有只有DD位,网卡驱动可以通过该位是否被置位来判断报文发送描述符对应的报文数据是否已经被网卡处理过了。

  在初始化阶段,网卡驱动会申请一定数量的报文发送描述符,并将这些内存进行dma一致性映射,获取对应的物理地址,并写入到网卡的寄存器中,这样网卡驱动和网卡就能同时操作这些报文发送描述符了。当网卡驱动收到协议栈下发的skb对象后,会将skb对象中存放的报文数据进行dma映射,获取对应的物理地址,并存放到报文发送描述符中对应的成员中,这样网卡就能从报文发送描述符中获取存放了报文数据的物理地址,然后从该地址中读取报文数据,并发送到网络中去。

报文发送描述符环形队列

  上面说到,报文发送描述符承载了报文从主存流入到网卡的过程,是网卡驱动和网卡都会操作的对象,那么自然而然会有以下几个疑问:

  1)、报文发送描述符是以何种组织形式在网卡驱动和网卡之间进行传递的?

  2)、网卡驱动怎么通知网卡报文发送描述符可用的?

  在报文发送流程中,报文发送描述符是通过环形队列来管理的,当然这个环形队列是逻辑上的,队列中的描述符在内存上是连续的。网卡或者网卡驱动在进行操作的时候,如果发现已经到达了队列的末尾,那么下次操作又会从队列头部开始,从而实现环形的操作逻辑。报文发送描述符环形队列的结构体如下:

图4 报文发送描述符环形队列结构

  对于第一和第二个问题,其中也已经在上面的描述符环形队列图中有体现。在对问题进行回答之前先要了解下82599网卡中和报文发送描述符环形队列相关的几个寄存器。

  1)、TDBA寄存器。这个寄存器存放了报文发送描述符环形队列的起始地址,也就是上图中Base指向的地址。

  2)、TDLEN寄存器。这个寄存器存放了报文发送描述符环形队列的长度,也就是报文发送描述符环形队列所占用的字节数,对应上图中的Size。

  3)、TDH寄存器。这个寄存器存放的是一个距离队列头部的偏移值,代表的是第一个填充了报文地址信息的描述符。当网卡处理完一个描述符对应的报文数据后,就会更新TDH寄存器的值,使之指向下一个填充了报文地址信息的描述符。也就是说这个寄存器的值是由网卡来更新的,该寄存器对应上图中的Head。

  4)、TDT寄存器。这个寄存器存放的也是一个距离队列头部的偏移值,代表的是最后一个存放了报文地址信息的描述符的下一个描述符。当网卡驱动将一个skb对象中所有的数据分段对应的物理地址都填充到了对应的报文发送描述符中后,就会更新该寄存器的值,使之指向下一个即将被填充报文地址信息并给网卡使用的描述符,该寄存器对应上图中的Tail。

  在了解了这几个寄存器的作用之后,对于本节一开始提出的两个问题就比较容易知晓了。对于第一个问题,报文描述符是以环形队列的方式来组织的;对于第二个问题,因为网卡驱动在填充完一个skb对象中数据分段的报文地址信息到报文发送描述符后,网卡驱动都会更新TDT寄存器的值,所以网卡可以根据TDT寄存器知道自己当前可用的描述符信息,简单来说TDH和TDT之间的描述符就是网卡可以使用的。

数据分段和报文发送描述符关系

  上面说到网卡驱动会将skb对象中存放了报文数据的内存进行dma映射,并将得到的物理地址存放到报文发送描述符中,而一个skb对象中可能存有多个数据分段,对于这种情况,网卡驱动则会将一个数据分段对应一个报文发送描述符,其对应关系如下图:

图5 数据分段与报文发送描述符对应关系

报文发送描述符的回收

当网卡完成报文发送之后,就会触发硬件中断。这里需要注意的是,新的数据包达到或者外发数据包的传输已经完成所触发的中断对应的中断号是同一个,所以在这个中断号对应的中断处理函数中需要考虑到是新的数据包达到所产生的中断,还是外发数据包的传输已经完成触发的中断。

  另外,ixgbe驱动中因为使用了NAPI的收包方式,所以在中断处理函数中只是调用NAPI模块调度接口napi_schedule_irqoff()将设备加入到cpu私有数据中类型为struct softnet_data的对象的待轮询设备链表中,并触发软中断,而在软中断处理函数net_rx_action()中又只会调用设备注册的NAPI回调函数poll。所以无论是新的数据包达到,或者是外发数据包的传输已经完成所触发的中断,最终都会调用设备注册给NAPI接口的poll回调函数,因此报文发送描述符的回收也是在这个函数中完成的,在ixgbe驱动中,poll回调函数就是ixgbe_poll()。在ixgbe_poll()函数中又会调用ixgbe_clean_tx_irq()函数来完成报文发送描述符的回收,该函数实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
			       struct ixgbe_ring *tx_ring, int napi_budget)
{
	struct ixgbe_adapter *adapter = q_vector->adapter;
	struct ixgbe_tx_buffer *tx_buffer;
	union ixgbe_adv_tx_desc *tx_desc;
	unsigned int total_bytes = 0, total_packets = 0;
	unsigned int budget = q_vector->tx.work_limit;
   
	/* 获取第一个可以被网卡驱动处理的描述符索引 */
	unsigned int i = tx_ring->next_to_clean;

	if (test_bit(__IXGBE_DOWN, &adapter->state))
		return true;

	tx_buffer = &tx_ring->tx_buffer_info[i];
	tx_desc = IXGBE_TX_DESC(tx_ring, i);
	i -= tx_ring->count;

	do {

		/*
		 * tx_buffer->next_to_watch保存的是环形队列中第一个没有存放某个报文数据
		 * 的报文发送描述符
		 */
		union ixgbe_adv_tx_desc *eop_desc = tx_buffer->next_to_watch;

		/* if next_to_watch is not set then there is no work pending */
		/*
		 * 如果某个报文发送描述符对应的报文缓冲区的next_to_watch成员没有设置,
		 * 说明这个缓冲区对象并不是某个报文对应的第一个缓冲区(当报文以共享方式
		 * 存放的时候,一个报文可能会对应多个缓冲区)。
		 */
		if (!eop_desc)
			break;

		read_barrier_depends();

		/*
		 * 如果eop_desc描述符对应的dd为没有被设置,说明网卡还没有处理完属于该报文
		 * 对应的所有缓冲区,所以就暂时不处理对应的描述符了,而是要等到属于该报文
		 * 的所有描述符都被网卡处理完了之后才去处理属于该报文的所有描述符
		 */
		if (!(eop_desc->wb.status & cpu_to_le32(IXGBE_TXD_STAT_DD)))
			break;

		tx_buffer->next_to_watch = NULL;

		total_bytes += tx_buffer->bytecount;
		total_packets += tx_buffer->gso_segs;

		napi_consume_skb(tx_buffer->skb, napi_budget);

		/* 取消skb->data指向内存的dma映射,以让cpu可以使用该块内存 */
		dma_unmap_single(tx_ring->dev,
				 dma_unmap_addr(tx_buffer, dma),
				 dma_unmap_len(tx_buffer, len),
				 DMA_TO_DEVICE);

		tx_buffer->skb = NULL;
		dma_unmap_len_set(tx_buffer, len, 0);

		/* 取消skb中分片数据对应内存的dma映射,以让cpu可以使用该块内存 */
		while (tx_desc != eop_desc) {
			tx_buffer++;
			tx_desc++;
			i++;
			if (unlikely(!i)) {
				i -= tx_ring->count;
				tx_buffer = tx_ring->tx_buffer_info;
				tx_desc = IXGBE_TX_DESC(tx_ring, 0);
			}

			/* unmap any remaining paged data */
			if (dma_unmap_len(tx_buffer, len)) {
				dma_unmap_page(tx_ring->dev,
					       dma_unmap_addr(tx_buffer, dma),
					       dma_unmap_len(tx_buffer, len),
					       DMA_TO_DEVICE);
				dma_unmap_len_set(tx_buffer, len, 0);
			}
		}

		/* move us one more past the eop_desc for start of next pkt */
		tx_buffer++;
		tx_desc++;
		i++;
		if (unlikely(!i)) {
			i -= tx_ring->count;
			tx_buffer = tx_ring->tx_buffer_info;
			tx_desc = IXGBE_TX_DESC(tx_ring, 0);
		}

		/* issue prefetch for next Tx descriptor */
		prefetch(tx_desc);

		/* update budget accounting */
		budget--;
	} while (likely(budget));

	/* 更新环形队列中的next_to_clean */
	i += tx_ring->count;
	tx_ring->next_to_clean = i;
	……

	return !!budget;
}

  到这里,报文在二层的发送流程就介绍完了。

G9300 kernel

编译

https://opensource.samsung.com/uploadSearch?searchValue=G9300

https://opensource.samsung.com/uploadSearch?searchValue=G9350

较新的ROM没刷成功(8.0.0 BL锁了???),选择 7.0 ROM G9300ZCU2BRD1。

G9300公开的内核最接近的是G9300ZCU2BQI3,但G9350公开的G9350ZCU2BQK3内核更接近G9300ZCU2BRD1,但需要复制G9300的 arch/arm64/boot/dts/samsung/ 到 G9350的arch/arm64/boot/dts/samsung/

参造 build_kernel.sh 编译

编译器用 android-ndk-r20b-linux-x86_64.zip 中的 aarch64-linux-android-4.9。也可以用这个 tools/prebuilts/gcc-cfp-jopp-only/aarch64-linux-android-4.9/ ???

https://github.com/abcdxyzk/aarch64-linux-android-4.9 从 android-ndk-r20b-linux-x86_64.zip 提取的 aarch64-linux-android-4.9

修复wifi目录,它的写法是需要需要获取android版本,我们默认就是 7

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
diff --git a/drivers/net/wireless/bcmdhd4359/Makefile b/drivers/net/wireless/bcmdhd4359/Makefile
index 9acd0726..433bb7b1 100755
--- a/drivers/net/wireless/bcmdhd4359/Makefile
+++ b/drivers/net/wireless/bcmdhd4359/Makefile
@@ -271,16 +271,18 @@ FOUND_VERSION_PATH := $(foreach dir,$(CANDIDATE_VERSION_PATH), $(wildcard $(dir)
 FOUND_VERSION_PATH := $(word 1, $(FOUND_VERSION_PATH))
 ifeq ($(FOUND_VERSION_PATH),)
 $(warning Not found Android version file. Set as Legacy mode)
-DHDCFLAGS += -DDHD_LEGACY_FILE_PATH
-DHDCFLAGS += -DDHD_DISABLE_ANDROID_FEATURE_SET
+#DHDCFLAGS += -DDHD_LEGACY_FILE_PATH
+#DHDCFLAGS += -DDHD_DISABLE_ANDROID_FEATURE_SET
+DHDCFLAGS += -DDHD_SET_COUNTRY_SUPPORT
 else
 # Extract version string and get major number
 ANDROID_PLATFORM_VERSION := $(shell grep "PLATFORM_VERSION := " $(FOUND_VERSION_PATH) | cut -d "=" -f 2 | cut -d "." -f 1 | sed 's/ //g')
 $(warning Android Platform Version : $(ANDROID_PLATFORM_VERSION))
 # If Android version lower than 7(Nougat) => Use Legacy File path
 ifeq ($(shell expr $(ANDROID_PLATFORM_VERSION) \< 7),1)
-DHDCFLAGS += -DDHD_LEGACY_FILE_PATH
-DHDCFLAGS += -DDHD_DISABLE_ANDROID_FEATURE_SET
+#DHDCFLAGS += -DDHD_LEGACY_FILE_PATH
+#DHDCFLAGS += -DDHD_DISABLE_ANDROID_FEATURE_SET
+DHDCFLAGS += -DDHD_SET_COUNTRY_SUPPORT
 $(warning Will be use Legacy file path)
 else
 DHDCFLAGS += -DDHD_SET_COUNTRY_SUPPORT

编译后用到

1
2
3
4
5
6
7
8
9
10
11
12
13
14
out/arch/arm64/boot/Image.gz

$ find out/ -name '*.ko'
out/drivers/gator/gator.ko
out/drivers/scsi/ufs/ufs_test.ko
out/drivers/input/evbug.ko
out/drivers/spi/spidev.ko
out/drivers/mmc/card/mmc_block_test.ko
out/drivers/mmc/card/mmc_test.ko
out/drivers/char/rdbg.ko
out/block/test-iosched.ko
out/net/ipv4/tcp_westwood.ko
out/net/ipv4/tcp_htcp.ko
out/net/bridge/br_netfilter.ko

制作img

https://github.com/abcdxyzk/android_system_core

https://github.com/abcdxyzk/BootTools

1
2
3
4
5
6
7
8
9
10
11
12
13
$ ~/kk/BootTools/hdrboot boot.img
Magic: ANDROID!
Kernel size: 0x9D203F (10297407)
  Aligned size: 0x9D3000
Kernel addr: 0x80008000
Ramdisk size: 0x484ED0 (4738768)
Ramdisk addr: 0x82200000
Second size: 0x0 (0)
Second addr: 0x80F00000
Tags addr: 0x82000000
Page size: 0x1000 (4096)
Name: RILPA13A000KU
Cmdline: console=null androidboot.hardware=qcom user_debug=31 msm_rtb.filter=0x37 ehci-hcd.park=3 lpm_levels.sleep_disabled=1 cma=24M@0-0xffffffff rcupdate.rcu_expedited=1
1
2
3
4
5
6
7
8
9
10
$ ~/kk/android_system_core/mkbootimg/unpackbootimg -i boot.img
Android magic found at: 0
BOARD_KERNEL_CMDLINE console=null androidboot.hardware=qcom user_debug=31 msm_rtb.filter=0x37 ehci-hcd.park=3 lpm_levels.sleep_disabled=1 cma=24M@0-0xffffffff rcupdate.rcu_expedited=1
BOARD_KERNEL_BASE 00008000
BOARD_RAMDISK_OFFSET 02200000
BOARD_SECOND_OFFSET 00f00000
BOARD_TAGS_OFFSET 02000000
BOARD_PAGE_SIZE 4096
BOARD_SECOND_SIZE 0
BOARD_DT_SIZE 7122944

替换 boot.img-zImage,cp out/arch/arm64/boot/Image.gz boot.img-zImage,然后重新制作 boot.img

1
2
3
4
5
$ ~/kk/android_system_core/mkbootimg/mkbootimg --kernel boot.img-zImage --ramdisk boot.img-ramdisk.gz --base 0x80000000 --ramdisk_offset 0xFF8000 --pagesize 4096 --cmdline "console=null androidboot.hardware=qcom user_debug=31 msm_rtb.filter=0x37 ehci-hcd.park=3 lpm_levels.sleep_disabled=1 cma=24M@0-0xffffffff rcupdate.rcu_expedited=1" --ramdisk_offset 0x2200000 --board RILPA13A003KU --tags_offset 0x2000000 --dt boot.img-dt -o my_boot.img

$ echo -n "SEANDROIDENFORCE" >> my_boot.img  # 解决开机出现 Kernel is not Seandroid Enforcing,https://tricksempire.com/kernel-is-not-seandroid-enforcing-android/

$ lz4 -B6 boot.img  # 可选 https://stackoverflow.com/questions/58517762/odin-fail-lz4-is-invalid

G9300 ROM包相关及降级原理-BL

修改内核

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
$ diff arch/arm64/configs/hero2qlte_chn_open_defconfig out/.config
3c3
< # Linux/arm64 3.18.31 Kernel Configuration 
---
> # Linux/arm64 3.18.31-13341302 Kernel Configuration
325,336c325,337
< # CONFIG_SEC_HEROQLTE_PROJECT is not set   
< CONFIG_SEC_HERO2QLTE_PROJECT=y
< # CONFIG_MACH_HERO2QLTE_ATT is not set
< CONFIG_MACH_HERO2QLTE_CHNZC=y
< # CONFIG_MACH_HERO2QLTE_SPR is not set
< # CONFIG_MACH_HERO2QLTE_TMO is not set
< # CONFIG_MACH_HERO2QLTE_USC is not set
< # CONFIG_MACH_HERO2QLTE_VZW is not set
< # CONFIG_MACH_HERO2QLTE_DCM is not set
< # CONFIG_MACH_HERO2QLTE_KDI is not set
< # CONFIG_MACH_HERO2QLTE_SED is not set
< # CONFIG_MACH_HERO2QLTE_SINGLE is not set  
---
> CONFIG_SEC_HEROQLTE_PROJECT=y
> # CONFIG_MACH_HEROQLTE_ACG is not set
> # CONFIG_MACH_HEROQLTE_ATT is not set
> CONFIG_MACH_HEROQLTE_CHNZC=y
> # CONFIG_MACH_HEROQLTE_DCM is not set
> # CONFIG_MACH_HEROQLTE_KDI is not set
> # CONFIG_MACH_HEROQLTE_SPR is not set
> # CONFIG_MACH_HEROQLTE_TMO is not set
> # CONFIG_MACH_HEROQLTE_USC is not set
> # CONFIG_MACH_HEROQLTE_VZW is not set
> # CONFIG_MACH_HEROQLTE_MTR is not set
> # CONFIG_MACH_HEROQLTE_SED is not set
> # CONFIG_SEC_HERO2QLTE_PROJECT is not set
582c583
< CONFIG_RKP_CFP=y
---
> # CONFIG_RKP_CFP is not set
584,585c585,586
< CONFIG_RKP_CFP_JOPP=y
< CONFIG_RKP_CFP_JOPP_MAGIC=0x00be7bad
---
> # CONFIG_RKP_CFP_JOPP is not set
> CONFIG_RKP_CFP_JOPP_MAGIC=0xb3ea3bad
592,595c593
< CONFIG_TIMA_RKP=y
< CONFIG_RKP_KDP=y
< CONFIG_RKP_NS_PROT=y
< CONFIG_RKP_DMAP_PROT=y
---
> # CONFIG_TIMA_RKP is not set
1243c1241
< CONFIG_KNOX_KAP=y
---
> # CONFIG_KNOX_KAP is not set
1431d1428
< CONFIG_DM_BUFIO=y
1445,1446c1442
< CONFIG_DM_VERITY=y
< CONFIG_DM_VERITY_FEC=y
---
> # CONFIG_DM_VERITY is not set
4026,4032c4022,4024
< CONFIG_TIMA_RKP_L1_TABLES=y
< CONFIG_TIMA_RKP_L2_TABLES=y
< CONFIG_TIMA_RKP_LAZY_MMU=y
< # CONFIG_TIMA_RKP_DEBUG is not set
< CONFIG_TIMA=y
< CONFIG_TIMA_LKMAUTH=y
< CONFIG_TIMA_LKMAUTH_CODE_PROT=y
---
> # CONFIG_TIMA is not set
> # CONFIG_TIMA_LKMAUTH is not set
> # CONFIG_TIMA_LKMAUTH_CODE_PROT is not set 
4034d4025
< CONFIG_TIMA_UEVENT=y

模块警告

内核比较严格,未使用变量都是ERROR

1
EXTRA_CFLAGS += -g -Wno-unused-function -Wno-unused-variable

G9300 ROM包相关及降级原理-BL

https://zhuanlan.zhihu.com/p/102050317

http://romup.com/

https://www.sammobile.com/samsung/galaxy-s7/firmware/SM-G9300/CHC/download/G9300ZCU2BRD1/216945/

https://www.netded.com/a/jishuyingyong/2016/0305/31324.html


能否降级原理 就是看BL(bootloader版本)

1
2
3
4
5
6
2018-10-16   8.0.0   G9300ZCS3CRI1
2018-09-02    8.0.0   G9300ZCU3CRH1
2018-08-06    8.0.0   G9300ZCU3CRG3
2018-06-26    8.0.0   G9300ZCU2CRF5
2018-04-25    7.0 G9300ZCU2BRD1
2018-01-17    7.0 G9300ZCU2BQL3

看中间的 S3, U3, U2, 其中 S3=U3。数字不能下降,数字相同的可以降级,例如从 G9300ZCU2CRF5(8.0.0) 降到 G9300ZCU2BRD1(7.0)


刷 TRWP 和 root

原始来源是这里 https://dl.twrp.me/heroqltechn/ ???

G9300_twrp-3.0.2-0-heroqltechn.img.tar

SuperSU-v2.82.zip

https://build.nethunter.com/android-tools/no-verity-opt-encrypt/

https://www.muzisoft.com/shuaji/223499.html

先刷 TWRP 再刷 supersu。supersu 也会去除 verity,不需要再刷 no-verity-opt-encrypt

解决wifi无法保存密码 或 多次尝试才能打开 的情况

https://forum.xda-developers.com/samsung-a-series-2017/how-to/guide-fix-bluetooth-losing-pairings-t3798262

Fix_Bluetooth.zip

https://github.com/Magisk-Modules-Repo/libsecure_storage

https://github.com/rovo89/Xposed/issues/294

1
2
3
4
5
6
7
$ vim /system/build.prop
ro.securestorage.support=true 改成 ro.securestorage.support=false

$ cp Fix_Bluetooth/system/lib/libsecure_storage.so   /system/vendor/lib/libsecure_storage.so
$ cp Fix_Bluetooth/system/lib64/libsecure_storage.so /system/vendor/lib64/libsecure_storage.so

修改后的明文密码保存在 data/misc/wifi/wpa_supplicant.conf

file_contexts.bin和file_contexts转换

https://github.com/rkhat2/android-rom-repacker/releases/tag/android-7-v3

android-rom-repacker-20180401-610b6d2.tar.gz

1
2
3
./sefcontext_decompile file_contexts.bin -o file_contexts

./sefcontext_compile file_contexts -o file_contexts.bin_new

第三方 ROM

http://blog.sina.com.cn/s/blog_6de000c20102z9ur.html

http://rom.tomatolei.com/g9300.html

可能有用

https://android.stackexchange.com/questions/69954/how-to-unpack-and-edit-boot-img-for-rom-porting

http://i.lckiss.com/?p=1345

制作卡刷 ROM

META-INF.tar

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$ cat META-INF/com/google/android/updater-script
ui_print("+------------start--------------+");

#ifelse(is_mounted("/system"), unmount("/system"));
#ui_print("+------------umount /system--------------+");

#format("ext4", "EMMC", "/dev/block/bootdevice/by-name/system");
#run_program("/sbin/sleep", "2");
#ui_print("+------------format /system--------------+");

#mount("ext4", "EMMC", "/dev/block/bootdevice/by-name/system", "/system");
#ui_print("+------------mount /system--------------+");

package_extract_file("system.img", "/dev/block/bootdevice/by-name/system");
ui_print("+------------copied /system--------------+");

ui_print("Done!");

解压 META-INF.tar,编辑 system.img,将 META-INF 和 system.img 一起打包成 zip,卡刷。

BUG:刷完后需要进官方recovery再执行一些升级操作,但是改了system后,官方recovery会校验失败,导致升级失败,会在设置里出现多余内容。。。

试了第三方的ROM可以升级,所以单纯删除system.img的一些东西还是不够的

ROM 简化命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
set -x

mount -o rw,remount /system

rm -rf /system/app/AllshareFileShare
rm -rf /system/app/AllshareMediaShare
rm -rf /system/app/ApexService
rm -rf /system/app/BBCAgent
rm -rf /system/app/Bluetooth
rm -rf /system/app/BluetoothMidiService
rm -rf /system/app/BluetoothTest
rm -rf /system/app/BookmarkProvider
rm -rf /system/app/CoreApps_SDK_2017
rm -rf /system/app/GearManagerStub
rm -rf /system/app/HongbaoAssistant
rm -rf /system/app/Kaiti
rm -rf /system/app/KnoxAppsUpdateAgent
rm -rf /system/app/KnoxAttestationAgent
rm -rf /system/app/KnoxFolderContainer2
rm -rf /system/app/KnoxRemoteContentsProvider
rm -rf /system/app/KnoxSetupWizardClient
rm -rf /system/app/KnoxSwitcher
rm -rf /system/app/Miao
rm -rf /system/app/MirrorLink
rm -rf /system/app/MobilePrintSvc_Samsung
rm -rf /system/app/MoreServices
rm -rf /system/app/QuickConnect
rm -rf /system/app/RemoteControl
rm -rf /system/app/SamsungDLPService
rm -rf /system/app/SBrowser_5.0
rm -rf /system/app/SearchBoxBaidu_OPEN_V8.0
rm -rf /system/app/SecurityLogAgent
rm -rf /system/app/ShaoNv
rm -rf /system/app/ShareLink
rm -rf /system/app/SmartSwitchAgent
rm -rf /system/app/SPrintSpooler7
rm -rf /system/app/UniversalMDMClient
rm -rf /system/app/Weather2017_SE
rm -rf /system/app/WeatherWidget2017_SE
rm -rf /system/app/WeChatWifiService
rm -rf /system/container/ContainerAgent2
rm -rf /system/container/KnoxBBCProvider
rm -rf /system/container/KnoxBluetooth
rm -rf /system/container/KnoxKeyguard
rm -rf /system/container/KnoxShortcuts
rm -rf /system/container/KnoxTrustAgent
rm -rf /system/container/resources
rm -rf /system/container/SharedDeviceKeyguard
rm -rf /system/dummy/OnlineMusicChinaDummy
rm -rf /system/dummy/SecEmail_N
rm -rf /system/dummy/SHealth5
rm -rf /system/dummy/SRoaming_v11_N
rm -rf /system/preload/GalaxyCare_CHN_Deletable
rm -rf /system/preload/MM_Phone_V5.0_M
rm -rf /system/preload/mm_safe_5.0_M
rm -rf /system/preload/OnlineMusicChina
rm -rf /system/preload/SamsungOnlineVideo
rm -rf /system/preload/SAssistant_downloadable
rm -rf /system/preload/SecEmail_N_R
rm -rf /system/preload/SHealthDeletable5.9
rm -rf /system/preload/SmartSwitch
rm -rf /system/preload/SRoaming_v12_N_Deletable
rm -rf /system/priv-app/Alipay_Service
rm -rf /system/priv-app/DiagMonAgent
rm -rf /system/priv-app/FotaAgent
rm -rf /system/priv-app/GalaxyApps_3xh
rm -rf /system/priv-app/GalaxyAppsWidget_Phone_Hero
rm -rf /system/priv-app/GalaxyThemes
rm -rf /system/priv-app/GameHome
rm -rf /system/priv-app/GameTools
rm -rf /system/priv-app/GearManager
rm -rf /system/priv-app/HancomOfficeEditor
rm -rf /system/priv-app/HealthService
rm -rf /system/priv-app/KLMSAgent
rm -rf /system/priv-app/NetworkLocation_Autonavi
rm -rf /system/priv-app/NSFusedLocation_v2.2
rm -rf /system/priv-app/OfflineNetworkLocation_Baidu
rm -rf /system/priv-app/RNB
rm -rf /system/priv-app/RNBShell
rm -rf /system/priv-app/SamsungAccount_Dream
rm -rf /system/priv-app/SamsungBilling
rm -rf /system/priv-app/SamsungCloud
rm -rf /system/priv-app/SamsungPayStub
rm -rf /system/priv-app/SamsungUpdates
rm -rf /system/priv-app/SEMFactoryApp
rm -rf /system/priv-app/SKMSAgent
rm -rf /system/priv-app/SOAgent
rm -rf /system/priv-app/SPPPushClient_Prod
rm -rf /system/priv-app/VRSetupWizardStub

rm -rf /system/hidden/Common_app/*

rm -rf /data/misc/profiles/cur/0/com.mobilesrepublic.sohu.launcher
rm -rf /data/misc/profiles/ref/com.mobilesrepublic.sohu.launcher
rm -rf /data/data/com.mobilesrepublic.sohu.launcher
rm -rf /data/app/com.mobilesrepublic.sohu.launcher-1
rm -rf /data/user_de/0/com.mobilesrepublic.sohu.launcher

rm -rf /data/data/com.sec.android.app.SecSetupWizard/shared_prefs/chn.BaiduLocationActivity.xml
rm -rf /data/data/com.speedsoftware.rootexplorer/shared_prefs
rm -rf /data/media/0/Android/data/com.baidu.searchbox_samsung


cp Fix_Bluetooth/system/lib/libsecure_storage.so   /system/vendor/lib/libsecure_storage.so
cp Fix_Bluetooth/system/lib64/libsecure_storage.so /system/vendor/lib64/libsecure_storage.so

cp build.prop /system/build.prop

TIME-WAIT

1. tw_reuse,tw_recycle 必须在客户端和服务端 timestamps 开启时才管用

1
cat /proc/sys/net/ipv4/tcp_timestamps

2. tw_reuse 只对客户端起作用

开启后超过1s的time-wait sk被reuse, 如下代码。否则inet_hash_connect会继续尝试寻在可用端口。

tcp_v4_connect() -> inet_hash_connect() -> __inet_check_established() -> twsk_unique() -> tcp_twsk_unique()

vim net/ipv4/tcp_ipv4.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
int tcp_twsk_unique(struct sock *sk, struct sock *sktw, void *twp)
{
        const struct tcp_timewait_sock *tcptw = tcp_twsk(sktw);
        struct tcp_sock *tp = tcp_sk(sk);

        if (tcptw->tw_ts_recent_stamp &&
            (twp == NULL || (sysctl_tcp_tw_reuse &&
                             get_seconds() - tcptw->tw_ts_recent_stamp > 1))) {
                tp->write_seq = tcptw->tw_snd_nxt + 65535 + 2;
                if (tp->write_seq == 0)
                        tp->write_seq = 1;
                tp->rx_opt.ts_recent       = tcptw->tw_ts_recent;
                tp->rx_opt.ts_recent_stamp = tcptw->tw_ts_recent_stamp;
                sock_hold(sktw);
                return 1;
        }

        return 0;
}

3. tw_recycle 和 TCP_TIMEWAIT_LEN

tw_recycle 对客户端和服务器同时起作用,有两个作用:
a) 开启后在 3*RTO 后回收 sk。没开启在 TCP_TIMEWAIT_LEN = 60 后回收 sk。
b) tcp会缓存每个连接最新的时间戳,后续请求中如果时间戳小于缓存的时间戳,相应的数据包会被丢弃。如果多个客户端在NAT后面就会出问题。

有些内核删除了b功能,如tlinux。 https://github.com/torvalds/linux/commit/4396e46187ca5070219b81773c4e65088dac50cc

最新的内核删除了a、b两个功能,且 TCP_TIMEWAIT_LEN 不可配置。。。

4. tcp_max_tw_buckets

1
cat /proc/sys/net/ipv4/tcp_max_tw_buckets

time-wait sk 的最大数量。

设置成0就部不分配time-wait sk,只回一个ack,如果ack丢了下次就只能回rst了,测试的时候可以用。

5. 服务端处于 time-wait 时收包处理

TIME_WAIT状态下对接收到的数据包如何处理

centos 设置默认启动内核

https://www.4spaces.org/centos7-change-kernel-order/

查看当前默认启动内核

1
grub2-editenv list

查看所有内核

1
2
cat /boot/grub2/grub.cfg | grep menuentry
menuentry 'CentOS Linux (3.10.0-693.5.2.el7.x86_64) 7 (Core)' --class centos --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-3.10.0-693.el7.x86_64-advanced-a5c5c2e2-9baf-46e5-9703-ee9d6b421f66' {

设置新的启动内核

1
grub2-set-default 'CentOS Linux (3.10.0-693.5.2.el7.x86_64) 7 (Core)'