X-Git-Url: https://git.tcpdump.org/tcpdump/blobdiff_plain/2c2ad4f4ae108fffd2b1f1ee963d183ef62ca149..HEAD:/print-macsec.c diff --git a/print-macsec.c b/print-macsec.c index e5030588..5fca3922 100644 --- a/print-macsec.c +++ b/print-macsec.c @@ -21,17 +21,12 @@ /* \summary: MACsec printer */ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif +#include -#include - -#include +#include "netdissect-stdinc.h" #include "netdissect.h" #include "addrtoname.h" -#include "ethertype.h" #include "extract.h" #define MACSEC_DEFAULT_ICV_LEN 16 @@ -89,9 +84,31 @@ static const struct tok macsec_flag_values[] = { { 0, NULL } }; +static void +macsec_print_header(netdissect_options *ndo, + const struct macsec_sectag *sectag, + u_int short_length) +{ + ND_PRINT("an %u, pn %u, flags %s", + GET_U_1(sectag->tci_an) & MACSEC_AN_MASK, + GET_BE_U_4(sectag->packet_number), + bittok2str_nosep(macsec_flag_values, "none", + GET_U_1(sectag->tci_an) & MACSEC_TCI_FLAGS)); + + if (short_length != 0) + ND_PRINT(", sl %u", short_length); + + if (GET_U_1(sectag->tci_an) & MACSEC_TCI_SC) + ND_PRINT(", sci " SCI_FMT, GET_BE_U_8(sectag->secure_channel_id)); + + ND_PRINT(", "); +} + /* returns < 0 iff the packet can be decoded completely */ -int macsec_print(netdissect_options *ndo, const u_char **bp, - u_int *lengthp, u_int *caplenp, u_int *hdrlenp) +int +macsec_print(netdissect_options *ndo, const u_char **bp, + u_int *lengthp, u_int *caplenp, u_int *hdrlenp, + const struct lladdr_info *src, const struct lladdr_info *dst) { const char *save_protocol; const u_char *p = *bp; @@ -100,9 +117,10 @@ int macsec_print(netdissect_options *ndo, const u_char **bp, u_int hdrlen = *hdrlenp; const struct macsec_sectag *sectag = (const struct macsec_sectag *)p; u_int sectag_len; + u_int short_length; save_protocol = ndo->ndo_protocol; - ndo->ndo_protocol = "MACsec"; + ndo->ndo_protocol = "macsec"; /* we need the full MACsec header in the capture */ if (caplen < MACSEC_SECTAG_LEN_NOSCI) { @@ -110,6 +128,11 @@ int macsec_print(netdissect_options *ndo, const u_char **bp, ndo->ndo_protocol = save_protocol; return hdrlen + caplen; } + if (length < MACSEC_SECTAG_LEN_NOSCI) { + nd_print_trunc(ndo); + ndo->ndo_protocol = save_protocol; + return hdrlen + caplen; + } if (GET_U_1(sectag->tci_an) & MACSEC_TCI_SC) { sectag_len = MACSEC_SECTAG_LEN_SCI; @@ -118,31 +141,24 @@ int macsec_print(netdissect_options *ndo, const u_char **bp, ndo->ndo_protocol = save_protocol; return hdrlen + caplen; } + if (length < MACSEC_SECTAG_LEN_SCI) { + nd_print_trunc(ndo); + ndo->ndo_protocol = save_protocol; + return hdrlen + caplen; + } } else sectag_len = MACSEC_SECTAG_LEN_NOSCI; - if ((GET_U_1(sectag->short_length) & ~MACSEC_SL_MASK) != 0 || + if ((GET_U_1(sectag->short_length) & ~MACSEC_SL_MASK) != 0 || GET_U_1(sectag->tci_an) & MACSEC_TCI_VERSION) { nd_print_invalid(ndo); ndo->ndo_protocol = save_protocol; return hdrlen + caplen; } - if (ndo->ndo_eflag) { - ND_PRINT("an %u, pn %u, flags %s", - GET_U_1(sectag->tci_an) & MACSEC_AN_MASK, - GET_BE_U_4(sectag->packet_number), - bittok2str_nosep(macsec_flag_values, "none", - GET_U_1(sectag->tci_an) & MACSEC_TCI_FLAGS)); - - if ((GET_U_1(sectag->short_length) & MACSEC_SL_MASK) != 0) - ND_PRINT(", sl %u", GET_U_1(sectag->short_length) & MACSEC_SL_MASK); - - if (GET_U_1(sectag->tci_an) & MACSEC_TCI_SC) - ND_PRINT(", sci " SCI_FMT, GET_BE_U_8(sectag->secure_channel_id)); - - ND_PRINT(", "); - } + short_length = GET_U_1(sectag->short_length) & MACSEC_SL_MASK; + if (ndo->ndo_eflag) + macsec_print_header(ndo, sectag, short_length); /* Skip the MACsec header. */ *bp += sectag_len; @@ -154,20 +170,86 @@ int macsec_print(netdissect_options *ndo, const u_char **bp, if ((GET_U_1(sectag->tci_an) & MACSEC_TCI_CONFID)) { /* - * The payload is encrypted. Tell our - * caller it can't be dissected. + * The payload is encrypted. Print link-layer + * information, if it hasn't already been printed. + */ + if (!ndo->ndo_eflag) { + /* + * Nobody printed the link-layer addresses, + * so print them, if we have any. + */ + if (src != NULL && dst != NULL) { + ND_PRINT("%s > %s ", + (src->addr_string)(ndo, src->addr), + (dst->addr_string)(ndo, dst->addr)); + } + + ND_PRINT("802.1AE MACsec, "); + + /* + * Print the MACsec header. + */ + macsec_print_header(ndo, sectag, short_length); + } + + /* + * Tell our caller it can't be dissected. */ ndo->ndo_protocol = save_protocol; return 0; - } else { + } + + /* + * The payload isn't encrypted; remove the + * ICV length from the lengths, so our caller + * doesn't treat it as payload. + */ + if (*lengthp < MACSEC_DEFAULT_ICV_LEN) { + nd_print_trunc(ndo); + ndo->ndo_protocol = save_protocol; + return hdrlen + caplen; + } + if (*caplenp < MACSEC_DEFAULT_ICV_LEN) { + nd_print_trunc(ndo); + ndo->ndo_protocol = save_protocol; + return hdrlen + caplen; + } + *lengthp -= MACSEC_DEFAULT_ICV_LEN; + *caplenp -= MACSEC_DEFAULT_ICV_LEN; + /* + * Update the snapend thus the ICV field is not in the payload for + * the caller. + * The ICV (Integrity Check Value) is at the end of the frame, after + * the secure data. + */ + ndo->ndo_snapend -= MACSEC_DEFAULT_ICV_LEN; + + /* + * If the SL field is non-zero, then it's the length of the + * Secure Data; otherwise, the Secure Data is what's left + * ver after the MACsec header and ICV are removed. + */ + if (short_length != 0) { /* - * The payload isn't encrypted; remove the - * ICV length from the lengths, so our caller - * doesn't treat it as payload. + * If the short length is more than we *have*, + * that's an error. */ - *lengthp -= MACSEC_DEFAULT_ICV_LEN; - *caplenp -= MACSEC_DEFAULT_ICV_LEN; - ndo->ndo_protocol = save_protocol; - return -1; + if (short_length > *lengthp) { + nd_print_trunc(ndo); + ndo->ndo_protocol = save_protocol; + return hdrlen + caplen; + } + if (short_length > *caplenp) { + nd_print_trunc(ndo); + ndo->ndo_protocol = save_protocol; + return hdrlen + caplen; + } + if (*lengthp > short_length) + *lengthp = short_length; + if (*caplenp > short_length) + *caplenp = short_length; } + + ndo->ndo_protocol = save_protocol; + return -1; }