+ static const char *rtpref_str[] = {
+ "medium", /* 00 */
+ "high", /* 01 */
+ "rsv", /* 10 */
+ "low" /* 11 */
+ };
+
+ return rtpref_str[((v & ND_RA_FLAG_RTPREF_MASK) >> 3) & 0xff];
+}
+
+static const char *
+get_lifetime(uint32_t v)
+{
+ static char buf[20];
+
+ if (v == (uint32_t)~0UL)
+ return "infinity";
+ else {
+ snprintf(buf, sizeof(buf), "%us", v);
+ return buf;
+ }
+}
+
+static void
+print_lladdr(netdissect_options *ndo, const uint8_t *p, size_t l)
+{
+ const uint8_t *ep, *q;
+
+ q = p;
+ ep = p + l;
+ while (l > 0 && q < ep) {
+ if (q > p)
+ ND_PRINT((ndo,":"));
+ ND_PRINT((ndo,"%02x", EXTRACT_U_1(q)));
+ q++;
+ l--;
+ }
+}
+
+static int icmp6_cksum(netdissect_options *ndo, const struct ip6_hdr *ip6,
+ const struct icmp6_hdr *icp, u_int len)
+{
+ return nextproto6_cksum(ndo, ip6, (const uint8_t *)(const void *)icp, len, len,
+ IPPROTO_ICMPV6);
+}
+
+static const struct tok rpl_mop_values[] = {
+ { RPL_DIO_NONSTORING, "nonstoring"},
+ { RPL_DIO_STORING, "storing"},
+ { RPL_DIO_NONSTORING_MULTICAST, "nonstoring-multicast"},
+ { RPL_DIO_STORING_MULTICAST, "storing-multicast"},
+ { 0, NULL},
+};
+
+static const struct tok rpl_subopt_values[] = {
+ { RPL_OPT_PAD0, "pad0"},
+ { RPL_OPT_PADN, "padN"},
+ { RPL_DIO_METRICS, "metrics"},
+ { RPL_DIO_ROUTINGINFO, "routinginfo"},
+ { RPL_DIO_CONFIG, "config"},
+ { RPL_DAO_RPLTARGET, "rpltarget"},
+ { RPL_DAO_TRANSITINFO, "transitinfo"},
+ { RPL_DIO_DESTPREFIX, "destprefix"},
+ { RPL_DAO_RPLTARGET_DESC, "rpltargetdesc"},
+ { 0, NULL},
+};
+
+static void
+rpl_dio_printopt(netdissect_options *ndo,
+ const struct rpl_dio_genoption *opt,
+ u_int length)
+{
+ if(length < RPL_DIO_GENOPTION_LEN) return;
+ length -= RPL_DIO_GENOPTION_LEN;
+
+ ND_TCHECK(opt->rpl_dio_len);
+
+ while((opt->rpl_dio_type == RPL_OPT_PAD0 &&
+ (const u_char *)opt < ndo->ndo_snapend) ||
+ ND_TTEST2(*opt,(opt->rpl_dio_len+2))) {
+
+ unsigned int optlen = opt->rpl_dio_len+2;
+ if(opt->rpl_dio_type == RPL_OPT_PAD0) {
+ optlen = 1;
+ ND_PRINT((ndo, " opt:pad0"));
+ } else {
+ ND_PRINT((ndo, " opt:%s len:%u ",
+ tok2str(rpl_subopt_values, "subopt:%u", opt->rpl_dio_type),
+ optlen));
+ if(ndo->ndo_vflag > 2) {
+ unsigned int paylen = opt->rpl_dio_len;
+ if(paylen > length) paylen = length;
+ hex_print(ndo,
+ " ",
+ ((const uint8_t *)opt) + RPL_DIO_GENOPTION_LEN, /* content of DIO option */
+ paylen);
+ }
+ }
+ opt = (const struct rpl_dio_genoption *)(((const char *)opt) + optlen);
+ length -= optlen;
+ }
+ return;
+trunc:
+ ND_PRINT((ndo," [|truncated]"));
+ return;
+}
+
+static void
+rpl_dio_print(netdissect_options *ndo,
+ const u_char *bp, u_int length)
+{
+ const struct nd_rpl_dio *dio = (const struct nd_rpl_dio *)bp;
+ const char *dagid_str;
+
+ ND_TCHECK(*dio);
+ dagid_str = ip6addr_string (ndo, dio->rpl_dagid);
+
+ ND_PRINT((ndo, " [dagid:%s,seq:%u,instance:%u,rank:%u,%smop:%s,prf:%u]",
+ dagid_str,
+ dio->rpl_dtsn,
+ dio->rpl_instanceid,
+ EXTRACT_BE_U_2(&dio->rpl_dagrank),
+ RPL_DIO_GROUNDED(dio->rpl_mopprf) ? "grounded,":"",
+ tok2str(rpl_mop_values, "mop%u", RPL_DIO_MOP(dio->rpl_mopprf)),
+ RPL_DIO_PRF(dio->rpl_mopprf)));
+
+ if(ndo->ndo_vflag > 1) {
+ const struct rpl_dio_genoption *opt = (const struct rpl_dio_genoption *)&dio[1];
+ rpl_dio_printopt(ndo, opt, length);
+ }
+ return;
+trunc:
+ ND_PRINT((ndo," [|truncated]"));
+ return;
+}
+
+static void
+rpl_dao_print(netdissect_options *ndo,
+ const u_char *bp, u_int length)
+{
+ const struct nd_rpl_dao *dao = (const struct nd_rpl_dao *)bp;
+ const char *dagid_str = "<elided>";
+
+ ND_TCHECK(*dao);
+ if (length < ND_RPL_DAO_MIN_LEN)
+ goto tooshort;
+
+ bp += ND_RPL_DAO_MIN_LEN;
+ length -= ND_RPL_DAO_MIN_LEN;
+ if(RPL_DAO_D(dao->rpl_flags)) {
+ ND_TCHECK2(dao->rpl_dagid, DAGID_LEN);
+ if (length < DAGID_LEN)
+ goto tooshort;
+ dagid_str = ip6addr_string (ndo, dao->rpl_dagid);
+ bp += DAGID_LEN;
+ length -= DAGID_LEN;
+ }
+
+ ND_PRINT((ndo, " [dagid:%s,seq:%u,instance:%u%s%s,%02x]",
+ dagid_str,
+ dao->rpl_daoseq,
+ dao->rpl_instanceid,
+ RPL_DAO_K(dao->rpl_flags) ? ",acK":"",
+ RPL_DAO_D(dao->rpl_flags) ? ",Dagid":"",
+ dao->rpl_flags));
+
+ if(ndo->ndo_vflag > 1) {
+ const struct rpl_dio_genoption *opt = (const struct rpl_dio_genoption *)bp;
+ rpl_dio_printopt(ndo, opt, length);
+ }
+ return;
+
+trunc:
+ ND_PRINT((ndo," [|truncated]"));
+ return;
+
+tooshort:
+ ND_PRINT((ndo," [|length too short]"));
+ return;
+}
+
+static void
+rpl_daoack_print(netdissect_options *ndo,
+ const u_char *bp, u_int length)
+{
+ const struct nd_rpl_daoack *daoack = (const struct nd_rpl_daoack *)bp;
+ const char *dagid_str = "<elided>";
+
+ ND_TCHECK2(*daoack, ND_RPL_DAOACK_MIN_LEN);
+ if (length < ND_RPL_DAOACK_MIN_LEN)
+ goto tooshort;
+
+ bp += ND_RPL_DAOACK_MIN_LEN;
+ length -= ND_RPL_DAOACK_MIN_LEN;
+ if(RPL_DAOACK_D(daoack->rpl_flags)) {
+ ND_TCHECK2(daoack->rpl_dagid, DAGID_LEN);
+ if (length < DAGID_LEN)
+ goto tooshort;
+ dagid_str = ip6addr_string (ndo, daoack->rpl_dagid);
+ bp += DAGID_LEN;
+ length -= DAGID_LEN;
+ }
+
+ ND_PRINT((ndo, " [dagid:%s,seq:%u,instance:%u,status:%u]",
+ dagid_str,
+ daoack->rpl_daoseq,
+ daoack->rpl_instanceid,
+ daoack->rpl_status));
+
+ /* no officially defined options for DAOACK, but print any we find */
+ if(ndo->ndo_vflag > 1) {
+ const struct rpl_dio_genoption *opt = (const struct rpl_dio_genoption *)bp;
+ rpl_dio_printopt(ndo, opt, length);
+ }
+ return;
+
+trunc:
+ ND_PRINT((ndo," [|dao-truncated]"));
+ return;
+
+tooshort:
+ ND_PRINT((ndo," [|dao-length too short]"));
+ return;
+}
+
+static void
+rpl_print(netdissect_options *ndo,
+ const struct icmp6_hdr *hdr,
+ const u_char *bp, u_int length)
+{
+ int secured = hdr->icmp6_code & 0x80;
+ int basecode= hdr->icmp6_code & 0x7f;
+
+ if(secured) {
+ ND_PRINT((ndo, ", (SEC) [worktodo]"));
+ /* XXX
+ * the next header pointer needs to move forward to
+ * skip the secure part.
+ */
+ return;
+ } else {
+ ND_PRINT((ndo, ", (CLR)"));
+ }
+
+ switch(basecode) {
+ case ND_RPL_DAG_IS:
+ ND_PRINT((ndo, "DODAG Information Solicitation"));
+ if(ndo->ndo_vflag) {
+ }
+ break;
+ case ND_RPL_DAG_IO:
+ ND_PRINT((ndo, "DODAG Information Object"));
+ if(ndo->ndo_vflag) {
+ rpl_dio_print(ndo, bp, length);
+ }
+ break;
+ case ND_RPL_DAO:
+ ND_PRINT((ndo, "Destination Advertisement Object"));
+ if(ndo->ndo_vflag) {
+ rpl_dao_print(ndo, bp, length);
+ }
+ break;
+ case ND_RPL_DAO_ACK:
+ ND_PRINT((ndo, "Destination Advertisement Object Ack"));
+ if(ndo->ndo_vflag) {
+ rpl_daoack_print(ndo, bp, length);
+ }
+ break;
+ default:
+ ND_PRINT((ndo, "RPL message, unknown code %u",hdr->icmp6_code));
+ break;
+ }
+ return;