Support for RTL838x based managed switches

TL;DR

  1. I want realtek-poe to work, but to do so we need an agreed-upon place for it to be developed
  2. I don't think realtek-poe will make it to mainline OpenWrt, but as it stands there's no OpenWrt-based implementation that can successfully control this very commonly seen MCU+BCM59XXX-backed PoE hardware, and I think realtek-poe is useful as an open-source reference implementation for debugging.

On my GS1900-24HPv1, the issue I'm replying to was caused by MAX_PORTS being hard-set as 8 in realtek-poe's main.c. After changing that (and another instance which hard-codes 8 in a for loop in poe_reply_port_overview), the program runs, but does not successfully initialize PoE on any ports (so far that I've tested). I think this is because of a port mapping issue which must be dealt with for these 24-port switches.

Two things in particular:

  1. The 0x0ath sent frame always receives a response 0xfe, AKA 'Request Checksum Frame was incorrect'. I've tested multiple different configurations and found that no matter what the frame is, as long as it's the 0x0ath one, it will fail. I don't believe this is true when the Frame ID wraps over to 0x0a again.

  2. Frames sent to manipulate configuration on port 0x0a always fail with response 0xfe -- and frames to manipulate port 0x0d respond with information from port 0x0a. I suspect this has to do with port mapping, and that we will have to find the original firmware's port mapping and reproduce it.

I have implemented a ubus callback to queue up one frame:

root@OpenWrt:/# ubus -v list poe
'poe' @38a3bba9
        "info":{}
        "reload":{}
        "sendframe":{"frame":"String"}

Using (roughly) this patch:

@ -773,6 +866,47 @@ ubus_poe_info_cb(struct ubus_context *ctx, struct ubus_object *obj,
     return UBUS_STATUS_OK;
 }

+enum {
+    POE_SENDFRAME_STRING,
+    __POE_SENDFRAME_MAX
+};
+
+static const struct blobmsg_policy ubus_poe_sendframe_policy[__POE_SENDFRAME_MAX] = {
+    [POE_SENDFRAME_STRING] = { "frame", BLOBMSG_TYPE_STRING },
+};
+
+static int
+ubus_poe_sendframe_cb(struct ubus_context *ctx, struct ubus_object *obj,
+           struct ubus_request_data *req, const char *method,
+           struct blob_attr *msg)
+{
+    struct blob_attr *tb[__POE_SENDFRAME_MAX];
+    blobmsg_parse(ubus_poe_sendframe_policy, __POE_SENDFRAME_MAX, tb, blob_data(msg), blob_len(msg));
+
+    if (!tb[POE_SENDFRAME_STRING])
+        return UBUS_STATUS_INVALID_ARGUMENT;
+
+    char *frame = blobmsg_get_string(tb[POE_SENDFRAME_STRING]);
+
+    unsigned int frame_strlen = strlen(frame);
+    unsigned char cmd[9];
+    unsigned int cmdsize = 0;
+    unsigned char *end = cmd + sizeof(cmd);
+    unsigned int u;
+    unsigned int i = 0;
+
+    while ((cmd + cmdsize < end) && (i < frame_strlen)) {
+        if (sscanf((frame+i), "0x%2x", &u) == 1) {
+            cmd[cmdsize++] = u;
+            i += 4;
+        } else
+            i += 1;
+    }
+    return poe_cmd_queue(cmd, cmdsize);
+}
+
 static int
 ubus_poe_reload_cb(struct ubus_context *ctx, struct ubus_object *obj,
            struct ubus_request_data *req, const char *method,
@@ -787,6 +921,7 @@ ubus_poe_reload_cb(struct ubus_context *ctx, struct ubus_object *obj,
 static const struct ubus_method ubus_poe_methods[] = {
     UBUS_METHOD_NOARG("info", ubus_poe_info_cb),
     UBUS_METHOD_NOARG("reload", ubus_poe_reload_cb),
+    UBUS_METHOD("sendframe", ubus_poe_sendframe_cb, ubus_poe_sendframe_policy),
 };

This will enqueue up to 9 bytes as a frame (using the same code path as all of the frame command senders to handle frame number / checksumming); unfortunately I'm not a strong C programmer and haven't thought of a good way to retrieve the response to the frame as the frame is only enqueued and not waited on -- but I might be misunderstanding the running context of the ubus_poe_sendframe_cb when one calls ubus call poe sendframe '{"frame": "0x01 0x01"}' (to enable port 1, for example); it might be possible to have the method here spin / wait for the frame response, I'm just not really familiar with the ubus architecture.

To be clear, the code does work and does send the frame you ask; if running realtek-poe -d you do see the frame being sent upon running that ubus call.

It'd be nice to have a place to send my patches, or even an official home for realtek-poe to be developed, but ca n'existe pas at this point. I'm happy to create a repository / specific branch for code development on Github if that would help centralize efforts, @blogic.

4 Likes