📄 pcap-dlpi.c
字号:
static char primbuf[80];
switch (prim) {
case DL_INFO_REQ:
return ("DL_INFO_REQ");
case DL_INFO_ACK:
return ("DL_INFO_ACK");
case DL_ATTACH_REQ:
return ("DL_ATTACH_REQ");
case DL_DETACH_REQ:
return ("DL_DETACH_REQ");
case DL_BIND_REQ:
return ("DL_BIND_REQ");
case DL_BIND_ACK:
return ("DL_BIND_ACK");
case DL_UNBIND_REQ:
return ("DL_UNBIND_REQ");
case DL_OK_ACK:
return ("DL_OK_ACK");
case DL_ERROR_ACK:
return ("DL_ERROR_ACK");
case DL_SUBS_BIND_REQ:
return ("DL_SUBS_BIND_REQ");
case DL_SUBS_BIND_ACK:
return ("DL_SUBS_BIND_ACK");
case DL_UNITDATA_REQ:
return ("DL_UNITDATA_REQ");
case DL_UNITDATA_IND:
return ("DL_UNITDATA_IND");
case DL_UDERROR_IND:
return ("DL_UDERROR_IND");
case DL_UDQOS_REQ:
return ("DL_UDQOS_REQ");
case DL_CONNECT_REQ:
return ("DL_CONNECT_REQ");
case DL_CONNECT_IND:
return ("DL_CONNECT_IND");
case DL_CONNECT_RES:
return ("DL_CONNECT_RES");
case DL_CONNECT_CON:
return ("DL_CONNECT_CON");
case DL_TOKEN_REQ:
return ("DL_TOKEN_REQ");
case DL_TOKEN_ACK:
return ("DL_TOKEN_ACK");
case DL_DISCONNECT_REQ:
return ("DL_DISCONNECT_REQ");
case DL_DISCONNECT_IND:
return ("DL_DISCONNECT_IND");
case DL_RESET_REQ:
return ("DL_RESET_REQ");
case DL_RESET_IND:
return ("DL_RESET_IND");
case DL_RESET_RES:
return ("DL_RESET_RES");
case DL_RESET_CON:
return ("DL_RESET_CON");
default:
(void) sprintf(primbuf, "unknown primitive 0x%x", prim);
return (primbuf);
}
}
static int
dlattachreq(int fd, bpf_u_int32 ppa, char *ebuf)
{
dl_attach_req_t req;
req.dl_primitive = DL_ATTACH_REQ;
req.dl_ppa = ppa;
return (send_request(fd, (char *)&req, sizeof(req), "attach", ebuf));
}
static int
dlbindreq(int fd, bpf_u_int32 sap, char *ebuf)
{
dl_bind_req_t req;
memset((char *)&req, 0, sizeof(req));
req.dl_primitive = DL_BIND_REQ;
#ifdef DL_HP_RAWDLS
req.dl_max_conind = 1; /* XXX magic number */
/* 22 is INSAP as per the HP-UX DLPI Programmer's Guide */
req.dl_sap = 22;
req.dl_service_mode = DL_HP_RAWDLS;
#else
req.dl_sap = sap;
#ifdef DL_CLDLS
req.dl_service_mode = DL_CLDLS;
#endif
#endif
return (send_request(fd, (char *)&req, sizeof(req), "bind", ebuf));
}
static int
dlbindack(int fd, char *bufp, char *ebuf)
{
return (recv_ack(fd, DL_BIND_ACK_SIZE, "bind", bufp, ebuf));
}
static int
dlpromisconreq(int fd, bpf_u_int32 level, char *ebuf)
{
dl_promiscon_req_t req;
req.dl_primitive = DL_PROMISCON_REQ;
req.dl_level = level;
return (send_request(fd, (char *)&req, sizeof(req), "promiscon", ebuf));
}
static int
dlokack(int fd, const char *what, char *bufp, char *ebuf)
{
return (recv_ack(fd, DL_OK_ACK_SIZE, what, bufp, ebuf));
}
static int
dlinforeq(int fd, char *ebuf)
{
dl_info_req_t req;
req.dl_primitive = DL_INFO_REQ;
return (send_request(fd, (char *)&req, sizeof(req), "info", ebuf));
}
static int
dlinfoack(int fd, char *bufp, char *ebuf)
{
return (recv_ack(fd, DL_INFO_ACK_SIZE, "info", bufp, ebuf));
}
#ifdef HAVE_SYS_BUFMOD_H
static int
strioctl(int fd, int cmd, int len, char *dp)
{
struct strioctl str;
int rc;
str.ic_cmd = cmd;
str.ic_timout = -1;
str.ic_len = len;
str.ic_dp = dp;
rc = ioctl(fd, I_STR, &str);
if (rc < 0)
return (rc);
else
return (str.ic_len);
}
#endif
#if defined(HAVE_SOLARIS) && defined(HAVE_SYS_BUFMOD_H)
static char *
get_release(bpf_u_int32 *majorp, bpf_u_int32 *minorp, bpf_u_int32 *microp)
{
char *cp;
static char buf[32];
*majorp = 0;
*minorp = 0;
*microp = 0;
if (sysinfo(SI_RELEASE, buf, sizeof(buf)) < 0)
return ("?");
cp = buf;
if (!isdigit((unsigned char)*cp))
return (buf);
*majorp = strtol(cp, &cp, 10);
if (*cp++ != '.')
return (buf);
*minorp = strtol(cp, &cp, 10);
if (*cp++ != '.')
return (buf);
*microp = strtol(cp, &cp, 10);
return (buf);
}
#endif
#ifdef DL_HP_PPA_REQ
/*
* Under HP-UX 10 and HP-UX 11, we can ask for the ppa
*/
/*
* Determine ppa number that specifies ifname.
*
* If the "dl_hp_ppa_info_t" doesn't have a "dl_module_id_1" member,
* the code that's used here is the old code for HP-UX 10.x.
*
* However, HP-UX 10.20, at least, appears to have such a member
* in its "dl_hp_ppa_info_t" structure, so the new code is used.
* The new code didn't work on an old 10.20 system on which Rick
* Jones of HP tried it, but with later patches installed, it
* worked - it appears that the older system had those members but
* didn't put anything in them, so, if the search by name fails, we
* do the old search.
*
* Rick suggests that making sure your system is "up on the latest
* lancommon/DLPI/driver patches" is probably a good idea; it'd fix
* that problem, as well as allowing libpcap to see packets sent
* from the system on which the libpcap application is being run.
* (On 10.20, in addition to getting the latest patches, you need
* to turn the kernel "lanc_outbound_promisc_flag" flag on with ADB;
* a posting to "comp.sys.hp.hpux" at
*
* http://www.deja.com/[ST_rn=ps]/getdoc.xp?AN=558092266
*
* says that, to see the machine's outgoing traffic, you'd need to
* apply the right patches to your system, and also set that variable
* with:
echo 'lanc_outbound_promisc_flag/W1' | /usr/bin/adb -w /stand/vmunix /dev/kmem
* which could be put in, for example, "/sbin/init.d/lan".
*
* Setting the variable is not necessary on HP-UX 11.x.
*/
static int
get_dlpi_ppa(register int fd, register const char *device, register int unit,
register char *ebuf)
{
register dl_hp_ppa_ack_t *ap;
register dl_hp_ppa_info_t *ipstart, *ip;
register int i;
char dname[100];
register u_long majdev;
struct stat statbuf;
dl_hp_ppa_req_t req;
char buf[MAXDLBUF];
char *ppa_data_buf;
dl_hp_ppa_ack_t *dlp;
struct strbuf ctl;
int flags;
int ppa;
memset((char *)&req, 0, sizeof(req));
req.dl_primitive = DL_HP_PPA_REQ;
memset((char *)buf, 0, sizeof(buf));
if (send_request(fd, (char *)&req, sizeof(req), "hpppa", ebuf) < 0)
return (-1);
ctl.maxlen = DL_HP_PPA_ACK_SIZE;
ctl.len = 0;
ctl.buf = (char *)buf;
flags = 0;
/*
* DLPI may return a big chunk of data for a DL_HP_PPA_REQ. The normal
* recv_ack will fail because it set the maxlen to MAXDLBUF (8192)
* which is NOT big enough for a DL_HP_PPA_REQ.
*
* This causes libpcap applications to fail on a system with HP-APA
* installed.
*
* To figure out how big the returned data is, we first call getmsg
* to get the small head and peek at the head to get the actual data
* length, and then issue another getmsg to get the actual PPA data.
*/
/* get the head first */
if (getmsg(fd, &ctl, (struct strbuf *)NULL, &flags) < 0) {
snprintf(ebuf, PCAP_ERRBUF_SIZE,
"get_dlpi_ppa: hpppa getmsg: %s", pcap_strerror(errno));
return (-1);
}
dlp = (dl_hp_ppa_ack_t *)ctl.buf;
if (dlp->dl_primitive != DL_HP_PPA_ACK) {
snprintf(ebuf, PCAP_ERRBUF_SIZE,
"get_dlpi_ppa: hpppa unexpected primitive ack 0x%x",
(bpf_u_int32)dlp->dl_primitive);
return (-1);
}
if (ctl.len < DL_HP_PPA_ACK_SIZE) {
snprintf(ebuf, PCAP_ERRBUF_SIZE,
"get_dlpi_ppa: hpppa ack too small (%d < %lu)",
ctl.len, (unsigned long)DL_HP_PPA_ACK_SIZE);
return (-1);
}
/* allocate buffer */
if ((ppa_data_buf = (char *)malloc(dlp->dl_length)) == NULL) {
snprintf(ebuf, PCAP_ERRBUF_SIZE,
"get_dlpi_ppa: hpppa malloc: %s", pcap_strerror(errno));
return (-1);
}
ctl.maxlen = dlp->dl_length;
ctl.len = 0;
ctl.buf = (char *)ppa_data_buf;
/* get the data */
if (getmsg(fd, &ctl, (struct strbuf *)NULL, &flags) < 0) {
snprintf(ebuf, PCAP_ERRBUF_SIZE,
"get_dlpi_ppa: hpppa getmsg: %s", pcap_strerror(errno));
free(ppa_data_buf);
return (-1);
}
if (ctl.len < dlp->dl_length) {
snprintf(ebuf, PCAP_ERRBUF_SIZE,
"get_dlpi_ppa: hpppa ack too small (%d < %d)",
ctl.len, dlp->dl_length);
free(ppa_data_buf);
return (-1);
}
ap = (dl_hp_ppa_ack_t *)buf;
ipstart = (dl_hp_ppa_info_t *)ppa_data_buf;
ip = ipstart;
#ifdef HAVE_HP_PPA_INFO_T_DL_MODULE_ID_1
/*
* The "dl_hp_ppa_info_t" structure has a "dl_module_id_1"
* member that should, in theory, contain the part of the
* name for the device that comes before the unit number,
* and should also have a "dl_module_id_2" member that may
* contain an alternate name (e.g., I think Ethernet devices
* have both "lan", for "lanN", and "snap", for "snapN", with
* the former being for Ethernet packets and the latter being
* for 802.3/802.2 packets).
*
* Search for the device that has the specified name and
* instance number.
*/
for (i = 0; i < ap->dl_count; i++) {
if ((strcmp((const char *)ip->dl_module_id_1, device) == 0 ||
strcmp((const char *)ip->dl_module_id_2, device) == 0) &&
ip->dl_instance_num == unit)
break;
ip = (dl_hp_ppa_info_t *)((u_char *)ipstart + ip->dl_next_offset);
}
#else
/*
* We don't have that member, so the search is impossible; make it
* look as if the search failed.
*/
i = ap->dl_count;
#endif
if (i == ap->dl_count) {
/*
* Well, we didn't, or can't, find the device by name.
*
* HP-UX 10.20, whilst it has "dl_module_id_1" and
* "dl_module_id_2" fields in the "dl_hp_ppa_info_t",
* doesn't seem to fill them in unless the system is
* at a reasonably up-to-date patch level.
*
* Older HP-UX 10.x systems might not have those fields
* at all.
*
* Therefore, we'll search for the entry with the major
* device number of a device with the name "/dev/<dev><unit>",
* if such a device exists, as the old code did.
*/
snprintf(dname, sizeof(dname), "/dev/%s%d", device, unit);
if (stat(dname, &statbuf) < 0) {
snprintf(ebuf, PCAP_ERRBUF_SIZE, "stat: %s: %s",
dname, pcap_strerror(errno));
return (-1);
}
majdev = major(statbuf.st_rdev);
ip = ipstart;
for (i = 0; i < ap->dl_count; i++) {
if (ip->dl_mjr_num == majdev &&
ip->dl_instance_num == unit)
break;
ip = (dl_hp_ppa_info_t *)((u_char *)ipstart + ip->dl_next_offset);
}
}
if (i == ap->dl_count) {
snprintf(ebuf, PCAP_ERRBUF_SIZE,
"can't find /dev/dlpi PPA for %s%d", device, unit);
return (-1);
}
if (ip->dl_hdw_state == HDW_DEAD) {
snprintf(ebuf, PCAP_ERRBUF_SIZE,
"%s%d: hardware state: DOWN\n", device, unit);
free(ppa_data_buf);
return (-1);
}
ppa = ip->dl_ppa;
free(ppa_data_buf);
return (ppa);
}
#endif
#ifdef HAVE_HPUX9
/*
* Under HP-UX 9, there is no good way to determine the ppa.
* So punt and read it from /dev/kmem.
*/
static struct nlist nl[] = {
#define NL_IFNET 0
{ "ifnet" },
{ "" }
};
static char path_vmunix[] = "/hp-ux";
/* Determine ppa number that specifies ifname */
static int
get_dlpi_ppa(register int fd, register const char *ifname, register int unit,
register char *ebuf)
{
register const char *cp;
register int kd;
void *addr;
struct ifnet ifnet;
char if_name[sizeof(ifnet.if_name) + 1];
cp = strrchr(ifname, '/');
if (cp != NULL)
ifname = cp + 1;
if (nlist(path_vmunix, &nl) < 0) {
snprintf(ebuf, PCAP_ERRBUF_SIZE, "nlist %s failed",
path_vmunix);
return (-1);
}
if (nl[NL_IFNET].n_value == 0) {
snprintf(ebuf, PCAP_ERRBUF_SIZE,
"could't find %s kernel symbol",
nl[NL_IFNET].n_name);
return (-1);
}
kd = open("/dev/kmem", O_RDONLY);
if (kd < 0) {
snprintf(ebuf, PCAP_ERRBUF_SIZE, "kmem open: %s",
pcap_strerror(errno));
return (-1);
}
if (dlpi_kread(kd, nl[NL_IFNET].n_value,
&addr, sizeof(addr), ebuf) < 0) {
close(kd);
return (-1);
}
for (; addr != NULL; addr = ifnet.if_next) {
if (dlpi_kread(kd, (off_t)addr,
&ifnet, sizeof(ifnet), ebuf) < 0 ||
dlpi_kread(kd, (off_t)ifnet.if_name,
if_name, sizeof(ifnet.if_name), ebuf) < 0) {
(void)close(kd);
return (-1);
}
if_name[sizeof(ifnet.if_name)] = '\0';
if (strcmp(if_name, ifname) == 0 && ifnet.if_unit == unit)
return (ifnet.if_index);
}
snprintf(ebuf, PCAP_ERRBUF_SIZE, "Can't find %s", ifname);
return (-1);
}
static int
dlpi_kread(register int fd, register off_t addr,
register void *buf, register u_int len, register char *ebuf)
{
register int cc;
if (lseek(fd, addr, SEEK_SET) < 0) {
snprintf(ebuf, PCAP_ERRBUF_SIZE, "lseek: %s",
pcap_strerror(errno));
return (-1);
}
cc = read(fd, buf, len);
if (cc < 0) {
snprintf(ebuf, PCAP_ERRBUF_SIZE, "read: %s",
pcap_strerror(errno));
return (-1);
} else if (cc != len) {
snprintf(ebuf, PCAP_ERRBUF_SIZE, "short read (%d != %d)", cc,
len);
return (-1);
}
return (cc);
}
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -