Generate an RFC-like representation of a packet def. :param cls: the Packet class :param ret: return the result instead of printing (def. False) :param legend: show text under the diagram (default True) Ex:: >>> rfc(Ether)
(cls, ret=False, legend=True)
| 2513 | |
| 2514 | @conf.commands.register |
| 2515 | def rfc(cls, ret=False, legend=True): |
| 2516 | # type: (Type[Packet], bool, bool) -> Optional[str] |
| 2517 | """ |
| 2518 | Generate an RFC-like representation of a packet def. |
| 2519 | |
| 2520 | :param cls: the Packet class |
| 2521 | :param ret: return the result instead of printing (def. False) |
| 2522 | :param legend: show text under the diagram (default True) |
| 2523 | |
| 2524 | Ex:: |
| 2525 | |
| 2526 | >>> rfc(Ether) |
| 2527 | |
| 2528 | """ |
| 2529 | if not issubclass(cls, Packet): |
| 2530 | raise TypeError("Packet class expected") |
| 2531 | cur_len = 0 |
| 2532 | cur_line = [] |
| 2533 | lines = [] |
| 2534 | # Get the size (width) that a field will take |
| 2535 | # when formatted, from its length in bits |
| 2536 | clsize = lambda x: 2 * x - 1 # type: Callable[[int], int] |
| 2537 | ident = 0 # Fields UUID |
| 2538 | |
| 2539 | # Generate packet groups |
| 2540 | def _iterfields() -> Iterator[Tuple[str, int]]: |
| 2541 | for f in cls.fields_desc: |
| 2542 | # Fancy field name |
| 2543 | fname = f.name.upper().replace("_", " ") |
| 2544 | fsize = int(f.sz * 8) |
| 2545 | yield fname, fsize |
| 2546 | # Add padding optionally |
| 2547 | if isinstance(f, PadField): |
| 2548 | if isinstance(f._align, tuple): |
| 2549 | pad = - cur_len % (f._align[0] * 8) |
| 2550 | else: |
| 2551 | pad = - cur_len % (f._align * 8) |
| 2552 | if pad: |
| 2553 | yield "padding", pad |
| 2554 | for fname, flen in _iterfields(): |
| 2555 | cur_len += flen |
| 2556 | ident += 1 |
| 2557 | # The field might exceed the current line or |
| 2558 | # take more than one line. Copy it as required |
| 2559 | while True: |
| 2560 | over = max(0, cur_len - 32) # Exceed |
| 2561 | len1 = clsize(flen - over) # What fits |
| 2562 | cur_line.append((fname[:len1], len1, ident)) |
| 2563 | if cur_len >= 32: |
| 2564 | # Current line is full. start a new line |
| 2565 | lines.append(cur_line) |
| 2566 | cur_len = flen = over |
| 2567 | fname = "" # do not repeat the field |
| 2568 | cur_line = [] |
| 2569 | if not over: |
| 2570 | # there is no data left |
| 2571 | break |
| 2572 | else: |
no test coverage detected