Vietnamese (machine translation)

Lưu ý

Mục đích của file này là để độc giả tiếng Việt có thể đọc và hiểu tài liệu nhân kernel dễ dàng hơn, không phải để tạo ra một nhánh tài liệu riêng. Nếu bạn có bất kỳ nhận xét hoặc cập nhật nào cho file này, vui lòng thử cập nhật file tiếng Anh gốc trước. Nếu bạn thấy có sự khác biệt giữa bản dịch và bản gốc, hoặc có vấn đề về bản dịch, vui lòng gửi góp ý hoặc patch cho người dịch của file này, hoặc nhờ người bảo trì và người review tài liệu tiếng Việt giúp đỡ.

Bản gốc:

usbmon

Người dịch:

Google Translate (machine translation)

Phiên bản gốc:

8541d8f725c6

Cảnh báo

Tài liệu này được dịch tự động bằng máy và chưa được review bởi người dịch. Nội dung có thể không chính xác hoặc khó hiểu ở một số chỗ. Khi có sự khác biệt với bản gốc, bản gốc luôn là chuẩn. Bản dịch chất lượng cao (được review) được đặt trong thư mục vi_VN/.

usbmon

Giới thiệu

Tên “usbmon” bằng chữ thường đề cập đến một tiện ích trong kernel được được sử dụng để thu thập dấu vết I/O trên bus USB. Chức năng này tương tự tới ổ cắm gói được sử dụng bởi các công cụ giám sát mạng như tcpdump(1) hoặc thanh tao. Tương tự, người ta hy vọng rằng một công cụ như usbdump hoặc USBMon (có chữ in hoa) được sử dụng để kiểm tra các dấu vết thô được tạo ra bởi usbmon.

USBmon báo cáo các yêu cầu được thực hiện bởi trình điều khiển dành riêng cho thiết bị ngoại vi tới Máy chủ Trình điều khiển bộ điều khiển (HCD). Vì vậy, nếu HCD có lỗi, dấu vết được báo cáo bởi usbmon có thể không tương ứng chính xác với các giao dịch trên xe buýt. Đây là điều tương tự tình huống như với tcpdump.

Hai API hiện đang được triển khai: “văn bản” và “nhị phân”. API nhị phân có sẵn thông qua một thiết bị ký tự trong không gian tên /dev và là ABI. Văn bản API không còn được dùng kể từ phiên bản 2.6.35 nhưng vẫn có sẵn để thuận tiện.

Cách sử dụng usbmon để thu thập dấu vết văn bản thô

Không giống như ổ cắm gói, usbmon có giao diện cung cấp dấu vết ở dạng văn bản. Điều này được sử dụng cho hai mục đích. Đầu tiên, nó phục vụ như một định dạng trao đổi dấu vết phổ biến cho các công cụ trong khi các định dạng phức tạp hơn được hoàn thiện. Thứ hai, con người có thể đọc nó trong trường hợp không có công cụ.

Để thu thập dấu vết văn bản thô, hãy thực hiện các bước sau.

1. Chuẩn bị

Gắn debugfs (nó phải được kích hoạt trong cấu hình kernel của bạn) và tải mô-đun usbmon (nếu được xây dựng dưới dạng mô-đun). Bước thứ hai được bỏ qua nếu usbmon được tích hợp vào kernel

# mount -t debugfs none_debugs/sys/kernel/debug

USBmon # modprobe #

Xác minh rằng có ổ cắm xe buýt:

# ls/sys/kernel/gỡ lỗi/usb/usbmon

0s 0u 1s 1t 1u 2s 2t 2u 3s 3t 3u 4s 4t 4u #

Bây giờ bạn có thể chọn sử dụng socket ‘0u’ (để chụp các gói trên tất cả xe buýt) và chuyển sang bước #3 hoặc tìm xe buýt được thiết bị của bạn sử dụng bằng bước #2. Điều này cho phép lọc đi các thiết bị gây phiền nhiễu nói chuyện liên tục.

2. Tìm bus nào kết nối với thiết bị mong muốn

Chạy “cat /sys/kernel/debug/usb/devices” và tìm dòng chữ T tương ứng tới thiết bị. Thông thường bạn làm điều đó bằng cách tìm kiếm chuỗi nhà cung cấp. Nếu bạn có nhiều thiết bị tương tự nhau, hãy rút phích cắm của một thiết bị và so sánh hai thiết bị /sys/kernel/debug/usb/thiết bị đầu ra. Tuyến T sẽ có số xe buýt.

Ví dụ:

T: Bus=03 Lev=01 Prnt=01 Cổng=00 Cnt=01 Dev#= 2 Spd=12 MxCh= 0

D: Ver= 1.10 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1 P: Nhà cung cấp=0557 ProdID=2004 Rev= 1,00 S: Nhà sản xuất=ATEN S: Sản phẩm=UC100KM V2.00

“Bus=03” có nghĩa là bus 3. Ngoài ra, bạn có thể xem kết quả từ “lsusb” và lấy số xe buýt từ dòng thích hợp. Ví dụ:

Bus 003 Thiết bị 002: ID 0557:2004 ATEN UC100KM V2.00

3. Bắt đầu từ ‘con mèo’

# cat /sys/kernel/debug/usb/usbmon/3u > /tmp/1.mon.out

để nghe trên một xe buýt, nếu không, để nghe trên tất cả các xe buýt, hãy nhập:

# cat /sys/kernel/debug/usb/usbmon/0u > /tmp/1.mon.out

Quá trình này sẽ đọc cho đến khi nó bị giết. Đương nhiên, đầu ra có thể là được chuyển hướng đến một vị trí mong muốn. Điều này được ưa thích hơn vì nó sẽ sẽ khá dài.

4. Thực hiện thao tác mong muốn trên bus USB

Đây là nơi bạn làm điều gì đó để tạo ra lưu lượng truy cập: cắm phím flash, sao chép tập tin, điều khiển webcam, v.v.

5. Giết mèo

Thông thường, việc này được thực hiện bằng cách ngắt bàn phím (Control-C).

Tại thời điểm này, tệp đầu ra (/tmp/1.mon.out trong ví dụ này) có thể được lưu, được gửi qua e-mail hoặc được kiểm tra bằng trình soạn thảo văn bản. Trong trường hợp cuối cùng, hãy đảm bảo rằng kích thước tệp không quá lớn đối với trình chỉnh sửa yêu thích của bạn.

Định dạng dữ liệu văn bản thô

Hiện tại có hai định dạng được hỗ trợ: định dạng gốc hoặc định dạng ‘1t’ và định dạng ‘1u’. Định dạng ‘1t’ không được dùng nữa trong kernel 2.6.21. ‘1u’ định dạng thêm một số trường, chẳng hạn như bộ mô tả khung ISO, khoảng thời gian, v.v. Nó tạo ra những dòng dài hơn một chút, nhưng mặt khác lại là một superset hoàn hảo định dạng ‘1t’.

Nếu muốn nhận ra cái này với cái kia trong một chương trình, hãy nhìn vào Từ “địa chỉ” (xem bên dưới), trong đó định dạng ‘1u’ thêm số xe buýt. Nếu 2 dấu hai chấm có mặt, đó là định dạng ‘1t’, nếu không thì là ‘1u’.

Mọi dữ liệu định dạng văn bản đều bao gồm một luồng sự kiện, chẳng hạn như gửi URB, Gọi lại URB, lỗi gửi. Mỗi sự kiện là một dòng văn bản, bao gồm các từ được phân tách bằng khoảng trắng. Số lượng hoặc vị trí của từ có thể phụ thuộc về loại sự kiện, nhưng có một tập hợp các từ chung cho tất cả các loại.

Đây là danh sách các từ, từ trái sang phải:

  • Thẻ URB. Địa chỉ này được sử dụng để xác định URB và thường là địa chỉ trong kernel của cấu trúc URB ở dạng thập lục phân, nhưng có thể là số thứ tự hoặc bất kỳ chuỗi duy nhất khác, trong phạm vi lý do.

  • Dấu thời gian tính bằng micro giây, số thập phân. Độ phân giải của dấu thời gian phụ thuộc vào đồng hồ có sẵn và do đó nó có thể tệ hơn nhiều so với một phần triệu giây (ví dụ: nếu việc triển khai sử dụng jiffies).

  • Loại sự kiện. Loại này đề cập đến định dạng của sự kiện, không phải loại URB. Các loại có sẵn là: S - gửi, C - gọi lại, E - lỗi gửi.

  • Từ “Địa chỉ” (trước đây là “ống”). Nó bao gồm bốn trường, cách nhau bởi dấu hai chấm: loại và hướng URB, Số xe buýt, Địa chỉ thiết bị, Số điểm cuối. Loại và hướng được mã hóa bằng hai byte theo cách sau:

Kiến trúc tổng thể của API gần giống như kiến trúc ở trên, chỉ các sự kiện được phân phối ở định dạng nhị phân. Mỗi sự kiện được gửi vào Cấu trúc như sau (tên nó được tạo nên để chúng ta tham khảo):

cấu trúc usbmon_packet {

id u64; /* 0: ID URB - từ gửi đến gọi lại / loại char không dấu; / 8: Tương tự như văn bản; có thể mở rộng. / char xfer_type không dấu; / ISO (0), Intr, Control, Bulk (3) / ký tự không dấu epnum; / Số điểm cuối và hướng truyền / devnum ký tự không dấu; /*Địa chỉ thiết bị */ u16 busnum; / 12: Số xe buýt / char flag_setup; / 14: Giống như văn bản / char flag_data; / 15: Giống như văn bản; Số 0 nhị phân là được. / s64 ts_sec; / 16: gettimeofday / s32 ts_usec; / 24: gettimeofday / trạng thái int; / 28: / chiều dài int không dấu; / 32: Độ dài dữ liệu (đã gửi hoặc thực tế) / unsigned int len_cap; / 36: Chiều dài đã gửi / công đoàn { / 40: */

thiết lập char không dấu [SETUP_LEN]; /* Chỉ dành cho loại điều khiển S / struct iso_rec { / Chỉ dành cho ISO */

int error_count; int numdesc;

} iso;

} s; khoảng int; /* 48: Chỉ dành cho Ngắt và ISO / int start_frame; / 52: Dành cho ISO / int xfer_flags không dấu; / 56: bản sao transfer_flags của URB / int unsigned ndesc; / 60: Số lượng bộ mô tả ISO thực tế */

}; /* Tổng chiều dài 64 */

Những sự kiện này có thể được nhận từ thiết bị ký tự bằng cách đọc với read(2), bằng ioctl(2) hoặc bằng cách truy cập bộ đệm bằng mmap. Tuy nhiên, đọc (2) chỉ trả về 48 byte đầu tiên vì lý do tương thích.

Thiết bị ký tự thường được gọi là /dev/usbmonN, trong đó N là bus USB số. Số 0 (/dev/usbmon0) là số đặc biệt và có nghĩa là “tất cả các xe buýt”. Lưu ý rằng chính sách đặt tên cụ thể do bản phân phối Linux của bạn đặt ra.

Nếu bạn tạo /dev/usbmon0 bằng tay, hãy đảm bảo rằng nó thuộc quyền sở hữu của root và có chế độ 0600. Nếu không, người dùng không có đặc quyền sẽ có thể rình mò lưu lượng truy cập bàn phím.

Các lệnh gọi ioctl sau đây khả dụng với MON_IOC_MAGIC 0x92:

MON_IOCQ_URB_LEN, được định nghĩa là _IO(MON_IOC_MAGIC, 1)

Cuộc gọi này trả về độ dài của dữ liệu trong sự kiện tiếp theo. Lưu ý rằng phần lớn các sự kiện không chứa dữ liệu, vì vậy nếu lệnh gọi này trả về 0, điều đó không có nghĩa là không có sự kiện nào có sẵn

MON_IOCG_STATS, được định nghĩa là _IOR(MON_IOC_MAGIC, 3, struct mon_bin_stats)

Đối số là một con trỏ tới cấu trúc sau:

cấu trúc mon_bin_stats {

u32 xếp hàng; u32 rớt hạng;

};

Thành viên “xếp hàng” đề cập đến số lượng sự kiện hiện đang được xếp hàng trong bộ đệm (chứ không phải số lượng sự kiện được xử lý kể từ lần đặt lại cuối cùng).

Thành viên “rớt” là số sự kiện bị mất kể từ lần gọi cuối cùng tới MON_IOCG_STATS.

MON_IOCT_RING_SIZE, được định nghĩa là _IO(MON_IOC_MAGIC, 4)

Cuộc gọi này đặt kích thước bộ đệm. Đối số là kích thước tính bằng byte. Kích thước có thể được làm tròn xuống đoạn (hoặc trang) tiếp theo. Nếu được yêu cầu kích thước vượt quá giới hạn [không xác định] cho hạt nhân này, cuộc gọi không thành công với -EINVAL.

MON_IOCQ_RING_SIZE, được định nghĩa là _IO(MON_IOC_MAGIC, 5)

Cuộc gọi này trả về kích thước hiện tại của bộ đệm tính bằng byte.

MON_IOCX_GET, được định nghĩa là _IOW(MON_IOC_MAGIC, 6, struct mon_get_arg)

MON_IOCX_GETX, được định nghĩa là _IOW(MON_IOC_MAGIC, 10, struct mon_get_arg)

Các cuộc gọi này chờ các sự kiện đến nếu không có sự kiện nào trong bộ đệm kernel, sau đó trả lại sự kiện đầu tiên. Đối số là một con trỏ tới sau cấu trúc:

cấu trúc mon_get_arg {

cấu trúc usbmon_packet hdr; void *dữ liệu; size_t phân bổ; / Độ dài dữ liệu (có thể bằng 0) */

};

Trước cuộc gọi, phải điền hdr, dữ liệu và phân bổ. Khi trở về, khu vực được trỏ bởi hdr chứa cấu trúc sự kiện tiếp theo và bộ đệm dữ liệu chứa dữ liệu nếu có. Sự kiện này bị xóa khỏi bộ đệm kernel.

MON_IOCX_GET sao chép 48 byte vào vùng hdr, MON_IOCX_GETX sao chép 64 byte.

MON_IOCX_MFETCH, được định nghĩa là _IOWR(MON_IOC_MAGIC, 7, struct mon_mfetch_arg)

Ioctl này chủ yếu được sử dụng khi ứng dụng truy cập vào bộ đệm với mmap(2). Đối số của nó là một con trỏ tới cấu trúc sau:

cấu trúc mon_mfetch_arg {

uint32_t ZZ0000ZZ Vector sự kiện được tìm nạp / uint32_t nfetch; / Số sự kiện cần tìm nạp (out: đã tìm nạp) */ uint32_t nflush; /*Số sự kiện cần xóa */

};

Ioctl hoạt động theo 3 giai đoạn.

Đầu tiên, nó loại bỏ và loại bỏ tối đa các sự kiện nflush khỏi bộ đệm kernel. Số lượng sự kiện thực tế bị loại bỏ sẽ được trả về trong nflush.

Thứ hai, nó đợi một sự kiện xuất hiện trong bộ đệm, trừ khi giả thiết bị đang mở với O_NONBLOCK.

Thứ ba, nó trích xuất tối đa nfetch offset vào bộ đệm mmap và lưu trữ chúng vào offvec. Số lượng bù đắp sự kiện thực tế được lưu trữ vào tìm nạp.

MON_IOCH_MFLUSH, được định nghĩa là _IO(MON_IOC_MAGIC, 8)

Cuộc gọi này loại bỏ một số sự kiện khỏi bộ đệm kernel. Lập luận của nó là số lượng sự kiện cần loại bỏ. Nếu bộ đệm chứa ít sự kiện hơn hơn yêu cầu, tất cả các sự kiện hiện tại sẽ bị xóa và không có lỗi nào được báo cáo. Điều này hoạt động khi không có sự kiện nào có sẵn.

FIONBIO

ioctl FIONBIO có thể được triển khai trong tương lai nếu có nhu cầu.

Ngoài ioctl(2) và read(2), tệp đặc biệt của nhị phân API có thể được thăm dò ý kiến ​​với select(2) và poll(2). Nhưng lseek(2) không hoạt động.

  • Quyền truy cập được ánh xạ bộ nhớ của bộ đệm kernel cho API nhị phân

Ý tưởng cơ bản rất đơn giản:

Để chuẩn bị, hãy ánh xạ bộ đệm bằng cách lấy kích thước hiện tại, sau đó sử dụng mmap(2). Sau đó, thực hiện một vòng lặp tương tự như vòng lặp được viết bằng mã giả bên dưới:

struct mon_mfetch_arg tìm nạp;

cấu trúc usbmon_packet *hdr; int nflush = 0; cho (;;) {

lấy.offvec = vec; // Có N từ 32-bit tìm nạp.nfetch = N; // Hoặc nhỏ hơn N lấy.nflush = nflush; ioctl(fd, MON_IOCX_MFETCH, &tìm nạp); // Lỗi xử lý nữa nflush = tìm nạp.nfetch; // Nhiều gói này sẽ được xóa khi hoàn tất cho (i = 0; i < nflush; i++) {

hdr = (struct ubsmon_packet *) &mmap_area[vec[i]]; if (hdr->type == ‘@’) // Gói phụ

tiếp tục;

dữ liệu caddr_t = &mmap_area[vec[i]] + 64; process_packet(hdr, dữ liệu);

}

}

Vì vậy, ý tưởng chính là chỉ thực hiện một ioctl cho mỗi N sự kiện.

Mặc dù bộ đệm có dạng tròn nhưng các tiêu đề và dữ liệu được trả về không giao nhau phần cuối của bộ đệm, do đó mã giả ở trên không cần bất kỳ sự thu thập nào.