Added very basic support of VLANs, read only.
Lib: handling error code on 2 bytes instead of 1.
end:
free(ports);
- return true;
+ return ret;
}
+// =============================================================================
+// netconf
+
+
+static bool do_netconf_set (int nb, const char **com, struct ngadmin *nga) {
+
+ int i, k;
+ const struct swi_attr *sa;
+ struct net_conf nc;
+ bool ret=true;
+
+
+ if ( nb==0 ) {
+ printf("Usage: netconf set [dhcp yes|no] [ip <ip>] [mask <mask>] [gw <gw>]\n");
+ return false;
+ }
+
+ if ( (sa=ngadmin_getCurrentSwitch(nga))==NULL ) {
+ printf("must be logged\n");
+ return false;
+ }
+
+
+ memset(&nc, 0, sizeof(struct net_conf));
+
+ for (k=0; k<nb; k+=2) {
+
+ if ( strcasecmp(com[k], "dhcp")==0 ) {
+ if ( strcasecmp(com[k+1], "yes")==0 ) {
+ nc.dhcp=true;
+ } else if ( strcasecmp(com[k+1], "no")==0 ) {
+ nc.dhcp=false;
+ } else {
+ printf("Incorrect DHCP value\n");
+ ret=false;
+ goto end;
+ }
+
+ } else if ( strcasecmp(com[k], "ip")==0 ) {
+ if ( inet_aton(com[k+1], &nc.ip)==0 ) {
+ printf("Incorrect IP value\n");
+ ret=false;
+ goto end;
+ }
+
+ } else if ( strcasecmp(com[k], "mask")==0 ) {
+ if ( inet_aton(com[k+1], &nc.netmask)==0 ) { // TODO: check if it is a correct mask
+ printf("Incorrect mask value\n");
+ ret=false;
+ goto end;
+ }
+
+ } else if ( strcasecmp(com[k], "gw")==0 ) {
+ if ( inet_aton(com[k+1], &nc.gw)==0 ) {
+ printf("Incorrect gateway value\n");
+ ret=false;
+ goto end;
+ }
+
+ }
+
+ }
+
+
+ i=ngadmin_setNetConf(nga, &nc);
+ if ( i!=ERR_OK ) {
+ printErrCode(i);
+ ret=false;
+ }
+
+
+ end:
+
+ return ret;
+
+}
+
+
+
// =============================================================================
// password
if ( nb!=1 ) {
- printf("Usage: password set <value>\n");
+ printf("Usage: password change <value>\n");
return false;
}
+// =============================================================================
+// vlan
+
+
+static char vlan_char (int t) {
+
+ switch ( t ) {
+ case VLAN_TAGGED: return 'T';
+ case VLAN_UNTAGGED: return 'U';
+ case VLAN_NO: return ' ';
+ default: return '?';
+ }
+
+}
+
+
+static bool print_vlan_dot_adv (struct ngadmin *nga) {
+
+ char buffer[512], *b=buffer;
+ const struct swi_attr *sa;
+ int i, t;
+
+
+ sa=ngadmin_getCurrentSwitch(nga);
+
+ t=sizeof(buffer);
+ i=ngadmin_getVLANDotConf(nga, buffer, &t);
+ if ( i!=ERR_OK ) {
+ printErrCode(i);
+ return false;
+ }
+
+ printf("Ports configuration: \n");
+ printf("VLAN\t");
+ for (i=1; i<=sa->ports; ++i) {
+ printf("%i\t", i);
+ }
+ putchar('\n');
+
+ while ( b-buffer<t ) {
+ printf("%u\t", *(unsigned short*)b);b+=2;
+ for (i=1; i<=sa->ports; ++i) {
+ printf("%c\t", vlan_char(*b++));
+ }
+ putchar('\n');
+ }
+
+
+ return true;
+
+}
+
+
+static bool do_vlan_show (int nb UNUSED, const char **com UNUSED, struct ngadmin *nga) {
+
+ int i, t, ret=true;
+
+
+ if ( ngadmin_getCurrentSwitch(nga)==NULL ) {
+ printf("must be logged\n");
+ ret=false;
+ goto end;
+ }
+
+ if ( (i=ngadmin_getVLANType(nga, &t))!=ERR_OK ) {
+ printErrCode(i);
+ ret=false;
+ goto end;
+ }
+
+
+ printf("VLAN type: ");
+ switch ( t ) {
+ case VLAN_DISABLED: printf("disabled\n"); break;
+ case VLAN_PORT_BASIC: printf("port basic\n"); break;
+ case VLAN_PORT_ADV: printf("port advanced\n"); break;
+ case VLAN_DOT_BASIC: printf("802.1Q basic\n"); break;
+
+ case VLAN_DOT_ADV:
+ printf("802.1Q advanced\n\n");
+ ret=print_vlan_dot_adv(nga);
+ break;
+
+ default: printf("unknown (%i)\n", t);
+ }
+
+
+
+ end:
+
+ return ret;
+
+}
+
+
+
// =============================================================================
COM_END
COM_START(netconf)
- COM_TERM(show, NULL, false)
- COM_TERM(set, NULL, true)
+ COM_TERM(set, do_netconf_set, true)
COM_END
COM_START(password)
COM_TERM(tree, do_tree, false)
COM_START(vlan)
- COM_TERM(show, NULL, false)
+ COM_TERM(show, do_vlan_show, false)
COM_TERM(mode, NULL, true)
COM_END
}
- printf("Num\tMac\t\t\tProduct\t\tName\t\t\tIP/mask\t\t\t\tDHCP\tPorts\tFirmware\n");
+ printf("Num\tMac\t\t\tProduct\t\tName\t\t\tIP/mask\t\t\tDHCP\tPorts\tFirmware\n");
for (i=0; i<nb; ++i) {
printf("%i\t%s\t%s\t\t%s\t%s/", i, ether_ntoa(&sa[i].mac), sa[i].product, sa[i].name, inet_ntoa(sa[i].nc.ip));
#define SPEED_100 4
#define SPEED_1000 5
+#define VLAN_DISABLED 0
#define VLAN_PORT_BASIC 1
#define VLAN_PORT_ADV 2
#define VLAN_DOT_BASIC 3
#define VLAN_DOT_ADV 4
+#define VLAN_NO 0
+#define VLAN_UNTAGGED 1
+#define VLAN_TAGGED 2
+
#define QOS_PORT 1
#define QOS_DOT 2
int ngadmin_cabletest (struct ngadmin *nga, struct cabletest *ct, int nb) EXPORT;
+//
+int ngadmin_setNetConf (struct ngadmin *nga, const struct net_conf *nc) EXPORT;
+
+
+//
+int ngadmin_getVLANType (struct ngadmin *nga, int *t) EXPORT;
+
+
+//
+int ngadmin_getVLANDotConf (struct ngadmin *nga, char *buf, int *len) EXPORT;
+
+
+
#endif
#define ATTR_VLAN_TYPE 0x2000
#define ATTR_VLAN_PORT_CONF 0x2400
#define ATTR_VLAN_DOT_CONF 0x2800
+#define ATTR_VLAN_DESTROY 0x2C00
+#define ATTR_VLAN_PVID 0x3000
#define ATTR_QOS_TYPE 0x3400
#define ATTR_QOS_CONFIG 0x3800
#define ATTR_BITRATE_INPUT 0x4C00
#define ATTR_STORM_BITRATE 0x5800
#define ATTR_MIRROR 0x5C00
#define ATTR_PORTS_COUNT 0x6000
+#define ATTR_UNK_6400 0x6400
#define ATTR_IGMP_ENABLE_VLAN 0x6800
#define ATTR_IGMP_BLOCK_UNK 0x6C00
#define ATTR_IGMP_VALID_V3 0x7000
int ret;
-
/*
As described bellow, when you have multiple interfaces, this forces the packet
to go to a particular interface.
*/
- ret=1;
if ( (ret=setsockopt(nga->sock, SOL_SOCKET, SO_BINDTODEVICE, nga->iface, strlen(nga->iface)+1))<0 ) {
perror("setsockopt(SO_BINDTODEVICE)");
return ret;
-// ---------------------------------------------------------------------------------------------------
-int recvNgPacket (struct ngadmin *nga, char code, char *error, unsigned short *attr_error, List *attr) {
+// -------------------------------------------------------------------------------------------------------------
+int recvNgPacket (struct ngadmin *nga, char code, unsigned short *error, unsigned short *attr_error, List *attr) {
char buffer[1500];
struct ng_packet np;
int readRequest (struct ngadmin *nga, List *attr) {
int i, ret=ERR_OK;
- unsigned short attr_error;
- char err;
+ unsigned short err, attr_error;
if ( nga==NULL ) {
ret=ERR_NET;
}
- if ( err==7 && attr_error==ATTR_PASSWORD ) {
+ if ( err==0x0700 && attr_error==ATTR_PASSWORD ) {
ret=ERR_BADPASS;
goto end;
}
int writeRequest (struct ngadmin *nga, List *attr) {
int i, ret=ERR_OK;
- unsigned short attr_error;
- char err;
+ unsigned short err, attr_error;
if ( nga==NULL ) {
goto end;
}
- if ( err==7 && attr_error==ATTR_PASSWORD ) {
+ if ( err==0x0700 && attr_error==ATTR_PASSWORD ) {
ret=ERR_BADPASS;
goto end;
}
+ // err==0x0500
+
end:
// the switch replies to write request by just a header (no attributes), so the list can be destroyed
int sendNgPacket (struct ngadmin *nga, char code, const List *attr);
//
-int recvNgPacket (struct ngadmin *nga, char code, char *error, unsigned short *attr_error, List *attr);
+int recvNgPacket (struct ngadmin *nga, char code, unsigned short *error, unsigned short *attr_error, List *attr);
//
int readRequest (struct ngadmin *nga, List *attr);
List *attr;
ListNode *ln;
struct attr *at;
- int ret=ERR_OK, i;
+ int ret=ERR_OK;
+ struct {
+ char port;
+ int bitrate;
+ } __attribute__((packed)) *p;
if ( nga==NULL || ports==NULL ) {
for (ln=attr->first; ln!=NULL; ln=ln->next) {
at=ln->data;
- if ( at->attr==ATTR_BITRATE_INPUT && at->size>=5 && (i=*(char*)(at->data)-1)>=0 && i<nga->current->ports ) {
- ports[i*2+0]=ntohl(*(int*)(1+(char*)at->data));
- } else if ( at->attr==ATTR_BITRATE_OUTPUT && at->size>=5 && (i=*(char*)(at->data)-1)>=0 && i<nga->current->ports ) {
- ports[i*2+1]=ntohl(*(int*)(1+(char*)at->data));
+ p=at->data;
+ if ( at->size<sizeof(*p) || p->port<1 || p->port>nga->current->ports ) continue;
+ if ( at->attr==ATTR_BITRATE_INPUT ) {
+ ports[(p->port-1)*2+0]=ntohl(p->bitrate);
+ } else if ( at->attr==ATTR_BITRATE_OUTPUT ) {
+ ports[(p->port-1)*2+1]=ntohl(p->bitrate);
}
}
for (ln=attr->first; ln!=NULL; ln=ln->next) {
at=ln->data;
p=at->data;
- if ( at->attr==ATTR_MIRROR && at->size>=2+sa->ports/8 && p[0]<=nga->current->ports ) {
+ if ( at->attr==ATTR_MIRROR && at->size>=3 && p[0]<=nga->current->ports ) {
ports[0]=p[0];
for (i=1; i<=sa->ports; ++i) { // FIXME: if ports>8
ports[i]=(p[2]>>(sa->ports-i))&1;
+// --------------------------------------------------------------------
+int ngadmin_setNetConf (struct ngadmin *nga, const struct net_conf *nc) {
+
+ List *attr;
+ struct swi_attr *sa;
+ int ret=ERR_OK;
+
+
+ if ( nga==NULL || nc==NULL ) {
+ return ERR_INVARG;
+ } else if ( (sa=nga->current)==NULL ) {
+ return ERR_NOTLOG;
+ }
+
+
+ attr=createEmptyList();
+
+ if ( nc->dhcp ) {
+ pushBackList(attr, newByteAttr(ATTR_DHCP, 1));
+ } else {
+ pushBackList(attr, newByteAttr(ATTR_DHCP, 0));
+ if ( nc->ip.s_addr!=0 ) pushBackList(attr, newAddrAttr(ATTR_IP, nc->ip));
+ if ( nc->netmask.s_addr!=0 ) pushBackList(attr, newAddrAttr(ATTR_NETMASK, nc->netmask));
+ if ( nc->gw.s_addr!=0 ) pushBackList(attr, newAddrAttr(ATTR_GATEWAY, nc->gw));
+ }
+
+ if ( (ret=writeRequest(nga, attr))!=ERR_OK ) {
+ goto end;
+ }
+
+
+ if ( nc->dhcp ) {
+ sa->nc.dhcp=true;
+ } else {
+ memcpy(&sa->nc, nc, sizeof(struct net_conf));
+ }
+
+
+ end:
+
+ return ret;
+
+}
+
+
+
+// --------------------------------------------------
+int ngadmin_getVLANType (struct ngadmin *nga, int *t) {
+
+ List *attr;
+ ListNode *ln;
+ struct attr *at;
+ int ret=ERR_OK;
+
+
+ if ( nga==NULL || t==NULL ) {
+ return ERR_INVARG;
+ } else if ( nga->current==NULL ) {
+ return ERR_NOTLOG;
+ }
+
+
+ attr=createEmptyList();
+ pushBackList(attr, newEmptyAttr(ATTR_VLAN_TYPE));
+ if ( (ret=readRequest(nga, attr))!=ERR_OK ) {
+ goto end;
+ }
+
+
+ for (ln=attr->first; ln!=NULL; ln=ln->next) {
+ at=ln->data;
+ if ( at->attr==ATTR_VLAN_TYPE && at->size>=1 ) {
+ *t= (int)*(char*)at->data ;
+ break;
+ }
+ }
+
+
+ end:
+ destroyList(attr, (void(*)(void*))freeAttr);
+
+ return ret;
+
+}
+
+
+
+// ------------------------------------------------------------------
+int ngadmin_getVLANDotConf (struct ngadmin *nga, char *buf, int *len) {
+
+ List *attr;
+ ListNode *ln;
+ struct attr *at;
+ struct swi_attr *sa;
+ int ret=ERR_OK, i;
+ char *b=buf, *p=NULL;
+
+
+ if ( nga==NULL || buf==NULL || len==NULL || *len<=0 ) {
+ return ERR_INVARG;
+ } else if ( (sa=nga->current)==NULL ) {
+ return ERR_NOTLOG;
+ }
+
+
+ attr=createEmptyList();
+ pushBackList(attr, newEmptyAttr(ATTR_VLAN_DOT_CONF));
+ if ( (ret=readRequest(nga, attr))!=ERR_OK ) {
+ goto end;
+ }
+
+
+ for (ln=attr->first; ln!=NULL; ln=ln->next) {
+ at=ln->data;
+ p=at->data;
+ if ( (b-buf)+2+sa->ports>*len ) break; // no more room
+ if ( at->attr==ATTR_VLAN_DOT_CONF && at->size>=4 ) {
+ *(unsigned short*)b=ntohs(*(unsigned short*)p);b+=2;
+ for (i=1; i<=sa->ports; ++i) {
+ if ( (p[3]>>(sa->ports-i))&1 ) *b++=VLAN_TAGGED; // tagged
+ else if ( (p[2]>>(sa->ports-i))&1 ) *b++=VLAN_UNTAGGED; // untagged
+ else *b++=VLAN_NO;
+ }
+ }
+ }
+
+ *len=b-buf;
+
+
+ end:
+ destroyList(attr, (void(*)(void*))freeAttr);
+
+ return ret;
+
+}
+
+
+
+
+
return false;
}
- if ( nh->unk2!=0 ) {
- return false;
- }
-
- if ( *(unsigned short*)nh->unk3!=0 ) {
+ if ( *(unsigned short*)nh->unk2!=0 ) {
return false;
}
return false;
}
- if ( *(unsigned int*)nh->unk4!=0 ) {
+ if ( *(unsigned int*)nh->unk3!=0 ) {
return false;
}
+// ---------------------------------------------------------
+struct attr* newShortAttr (unsigned short attr, short value) {
+
+ short *v=malloc(sizeof(short));
+
+ *v=value;
+
+ return newAttr(attr, sizeof(short), v);
+
+}
+
+
+
// -----------------------------------------------------
struct attr* newIntAttr (unsigned short attr, int value) {
+// -----------------------------------------------------------------
+struct attr* newAddrAttr (unsigned short attr, struct in_addr value) {
+
+ struct in_addr *v=malloc(sizeof(struct in_addr));
+
+ *v=value;
+
+ return newAttr(attr, sizeof(struct in_addr), v);
+
+}
+
+
+
// ----------------------------
void freeAttr (struct attr *at) {
-// -----------------------------------------------------------------------------------------------------
-void extractPacketAttributes (struct ng_packet *np, char *error, unsigned short *attr_error, List *attr) {
+// ---------------------------------------------------------------------------------------------------------------
+void extractPacketAttributes (struct ng_packet *np, unsigned short *error, unsigned short *attr_error, List *attr) {
struct attr *at;
- if ( error!=NULL ) {
- *error=np->nh->error;
- }
-
- if ( attr_error!=NULL ) {
- *attr_error=ntohs(np->nh->attr);
- }
+ if ( error!=NULL ) *error=ntohs(np->nh->error);
+ if ( attr_error!=NULL ) *attr_error=ntohs(np->nh->attr);
while ( getPacketTotalSize(np)<np->maxlen ) {
struct ng_header {
- char unk1; // always 1
- char code;
- char error;
- char unk2; // always 0
- unsigned short attr; // attribute code which caused error
- char unk3[2]; // always 0
- char client_mac[ETH_ALEN];
- char switch_mac[ETH_ALEN];
- unsigned int seqnum;
- char proto_id[4]; // always "NSDP"
- char unk4[4]; // always 0
+ char unk1; // always 1, maybe version
+ char code; // request code: read request, read reply, write request, write reply
+ unsigned short error; // error code, 0 when no error
+ unsigned short attr; // attribute code which caused error, 0 when no error
+ char unk2[2]; // always 0, unknown
+ char client_mac[ETH_ALEN]; // client MAC address
+ char switch_mac[ETH_ALEN]; // switch MAC address
+ unsigned int seqnum; // sequence number
+ char proto_id[4]; // always "NSDP", maybe short for "Netgear Switch Description Protocol"
+ char unk3[4]; // always 0, unknown
char data[0];
} __attribute__((packed)) ;
-extern const unsigned short helloRequest[];
-
extern const struct ether_addr nullMac;
//
struct attr* newByteAttr (unsigned short attr, unsigned char value);
+//
+struct attr* newShortAttr (unsigned short attr, short value);
+
//
struct attr* newIntAttr (unsigned short attr, int value);
+//
+struct attr* newAddrAttr (unsigned short attr, struct in_addr value);
+
//
void freeAttr (struct attr *at);
//
-void extractPacketAttributes (struct ng_packet *np, char *error, unsigned short *attr_error, List *attr);
+void extractPacketAttributes (struct ng_packet *np, unsigned short *error, unsigned short *attr_error, List *attr);
//
void extractSwitchAttributes (struct swi_attr *sa, const List *l);