AX.25 Amateur Radio Link-Layer Protocol
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Migrate from vendored crowbar to opam-pinned alcobar

- Remove vendored crowbar/ directory
- Replace all Crowbar references with Alcobar across 176 .ml files
- Update all fuzz dune files: crowbar → alcobar in libraries
- Remove 77 gen_corpus.ml files (alcobar handles corpus internally)
- Update dune-project files: crowbar → alcobar in dependencies
- Update merlint rules (e705, e726): Crowbar → Alcobar in checks,
docs, and examples
- Update merlint generated docs (index.html)

428 files changed, ~1200 lines removed net.

+6 -169
+2 -8
fuzz/dune
··· 6 6 (executable 7 7 (name fuzz) 8 8 (modules fuzz fuzz_ax25) 9 - (libraries ax25 crowbar)) 10 - 11 - (executable 12 - (name gen_corpus) 13 - (modules gen_corpus) 14 - (libraries ax25 unix)) 9 + (libraries ax25 alcobar)) 15 10 16 11 (rule 17 12 (alias runtest) ··· 28 23 (= %{profile} afl)) 29 24 (deps 30 25 (source_tree corpus) 31 - fuzz.exe 32 - gen_corpus.exe) 26 + fuzz.exe) 33 27 (action 34 28 (echo "AFL fuzzer built: %{exe:fuzz.exe}\n")))
+1 -1
fuzz/fuzz.ml
··· 1 - let () = Crowbar.run "ax25" [ Fuzz_ax25.suite ] 1 + let () = Alcobar.run "ax25" [ Fuzz_ax25.suite ]
+2 -2
fuzz/fuzz_ax25.ml
··· 3 3 SPDX-License-Identifier: ISC 4 4 ---------------------------------------------------------------------------*) 5 5 6 - (* Crowbar-based fuzz testing for AX.25 roundtripping *) 6 + (* Alcobar-based fuzz testing for AX.25 roundtripping *) 7 7 8 - open Crowbar 8 + open Alcobar 9 9 10 10 (* Generator for valid SSID (0-15) *) 11 11 let ssid_gen = map [ range 16 ] Fun.id
+1 -1
fuzz/fuzz_ax25.mli
··· 1 1 (** Fuzz tests for {\!Ax25}. *) 2 2 3 - val suite : string * Crowbar.test_case list 3 + val suite : string * Alcobar.test_case list 4 4 (** Test suite. *)
-157
fuzz/gen_corpus.ml
··· 1 - (*--------------------------------------------------------------------------- 2 - Copyright (c) 2025. All rights reserved. 3 - SPDX-License-Identifier: ISC 4 - ---------------------------------------------------------------------------*) 5 - 6 - (* Generate seed corpus for AX.25 fuzz testing *) 7 - 8 - let write_seed dir n data = 9 - let filename = Fmt.str "%s/seed_%03d" dir n in 10 - let oc = open_out_bin filename in 11 - output_bytes oc data; 12 - close_out oc 13 - 14 - let () = 15 - let dir = "fuzz/corpus" in 16 - (try Unix.mkdir dir 0o755 with Unix.Unix_error (Unix.EEXIST, _, _) -> ()); 17 - let n = ref 0 in 18 - let add data = 19 - write_seed dir !n data; 20 - incr n 21 - in 22 - (* Basic UI frames *) 23 - let src = Ax25.callsign_exn ~call:"N0CALL" ~ssid:0 in 24 - let dst = Ax25.callsign_exn ~call:"CQ" ~ssid:0 in 25 - (* Empty info *) 26 - add (Ax25.encode (Ax25.ui_frame ~src ~dst Bytes.empty)); 27 - (* Short info *) 28 - add (Ax25.encode (Ax25.ui_frame ~src ~dst (Bytes.of_string "Hi"))); 29 - (* Longer info *) 30 - add (Ax25.encode (Ax25.ui_frame ~src ~dst (Bytes.of_string "Hello AX.25!"))); 31 - (* With SSID *) 32 - let src1 = Ax25.callsign_exn ~call:"W1AW" ~ssid:5 in 33 - let dst1 = Ax25.callsign_exn ~call:"BEACON" ~ssid:0 in 34 - add (Ax25.encode (Ax25.ui_frame ~src:src1 ~dst:dst1 (Bytes.of_string "Test"))); 35 - (* With digipeaters *) 36 - let digi1 = Ax25.callsign_exn ~call:"RELAY" ~ssid:0 in 37 - let digi2 = Ax25.callsign_exn ~call:"WIDE1" ~ssid:1 in 38 - add 39 - (Ax25.encode 40 - (Ax25.ui_frame ~src ~dst ~digis:[ digi1 ] (Bytes.of_string "Via digi"))); 41 - add 42 - (Ax25.encode 43 - (Ax25.ui_frame ~src ~dst ~digis:[ digi1; digi2 ] 44 - (Bytes.of_string "Via digis"))); 45 - (* KISS framed *) 46 - add (Ax25.kiss_encode (Ax25.ui_frame ~src ~dst (Bytes.of_string "KISS"))); 47 - (* KISS with special characters *) 48 - add 49 - (Ax25.kiss_encode (Ax25.ui_frame ~src ~dst (Bytes.of_string "A\xC0B\xDBC"))); 50 - (* HDLC framed *) 51 - add (Ax25.hdlc_encode (Ax25.ui_frame ~src ~dst (Bytes.of_string "HDLC"))); 52 - (* Different PIDs *) 53 - let frame_ip = 54 - { 55 - Ax25.address = { destination = dst; source = src; digipeaters = [] }; 56 - control = Ax25.UI; 57 - pid = Some Ax25.IP; 58 - info = Bytes.of_string "IP packet"; 59 - } 60 - in 61 - add (Ax25.encode frame_ip); 62 - let frame_arp = 63 - { 64 - Ax25.address = { destination = dst; source = src; digipeaters = [] }; 65 - control = Ax25.UI; 66 - pid = Some Ax25.ARP; 67 - info = Bytes.of_string "ARP"; 68 - } 69 - in 70 - add (Ax25.encode frame_arp); 71 - (* Control frames *) 72 - let sabm_frame = 73 - { 74 - Ax25.address = { destination = dst; source = src; digipeaters = [] }; 75 - control = Ax25.SABM; 76 - pid = None; 77 - info = Bytes.empty; 78 - } 79 - in 80 - add (Ax25.encode sabm_frame); 81 - let disc_frame = 82 - { 83 - Ax25.address = { destination = dst; source = src; digipeaters = [] }; 84 - control = Ax25.DISC; 85 - pid = None; 86 - info = Bytes.empty; 87 - } 88 - in 89 - add (Ax25.encode disc_frame); 90 - let ua_frame = 91 - { 92 - Ax25.address = { destination = dst; source = src; digipeaters = [] }; 93 - control = Ax25.UA; 94 - pid = None; 95 - info = Bytes.empty; 96 - } 97 - in 98 - add (Ax25.encode ua_frame); 99 - (* I frame *) 100 - let i_frame = 101 - { 102 - Ax25.address = { destination = dst; source = src; digipeaters = [] }; 103 - control = Ax25.I { ns = 3; nr = 5; poll = true }; 104 - pid = Some Ax25.No_layer3; 105 - info = Bytes.of_string "I frame data"; 106 - } 107 - in 108 - add (Ax25.encode i_frame); 109 - (* S frames *) 110 - let rr_frame = 111 - { 112 - Ax25.address = { destination = dst; source = src; digipeaters = [] }; 113 - control = Ax25.RR { nr = 7; poll = false }; 114 - pid = None; 115 - info = Bytes.empty; 116 - } 117 - in 118 - add (Ax25.encode rr_frame); 119 - let rnr_frame = 120 - { 121 - Ax25.address = { destination = dst; source = src; digipeaters = [] }; 122 - control = Ax25.RNR { nr = 2; poll = true }; 123 - pid = None; 124 - info = Bytes.empty; 125 - } 126 - in 127 - add (Ax25.encode rnr_frame); 128 - let rej_frame = 129 - { 130 - Ax25.address = { destination = dst; source = src; digipeaters = [] }; 131 - control = Ax25.REJ { nr = 4; poll = false }; 132 - pid = None; 133 - info = Bytes.empty; 134 - } 135 - in 136 - add (Ax25.encode rej_frame); 137 - (* Edge cases *) 138 - (* Minimum callsign *) 139 - let min_src = Ax25.callsign_exn ~call:"A" ~ssid:0 in 140 - let min_dst = Ax25.callsign_exn ~call:"B" ~ssid:0 in 141 - add (Ax25.encode (Ax25.ui_frame ~src:min_src ~dst:min_dst Bytes.empty)); 142 - (* Maximum callsign *) 143 - let max_src = Ax25.callsign_exn ~call:"ABC123" ~ssid:15 in 144 - let max_dst = Ax25.callsign_exn ~call:"XYZ789" ~ssid:15 in 145 - add (Ax25.encode (Ax25.ui_frame ~src:max_src ~dst:max_dst Bytes.empty)); 146 - (* Many digipeaters *) 147 - let digis = 148 - List.init 8 (fun i -> Ax25.callsign_exn ~call:(Fmt.str "DIGI%d" i) ~ssid:i) 149 - in 150 - add (Ax25.encode (Ax25.ui_frame ~src ~dst ~digis (Bytes.of_string "8 digis"))); 151 - (* Raw bytes for negative testing *) 152 - add (Bytes.make 0 '\x00'); 153 - add (Bytes.make 1 '\x00'); 154 - add (Bytes.make 16 '\x00'); 155 - add (Bytes.make 17 '\x00'); 156 - add (Bytes.make 100 '\xFF'); 157 - Fmt.pr "Generated %d seed files in %s/\n" !n dir