13340d773SGleb Smirnoff /* 23340d773SGleb Smirnoff * Copyright (c) 1988-1997 33340d773SGleb Smirnoff * The Regents of the University of California. All rights reserved. 43340d773SGleb Smirnoff * 53340d773SGleb Smirnoff * Copyright (c) 1998-2012 Michael Richardson <mcr@tcpdump.org> 63340d773SGleb Smirnoff * The TCPDUMP project 73340d773SGleb Smirnoff * 83340d773SGleb Smirnoff * Redistribution and use in source and binary forms, with or without 93340d773SGleb Smirnoff * modification, are permitted provided that: (1) source code distributions 103340d773SGleb Smirnoff * retain the above copyright notice and this paragraph in its entirety, (2) 113340d773SGleb Smirnoff * distributions including binary code include the above copyright notice and 123340d773SGleb Smirnoff * this paragraph in its entirety in the documentation or other materials 133340d773SGleb Smirnoff * provided with the distribution, and (3) all advertising materials mentioning 143340d773SGleb Smirnoff * features or use of this software display the following acknowledgement: 153340d773SGleb Smirnoff * ``This product includes software developed by the University of California, 163340d773SGleb Smirnoff * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 173340d773SGleb Smirnoff * the University nor the names of its contributors may be used to endorse 183340d773SGleb Smirnoff * or promote products derived from this software without specific prior 193340d773SGleb Smirnoff * written permission. 203340d773SGleb Smirnoff * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 213340d773SGleb Smirnoff * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 223340d773SGleb Smirnoff * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 233340d773SGleb Smirnoff */ 243340d773SGleb Smirnoff 25ee67461eSJoseph Mingrone #include <config.h> 263340d773SGleb Smirnoff 27ee67461eSJoseph Mingrone #include "netdissect-stdinc.h" 283340d773SGleb Smirnoff #include "netdissect.h" 293340d773SGleb Smirnoff #include <string.h> 303340d773SGleb Smirnoff #include <stdio.h> 31ee67461eSJoseph Mingrone #include <stdlib.h> 323340d773SGleb Smirnoff 333340d773SGleb Smirnoff #ifdef USE_LIBSMI 343340d773SGleb Smirnoff #include <smi.h> 353340d773SGleb Smirnoff #endif 363340d773SGleb Smirnoff 373340d773SGleb Smirnoff /* 383340d773SGleb Smirnoff * Initialize anything that must be initialized before dissecting 393340d773SGleb Smirnoff * packets. 403340d773SGleb Smirnoff * 413340d773SGleb Smirnoff * This should be called at the beginning of the program; it does 423340d773SGleb Smirnoff * not need to be called, and should not be called, for every 433340d773SGleb Smirnoff * netdissect_options structure. 443340d773SGleb Smirnoff */ 453340d773SGleb Smirnoff int 463340d773SGleb Smirnoff nd_init(char *errbuf, size_t errbuf_size) 473340d773SGleb Smirnoff { 483340d773SGleb Smirnoff #ifdef _WIN32 493340d773SGleb Smirnoff WORD wVersionRequested; 503340d773SGleb Smirnoff WSADATA wsaData; 513340d773SGleb Smirnoff int err; 523340d773SGleb Smirnoff 533340d773SGleb Smirnoff /* 543340d773SGleb Smirnoff * Request Winsock 2.2; we expect Winsock 2. 553340d773SGleb Smirnoff */ 563340d773SGleb Smirnoff wVersionRequested = MAKEWORD(2, 2); 573340d773SGleb Smirnoff err = WSAStartup(wVersionRequested, &wsaData); 583340d773SGleb Smirnoff if (err != 0) { 593340d773SGleb Smirnoff strlcpy(errbuf, "Attempting to initialize Winsock failed", 603340d773SGleb Smirnoff errbuf_size); 613340d773SGleb Smirnoff return (-1); 623340d773SGleb Smirnoff } 633340d773SGleb Smirnoff #endif /* _WIN32 */ 643340d773SGleb Smirnoff 653340d773SGleb Smirnoff #ifdef USE_LIBSMI 663340d773SGleb Smirnoff /* 673340d773SGleb Smirnoff * XXX - should we just fail if this fails? Some of the 683340d773SGleb Smirnoff * libsmi calls may fail. 693340d773SGleb Smirnoff */ 703340d773SGleb Smirnoff smiInit("tcpdump"); 713340d773SGleb Smirnoff #endif 723340d773SGleb Smirnoff 733340d773SGleb Smirnoff /* 743340d773SGleb Smirnoff * Clears the error buffer, and uses it so we don't get 753340d773SGleb Smirnoff * "unused argument" warnings at compile time. 763340d773SGleb Smirnoff */ 773340d773SGleb Smirnoff strlcpy(errbuf, "", errbuf_size); 783340d773SGleb Smirnoff return (0); 793340d773SGleb Smirnoff } 803340d773SGleb Smirnoff 813340d773SGleb Smirnoff /* 823340d773SGleb Smirnoff * Clean up anything that ndo_init() did. 833340d773SGleb Smirnoff */ 843340d773SGleb Smirnoff void 853340d773SGleb Smirnoff nd_cleanup(void) 863340d773SGleb Smirnoff { 873340d773SGleb Smirnoff #ifdef USE_LIBSMI 883340d773SGleb Smirnoff /* 893340d773SGleb Smirnoff * This appears, in libsmi 0.4.8, to do nothing if smiInit() 903340d773SGleb Smirnoff * wasn't done or failed, so we call it unconditionally. 913340d773SGleb Smirnoff */ 923340d773SGleb Smirnoff smiExit(); 933340d773SGleb Smirnoff #endif 943340d773SGleb Smirnoff 953340d773SGleb Smirnoff #ifdef _WIN32 963340d773SGleb Smirnoff /* 973340d773SGleb Smirnoff * Undo the WSAStartup() call above. 983340d773SGleb Smirnoff */ 993340d773SGleb Smirnoff WSACleanup(); 1003340d773SGleb Smirnoff #endif 1013340d773SGleb Smirnoff } 1023340d773SGleb Smirnoff 1033340d773SGleb Smirnoff int 1043340d773SGleb Smirnoff nd_have_smi_support(void) 1053340d773SGleb Smirnoff { 1063340d773SGleb Smirnoff #ifdef USE_LIBSMI 1073340d773SGleb Smirnoff return (1); 1083340d773SGleb Smirnoff #else 1093340d773SGleb Smirnoff return (0); 1103340d773SGleb Smirnoff #endif 1113340d773SGleb Smirnoff } 1123340d773SGleb Smirnoff 1133340d773SGleb Smirnoff /* 1143340d773SGleb Smirnoff * Indicates whether an SMI module has been loaded, so that we can use 1153340d773SGleb Smirnoff * libsmi to translate OIDs. 1163340d773SGleb Smirnoff */ 1173340d773SGleb Smirnoff int nd_smi_module_loaded; 1183340d773SGleb Smirnoff 1193340d773SGleb Smirnoff int 1203340d773SGleb Smirnoff nd_load_smi_module(const char *module, char *errbuf, size_t errbuf_size) 1213340d773SGleb Smirnoff { 1223340d773SGleb Smirnoff #ifdef USE_LIBSMI 1233340d773SGleb Smirnoff if (smiLoadModule(module) == 0) { 1243340d773SGleb Smirnoff snprintf(errbuf, errbuf_size, "could not load MIB module %s", 1253340d773SGleb Smirnoff module); 1263340d773SGleb Smirnoff return (-1); 1273340d773SGleb Smirnoff } 1283340d773SGleb Smirnoff nd_smi_module_loaded = 1; 1293340d773SGleb Smirnoff return (0); 1303340d773SGleb Smirnoff #else 1313340d773SGleb Smirnoff snprintf(errbuf, errbuf_size, "MIB module %s not loaded: no libsmi support", 1323340d773SGleb Smirnoff module); 1333340d773SGleb Smirnoff return (-1); 1343340d773SGleb Smirnoff #endif 1353340d773SGleb Smirnoff } 1363340d773SGleb Smirnoff 1373340d773SGleb Smirnoff const char * 1383340d773SGleb Smirnoff nd_smi_version_string(void) 1393340d773SGleb Smirnoff { 1403340d773SGleb Smirnoff #ifdef USE_LIBSMI 1413340d773SGleb Smirnoff return (smi_version_string); 1423340d773SGleb Smirnoff #else 1433340d773SGleb Smirnoff return (NULL); 1443340d773SGleb Smirnoff #endif 1453340d773SGleb Smirnoff } 146ee67461eSJoseph Mingrone 147ee67461eSJoseph Mingrone 148ee67461eSJoseph Mingrone int 149ee67461eSJoseph Mingrone nd_push_buffer(netdissect_options *ndo, u_char *new_buffer, 150ee67461eSJoseph Mingrone const u_char *new_packetp, const u_int newlen) 151ee67461eSJoseph Mingrone { 152ee67461eSJoseph Mingrone struct netdissect_saved_packet_info *ndspi; 153ee67461eSJoseph Mingrone 154ee67461eSJoseph Mingrone ndspi = (struct netdissect_saved_packet_info *)malloc(sizeof(struct netdissect_saved_packet_info)); 155ee67461eSJoseph Mingrone if (ndspi == NULL) 156ee67461eSJoseph Mingrone return (0); /* fail */ 157ee67461eSJoseph Mingrone ndspi->ndspi_buffer = new_buffer; 158ee67461eSJoseph Mingrone ndspi->ndspi_packetp = ndo->ndo_packetp; 159ee67461eSJoseph Mingrone ndspi->ndspi_snapend = ndo->ndo_snapend; 160ee67461eSJoseph Mingrone ndspi->ndspi_prev = ndo->ndo_packet_info_stack; 161ee67461eSJoseph Mingrone 162ee67461eSJoseph Mingrone ndo->ndo_packetp = new_packetp; 163ee67461eSJoseph Mingrone ndo->ndo_snapend = new_packetp + newlen; 164ee67461eSJoseph Mingrone ndo->ndo_packet_info_stack = ndspi; 165ee67461eSJoseph Mingrone 166ee67461eSJoseph Mingrone return (1); /* success */ 167ee67461eSJoseph Mingrone } 168ee67461eSJoseph Mingrone 169ee67461eSJoseph Mingrone 170ee67461eSJoseph Mingrone /* 171ee67461eSJoseph Mingrone * In a given netdissect_options structure: 172ee67461eSJoseph Mingrone * 173ee67461eSJoseph Mingrone * push the current packet information onto the packet information 174ee67461eSJoseph Mingrone * stack; 175ee67461eSJoseph Mingrone * 176ee67461eSJoseph Mingrone * given a pointer into the packet and a length past that point in 177ee67461eSJoseph Mingrone * the packet, calculate a new snapshot end that's at the lower 178ee67461eSJoseph Mingrone * of the current snapshot end and that point in the packet; 179ee67461eSJoseph Mingrone * 180ee67461eSJoseph Mingrone * set the snapshot end to that new value. 181ee67461eSJoseph Mingrone */ 182ee67461eSJoseph Mingrone int 183ee67461eSJoseph Mingrone nd_push_snaplen(netdissect_options *ndo, const u_char *bp, const u_int newlen) 184ee67461eSJoseph Mingrone { 185ee67461eSJoseph Mingrone struct netdissect_saved_packet_info *ndspi; 186ee67461eSJoseph Mingrone u_int snaplen_remaining; 187ee67461eSJoseph Mingrone 188ee67461eSJoseph Mingrone ndspi = (struct netdissect_saved_packet_info *)malloc(sizeof(struct netdissect_saved_packet_info)); 189ee67461eSJoseph Mingrone if (ndspi == NULL) 190ee67461eSJoseph Mingrone return (0); /* fail */ 191ee67461eSJoseph Mingrone ndspi->ndspi_buffer = NULL; /* no new buffer */ 192ee67461eSJoseph Mingrone ndspi->ndspi_packetp = ndo->ndo_packetp; 193ee67461eSJoseph Mingrone ndspi->ndspi_snapend = ndo->ndo_snapend; 194ee67461eSJoseph Mingrone ndspi->ndspi_prev = ndo->ndo_packet_info_stack; 195ee67461eSJoseph Mingrone 196ee67461eSJoseph Mingrone /* 197ee67461eSJoseph Mingrone * Push the saved previous data onto the stack. 198ee67461eSJoseph Mingrone */ 199ee67461eSJoseph Mingrone ndo->ndo_packet_info_stack = ndspi; 200ee67461eSJoseph Mingrone 201ee67461eSJoseph Mingrone /* 202ee67461eSJoseph Mingrone * Find out how many bytes remain after the current snapend. 203ee67461eSJoseph Mingrone * 204ee67461eSJoseph Mingrone * We're restricted to packets with at most UINT_MAX bytes; 205ee67461eSJoseph Mingrone * cast the result to u_int, so that we don't get truncation 206ee67461eSJoseph Mingrone * warnings on LP64 and LLP64 platforms. (ptrdiff_t is 207ee67461eSJoseph Mingrone * signed and we want an unsigned difference; the pointer 208ee67461eSJoseph Mingrone * should at most be equal to snapend, and must *never* 209ee67461eSJoseph Mingrone * be past snapend.) 210ee67461eSJoseph Mingrone */ 211ee67461eSJoseph Mingrone snaplen_remaining = (u_int)(ndo->ndo_snapend - bp); 212ee67461eSJoseph Mingrone 213ee67461eSJoseph Mingrone /* 214ee67461eSJoseph Mingrone * If the new snapend is smaller than the one calculated 215ee67461eSJoseph Mingrone * above, set the snapend to that value, otherwise leave 216ee67461eSJoseph Mingrone * it unchanged. 217ee67461eSJoseph Mingrone */ 218ee67461eSJoseph Mingrone if (newlen <= snaplen_remaining) { 219ee67461eSJoseph Mingrone /* Snapend isn't past the previous snapend */ 220ee67461eSJoseph Mingrone ndo->ndo_snapend = bp + newlen; 221ee67461eSJoseph Mingrone } 222ee67461eSJoseph Mingrone 223ee67461eSJoseph Mingrone return (1); /* success */ 224ee67461eSJoseph Mingrone } 225ee67461eSJoseph Mingrone 226ee67461eSJoseph Mingrone /* 227ee67461eSJoseph Mingrone * In a given netdissect_options structure: 228ee67461eSJoseph Mingrone * 229ee67461eSJoseph Mingrone * given a pointer into the packet and a length past that point in 230ee67461eSJoseph Mingrone * the packet, calculate a new snapshot end that's at the lower 231ee67461eSJoseph Mingrone * of the previous snapshot end - or, if there is no previous 232ee67461eSJoseph Mingrone * snapshot end, the current snapshot end - and that point in the 233ee67461eSJoseph Mingrone * packet; 234ee67461eSJoseph Mingrone * 235ee67461eSJoseph Mingrone * set the snapshot end to that new value. 236ee67461eSJoseph Mingrone * 237ee67461eSJoseph Mingrone * This is to change the current snapshot end. This may increase the 238ee67461eSJoseph Mingrone * snapshot end, as it may be used, for example, for a Jumbo Payload 239ee67461eSJoseph Mingrone * option in IPv6. It must not increase it past the snapshot length 240ee67461eSJoseph Mingrone * atop which the current one was pushed, however. 241ee67461eSJoseph Mingrone */ 242ee67461eSJoseph Mingrone void 243ee67461eSJoseph Mingrone nd_change_snaplen(netdissect_options *ndo, const u_char *bp, const u_int newlen) 244ee67461eSJoseph Mingrone { 245ee67461eSJoseph Mingrone struct netdissect_saved_packet_info *ndspi; 246ee67461eSJoseph Mingrone const u_char *previous_snapend; 247ee67461eSJoseph Mingrone u_int snaplen_remaining; 248ee67461eSJoseph Mingrone 249ee67461eSJoseph Mingrone ndspi = ndo->ndo_packet_info_stack; 250ee67461eSJoseph Mingrone if (ndspi->ndspi_prev != NULL) 251ee67461eSJoseph Mingrone previous_snapend = ndspi->ndspi_prev->ndspi_snapend; 252ee67461eSJoseph Mingrone else 253ee67461eSJoseph Mingrone previous_snapend = ndo->ndo_snapend; 254ee67461eSJoseph Mingrone 255ee67461eSJoseph Mingrone /* 256ee67461eSJoseph Mingrone * Find out how many bytes remain after the previous 257ee67461eSJoseph Mingrone * snapend - or, if there is no previous snapend, after 258ee67461eSJoseph Mingrone * the current snapend. 259ee67461eSJoseph Mingrone * 260ee67461eSJoseph Mingrone * We're restricted to packets with at most UINT_MAX bytes; 261ee67461eSJoseph Mingrone * cast the result to u_int, so that we don't get truncation 262ee67461eSJoseph Mingrone * warnings on LP64 and LLP64 platforms. (ptrdiff_t is 263ee67461eSJoseph Mingrone * signed and we want an unsigned difference; the pointer 264ee67461eSJoseph Mingrone * should at most be equal to snapend, and must *never* 265ee67461eSJoseph Mingrone * be past snapend.) 266ee67461eSJoseph Mingrone */ 267ee67461eSJoseph Mingrone snaplen_remaining = (u_int)(previous_snapend - bp); 268ee67461eSJoseph Mingrone 269ee67461eSJoseph Mingrone /* 270ee67461eSJoseph Mingrone * If the new snapend is smaller than the one calculated 271ee67461eSJoseph Mingrone * above, set the snapend to that value, otherwise leave 272ee67461eSJoseph Mingrone * it unchanged. 273ee67461eSJoseph Mingrone */ 274ee67461eSJoseph Mingrone if (newlen <= snaplen_remaining) { 275ee67461eSJoseph Mingrone /* Snapend isn't past the previous snapend */ 276ee67461eSJoseph Mingrone ndo->ndo_snapend = bp + newlen; 277ee67461eSJoseph Mingrone } 278ee67461eSJoseph Mingrone } 279ee67461eSJoseph Mingrone 280ee67461eSJoseph Mingrone void 281ee67461eSJoseph Mingrone nd_pop_packet_info(netdissect_options *ndo) 282ee67461eSJoseph Mingrone { 283ee67461eSJoseph Mingrone struct netdissect_saved_packet_info *ndspi; 284ee67461eSJoseph Mingrone 285ee67461eSJoseph Mingrone ndspi = ndo->ndo_packet_info_stack; 286ee67461eSJoseph Mingrone ndo->ndo_packetp = ndspi->ndspi_packetp; 287ee67461eSJoseph Mingrone ndo->ndo_snapend = ndspi->ndspi_snapend; 288ee67461eSJoseph Mingrone ndo->ndo_packet_info_stack = ndspi->ndspi_prev; 289ee67461eSJoseph Mingrone 290ee67461eSJoseph Mingrone free(ndspi->ndspi_buffer); 291ee67461eSJoseph Mingrone free(ndspi); 292ee67461eSJoseph Mingrone } 293ee67461eSJoseph Mingrone 294ee67461eSJoseph Mingrone void 295ee67461eSJoseph Mingrone nd_pop_all_packet_info(netdissect_options *ndo) 296ee67461eSJoseph Mingrone { 297ee67461eSJoseph Mingrone while (ndo->ndo_packet_info_stack != NULL) 298ee67461eSJoseph Mingrone nd_pop_packet_info(ndo); 299ee67461eSJoseph Mingrone } 300*0a7e5f1fSJoseph Mingrone 301*0a7e5f1fSJoseph Mingrone NORETURN void 302*0a7e5f1fSJoseph Mingrone nd_trunc_longjmp(netdissect_options *ndo) 303*0a7e5f1fSJoseph Mingrone { 304*0a7e5f1fSJoseph Mingrone longjmp(ndo->ndo_early_end, ND_TRUNCATED); 305*0a7e5f1fSJoseph Mingrone #ifdef _AIX 306*0a7e5f1fSJoseph Mingrone /* 307*0a7e5f1fSJoseph Mingrone * In AIX <setjmp.h> decorates longjmp() with "#pragma leaves", which tells 308*0a7e5f1fSJoseph Mingrone * XL C that the function is noreturn, but GCC remains unaware of that and 309*0a7e5f1fSJoseph Mingrone * yields a "'noreturn' function does return" warning. 310*0a7e5f1fSJoseph Mingrone */ 311*0a7e5f1fSJoseph Mingrone ND_UNREACHABLE 312*0a7e5f1fSJoseph Mingrone #endif /* _AIX */ 313*0a7e5f1fSJoseph Mingrone } 314