📄 if.c
字号:
}
/* allocate a receive packet buffer */
if (ioctl(fd, BIOCGBLEN, &bpfLength) < 0) {
fatalSys("ioctl(BIOCGBLEN)");
}
if (!(bpfBuffer = (unsigned char *) malloc(bpfLength))) {
rp_fatal("malloc");
}
/* reads should return as soon as there is a packet available */
optval = 1;
if (ioctl(fd, BIOCIMMEDIATE, &optval) < 0) {
fatalSys("ioctl(BIOCIMMEDIATE)");
}
/* Bind the interface to the filter */
strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
if (ioctl(fd, BIOCSETIF, &ifr) < 0) {
char buffer[256];
sprintf(buffer, "ioctl(BIOCSETIF) can't select interface %.16s",
ifname);
rp_fatal(buffer);
}
syslog(LOG_INFO, "Interface=%.16s HWaddr=%02X:%02X:%02X:%02X:%02X:%02X Device=%.32s Buffer size=%d",
ifname,
hwaddr[0], hwaddr[1], hwaddr[2],
hwaddr[3], hwaddr[4], hwaddr[5],
bpfName, bpfLength);
return fd;
}
#endif /* USE_BPF */
#ifdef USE_LINUX_PACKET
/**********************************************************************
*%FUNCTION: openInterface
*%ARGUMENTS:
* ifname -- name of interface
* type -- Ethernet frame type
* hwaddr -- if non-NULL, set to the hardware address
*%RETURNS:
* A raw socket for talking to the Ethernet card. Exits on error.
*%DESCRIPTION:
* Opens a raw Ethernet socket
***********************************************************************/
int
openInterface(char const *ifname, UINT16_t type, unsigned char *hwaddr)
{
int optval=1;
int fd;
struct ifreq ifr;
int domain, stype;
#ifdef HAVE_STRUCT_SOCKADDR_LL
struct sockaddr_ll sa;
#else
struct sockaddr sa;
#endif
memset(&sa, 0, sizeof(sa));
#ifdef HAVE_STRUCT_SOCKADDR_LL
domain = PF_PACKET;
stype = SOCK_RAW;
#else
domain = PF_INET;
stype = SOCK_PACKET;
#endif
if ((fd = socket(domain, stype, htons(type))) < 0) {
/* Give a more helpful message for the common error case */
if (errno == EPERM) {
rp_fatal("Cannot create raw socket -- pppoe must be run as root.");
}
fatalSys("socket");
}
if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &optval, sizeof(optval)) < 0) {
fatalSys("setsockopt");
}
/* Fill in hardware address */
if (hwaddr) {
strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0) {
fatalSys("ioctl(SIOCGIFHWADDR)");
}
memcpy(hwaddr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
#ifdef ARPHRD_ETHER
if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
char buffer[256];
sprintf(buffer, "Interface %.16s is not Ethernet", ifname);
rp_fatal(buffer);
}
#endif
if (NOT_UNICAST(hwaddr)) {
char buffer[256];
sprintf(buffer,
"Interface %.16s has broadcast/multicast MAC address??",
ifname);
rp_fatal(buffer);
}
}
/* Sanity check on MTU */
strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
if (ioctl(fd, SIOCGIFMTU, &ifr) < 0) {
fatalSys("ioctl(SIOCGIFMTU)");
}
if (ifr.ifr_mtu < ETH_DATA_LEN) {
char buffer[256];
sprintf(buffer, "Interface %.16s has MTU of %d -- should be %d. You may have serious connection problems.",
ifname, ifr.ifr_mtu, ETH_DATA_LEN);
printErr(buffer);
}
#ifdef HAVE_STRUCT_SOCKADDR_LL
/* Get interface index */
sa.sll_family = AF_PACKET;
sa.sll_protocol = htons(type);
strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
if (ioctl(fd, SIOCGIFINDEX, &ifr) < 0) {
fatalSys("ioctl(SIOCFIGINDEX): Could not get interface index");
}
sa.sll_ifindex = ifr.ifr_ifindex;
#else
strcpy(sa.sa_data, ifname);
#endif
/* We're only interested in packets on specified interface */
if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
fatalSys("bind");
}
return fd;
}
#endif /* USE_LINUX */
/***********************************************************************
*%FUNCTION: sendPacket
*%ARGUMENTS:
* sock -- socket to send to
* pkt -- the packet to transmit
* size -- size of packet (in bytes)
*%RETURNS:
* 0 on success; -1 on failure
*%DESCRIPTION:
* Transmits a packet
***********************************************************************/
int
sendPacket(PPPoEConnection *conn, int sock, PPPoEPacket *pkt, int size)
{
#if defined(USE_BPF)
if (write(sock, pkt, size) < 0) {
sysErr("write (sendPacket)");
return -1;
}
#elif defined(HAVE_STRUCT_SOCKADDR_LL)
if (send(sock, pkt, size, 0) < 0) {
sysErr("send (sendPacket)");
return -1;
}
#else
#ifdef USE_DLPI
#define ABS(x) ((x) < 0 ? -(x) : (x))
u_char addr[MAXDLADDR];
u_char phys[MAXDLADDR];
u_char sap[MAXDLADDR];
u_char xmitbuf[MAXDLBUF];
int data_size;
short tmp_sap;
tmp_sap = htons(pkt->ethHdr.h_proto);
data_size = size - sizeof(struct ethhdr);
memcpy((char *)phys, (char *)pkt->ethHdr.h_dest, ETHERADDRL);
memcpy((char *)sap, (char *)&tmp_sap, sizeof(ushort_t));
memcpy((char *)xmitbuf, (char *)pkt + sizeof(struct ethhdr), data_size);
if (dl_saplen > 0) { /* order is sap+phys */
(void) memcpy((char*)addr, (char*)&sap, dl_abssaplen);
(void) memcpy((char*)addr+dl_abssaplen, (char*)phys, ETHERADDRL);
} else { /* order is phys+sap */
(void) memcpy((char*)addr, (char*)phys, ETHERADDRL);
(void) memcpy((char*)addr+ETHERADDRL, (char*)&sap, dl_abssaplen);
}
#ifdef DL_DEBUG
printf("%02x:%02x:%02x:%02x:%02x:%02x %02x:%02x\n",
addr[0],addr[1],addr[2],addr[3],addr[4],addr[5],
addr[6],addr[7]);
#endif
dlunitdatareq(sock, addr, dl_addrlen, 0, 0, xmitbuf, data_size);
#else
struct sockaddr sa;
if (!conn) {
rp_fatal("relay and server not supported on Linux 2.0 kernels");
}
strcpy(sa.sa_data, conn->ifName);
if (sendto(sock, pkt, size, 0, &sa, sizeof(sa)) < 0) {
sysErr("sendto (sendPacket)");
return -1;
}
#endif
#endif
return 0;
}
#ifdef USE_BPF
/***********************************************************************
*%FUNCTION: clearPacketHeader
*%ARGUMENTS:
* pkt -- packet that needs its head clearing
*%RETURNS:
* nothing
*%DESCRIPTION:
* Clears a PPPoE packet header after a truncated packet has been
* received. Insures that the packet will fail any integrity tests
* and will be discarded by upper level routines. Also resets the
* bpfSize and bpfOffset variables to force a new read on the next
* call to receivePacket().
***********************************************************************/
void
clearPacketHeader(PPPoEPacket *pkt)
{
bpfSize = bpfOffset = 0;
memset(pkt, 0, HDR_SIZE);
}
#endif
/***********************************************************************
*%FUNCTION: receivePacket
*%ARGUMENTS:
* sock -- socket to read from
* pkt -- place to store the received packet
* size -- set to size of packet in bytes
*%RETURNS:
* >= 0 if all OK; < 0 if error
*%DESCRIPTION:
* Receives a packet
***********************************************************************/
int
receivePacket(int sock, PPPoEPacket *pkt, int *size)
{
#ifdef USE_BPF
struct bpf_hdr hdr;
int seglen, copylen;
if (bpfSize <= 0) {
bpfOffset = 0;
if ((bpfSize = read(sock, bpfBuffer, bpfLength)) < 0) {
sysErr("read (receivePacket)");
return -1;
}
}
if (bpfSize < sizeof(hdr)) {
syslog(LOG_ERR, "Truncated bpf packet header: len=%d", bpfSize);
clearPacketHeader(pkt); /* resets bpfSize and bpfOffset */
return 0;
}
memcpy(&hdr, bpfBuffer + bpfOffset, sizeof(hdr));
if (hdr.bh_caplen != hdr.bh_datalen) {
syslog(LOG_ERR, "Truncated bpf packet: caplen=%d, datalen=%d",
hdr.bh_caplen, hdr.bh_datalen);
clearPacketHeader(pkt); /* resets bpfSize and bpfOffset */
return 0;
}
seglen = hdr.bh_hdrlen + hdr.bh_caplen;
if (seglen > bpfSize) {
syslog(LOG_ERR, "Truncated bpf packet: seglen=%d, bpfSize=%d",
seglen, bpfSize);
clearPacketHeader(pkt); /* resets bpfSize and bpfOffset */
return 0;
}
seglen = BPF_WORDALIGN(seglen);
*size = copylen = ((hdr.bh_caplen < sizeof(PPPoEPacket)) ?
hdr.bh_caplen : sizeof(PPPoEPacket));
memcpy(pkt, bpfBuffer + bpfOffset + hdr.bh_hdrlen, copylen);
if (seglen >= bpfSize) {
bpfSize = bpfOffset = 0;
} else {
bpfSize -= seglen;
bpfOffset += seglen;
}
#else
#ifdef USE_DLPI
struct strbuf data;
int flags = 0;
int retval;
data.buf = (char *) pkt;
data.maxlen = MAXDLBUF;
data.len = 0;
if ((retval = getmsg(sock, NULL, &data, &flags)) < 0) {
sysErr("read (receivePacket)");
return -1;
}
*size = data.len;
#else
if ((*size = recv(sock, pkt, sizeof(PPPoEPacket), 0)) < 0) {
sysErr("recv (receivePacket)");
return -1;
}
#endif
#endif
return 0;
}
#ifdef USE_DLPI
/**********************************************************************
*%FUNCTION: openInterface
*%ARGUMENTS:
* ifname -- name of interface
* type -- Ethernet frame type
* hwaddr -- if non-NULL, set to the hardware address
*%RETURNS:
* A raw socket for talking to the Ethernet card. Exits on error.
*%DESCRIPTION:
* Opens a raw Ethernet socket
***********************************************************************/
int
openInterface(char const *ifname, UINT16_t type, unsigned char *hwaddr)
{
int fd;
long buf[MAXDLBUF];
union DL_primitives *dlp;
char base_dev[PATH_MAX];
int ppa;
if(strlen(ifname) > PATH_MAX) {
rp_fatal("socket: Interface name too long");
}
if (strlen(ifname) < 2) {
rp_fatal("socket: Interface name too short");
}
ppa = atoi(&ifname[strlen(ifname)-1]);
strncpy(base_dev, ifname, PATH_MAX);
base_dev[strlen(base_dev)-1] = '\0';
/* rearranged order of DLPI code - delphys 20010803 */
dlp = (union DL_primitives*) buf;
if ( (fd = open(base_dev, O_RDWR)) < 0) {
/* Give a more helpful message for the common error case */
if (errno == EPERM) {
rp_fatal("Cannot create raw socket -- pppoe must be run as root.");
}
/* Common error is to omit /dev/ */
if (errno == ENOENT) {
char ifname[512];
snprintf(ifname, sizeof(ifname), "/dev/%s", base_dev);
if ((fd = open(ifname, O_RDWR)) < 0) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -