ports.c (4533B)
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 #include <strings.h> 5 6 #include "finwo/cnfparse.h" 7 8 #include "util/config.h" 9 10 #include "ports.h" 11 12 static struct linkd_port *ports = NULL; 13 static struct linkd_port *ports_tail = NULL; 14 15 struct linkd_port * ports_list(void) { 16 return ports; 17 } 18 19 struct linkd_port * ports_find(const char *name) { 20 struct linkd_port *cur; 21 for ( cur = ports ; cur ; cur = cur->next ) { 22 if (!strcmp(cur->name, name)) return cur; 23 } 24 return NULL; 25 } 26 27 void ports_free(void) { 28 struct linkd_port *cur = ports; 29 struct linkd_port *next; 30 31 while (cur) { 32 next = cur->next; 33 if (cur->name) free(cur->name); 34 if (cur->breakout) free(cur->breakout); 35 free(cur); 36 cur = next; 37 } 38 39 ports = NULL; 40 ports_tail = NULL; 41 } 42 43 static enum dp_fec ports_parse_fec(const char *value) { 44 if (!strcasecmp("off" , value)) return DP_FEC_OFF; 45 if (!strcasecmp("none" , value)) return DP_FEC_OFF; 46 if (!strcasecmp("auto" , value)) return DP_FEC_AUTO; 47 if (!strcasecmp("rs" , value)) return DP_FEC_RS; 48 if (!strcasecmp("baser", value)) return DP_FEC_BASER; 49 if (!strcasecmp("fc" , value)) return DP_FEC_BASER; 50 return DP_FEC_UNSET; 51 } 52 53 static int ports_parse_bool(const char *value) { 54 if (!strcasecmp("on" , value)) return 1; 55 if (!strcasecmp("yes" , value)) return 1; 56 if (!strcasecmp("true", value)) return 1; 57 if (!strcasecmp("1" , value)) return 1; 58 return 0; 59 } 60 61 // Directives ifupdown already implements. Accepting them here would create a 62 // second source of truth for the same value, so reject them loudly and point 63 // at the right file rather than silently ignoring them. 64 static const char *ports_reserved[] = { 65 "address", "gateway", "netmask", "broadcast", "metric", 66 "mtu", "hwaddress", "admin", "up", "down", 67 NULL, 68 }; 69 70 static int ports_is_reserved(const char *name) { 71 int i; 72 for ( i = 0 ; ports_reserved[i] ; i++ ) { 73 if (!strcasecmp(ports_reserved[i], name)) return 1; 74 } 75 return 0; 76 } 77 78 static void port_free(struct linkd_port *port) { 79 if (!port) return; 80 free(port->name); 81 free(port->breakout); 82 free(port); 83 } 84 85 struct cnf_directive * cfg_parse_port(FILE *fd, struct cnf_directive *dir, void *user) { 86 struct linkd_port *port; 87 (void)user; 88 89 if (dir->argc != 1) { 90 cfg_error("`port` directive accepts only 1 argument"); 91 cnf_directive_free(dir); 92 return NULL; 93 } 94 95 if (ports_find(dir->argv[0])) { 96 cfg_error("duplicate `port` definition: %s", dir->argv[0]); 97 cnf_directive_free(dir); 98 return NULL; 99 } 100 101 port = calloc(1, sizeof(struct linkd_port)); 102 port->name = strdup(dir->argv[0]); 103 port->fec = DP_FEC_UNSET; 104 port->autoneg = -1; 105 106 for(;;) { 107 if (dir) cnf_directive_free(dir); 108 dir = cnf_directive_read(fd); 109 if (!dir) break; // EOF = done 110 111 // Make following blocks identical in structure 112 if(0) {} 113 114 else if (!strcasecmp("speed", dir->name)) { 115 if (dir->argc != 1) { 116 cfg_error("`speed` directive accepts only 1 argument"); 117 goto fail; 118 } 119 port->speed = (uint32_t)strtoul(dir->argv[0], NULL, 10); 120 } 121 122 else if (!strcasecmp("fec", dir->name)) { 123 if (dir->argc != 1) { 124 cfg_error("`fec` directive accepts only 1 argument"); 125 goto fail; 126 } 127 port->fec = ports_parse_fec(dir->argv[0]); 128 if (port->fec == DP_FEC_UNSET) { 129 cfg_error("unknown `fec` value: %s", dir->argv[0]); 130 goto fail; 131 } 132 } 133 134 else if (!strcasecmp("autoneg", dir->name)) { 135 if (dir->argc != 1) { 136 cfg_error("`autoneg` directive accepts only 1 argument"); 137 goto fail; 138 } 139 port->autoneg = ports_parse_bool(dir->argv[0]); 140 } 141 142 else if (!strcasecmp("breakout", dir->name)) { 143 if (dir->argc != 1) { 144 cfg_error("`breakout` directive accepts only 1 argument"); 145 goto fail; 146 } 147 if (port->breakout) free(port->breakout); 148 port->breakout = strdup(dir->argv[0]); 149 } 150 151 else if (ports_is_reserved(dir->name)) { 152 cfg_error("`%s` is handled by the interfaces config, not ports", dir->name); 153 goto fail; 154 } 155 156 else { 157 // unknown directive 158 break; 159 } 160 } 161 162 // Store the completed port 163 if (ports_tail) { 164 ports_tail->next = port; 165 } else { 166 ports = port; 167 } 168 ports_tail = port; 169 170 // Return the unparsed dir if set 171 return dir; 172 173 fail: 174 port_free(port); 175 cnf_directive_free(dir); 176 return NULL; 177 } 178 179 void ports_register(void) { 180 struct cfg_ns *ns = cfg_ns_get("ports"); 181 cfg_register_directive(ns, "port", cfg_parse_port); 182 }