10 #include <sys/ioctl.h>
13 #include <ngadmin.h> /* FIXME */
14 #include <nsdp/protocol.h>
15 #include <nsdp/attr.h>
17 #include <nsdp/misc.h>
20 #define MAX_STR_SIZE 64
23 char product[MAX_STR_SIZE];
24 char name[MAX_STR_SIZE];
25 char firmware[MAX_STR_SIZE];
26 char password[MAX_STR_SIZE];
29 unsigned char mac[ETH_ALEN];
37 static struct swi_info swi;
41 static int process_read_attr (struct nsdp_cmd *nc, List *attr, struct attr *at)
43 unsigned char p, *byte;
46 struct attr_port_status *apu;
47 struct attr_port_stat *api;
60 byte = malloc(MAX_STR_SIZE);
61 memcpy(byte, swi.product, MAX_STR_SIZE);
63 at->size = MAX_STR_SIZE;
67 byte = malloc(MAX_STR_SIZE);
68 memcpy(byte, swi.name, MAX_STR_SIZE);
70 at->size = MAX_STR_SIZE;
74 byte = malloc(MAX_STR_SIZE);
75 memcpy(byte, swi.firmware, MAX_STR_SIZE);
77 at->size = MAX_STR_SIZE;
81 byte = malloc(ETH_ALEN);
82 memcpy(byte, swi.mac, ETH_ALEN);
87 case ATTR_PORTS_COUNT:
95 byte = malloc(sizeof(in_addr_t));
96 *(in_addr_t*)byte = swi.ip;
98 at->size = sizeof(in_addr_t);
102 byte = malloc(sizeof(in_addr_t));
103 *(in_addr_t*)byte = swi.netmask;
105 at->size = sizeof(in_addr_t);
109 byte = malloc(sizeof(in_addr_t));
110 *(in_addr_t*)byte = swi.gw;
112 at->size = sizeof(in_addr_t);
116 /* Note: DHCP attribute is special, it is 2 two bytes long
117 * when sent by the switch but only 1 byte long when sent
135 case ATTR_PORT_STATUS:
136 for (p = 1; p <= swi.ports; p++) {
137 apu = malloc(sizeof(*apu));
139 apu->status = SPEED_1000;
142 pushFrontList(attr, newAttr(ATTR_PORT_STATUS, sizeof(*apu), apu));
146 case ATTR_PORT_STATISTICS:
147 for (p = 1; p <= swi.ports; p++) {
148 api = malloc(sizeof(*api));
149 memset(api, 0, sizeof(*api));
151 api->recv = p * 100000;
152 api->sent = p * 200000;
154 pushFrontList(attr, newAttr(ATTR_PORT_STATISTICS, sizeof(*api), api));
163 static int process_write_attr (struct nsdp_cmd *nc, List *attr, struct attr *at)
173 case ATTR_NEW_PASSWORD:
175 passwordEndecode(at->data, at->size);
177 trim(text, MAX_STR_SIZE);
178 strncpy(swi.password, text, MAX_STR_SIZE);
186 static int check_password (struct nsdp_cmd *nc, List *attr)
188 ListNode *ln = attr->first;
189 struct attr *at = NULL;
193 /* in a write request, the password attribute must be present
194 * and the first element of the list
195 * official win app never sends password inside a read request, but
196 * ngadmin does that because in that case the password is not echoed
197 * back by the switch, so we have to support that, though password in
198 * such requests are not mandatory
200 if (ln == NULL || (at = ln->data)->attr != ATTR_PASSWORD) {
201 if (nc->code == CODE_WRITE_REQ)
202 nc->error = ERROR_DENIED;
207 nc->error = ERROR_DENIED;
211 /* normally, we would expect password encryption to be handled
212 * in read requests as well as in write requests
213 * but it seems that real Netgear switches that support
214 * password encryption do NOT accept encrypted passwords in
216 * this seems more to be a bug in their firmwares, however, as
217 * the scope of this program is to simulate a switch, we adopt
218 * the same buggy behaviour
220 if (nc->code == CODE_WRITE_REQ && swi.encpass)
221 passwordEndecode(at->data, at->size);
223 text[at->size] = '\0';
224 trim(text, at->size);
225 if (strcmp(text, swi.password) != 0)
226 nc->error = ERROR_DENIED;
230 if (nc->error == 0) {
231 /* correct password */
232 if (ln != NULL && at->attr == ATTR_PASSWORD)
233 destroyElement(attr, ln, (void(*)(void*))freeAttr);
236 /* invalid password, empty list */
237 nc->attr_error = ATTR_PASSWORD;
238 clearList(attr, (void(*)(void*))freeAttr);
244 static void process_packet (struct nsdp_cmd *nc, List *attr)
246 struct ListNode *ln, *pr;
249 int (*process_attr)(struct nsdp_cmd *, List *, struct attr *);
252 check_password(nc, attr);
253 if (nc->code == CODE_READ_REQ) {
254 nc->code = CODE_READ_REP;
255 process_attr = process_read_attr;
256 } else if (nc->code == CODE_WRITE_REQ) {
257 nc->code = CODE_WRITE_REP;
258 process_attr = process_write_attr;
260 /* invalid operation code */
265 for (ln = attr->first; ln != NULL; ) {
268 err = process_attr(nc, attr, at);
271 /* destroy current attribute */
274 destroyElement(attr, pr, (void(*)(void*))freeAttr);
275 } else if (err == 0) {
276 /* keep current attribute */
284 memcpy(&nc->switch_mac, swi.mac, ETH_ALEN);
285 nc->remote_addr.sin_addr.s_addr = htonl(INADDR_BROADCAST);
287 sendNsdpPacket(sock, nc, attr);
291 static int netdev_info (const char *dev)
297 memset(&ifr, 0, sizeof(struct ifreq));
298 strncpy(ifr.ifr_name, dev, IFNAMSIZ - 1);
300 /* get interface MAC */
301 err = ioctl(sock, SIOCGIFHWADDR, &ifr, sizeof(struct ifreq));
303 perror("ioctl(SIOCGIFHWADDR)");
306 memcpy(swi.mac, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
308 /* get interface IP */
309 err = ioctl(sock, SIOCGIFADDR, &ifr, sizeof(struct ifreq));
311 perror("ioctl(SIOCGIFADDR)");
314 swi.ip = (*(struct sockaddr_in*)&ifr.ifr_addr).sin_addr.s_addr;
316 /* get interface netmask */
317 err = ioctl(sock, SIOCGIFNETMASK, &ifr, sizeof(struct ifreq));
319 perror("ioctl(SIOCGIFNETMASK)");
322 swi.netmask = (*(struct sockaddr_in*)&ifr.ifr_netmask).sin_addr.s_addr;
324 /* TODO: get netmask */
325 swi.gw = htonl(ntohl(swi.ip & swi.netmask) | 1);
332 static void handler (int sig)
335 printf("interrupt\n");
339 int main (int argc, char **argv)
341 static const struct option options[] = {
342 {"help", no_argument, NULL, 'h'},
343 {"interface", required_argument, NULL, 'i'},
347 const char *iface = "eth0";
348 struct sockaddr_in local;
356 while ((len = getopt_long(argc, argv, "hi:", options, NULL)) != -1) {
360 printf("usage: %s [-h] [-i <interface>]\n", argv[0]);
368 printf("unknown option: \"%s\"\n", argv[optind - 1]);
374 sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
381 memset(&local, 0, sizeof(struct sockaddr_in));
382 local.sin_family = AF_INET;
383 local.sin_addr.s_addr = htonl(INADDR_ANY);
384 local.sin_port = htons(SWITCH_PORT);
386 if (bind(sock, (struct sockaddr*)&local, sizeof(struct sockaddr_in)) < 0) {
392 /* allow broadcasting */
394 len = setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &len, sizeof(len));
396 perror("setsockopt(SO_BROADCAST)");
401 /* initialize switch infos */
402 memset(&swi, 0, sizeof(struct swi_info));
403 strncpy(swi.product, "NgEmu_0.1", MAX_STR_SIZE);
404 strncpy(swi.name, "Netgear Switch Emulator", MAX_STR_SIZE);
405 strncpy(swi.firmware, "0.1", MAX_STR_SIZE);
406 strncpy(swi.password, "password", MAX_STR_SIZE);
410 if (netdev_info(iface) < 0)
414 attr = createEmptyList();
416 memset(&sa, 0, sizeof(struct sigaction));
417 sa.sa_handler = handler;
418 sigaction(SIGINT, &sa, NULL);
419 sigaction(SIGTERM, &sa, NULL);
422 memset(&nc, 0, sizeof(struct nsdp_cmd));
423 nc.remote_addr.sin_family = AF_INET;
424 nc.remote_addr.sin_port = htons(CLIENT_PORT);
426 len = recvNsdpPacket(sock, &nc, attr, NULL);
430 /* ignore packets not for us */
431 for (len = 0; nc.switch_mac.ether_addr_octet[len] == 0 && len < ETH_ALEN; len++);
432 if (len < ETH_ALEN && memcmp(swi.mac, &nc.switch_mac, ETH_ALEN) != 0)
435 process_packet(&nc, attr);
436 clearList(attr, (void(*)(void*))freeAttr);
439 destroyList(attr, (void(*)(void*))freeAttr);