00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034 #ifndef lint
00035 static const char rcsid[] =
00036 "@(#) $Header: /nfs/jade/vint/CVSROOT/ns-2/emulate/net-pcap.cc,v 1.23 2005/09/07 06:35:45 tomh Exp $ (LBL)";
00037 #endif
00038
00039 #include <stdio.h>
00040 #ifndef WIN32
00041 #include <unistd.h>
00042 #endif
00043 #include <time.h>
00044 #include <errno.h>
00045 #include <string.h>
00046 #ifdef WIN32
00047 #include <io.h>
00048 #define close closesocket
00049 #else
00050 #include <sys/param.h>
00051 #include <sys/socket.h>
00052 #include <sys/ioctl.h>
00053 #endif
00054 #if defined(sun) && defined(__svr4__)
00055 #include <sys/systeminfo.h>
00056 #endif
00057
00058 #ifdef __cplusplus
00059 extern "C" {
00060 #include <pcap.h>
00061 }
00062 #else
00063 #include <pcap.h>
00064 #endif
00065
00066 #include "config.h"
00067 #include "scheduler.h"
00068 #include "net.h"
00069 #include "tclcl.h"
00070 #include "packet.h"
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097 #define PNET_PSTATE_INACTIVE 0
00098 #define PNET_PSTATE_ACTIVE 1
00099
00100
00101
00102
00103
00104
00105
00106
00107 class PcapNetwork : public Network {
00108
00109 public:
00110 PcapNetwork() : t_firstpkt_(0.0),
00111 pfd_(-1), pcnt_(0), local_netmask_(0) { }
00112 int rchannel() { return(pfd_); }
00113 int schannel() { return(pfd_); }
00114 virtual int command(int argc, const char*const* argv);
00115
00116 virtual int open(int mode, const char *) = 0;
00117 virtual int skiphdr() = 0;
00118 virtual double gents(pcap_pkthdr*) = 0;
00119 int recv(u_char *buf, int len, sockaddr&, double&);
00120 int send(u_char *buf, int len);
00121 int recv(netpkt_handler callback, void *clientdata);
00122 void close();
00123 void reset();
00124
00125 int filter(const char*);
00126 int stat_pkts();
00127 int stat_pdrops();
00128
00129 double offset_;
00130 double t_firstpkt_;
00131
00132 protected:
00133 static void phandler(u_char* u, const pcap_pkthdr* h, const u_char* p);
00134 static void phandler_callback(u_char* u, const pcap_pkthdr* h, const u_char* p);
00135 virtual void bindvars() = 0;
00136
00137 char errbuf_[PCAP_ERRBUF_SIZE];
00138 char srcname_[PATH_MAX];
00139 int pfd_;
00140 int pcnt_;
00141 int state_;
00142 int optimize_;
00143 pcap_t* pcap_;
00144 struct bpf_program bpfpgm_;
00145 struct pcap_stat pcs_;
00146
00147 unsigned int local_netmask_;
00148 };
00149
00150
00151
00152
00153
00154 struct NetworkAddress {
00155 u_int len_;
00156 u_char addr_[16];
00157 };
00158
00159 class PcapLiveNetwork : public PcapNetwork {
00160 public:
00161 PcapLiveNetwork() : local_net_(0), dlink_type_(-1) {
00162 linkaddr_.len_ = 0;
00163 netaddr_.len_ = 0;
00164 bindvars(); reset();
00165 }
00166 NetworkAddress& laddr() { return (linkaddr_); }
00167 NetworkAddress& naddr() { return (netaddr_); }
00168 protected:
00169 double gents(pcap_pkthdr*) {
00170 return Scheduler::instance().clock();
00171 }
00172
00173 int devtonaddr(const char* name, NetworkAddress&);
00174
00175 int open(int mode);
00176 int open(int mode, const char*);
00177 int command(int argc, const char*const* argv);
00178 int skiphdr();
00179 const char* autodevname();
00180 void bindvars();
00181
00182 int snaplen_;
00183 int promisc_;
00184 double timeout_;
00185 NetworkAddress linkaddr_;
00186 NetworkAddress netaddr_;
00187
00188 unsigned int local_net_;
00189 int dlink_type_;
00190 private:
00191
00192
00193 #ifdef MT_OWN_PCAP
00194 pcap_t * pcap_open_live(char *, int slen, int prom, int, char *, int);
00195 int bpf_open(pcap_t *p, char *errbuf, int how);
00196 #endif
00197 };
00198
00199 class PcapFileNetwork : public PcapNetwork {
00200 public:
00201 int open(int mode, const char *);
00202 int skiphdr() { return 0; }
00203 protected:
00204 double gents(pcap_pkthdr* p) {
00205
00206
00207 double pts = p->ts.tv_sec + p->ts.tv_usec * 0.000001;
00208 pts -= t_firstpkt_;
00209 pts += offset_ + Scheduler::instance().clock();
00210 return (pts);
00211 }
00212 void bindvars();
00213 int command(int argc, const char*const* argv);
00214 };
00215
00216 static class PcapLiveNetworkClass : public TclClass {
00217 public:
00218 PcapLiveNetworkClass() : TclClass("Network/Pcap/Live") {}
00219 TclObject* create(int, const char*const*) {
00220 return (new PcapLiveNetwork);
00221 }
00222 } net_pcaplive;
00223
00224 static class PcapFileNetworkClass : public TclClass {
00225 public:
00226 PcapFileNetworkClass() : TclClass("Network/Pcap/File") {}
00227 TclObject* create(int, const char*const*) {
00228 return (new PcapFileNetwork);
00229 }
00230 } net_pcapfile;
00231
00232
00233
00234
00235
00236 void
00237 PcapNetwork::bindvars()
00238 {
00239 bind_bool("optimize_", &optimize_);
00240 }
00241
00242 void
00243 PcapNetwork::reset()
00244 {
00245 state_ = PNET_PSTATE_INACTIVE;
00246 pfd_ = -1;
00247 pcap_ = NULL;
00248 *errbuf_ = '\0';
00249 *srcname_ = '\0';
00250 pcnt_ = 0;
00251 }
00252
00253 void
00254 PcapNetwork::close()
00255 {
00256 if (state_ == PNET_PSTATE_ACTIVE && pcap_)
00257 pcap_close(pcap_);
00258 reset();
00259 }
00260
00261
00262
00263
00264 int
00265 PcapNetwork::filter(const char *pgm)
00266 {
00267 if (pcap_compile(pcap_, &bpfpgm_, (char *)pgm,
00268 optimize_, local_netmask_) < 0) {
00269 fprintf(stderr, "pcapnet obj(%s): couldn't compile filter pgm",
00270 name());
00271 return -1;
00272 }
00273 if (pcap_setfilter(pcap_, &bpfpgm_) < 0) {
00274 fprintf(stderr, "pcapnet obj(%s): couldn't set filter pgm",
00275 name());
00276 return -1;
00277 }
00278 return(bpfpgm_.bf_len);
00279 }
00280
00281
00282 int
00283 PcapNetwork::stat_pkts()
00284 {
00285 if (pcap_stats(pcap_, &pcs_) < 0)
00286 return (-1);
00287
00288 return (pcs_.ps_recv);
00289 }
00290
00291
00292 int
00293 PcapNetwork::stat_pdrops()
00294 {
00295 if (pcap_stats(pcap_, &pcs_) < 0)
00296 return (-1);
00297
00298 return (pcs_.ps_drop);
00299 }
00300
00301 #ifndef MIN
00302 #define MIN(x, y) ((x)<(y) ? (x) : (y))
00303 #endif
00304
00305 #include "ether.h"
00306
00307
00308 struct pcap_singleton {
00309 struct pcap_pkthdr *hdr;
00310 const u_char *pkt;
00311 };
00312
00313 struct pcap_singleton_callback {
00314 netpkt_handler callback;
00315 void *clientdata;
00316 PcapNetwork *net;
00317 };
00318
00319 void
00320 PcapNetwork::phandler(u_char* userdata, const pcap_pkthdr* ph, const u_char* pkt)
00321 {
00322 pcap_singleton *ps = (pcap_singleton*) userdata;
00323 ps->hdr = (pcap_pkthdr*)ph;
00324 ps->pkt = (u_char*)pkt;
00325 }
00326
00327 void
00328 PcapNetwork::phandler_callback(u_char* userdata, const pcap_pkthdr* ph, const u_char* pkt)
00329 {
00330 pcap_singleton_callback *ps = (pcap_singleton_callback*) userdata;
00331
00332 Packet *p = Packet::alloc(ph->caplen);
00333 PcapNetwork *inst = ps->net;
00334
00335 if (++(inst->pcnt_) == 1) {
00336
00337 inst->t_firstpkt_ = ph->ts.tv_sec + ph->ts.tv_usec * 0.000001;
00338 }
00339
00340
00341 int s = inst->skiphdr();
00342 memcpy(p->accessdata(), pkt + s, ph->caplen - s);
00343
00344 ps->callback(ps->clientdata, p, ph->ts);
00345 }
00346
00347 int
00348 PcapNetwork::recv(u_char *buf, int len, sockaddr& , double &ts)
00349 {
00350
00351 if (state_ != PNET_PSTATE_ACTIVE) {
00352 fprintf(stderr, "warning: net/pcap obj(%s) read-- not active\n",
00353 name());
00354 return -1;
00355 }
00356
00357 int pktcnt = 1;
00358 int np;
00359 pcap_singleton ps = { 0, 0 };
00360 np = pcap_dispatch(pcap_, pktcnt, phandler, (u_char*) &ps);
00361 if (np < 0) {
00362 fprintf(stderr,
00363 "PcapNetwork(%s): recv: pcap_dispatch: %s\n",
00364 name(), pcap_strerror(errno));
00365 return (np);
00366 } else if (np == 0) {
00367
00368 return (np);
00369 } else if (np != pktcnt) {
00370 fprintf(stderr,
00371 "PcapNetwork(%s): warning: recv: pcap_dispatch: requested pktcnt (%d) doesn't match actual (%d)\n",
00372 name(), pktcnt, np);
00373 }
00374
00375 pcap_pkthdr* ph = ps.hdr;
00376
00377 if (ph == NULL || ps.pkt == NULL) {
00378 fprintf(stderr,
00379 "PcapNetwork(%s): recv: pcap_dispatch: no packet present\n",
00380 name());
00381 return (-1);
00382 }
00383
00384 if (++pcnt_ == 1) {
00385
00386 t_firstpkt_ = ph->ts.tv_sec + ph->ts.tv_usec * 0.000001;
00387 }
00388
00389 int n = MIN(ph->caplen, (unsigned)len);
00390 ts = gents(ph);
00391
00392 int s = skiphdr();
00393 memcpy(buf, ps.pkt + s, n - s);
00394 return n - s;
00395 }
00396
00397 int
00398 PcapNetwork::recv(netpkt_handler callback, void *clientdata)
00399 {
00400 if (state_ != PNET_PSTATE_ACTIVE) {
00401 fprintf(stderr, "warning: net/pcap obj(%s) read-- not active\n",
00402 name());
00403 return -1;
00404 }
00405
00406 int pktcnt = -1;
00407 int np;
00408 pcap_singleton_callback ps = { callback, clientdata, this };
00409
00410 np = pcap_dispatch(pcap_, pktcnt, phandler_callback, (u_char *)&ps);
00411
00412 #ifdef MY_OWN_PCAP // directly access pcap_t's member
00413 assert( pcap_->cc == 0 );
00414 #endif // MY_OWN_PCAP
00415 return np;
00416 }
00417
00418
00419 int
00420 PcapNetwork::send(u_char *buf, int len)
00421 {
00422 int n;
00423
00424 if ((n = write(pfd_, buf, len)) < 0)
00425 perror("write to pcap fd");
00426
00427 return n;
00428 }
00429
00430 int PcapNetwork::command(int argc, const char*const* argv)
00431 {
00432 Tcl& tcl = Tcl::instance();
00433 if (argc == 2) {
00434 if (strcmp(argv[1], "close") == 0) {
00435 close();
00436 return (TCL_OK);
00437 }
00438 if (strcmp(argv[1], "srcname") == 0) {
00439 tcl.result(srcname_);
00440 return (TCL_OK);
00441 }
00442 if (strcmp(argv[1], "pkts") == 0) {
00443 tcl.resultf("%d", stat_pkts());
00444 return (TCL_OK);
00445 }
00446 if (strcmp(argv[1], "pdrops") == 0) {
00447 tcl.resultf("%d", stat_pdrops());
00448 return (TCL_OK);
00449 }
00450 } else if (argc == 3) {
00451 if (strcmp(argv[1], "filter") == 0) {
00452 if (state_ != PNET_PSTATE_ACTIVE) {
00453 fprintf(stderr, "net/pcap obj(%s): can't install filter prior to opening data source\n",
00454 name());
00455 return (TCL_ERROR);
00456 }
00457 int plen;
00458 if ((plen = filter(argv[2])) < 0) {
00459 fprintf(stderr, "problem compiling/installing filter program\n");
00460 return (TCL_ERROR);
00461 }
00462 tcl.resultf("%d", plen);
00463 return (TCL_OK);
00464 }
00465 }
00466 return (Network::command(argc, argv));
00467 }
00468
00469
00470
00471
00472
00473 #include <fcntl.h>
00474
00475 #include <net/if.h>
00476 int
00477 PcapLiveNetwork::open(int mode, const char *devname)
00478 {
00479 close();
00480 #ifdef MY_OWN_PCAP
00481 pcap_ = pcap_open_live((char*) devname, snaplen_, promisc_,
00482 int(timeout_ * 1000.), errbuf_, mode);
00483 #else
00484 pcap_ = pcap_open_live((char*) devname, snaplen_, promisc_,
00485 int(timeout_ * 1000.), errbuf_);
00486 #endif // MY_OWN_PCAP
00487 if (pcap_ == NULL) {
00488 fprintf(stderr,
00489 "pcap/live object (%s) couldn't open packet source %s: %s\n",
00490 name(), devname, errbuf_);
00491 return -1;
00492 }
00493 mode_ = mode;
00494 dlink_type_ = pcap_datalink(pcap_);
00495 pfd_ = pcap_fileno(pcap_);
00496 strncpy(srcname_, devname, sizeof(srcname_)-1);
00497 {
00498
00499 struct ifreq ifr;
00500 struct sockaddr *sa = &ifr.ifr_addr;
00501 #ifdef HAVE_SIOCGIFHWADDR
00502 memset(&ifr, 0, sizeof(struct ifreq));
00503 strcpy(ifr.ifr_name, devname);
00504 if (ioctl(pfd_, SIOCGIFHWADDR, &ifr) < 0) {
00505 fprintf(stderr,
00506 "pcap/live (%s) SIOCGIFHWADDR on bpf fd %d\n",
00507 name(), pfd_);
00508 }
00509 #else
00510 if (ioctl(pfd_, SIOCGIFADDR, &ifr) < 0) {
00511 fprintf(stderr,
00512 "pcap/live (%s) SIOCGIFADDR on bpf fd %d\n",
00513 name(), pfd_);
00514 }
00515 #endif
00516 if (dlink_type_ != DLT_EN10MB) {
00517 fprintf(stderr,
00518 "sorry, only ethernet supported\n");
00519 return -1;
00520 }
00521 linkaddr_.len_ = ETHER_ADDR_LEN;
00522 memcpy(linkaddr_.addr_, sa->sa_data, linkaddr_.len_);
00523 }
00524
00525 (void) devtonaddr(devname, netaddr_);
00526
00527 state_ = PNET_PSTATE_ACTIVE;
00528
00529 if (pcap_lookupnet(srcname_, &local_net_, &local_netmask_, errbuf_) < 0) {
00530 fprintf(stderr,
00531 "warning: pcap/live (%s) couldn't get local IP network info: %s\n",
00532 name(), errbuf_) ;
00533 }
00534 #if !defined(__linux__)&&!defined(__APPLE__)
00535 {
00536 int immed = 1;
00537 if (ioctl(pfd_, BIOCIMMEDIATE, &immed) < 0) {
00538 fprintf(stderr,
00539 "warning: pcap/live (%s) couldn't set immed\n",
00540 name());
00541 perror("ioctl(BIOCIMMEDIATE)");
00542 }
00543 }
00544 #endif
00545 return 0;
00546 }
00547
00548
00549
00550
00551
00552 int
00553 PcapLiveNetwork::skiphdr()
00554 {
00555 switch (dlink_type_) {
00556 case DLT_NULL:
00557 return 0;
00558
00559 case DLT_EN10MB:
00560 return ETHER_HDR_LEN;
00561
00562 default:
00563 fprintf(stderr,
00564 "Network/Pcap/Live(%s): unknown link type: %d\n",
00565 name(), dlink_type_);
00566 }
00567 return -1;
00568 }
00569
00570 const char *
00571 PcapLiveNetwork::autodevname()
00572 {
00573 const char *dname;
00574 if ((dname = pcap_lookupdev(errbuf_)) == NULL) {
00575 fprintf(stderr, "warning: PcapNet/Live(%s) : %s\n",
00576 name(), errbuf_);
00577 return (NULL);
00578 }
00579 return (dname);
00580 }
00581
00582
00583
00584
00585
00586
00587
00588 #include <netinet/in.h>
00589
00590 int
00591 PcapLiveNetwork::devtonaddr(const char *devname, NetworkAddress& na)
00592 {
00593 register int fd;
00594 ifreq ifr;
00595
00596 fd = socket(AF_INET, SOCK_DGRAM, 0);
00597 if (fd < 0) {
00598 fprintf(stderr,
00599 "PcapLiveNet(%s): devtoaddr: couldn't create sock\n",
00600 name());
00601 return (-1);
00602 }
00603 memset(&ifr, 0, sizeof(ifr));
00604 #ifdef linux
00605
00606 ifr.ifr_addr.sa_family = AF_INET;
00607 #endif
00608 (void)strncpy(ifr.ifr_name, devname, sizeof(ifr.ifr_name));
00609 if (ioctl(fd, SIOCGIFADDR, (char *)&ifr) < 0) {
00610 fprintf(stderr, "PcapLiveNetwork(%s): devtoaddr: no addr\n",
00611 name());
00612 (void)::close(fd);
00613 return (-1);
00614 }
00615 sockaddr* sa = &ifr.ifr_addr;
00616 if (sa->sa_family != AF_INET) {
00617 fprintf(stderr,
00618 "PcapLiveNet(%s): af not AF_INET (%d)\n",
00619 name(), sa->sa_family);
00620 }
00621 sockaddr_in* sin = (sockaddr_in*) sa;
00622 na.len_ = 4;
00623 memset(na.addr_, 0, sizeof(na.addr_));
00624 unsigned sz = sizeof(na.addr_);
00625 if (sizeof(ifr) < sz)
00626 sz = sizeof(ifr);
00627 memcpy(na.addr_, &sin->sin_addr, sz);
00628 return (0);
00629 }
00630
00631
00632 void
00633 PcapLiveNetwork::bindvars()
00634 {
00635 bind("snaplen_", &snaplen_);
00636 bind_bool("promisc_", &promisc_);
00637 bind_time("timeout_", &timeout_);
00638 bind("offset_", &offset_);
00639 PcapNetwork::bindvars();
00640 }
00641
00642 void
00643 PcapFileNetwork::bindvars()
00644 {
00645 bind("offset_", &offset_);
00646 }
00647
00648 int
00649 PcapLiveNetwork::open(int mode)
00650 {
00651 return (open(mode, autodevname()));
00652 }
00653
00654 int PcapLiveNetwork::command(int argc, const char*const* argv)
00655 {
00656
00657 Tcl& tcl = Tcl::instance();
00658 if (argc == 2) {
00659 if (strcmp(argv[1], "linkaddr") == 0) {
00661 tcl.result(Ethernet::etheraddr_string(linkaddr_.addr_));
00662 return (TCL_OK);
00663 }
00664 if (strcmp(argv[1], "netaddr") == 0) {
00665 if (netaddr_.len_ != 4) {
00666 fprintf(stderr,
00667 "PcapLive(%s): net addr not len 4 (%d)\n",
00668 name(), netaddr_.len_);
00669 return (TCL_ERROR);
00670 }
00671 tcl.resultf("%d.%d.%d.%d",
00672 netaddr_.addr_[0],
00673 netaddr_.addr_[1],
00674 netaddr_.addr_[2],
00675 netaddr_.addr_[3]);
00676 return (TCL_OK);
00677 }
00678 } else if (argc == 3) {
00679
00680 if (strcmp(argv[1], "open") == 0) {
00681 int mode = parsemode(argv[2]);
00682 if (open(mode) < 0)
00683 return (TCL_ERROR);
00684 tcl.result(srcname_);
00685 return (TCL_OK);
00686 }
00687 } else if (argc == 4) {
00688
00689 if (strcmp(argv[1], "open") == 0) {
00690 int mode = parsemode(argv[2]);
00691 if (open(mode, argv[3]) < 0)
00692 return (TCL_ERROR);
00693 tcl.result(srcname_);
00694 return (TCL_OK);
00695 }
00696 }
00697 return (PcapNetwork::command(argc, argv));
00698 }
00699
00700
00701
00702
00703
00704
00705 int
00706 PcapFileNetwork::open(int , const char *filename)
00707 {
00708
00709 close();
00710 pcap_ = pcap_open_offline((char*) filename, errbuf_);
00711 if (pcap_ == NULL) {
00712 fprintf(stderr,
00713 "pcap/file object (%s) couldn't open packet source %s: %s\n",
00714 name(), filename, errbuf_);
00715 return -1;
00716 }
00717 mode_ = O_RDONLY;
00718
00719
00720
00721
00722 pfd_ = fileno(pcap_file(pcap_));
00723 strncpy(srcname_, filename, sizeof(srcname_)-1);
00724 state_ = PNET_PSTATE_ACTIVE;
00725 return 0;
00726 }
00727
00728 int PcapFileNetwork::command(int argc, const char*const* argv)
00729 {
00730
00731 Tcl& tcl = Tcl::instance();
00732 if (argc == 4) {
00733
00734 if (strcmp(argv[1], "open") == 0) {
00735 int mode = parsemode(argv[2]);
00736 if (open(mode, argv[3]) < 0)
00737 return (TCL_ERROR);
00738 tcl.resultf("%s", argv[3]);
00739 return (TCL_OK);
00740 }
00741 }
00742 return (PcapNetwork::command(argc, argv));
00743 }
00744
00745
00746
00747
00748
00749
00750
00751
00752
00753
00754
00755 struct pcap_sf {
00756 FILE *rfile;
00757 int swapped;
00758 int version_major;
00759 int version_minor;
00760 u_char *base;
00761 };
00762
00763 struct pcap_md {
00764 struct pcap_stat stat;
00765
00766 int use_bpf;
00767 u_long TotPkts;
00768 u_long TotAccepted;
00769 u_long TotDrops;
00770 long TotMissed;
00771 long OrigMissed;
00772 #ifdef linux
00773 int pad;
00774 int skip;
00775 char *device;
00776 #endif
00777 };
00778
00779
00780 struct pcap {
00781 int fd;
00782 int snapshot;
00783 int linktype;
00784 int tzoff;
00785 int offset;
00786
00787 struct pcap_sf sf;
00788 struct pcap_md md;
00789
00790
00791
00792
00793 int bufsize;
00794 u_char *buffer;
00795 u_char *bp;
00796 int cc;
00797
00798
00799
00800
00801 u_char *pkt;
00802
00803
00804
00805
00806
00807 struct bpf_program fcode;
00808
00809 char errbuf[PCAP_ERRBUF_SIZE];
00810 };
00811
00812
00813
00814
00815
00816
00817
00818
00819
00820
00821
00822 #include <net/if.h>
00823
00824 #ifdef MY_OWN_PCAP
00825 int
00826 PcapLiveNetwork::bpf_open(pcap_t *, char *errbuf, int how)
00827 {
00828 int fd;
00829 int n = 0;
00830 char device[sizeof "/dev/bpf000"];
00831
00832
00833
00834
00835 do {
00836 (void)sprintf(device, "/dev/bpf%d", n++);
00837 fd = ::open(device, how, 0);
00838 } while (fd < 0 && n < 1000 && errno == EBUSY);
00839
00840
00841
00842
00843 if (fd < 0)
00844 sprintf(errbuf, "%s: %s", device, pcap_strerror(errno));
00845
00846 return (fd);
00847 }
00848
00849 pcap_t *
00850 PcapLiveNetwork::pcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf, int how)
00851 {
00852 int fd;
00853 struct ifreq ifr;
00854 struct bpf_version bv;
00855 u_int v;
00856 pcap_t *p;
00857
00858 p = (pcap_t *)malloc(sizeof(*p));
00859 if (p == NULL) {
00860 sprintf(ebuf, "malloc: %s", pcap_strerror(errno));
00861 return (NULL);
00862 }
00863 bzero(p, sizeof(*p));
00864 fd = bpf_open(p, ebuf, how);
00865 if (fd < 0)
00866 goto bad;
00867
00868 p->fd = fd;
00869 p->snapshot = snaplen;
00870
00871 if (ioctl(fd, BIOCVERSION, (caddr_t)&bv) < 0) {
00872 sprintf(ebuf, "BIOCVERSION: %s", pcap_strerror(errno));
00873 goto bad;
00874 }
00875 if (bv.bv_major != BPF_MAJOR_VERSION ||
00876 bv.bv_minor < BPF_MINOR_VERSION) {
00877 sprintf(ebuf, "kernel bpf filter out of date");
00878 goto bad;
00879 }
00880 (void)strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
00881 if (ioctl(fd, BIOCSETIF, (caddr_t)&ifr) < 0) {
00882 sprintf(ebuf, "%s: %s", device, pcap_strerror(errno));
00883 goto bad;
00884 }
00885
00886 if (ioctl(fd, BIOCGDLT, (caddr_t)&v) < 0) {
00887 sprintf(ebuf, "BIOCGDLT: %s", pcap_strerror(errno));
00888 goto bad;
00889 }
00890 #if _BSDI_VERSION - 0 >= 199510
00891
00892 switch (v) {
00893
00894 case DLT_SLIP:
00895 v = DLT_SLIP_BSDOS;
00896 break;
00897 case DLT_PPP:
00898 v = DLT_PPP_BSDOS;
00899 break;
00900 }
00901 #endif
00902 p->linktype = v;
00903
00904
00905 if (to_ms != 0) {
00906 struct timeval to;
00907 to.tv_sec = to_ms / 1000;
00908 to.tv_usec = (to_ms * 1000) % 1000000;
00909 if (ioctl(p->fd, BIOCSRTIMEOUT, (caddr_t)&to) < 0) {
00910 sprintf(ebuf, "BIOCSRTIMEOUT: %s",
00911 pcap_strerror(errno));
00912 goto bad;
00913 }
00914 }
00915 if (promisc)
00916
00917 (void)ioctl(p->fd, BIOCPROMISC, NULL);
00918
00919 if (ioctl(fd, BIOCGBLEN, (caddr_t)&v) < 0) {
00920 sprintf(ebuf, "BIOCGBLEN: %s", pcap_strerror(errno));
00921 goto bad;
00922 }
00923 p->bufsize = v;
00924 p->buffer = (u_char *)malloc(p->bufsize);
00925 if (p->buffer == NULL) {
00926 sprintf(ebuf, "malloc: %s", pcap_strerror(errno));
00927 goto bad;
00928 }
00929
00930 return (p);
00931 bad:
00932 ::close(fd);
00933 free(p);
00934 return (NULL);
00935 }
00936 #endif // MY_OWN_PCAP