CLI: free memory from exploded commands.
Added stub to implement firmware upgrade in the future.
Lib: handle error code on 1 byte instead of 2.
Lib: added Doxygen comments for more functions.
for (next=cur->sub; next->name!=NULL && strcmp(next->name, com[i])!=0; ++next);
// sub command not found, exit
- if ( next->name==NULL ) {
- next=NULL;
- break;
- }
+ if ( next->name==NULL ) break;
// next command is now the current one
cur=next;
int i, n;
-
memset(com, 0, MAXCOM*sizeof(char*));
line=strdup(rl_line_buffer);
line[start]=0;
if ( i<n ) compcur=NULL;
matches=rl_completion_matches(text, my_generator);
+ for (i=0; com[i]!=NULL; ++i) {
+ free(com[i]);
+ }
+
return matches;
static const struct option opts[]={
{"keep-broadcasting", no_argument, NULL, 'b'},
{"force-interface", no_argument, NULL, 'f'},
+ {"global-broadcast", no_argument, NULL, 'g'},
{"interface", required_argument, NULL, 'i'},
{"help", no_argument, NULL, 'h'},
{"timeout", required_argument, NULL, 't'},
char *line, *com[MAXCOM];
const char *iface="eth0";
float timeout=0.f;
- bool kb=false, force=false;
+ bool kb=false, force=false, global=false;
struct ngadmin *nga=NULL;
struct timeval tv;
const struct TreeNode *cur, *next;
opterr=0;
- while ( (n=getopt_long(argc, argv, "bfi:ht:", opts, NULL))!=-1 ) {
+ while ( (n=getopt_long(argc, argv, "bfgi:ht:", opts, NULL))!=-1 ) {
switch ( n ) {
case 'b':
force=true;
break;
+ case 'g':
+ global=true;
+ break;
+
case 'i':
iface=optarg;
break;
case 'h':
- printf("Usage: %s [-b] [-f] [-i <interface>]\n", argv[0]);
+ printf("Usage: %s [-b] [-f] [-g] [-i <interface>]\n", argv[0]);
goto end;
case 't':
// set timeout
if ( timeout>0.f ) {
tv.tv_sec=(int)timeout;
- tv.tv_usec=(int)((timeout-(float)tv.tv_sec)*1e6f);
+ tv.tv_usec=(int)((timeout-(float)tv.tv_sec)*1.e6f);
ngadmin_setTimeout(nga, &tv);
}
if ( force && ngadmin_forceInterface(nga)!=ERR_OK ) goto end;
+ if ( global && ngadmin_useGlobalBroadcast(nga, true)!=ERR_OK ) goto end;
+
//rl_bind_key('\t', rl_abort); // disable auto completion
//rl_bind_key('\t', rl_complete); // enable auto-complete
while ( cont ) {
if ( (line=readline("> "))==NULL ) goto end;
- if ( *line!=0 ) add_history(line);
trim(line, strlen(line));
n=explode(line, com, MAXCOM);
- free(line);
- if ( n==0 ) continue;
+ if ( n==0 ) {
+ free(line);
+ continue;
+ } else {
+ add_history(line);
+ free(line);
+ }
cur=getSubCom(com, n, &i);
}
- for (i=0; i<MAXCOM; i++) {
- if ( com[i]!=NULL ) {
- free(com[i]);
- com[i]=NULL;
- }
+ for (i=0; com[i]!=NULL; ++i) {
+ free(com[i]);
+ com[i]=NULL;
}
}
const struct swi_attr *sa;
bool ret=true;
+ int i;
if ( nb!=1 ) {
printf("Usage: firmware upgrade <file>\n");
ret=false;
+ goto end;
}
if ( (sa=ngadmin_getCurrentSwitch(nga))==NULL ) {
goto end;
}
- printf("not implemented yet\n");
+
+ i=ngadmin_upgradeFirmware(nga, com[0]);
+ printErrCode(i);
end:
case ERR_BADID: printf("bad switch id\n"); break;
case ERR_INVARG: printf("invalid argument\n"); break;
case ERR_TIMEOUT: printf("timeout\n"); break;
+ case ERR_NOTIMPL: printf("not implemented\n"); break;
default: printf("unknown status code (%i)\n", err);
}
/**
* Force the use of the interface.
* This function allows to solve two problems:
- * - When you have multiple network interfaces, sending to the broadcast may not
- * send the packet on the interface you want. \n
+ * - When you have multiple network interfaces, sending to the global broadcast
+ * address may not send the packet on the interface you want. \n
* This function forces the packet to go on the interface you specified at
* the library initialization.
* - When the switch is not in your network range, because DHCP is disabled or
* you started the DHCP server after the switch. \n
* This function allows you to ignore the routing table and consider every
* address is directly reachable on the interface. \n
- * An alternative is to use ngadmin_setKeepBroadcasting.
+ * An alternative is to use ngadmin_setKeepBroadcasting, or simply add a route.
*
* @warning Requires root priviledges.
* @see ngadmin_setKeepBroadcasting()
int ngadmin_setKeepBroadcasting (struct ngadmin *nga, bool value) EXPORT;
+/**
+ * Use global broadcast address.
+ * By default, NgAdmin uses the interface broadcast address.
+ * This option forces the lib to use the global broadcast address
+ * (255.255.255.255) instead.
+ * @warning If you have multiple interfaces, enabling this may cause problems.
+ * @see ngadmin_forceInterface()
+ * @param nga A pointer to the ngadmin structure.
+ * @param value Enable or disable the use of the global broadcast address.
+ * @return ERR_OK when everything is well or an error code otherwise.
+ **/
+int ngadmin_useGlobalBroadcast (struct ngadmin *nga, bool value) EXPORT;
+
+
/**
* Specify the password to use to login.
* Sets the password to use to login on switches.
const struct swi_attr* ngadmin_getCurrentSwitch (struct ngadmin *nga) EXPORT;
+
+/**
+ * Upgrade the switch firmware.
+ * This function allows you to upgrade the switch firmware.
+ * @warning Currently not implemented.
+ * @note You must be logged on a switch.
+ * @param nga A pointer to the ngadmin structure.
+ * @param filename A path to the file of the new firmware to send.
+ * @return ERR_NOTIMPL
+ **/
+int ngadmin_upgradeFirmware (struct ngadmin *nga, const char *filename) EXPORT;
+
+
/**
* Login on a switch.
* This function permits to login on a switch.
* This changes the name of a switch.
* @note You must be logged on a switch.
* @param nga A pointer to the ngadmin structure.
- * @param name The name string to use.
+ * @param name The name string to use. A NULL value clears the name.
* @return ERR_OK when everything is well or an error code otherwise.
**/
int ngadmin_setName (struct ngadmin *nga, const char *name) EXPORT;
/**
* Get the QoS mode.
- * Retrieve the QoS mode.
+ * Retrieves the QoS mode.
* @note You must be logged on a switch.
* @param nga A pointer to the ngadmin structure.
* @param s A pointer to an integer. Must not be NULL.
/**
* Get the QoS values.
- * Retrieve the QoS priority values for all the ports.
+ * Retrieves the QoS priority values for all the ports.
* @note You must be logged on a switch.
* @note The switch QoS mode should be port based to use this function.
* @param nga A pointer to the ngadmin structure.
* Get the port mirroring values.
* Retrieves the port mirrorring values.
* @note The switch QoS mode should be port based to use this function.
+ * @note You must be logged on a switch.
* @param nga A pointer to the ngadmin structure.
* @param ports A pointer to an array of chars. Must not be NULL. \n
The first element of the array is the output port (or 0 if port
int ngadmin_setMirror (struct ngadmin *nga, const char *ports) EXPORT;
-//
+/**
+ * Get the IGMP configuration.
+ * Retrieves the IGMP & multicast configuration.
+ * @note You must be logged on a switch.
+ * @param nga A pointer to the ngadmin structure.
+ * @param ic A pointer to an igmp_conf structure. Must not be NULL.
+ * @return ERR_OK when everything is well or an error code otherwise.
+ **/
int ngadmin_getIGMPConf (struct ngadmin *nga, struct igmp_conf *ic) EXPORT;
-//
+/**
+ * Set the IGMP configuration.
+ * Changes the IGMP configuration.
+ * @note You must be logged on a switch.
+ * @param nga A pointer to the ngadmin structure.
+ * @param ic A pointer to an igmp_conf structure. Must not be NULL.
+ * @return ERR_OK when everything is well or an error code otherwise.
+ **/
int ngadmin_setIGMPConf (struct ngadmin *nga, const struct igmp_conf *ic) EXPORT;
-//
+/**
+ * Perform a cable test.
+ * Performs a cable test on one ore more ports.
+ * @note Results are still raw values.
+ * @note This function takes a very long time.
+ * @note You must be logged on a switch.
+ * @param nga A pointer to the ngadmin structure.
+ * @param ct A pointer to an array of cabletest structures. Must not be NULL.
+ * @param nb The number of elements in the array.
+ * @return ERR_OK when everything is well or an error code otherwise.
+ **/
int ngadmin_cabletest (struct ngadmin *nga, struct cabletest *ct, int nb) EXPORT;
-//
+/**
+ * Set the network configuration.
+ * Changes the network configuration.
+ * @note You must be logged on a switch.
+ * @param nga A pointer to the ngadmin structure.
+ * @param nc A pointer to a net_conf structure. Must not be NULL. \n
+ Only non-zero fields of the structure are taken into account.
+ * @return ERR_OK when everything is well or an error code otherwise.
+ **/
int ngadmin_setNetConf (struct ngadmin *nga, const struct net_conf *nc) EXPORT;
-//
+/**
+ * Get the VLAN type.
+ * Retrieves the VLAN type.
+ * @note You must be logged on a switch.
+ * @param nga A pointer to the ngadmin structure.
+ * @param t A pointer to an integer which will receive the VLAN type. Must not be NULL.
+ * @return ERR_OK when everything is well or an error code otherwise.
+ **/
int ngadmin_getVLANType (struct ngadmin *nga, int *t) EXPORT;
-//
+/**
+ * Set the VLAN type.
+ * Changes the VLAN type.
+ * @note You must be logged on a switch.
+ * @param nga A pointer to the ngadmin structure.
+ * @param t An integer which contains the new VLAN type.
+ * @return ERR_OK when everything is well or an error code otherwise.
+ **/
int ngadmin_setVLANType (struct ngadmin *nga, int t) EXPORT;
-//
+/**
+ * Get all the 802.1q VLAN configuration.
+ * Retrieves all the VLAN configuration in 802.1q mode.
+ * @note The switch should be in 802.1q mode.
+ * @note You must be logged on a switch.
+ * @param nga A pointer to the ngadmin structure.
+ * @param vlans A pointer to an array of unsigned shorts which will receive
+ * VLAN ids. Must not be NULL. \n
+ * The array size must be sizeof(unsigned short)*(*nb).
+ * @param ports A pointer to an array of unsigned chars which will receive the
+ 802.1q configuration for each VLAN. Must not be NULL. \n
+ The array size must be sizeof(unsigned char)*ports_count*(*nb).
+ * @param nb A pointer to an integer which contains the maximum number of
+ elements allowed in the array. Must not be NULL. \n
+ It will receive the actual number of VLAN written in the arrays.
+ * @return ERR_OK when everything is well or an error code otherwise.
+ **/
int ngadmin_getVLANDotAllConf (struct ngadmin *nga, unsigned short *vlans, unsigned char *ports, int *nb) EXPORT;
-//
+/**
+ * Get the configuration of a VLAN in 802.1q mode.
+ * Retrieves the configuration of a particular VLAN in 802.1q mode.
+ * @note The switch should be in 802.1q mode.
+ * @note You must be logged on a switch.
+ * @param nga A pointer to the ngadmin structure.
+ * @param vlan The VLAN you want to get the configuration.
+ * @param ports A pointer to an array of integers which will receive the
+ configuration. Must not be NULL.
+ * @return ERR_OK when everything is well or an error code otherwise.
+ **/
int ngadmin_getVLANDotConf (struct ngadmin *nga, unsigned short vlan, unsigned char *ports) EXPORT;
-//
+/**
+ * Set the configuration if a VLAN in 802.1q mode.
+ * Changes the configuration of a particular VLAN in 802.1q mode.
+ * @note The switch should be in 802.1q mode.
+ * @note You must be logged on a switch.
+ * @param nga A pointer to the ngadmin structure.
+ * @param vlan The VLAN you want to change the configuration.
+ * @param ports A pointer to an array of integers which contain the
+ configuration. Must not be NULL.
+ * @return ERR_OK when everything is well or an error code otherwise.
+ **/
int ngadmin_setVLANDotConf (struct ngadmin *nga, unsigned short vlan, const unsigned char *ports) EXPORT;
-//
+/**
+ * Destroy a VLAN in 802.1q mode.
+ * Destroys a particular VLAN in 802.1q mode.
+ * @note The switch should be in 802.1q mode.
+ * @note You must be logged on a switch.
+ * @param nga A pointer to the ngadmin structure.
+ * @param vlan The VLAN you want to destroy.
+ * @return ERR_OK when everything is well or an error code otherwise.
+ **/
int ngadmin_VLANDestroy (struct ngadmin *nga, unsigned short vlan) EXPORT;
-//
+/**
+ * Get the PVID values.
+ * Retrieves the PVID values of all the ports.
+ * @note You must be logged on a switch.
+ * @param nga A pointer to the ngadmin structure.
+ * @param ports A pointer to an array of unsigned shorts which will receive the
+ * PVID values. Must not be NULL. \n
+ * The array size must be sizeof(unsigned short)*ports_count.
+ * @return ERR_OK when everything is well or an error code otherwise.
+ **/
int ngadmin_getAllPVID (struct ngadmin *nga, unsigned short *ports) EXPORT;
-//
+/**
+ * Set the PVID of one port.
+ * Changes the PVID of one port.
+ * @note You must be logged on a switch.
+ * @param nga A pointer to the ngadmin structure.
+ * @param port The port you want to change PVID.
+ * @param vlan The new PVID value.
+ * @return ERR_OK when everything is well or an error code otherwise.
+ **/
int ngadmin_setPVID (struct ngadmin *nga, unsigned char port, unsigned short vlan) EXPORT;
#define ATTR_STORM_BITRATE 0x5800
#define ATTR_MIRROR 0x5C00
#define ATTR_PORTS_COUNT 0x6000
-#define ATTR_UNK_6400 0x6400
+#define ATTR_MAX_VLAN 0x6400
#define ATTR_IGMP_ENABLE_VLAN 0x6800
#define ATTR_IGMP_BLOCK_UNK 0x6C00
#define ATTR_IGMP_VALID_V3 0x7000
-#define ATTR_UNK_7400 0x7400
+#define ATTR_TLV_BITMAP 0x7400
#define ATTR_END 0xFFFF
struct ngadmin {
// network
int sock; // socket
- struct sockaddr_in local;
+ struct sockaddr_in local; // local address & port
+ struct in_addr brd; // broadcast address
char iface[IFNAMSIZ]; // interface
struct timeval timeout; // timeout
struct ether_addr localmac; // local MAC address
bool keepbroad; // keep broadcasting
+ bool globalbroad; // use global broadcast address (255.255.255.255)
//
char password[PASSWORD_MAX]; // password to use to login on switches
struct swi_attr *swi_tab; // array of detected switches
return nga->sock;
}
+ /*
// get the interface IP address
if ( (ret=ioctl(nga->sock, SIOCGIFADDR, &ifr))<0 ) {
perror("ioctl(SIOCGIFADDR)");
close(nga->sock);
return ret;
}
+ */
/*
Here we have a problem: when you have multiple interfaces, sending a packet to
255.255.255.255 may not send it to the interface you want. If you bind() to
*/
//local.sin_addr=(*(struct sockaddr_in*)&ifr.ifr_addr).sin_addr; // FIXME
+ // get the interface broadcast address
+ if ( (ret=ioctl(nga->sock, SIOCGIFBRDADDR, &ifr))<0 ) {
+ perror("ioctl(SIOCGIFBRDADDR)");
+ close(nga->sock);
+ return ret;
+ }
+ nga->brd=(*(struct sockaddr_in*)&ifr.ifr_addr).sin_addr;
+
// get the interface MAC address
if ( (ret=ioctl(nga->sock, SIOCGIFHWADDR, &ifr))<0 ) {
perror("ioctl(SIOCGIFHWADDR)");
+
np.buffer=buffer;
np.maxlen=sizeof(buffer);
initNgPacket(&np);
- initNgHeader(np.nh, code, &nga->localmac, sa==NULL ? &nullMac : &sa->mac , ++nga->seq);
+ initNgHeader(np.nh, code, &nga->localmac, sa==NULL ? NULL : &sa->mac , ++nga->seq);
if ( attr!=NULL ) {
for (ln=attr->first; ln!=NULL; ln=ln->next) {
memset(&remote, 0, sizeof(struct sockaddr_in));
remote.sin_family=AF_INET;
- remote.sin_addr.s_addr= sa==NULL || nga->keepbroad ? htonl(INADDR_BROADCAST) : sa->nc.ip.s_addr ;
remote.sin_port=htons(SWITCH_PORT);
+ if ( sa!=NULL && !nga->keepbroad ) remote.sin_addr=sa->nc.ip;
+ else if ( nga->globalbroad ) remote.sin_addr.s_addr=htonl(INADDR_BROADCAST);
+ else remote.sin_addr=nga->brd;
+
+
if ( (ret=sendto(nga->sock, buffer, getPacketTotalSize(&np), 0, (struct sockaddr*)&remote, sizeof(struct sockaddr_in)))<0 ) {
perror("sendto");
}
-// -------------------------------------------------------------------------------------------------------------
-int recvNgPacket (struct ngadmin *nga, char code, unsigned short *error, unsigned short *attr_error, List *attr) {
+// ------------------------------------------------------------------------------------------------------------
+int recvNgPacket (struct ngadmin *nga, char code, unsigned char *error, unsigned short *attr_error, List *attr) {
char buffer[1500];
struct ng_packet np;
-int checkErrorCode (unsigned short err, unsigned short attr_error) {
+int checkErrorCode (unsigned char err, unsigned short attr_error) {
- if ( err==0x0700 && attr_error==ATTR_PASSWORD ) {
+ if ( err==ERROR_INVALID_PASSWORD && attr_error==ATTR_PASSWORD ) {
return ERR_BADPASS;
}
- if ( err==0x0500 ) {
+ if ( err==ERROR_INVALID_VALUE ) {
return ERR_INVARG;
}
int readRequest (struct ngadmin *nga, List *attr) {
int i, ret=ERR_OK;
- unsigned short err, attr_error;
+ unsigned char err;
+ unsigned short attr_error;
if ( nga==NULL ) {
int writeRequest (struct ngadmin *nga, List *attr) {
int i, ret=ERR_OK;
- unsigned short err, attr_error;
+ unsigned char err;
+ unsigned short attr_error;
if ( nga==NULL ) {
int sendNgPacket (struct ngadmin *nga, char code, const List *attr);
//
-int recvNgPacket (struct ngadmin *nga, char code, unsigned short *error, unsigned short *attr_error, List *attr);
+int recvNgPacket (struct ngadmin *nga, char code, unsigned char *error, unsigned short *attr_error, List *attr);
//
int readRequest (struct ngadmin *nga, List *attr);
+// -------------------------------------------------------------
+int ngadmin_useGlobalBroadcast (struct ngadmin *nga, bool value) {
+
+
+ if ( nga==NULL ) {
+ return ERR_INVARG;
+ }
+
+
+ nga->globalbroad=value;
+
+
+ return ERR_OK;
+
+}
+
+
+
// ------------------------------------------------------------
int ngadmin_setPassword (struct ngadmin *nga, const char *pass) {
pushBackList(attr, newAttr(ATTR_PASSWORD, strlen(nga->password), strdup(nga->password)));
if ( (ret=readRequest(nga, attr))==ERR_OK ) {
// login succeeded
- // TODO: if keep broadcasting is disabled, connect() the UDP socket so icmp errors messages (port unreachable, TTL exceeded in transit, ...)can be received
+ // TODO: if keep broadcasting is disabled, connect() the UDP socket so icmp errors messages (port unreachable, TTL exceeded in transit, ...) can be received
} else {
// login failed
nga->current=NULL;
+// --------------------------------------------------------------------
+int ngadmin_upgradeFirmware (struct ngadmin *nga, const char *filename) {
+
+
+ if ( nga==NULL || filename==NULL || *filename==0 ) {
+ return ERR_INVARG;
+ } else if ( nga->current==NULL ) {
+ return ERR_NOTLOG;
+ }
+
+
+ /*
+ Firmware upgrade is not yet implemented.
+ This would require much more work and the use of a TFTP client.
+ Overall, it could be quite dangerous, as the switch may not check the binary
+ content sent to it.
+ */
+
+ return ERR_NOTIMPL;
+
+}
+
+
+
// -------------------------------------------------------------------
int ngadmin_getPortsStatus (struct ngadmin *nga, unsigned char *ports) {
for (ln=attr->first; ln!=NULL; ln=ln->next) {
at=ln->data;
p=at->data;
- if ( *nb>=total ) break; // no more room
if ( at->attr==ATTR_VLAN_DOT_CONF && at->size>=4 ) {
for (i=0; i<sa->ports; ++i) {
if ( (p[3]>>(7-i))&1 ) ports[i]=VLAN_TAGGED; // tagged
}
*vlans++=ntohs(*(unsigned short*)p);
ports+=sa->ports;
- ++*nb;
+ if ( ++*nb>total ) break; // no more room
}
}
// if all is to be changed, we do not need to read old config
if ( memchr(ports, VLAN_UNSPEC, sa->ports)!=NULL ) {
- attr=createEmptyList();
pushBackList(attr, newShortAttr(ATTR_VLAN_DOT_CONF, vlan));
if ( (ret=readRequest(nga, attr))!=ERR_OK ) {
goto end;
pushBackList(attr, newAttr(ATTR_VLAN_PVID, 3, p));
- return writeRequest(nga, attr);;
+ return writeRequest(nga, attr);
}
-
-const struct ether_addr nullMac={.ether_addr_octet={0, 0, 0, 0, 0, 0}};
-
-
-
-
// ----------------------------
int trim (char *txt, int start) {
memset(nh, 0, sizeof(struct ng_header));
- nh->unk1=1;
+ nh->version=1;
nh->code=code;
memcpy(nh->client_mac, client_mac, ETH_ALEN);
bool validateNgHeader (const struct ng_header *nh, char code, const struct ether_addr *client_mac, const struct ether_addr *switch_mac, unsigned int seqnum) {
- if ( nh->unk1!=1 ) {
+ if ( nh->version!=1 ) {
return false;
}
return false;
}
+ if ( nh->unk1!=0 ) {
+ return false;
+ }
+
if ( *(unsigned short*)nh->unk2!=0 ) {
return false;
}
-// ---------------------------------------------------------------------------------------------------------------
-void extractPacketAttributes (struct ng_packet *np, unsigned short *error, unsigned short *attr_error, List *attr) {
+// --------------------------------------------------------------------------------------------------------------
+void extractPacketAttributes (struct ng_packet *np, unsigned char *error, unsigned short *attr_error, List *attr) {
struct attr *at;
- if ( error!=NULL ) *error=ntohs(np->nh->error);
+ if ( error!=NULL ) *error=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, maybe version
+ char version; // 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 char error; // error code, 0 when no error
+ unsigned char unk1; // always 0, unknown
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
-extern const struct ether_addr nullMac;
-
-
-
//
int trim (char *txt, int start);
void freeAttr (struct attr *at);
//
-void extractPacketAttributes (struct ng_packet *np, unsigned short *error, unsigned short *attr_error, List *attr);
+void extractPacketAttributes (struct ng_packet *np, unsigned char *error, unsigned short *attr_error, List *attr);
//
void extractSwitchAttributes (struct swi_attr *sa, const List *l);
local status_codes={
[0]="down",
+ [1]="10M",
[4]="100M",
[5]="1000M"
}
[0x5800]={name="Broadcast Filtering Bitrate", dissect=dissect_bitrate},
[0x5C00]={name="Mirror", dissect=dissect_mirror},
[0x6000]={name="Ports Count", dissect="uint"},
+ [0x6400]={name="Max 802.1Q VLAN Group", dissect=nil},
[0x6800]={name="IGMP Enable & VLAN", dissect=dissect_igmp_enablevlan},
[0x6C00]={name="Block Unknown IGMP Addresses", dissect="uint"},
[0x7000]={name="Validate IGMPv3 Headers", dissect="uint"},
+ [0x7400]={name="TLV Bitmap", dissect=nil},
[0xFFFF]={name="End", dissect=nil}
}