Writing a blog post is hard. “I’ll do it later,” I keep thinking. Maybe it’s like flossing–“I’ll do it later.” Next thing I know I’m spraying blood onto the ceiling while the hygienist tut-tuts about my bad habits. I floss (write) now and my future self will thank me.
I’m tinkering with nl80211, the successor to WEXT. WEXT is the Linux Wireless Extensions, a set of standardized ioctl for communicating userspace to the kernel level wireless drivers. WEXT is amazing but limited so the smart people got together and created a much more flexible system around NetLink.
As I’m tinkering with nl80211, I discover a frustrating extensive use of C enum. Using C enum in a network protocol is frustrating because with a large enum (say, greater than 10 elements), converting from an integer in a debug message back to the actual enum is well nigh impossible.
Case in point, the nl80211.h enum nl80211_attrs is ~400 lines and about 260 elements. In my little nl80211 baby-steps code, I fetch NL80211_CMD_GET_INTERFACE and get back an array filled with attribute + value.
int i; for (i=0 ; i<NL80211_ATTR_MAX ; i++ ) { if (tb_msg[i]) { printf("%d=%p type=%d len=%d\n", i, (void *)tb_msg[i], nla_type(tb_msg[i]), nla_len(tb_msg[i])); hex_dump("msg", (unsigned char *)tb_msg[i], nla_len(tb_msg[i])); } }
Again this is baby steps code. I have no idea what I’m actually doing. I’m poking the box.
46=0x14db108 type=46 len=4 msg 0x00001080 08 00 2e 00 .... 206=0x14db110 type=206 len=1 msg 0x00001090 05 . 217=0x14db120 type=217 len=4 msg 0x000010a0 08 00 d9 00 .... 256=0x14db118 type=256 len=4 msg 0x000010b0 08 00 00 01 ....
Now I have a list of attributes coming back from the call. What the foo is 217? 256? A visit to gdb will give me answers! The last element in the enum is NL80211_ATTR_PORT_AUTHORIZED so what is its value? First print the symbol, gives me the symbol. Print as hex (p/x) and as decimal (p/d) shows me the numerical value.
(gdb) p NL80211_ATTR_PORT_AUTHORIZED $1 = NL80211_ATTR_PORT_AUTHORIZED (gdb) p/x NL80211_ATTR_PORT_AUTHORIZED $2 = 0x103 (gdb) p/d NL80211_ATTR_PORT_AUTHORIZED $3 = 259
To find the symbol value of my integer, I can do the reverse in gdb. The typecast will convert an integer to the enum type.
(gdb) p (enum nl80211_attrs)46 $6 = NL80211_ATTR_GENERATION (gdb) p (enum nl80211_attrs)206 $7 = NL80211_ATTR_MAX_CSA_COUNTERS (gdb) p (enum nl80211_attrs)217 $8 = NL80211_ATTR_EXT_FEATURES (gdb) p (enum nl80211_attrs)256 $9 = NL80211_ATTR_SCHED_SCAN_MAX_REQS
Having to dig into gdb for every enum in nl80211.h will be tiring. The problems grow in other header files that are nests of #ifdefs.
I me personally prefer using #define for symbols like this. The explicit link of a symbol to a value in source form is helpful.
Pingback: Parsing C ‘enum’ with Python Regex. | A Linux Lizard