DF-3501 / fecdrive.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 | #include <sys/param.h> #include <sys/kernel.h> #include <sys/module.h> #include <sys/systm.h> #include <sys/sysctl.h> #include <sys/malloc.h> #include <sys/errno.h> #include <sys/socket.h> #include <netgraph/ng_message.h> #include <netgraph/netgraph.h> /* from sys/netgraph/fec/ng_fec.h */ #define NGM_FEC_COOKIE 983566799 #define NGM_FEC_ADD_IFACE 0 #define NGM_FEC_DEL_IFACE 1 /* * fecdrive: drive the (patched) ng_fec node from a normal thread context * (kldload/sysctl), because the stock csock path runs netgraph messages * in netisr where ifnet_lock() is illegal (KASSERT panic). * * Commands (sysctl -n fecdrive.cmd="<cmd>"): * create - ng_make_node("fec") -> f_node (auto-named fec0) * create2 - same, second node (fec1) stored in g_node * add <ifname> - NGM_FEC_ADD_IFACE to f_node * del <ifname> - NGM_FEC_DEL_IFACE to f_node * addg <if> - ADD_IFACE to g_node * shutdown - ng_rmnode(f_node) * echo - create an echo node (churns ng_node chunks) * status - print f_node/g_node pointers */ static node_p f_node; static node_p g_node; static int fecdrive_send(node_p node, int cmd, const char *ifname) { struct ng_mesg *msg; int len, error; len = (ifname != NULL) ? strlen(ifname) + 1 : 0; NG_MKMESSAGE(msg, NGM_FEC_COOKIE, cmd, len, M_WAITOK); if (msg == NULL) return (ENOMEM); if (ifname != NULL) strlcpy((char *)msg->data, ifname, len); error = ng_send_msg(node, msg, ".", NULL); return (error); } static int fecdrive_sysctl(SYSCTL_HANDLER_ARGS) { char cmd[64]; int error; strlcpy(cmd, "", sizeof(cmd)); error = sysctl_handle_string(oidp, cmd, sizeof(cmd), req); if (error != 0 || req->newptr == NULL) return (error); kprintf("FECDRIVE: cmd='%s'\n", cmd); if (strcmp(cmd, "create") == 0 || strcmp(cmd, "create2") == 0) { node_p *slot = (strcmp(cmd, "create2") == 0) ? &g_node : &f_node; if (*slot != NULL) { kprintf("FECDRIVE: slot busy\n"); return (EBUSY); } error = ng_make_node("fec", slot); kprintf("FECDRIVE: ng_make_node(fec) = %d node=%p\n", error, *slot); } else if (strncmp(cmd, "add ", 4) == 0) { error = fecdrive_send(f_node, NGM_FEC_ADD_IFACE, cmd + 4); kprintf("FECDRIVE: add '%s' = %d\n", cmd + 4, error); } else if (strncmp(cmd, "addg ", 5) == 0) { error = fecdrive_send(g_node, NGM_FEC_ADD_IFACE, cmd + 5); kprintf("FECDRIVE: addg '%s' = %d\n", cmd + 5, error); } else if (strncmp(cmd, "del ", 4) == 0) { error = fecdrive_send(f_node, NGM_FEC_DEL_IFACE, cmd + 4); kprintf("FECDRIVE: del '%s' = %d\n", cmd + 4, error); } else if (strcmp(cmd, "shutdown") == 0) { if (f_node == NULL) { kprintf("FECDRIVE: no node\n"); return (ENOENT); } ng_rmnode(f_node); f_node = NULL; kprintf("FECDRIVE: rmnode done\n"); } else if (strcmp(cmd, "shutdowng") == 0) { if (g_node == NULL) { kprintf("FECDRIVE: no g node\n"); return (ENOENT); } ng_rmnode(g_node); g_node = NULL; kprintf("FECDRIVE: rmnode g done\n"); } else if (strcmp(cmd, "echo") == 0) { node_p e; error = ng_make_node("echo", &e); kprintf("FECDRIVE: ng_make_node(echo) = %d node=%p\n", error, e); } else if (strcmp(cmd, "status") == 0) { kprintf("FECDRIVE: f_node=%p g_node=%p\n", f_node, g_node); } else { kprintf("FECDRIVE: unknown cmd\n"); return (EINVAL); } return (0); } SYSCTL_PROC(_debug, OID_AUTO, fecdrive, CTLTYPE_STRING | CTLFLAG_RW, 0, 0, fecdrive_sysctl, "A", "drive ng_fec from thread context"); static int fecdrive_load(struct module *m, int what, void *arg) { switch (what) { case MOD_LOAD: kprintf("fecdrive: loaded\n"); return (0); default: return (0); } } static moduledata_t fecdrive_mod = { "fecdrive", fecdrive_load, NULL }; DECLARE_MODULE(fecdrive, fecdrive_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE); |