How do I pass an unsigned char * (an array of bytes representing binary data) from C to OCaml?

As the warning says, you are trying to pass an argument of type uint8_t * to a function that is waiting for a value of type char const *. For historical reasons, char and uint8_t are completely unrelated types, though they happen to have the same memory representation in practice. So, you should just cast one pointer type to the other:

value msg_data = caml_alloc_initialized_string(strlen((char *)data), (char *)data);

By the way, you can use caml_copy_string instead of caml_alloc_initialized_string here.

value msg_data = caml_copy_string((char *)data);

Also, you really need to protect your variables of type value with CAMLlocal, as any of the memory allocation might trigger a garbage collection, which would indirectly corrupt their content.

CAMLlocal2(msg_type, msg_data);
...
CAMLreturn(...);

As for the global variable closure, you would have to declare it as garbage collector root. (EDIT: as pointed out by @vrotaru, its content does not need to be protected any further.)