diff options
author | Pete Zaitcev <zaitcev@redhat.com> | 2006-12-31 01:43:10 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2007-02-07 18:44:34 -0500 |
commit | 6f23ee1fefdc1f80bd8a3ab04a1c41ab2dec14c9 (patch) | |
tree | 36a5241c29333580de3e3c75e2c62edc1cdf583c /Documentation/usb | |
parent | a8ef36bc0a5fe973bddaa54a5a07cda29e04a602 (diff) |
USB: add binary API to usbmon
This patch adds a new, "binary" API in addition to the old, text API usbmon
had before. The new API allows for less CPU use, and it allows to capture
all data from a packet where old API only captured 32 bytes at most. There
are some limitations and conditions to this, e.g. in case someone constructs
a URB with 1GB of data, it's not likely to be captured, because even the
huge buffers of the new reader are finite. Nonetheless, I expect this new
capability to capture all data for all real life scenarios.
The downside is, a special user mode application is required where cat(1)
worked before. I have sample code at http://people.redhat.com/zaitcev/linux/
and Paolo Abeni is working on patching libpcap.
This patch was initially written by Paolo and later I tweaked it, and
we had a little back-and-forth. So this is a jointly authored patch, but
I am submitting this I am responsible for the bugs.
Signed-off-by: Paolo Abeni <paolo.abeni@email.it>
Signed-off-by: Pete Zaitcev <zaitcev@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'Documentation/usb')
-rw-r--r-- | Documentation/usb/usbmon.txt | 152 |
1 files changed, 150 insertions, 2 deletions
diff --git a/Documentation/usb/usbmon.txt b/Documentation/usb/usbmon.txt index e65ec828d7aa..0f6808abd612 100644 --- a/Documentation/usb/usbmon.txt +++ b/Documentation/usb/usbmon.txt | |||
@@ -77,7 +77,7 @@ that the file size is not excessive for your favourite editor. | |||
77 | 77 | ||
78 | The '1t' type data consists of a stream of events, such as URB submission, | 78 | The '1t' type data consists of a stream of events, such as URB submission, |
79 | URB callback, submission error. Every event is a text line, which consists | 79 | URB callback, submission error. Every event is a text line, which consists |
80 | of whitespace separated words. The number of position of words may depend | 80 | of whitespace separated words. The number or position of words may depend |
81 | on the event type, but there is a set of words, common for all types. | 81 | on the event type, but there is a set of words, common for all types. |
82 | 82 | ||
83 | Here is the list of words, from left to right: | 83 | Here is the list of words, from left to right: |
@@ -170,4 +170,152 @@ dd65f0e8 4128379808 C Bo:005:02 0 31 > | |||
170 | 170 | ||
171 | * Raw binary format and API | 171 | * Raw binary format and API |
172 | 172 | ||
173 | TBD | 173 | The overall architecture of the API is about the same as the one above, |
174 | only the events are delivered in binary format. Each event is sent in | ||
175 | the following structure (its name is made up, so that we can refer to it): | ||
176 | |||
177 | struct usbmon_packet { | ||
178 | u64 id; /* 0: URB ID - from submission to callback */ | ||
179 | unsigned char type; /* 8: Same as text; extensible. */ | ||
180 | unsigned char xfer_type; /* ISO (0), Intr, Control, Bulk (3) */ | ||
181 | unsigned char epnum; /* Endpoint number and transfer direction */ | ||
182 | unsigned char devnum; /* Device address */ | ||
183 | u16 busnum; /* 12: Bus number */ | ||
184 | char flag_setup; /* 14: Same as text */ | ||
185 | char flag_data; /* 15: Same as text; Binary zero is OK. */ | ||
186 | s64 ts_sec; /* 16: gettimeofday */ | ||
187 | s32 ts_usec; /* 24: gettimeofday */ | ||
188 | int status; /* 28: */ | ||
189 | unsigned int length; /* 32: Length of data (submitted or actual) */ | ||
190 | unsigned int len_cap; /* 36: Delivered length */ | ||
191 | unsigned char setup[8]; /* 40: Only for Control 'S' */ | ||
192 | }; /* 48 bytes total */ | ||
193 | |||
194 | These events can be received from a character device by reading with read(2), | ||
195 | with an ioctl(2), or by accessing the buffer with mmap. | ||
196 | |||
197 | The character device is usually called /dev/usbmonN, where N is the USB bus | ||
198 | number. Number zero (/dev/usbmon0) is special and means "all buses". | ||
199 | However, this feature is not implemented yet. Note that specific naming | ||
200 | policy is set by your Linux distribution. | ||
201 | |||
202 | If you create /dev/usbmon0 by hand, make sure that it is owned by root | ||
203 | and has mode 0600. Otherwise, unpriviledged users will be able to snoop | ||
204 | keyboard traffic. | ||
205 | |||
206 | The following ioctl calls are available, with MON_IOC_MAGIC 0x92: | ||
207 | |||
208 | MON_IOCQ_URB_LEN, defined as _IO(MON_IOC_MAGIC, 1) | ||
209 | |||
210 | This call returns the length of data in the next event. Note that majority of | ||
211 | events contain no data, so if this call returns zero, it does not mean that | ||
212 | no events are available. | ||
213 | |||
214 | MON_IOCG_STATS, defined as _IOR(MON_IOC_MAGIC, 3, struct mon_bin_stats) | ||
215 | |||
216 | The argument is a pointer to the following structure: | ||
217 | |||
218 | struct mon_bin_stats { | ||
219 | u32 queued; | ||
220 | u32 dropped; | ||
221 | }; | ||
222 | |||
223 | The member "queued" refers to the number of events currently queued in the | ||
224 | buffer (and not to the number of events processed since the last reset). | ||
225 | |||
226 | The member "dropped" is the number of events lost since the last call | ||
227 | to MON_IOCG_STATS. | ||
228 | |||
229 | MON_IOCT_RING_SIZE, defined as _IO(MON_IOC_MAGIC, 4) | ||
230 | |||
231 | This call sets the buffer size. The argument is the size in bytes. | ||
232 | The size may be rounded down to the next chunk (or page). If the requested | ||
233 | size is out of [unspecified] bounds for this kernel, the call fails with | ||
234 | -EINVAL. | ||
235 | |||
236 | MON_IOCQ_RING_SIZE, defined as _IO(MON_IOC_MAGIC, 5) | ||
237 | |||
238 | This call returns the current size of the buffer in bytes. | ||
239 | |||
240 | MON_IOCX_GET, defined as _IOW(MON_IOC_MAGIC, 6, struct mon_get_arg) | ||
241 | |||
242 | This call waits for events to arrive if none were in the kernel buffer, | ||
243 | then returns the first event. Its argument is a pointer to the following | ||
244 | structure: | ||
245 | |||
246 | struct mon_get_arg { | ||
247 | struct usbmon_packet *hdr; | ||
248 | void *data; | ||
249 | size_t alloc; /* Length of data (can be zero) */ | ||
250 | }; | ||
251 | |||
252 | Before the call, hdr, data, and alloc should be filled. Upon return, the area | ||
253 | pointed by hdr contains the next event structure, and the data buffer contains | ||
254 | the data, if any. The event is removed from the kernel buffer. | ||
255 | |||
256 | MON_IOCX_MFETCH, defined as _IOWR(MON_IOC_MAGIC, 7, struct mon_mfetch_arg) | ||
257 | |||
258 | This ioctl is primarily used when the application accesses the buffer | ||
259 | with mmap(2). Its argument is a pointer to the following structure: | ||
260 | |||
261 | struct mon_mfetch_arg { | ||
262 | uint32_t *offvec; /* Vector of events fetched */ | ||
263 | uint32_t nfetch; /* Number of events to fetch (out: fetched) */ | ||
264 | uint32_t nflush; /* Number of events to flush */ | ||
265 | }; | ||
266 | |||
267 | The ioctl operates in 3 stages. | ||
268 | |||
269 | First, it removes and discards up to nflush events from the kernel buffer. | ||
270 | The actual number of events discarded is returned in nflush. | ||
271 | |||
272 | Second, it waits for an event to be present in the buffer, unless the pseudo- | ||
273 | device is open with O_NONBLOCK. | ||
274 | |||
275 | Third, it extracts up to nfetch offsets into the mmap buffer, and stores | ||
276 | them into the offvec. The actual number of event offsets is stored into | ||
277 | the nfetch. | ||
278 | |||
279 | MON_IOCH_MFLUSH, defined as _IO(MON_IOC_MAGIC, 8) | ||
280 | |||
281 | This call removes a number of events from the kernel buffer. Its argument | ||
282 | is the number of events to remove. If the buffer contains fewer events | ||
283 | than requested, all events present are removed, and no error is reported. | ||
284 | This works when no events are available too. | ||
285 | |||
286 | FIONBIO | ||
287 | |||
288 | The ioctl FIONBIO may be implemented in the future, if there's a need. | ||
289 | |||
290 | In addition to ioctl(2) and read(2), the special file of binary API can | ||
291 | be polled with select(2) and poll(2). But lseek(2) does not work. | ||
292 | |||
293 | * Memory-mapped access of the kernel buffer for the binary API | ||
294 | |||
295 | The basic idea is simple: | ||
296 | |||
297 | To prepare, map the buffer by getting the current size, then using mmap(2). | ||
298 | Then, execute a loop similar to the one written in pseudo-code below: | ||
299 | |||
300 | struct mon_mfetch_arg fetch; | ||
301 | struct usbmon_packet *hdr; | ||
302 | int nflush = 0; | ||
303 | for (;;) { | ||
304 | fetch.offvec = vec; // Has N 32-bit words | ||
305 | fetch.nfetch = N; // Or less than N | ||
306 | fetch.nflush = nflush; | ||
307 | ioctl(fd, MON_IOCX_MFETCH, &fetch); // Process errors, too | ||
308 | nflush = fetch.nfetch; // This many packets to flush when done | ||
309 | for (i = 0; i < nflush; i++) { | ||
310 | hdr = (struct ubsmon_packet *) &mmap_area[vec[i]]; | ||
311 | if (hdr->type == '@') // Filler packet | ||
312 | continue; | ||
313 | caddr_t data = &mmap_area[vec[i]] + 64; | ||
314 | process_packet(hdr, data); | ||
315 | } | ||
316 | } | ||
317 | |||
318 | Thus, the main idea is to execute only one ioctl per N events. | ||
319 | |||
320 | Although the buffer is circular, the returned headers and data do not cross | ||
321 | the end of the buffer, so the above pseudo-code does not need any gathering. | ||