1 /***********************************************************************
5 * Implementation of user-space PPPoE redirector for Linux.
7 * Functions for opening a raw socket and reading/writing raw Ethernet frames.
9 * Copyright (C) 2000 by Roaring Penguin Software Inc.
11 * This program may be distributed according to the terms of the GNU
12 * General Public License, version 2 or (at your option) any later version.
14 ***********************************************************************/
16 static char const RCSID[] =
17 "$Id: if.c,v 1.2 2008/06/09 08:34:23 paulus Exp $";
21 #include "pppd/pppd.h"
27 #ifdef HAVE_NETPACKET_PACKET_H
28 #include <netpacket/packet.h>
29 #elif defined(HAVE_LINUX_IF_PACKET_H)
30 #include <linux/if_packet.h>
33 #ifdef HAVE_ASM_TYPES_H
34 #include <asm/types.h>
37 #ifdef HAVE_SYS_IOCTL_H
38 #include <sys/ioctl.h>
45 #ifdef HAVE_NET_IF_ARP_H
46 #include <net/if_arp.h>
49 /* Initialize frame types to RFC 2516 values. Some broken peers apparently
50 use different frame types... sigh... */
52 UINT16_t Eth_PPPOE_Discovery = ETH_PPPOE_DISCOVERY;
53 UINT16_t Eth_PPPOE_Session = ETH_PPPOE_SESSION;
55 /**********************************************************************
58 * packet -- a received PPPoE packet
60 * ethernet packet type (see /usr/include/net/ethertypes.h)
62 * Checks the ethernet packet header to determine its type.
63 * We should only be receveing DISCOVERY and SESSION types if the BPF
64 * is set up correctly. Logs an error if an unexpected type is received.
65 * Note that the ethernet type names come from "pppoe.h" and the packet
66 * packet structure names use the LINUX dialect to maintain consistency
67 * with the rest of this file. See the BSD section of "pppoe.h" for
68 * translations of the data structure names.
69 ***********************************************************************/
71 etherType(PPPoEPacket *packet)
73 UINT16_t type = (UINT16_t) ntohs(packet->ethHdr.h_proto);
74 if (type != Eth_PPPOE_Discovery && type != Eth_PPPOE_Session) {
75 error("Invalid ether type 0x%x", type);
80 /**********************************************************************
81 *%FUNCTION: openInterface
83 * ifname -- name of interface
84 * type -- Ethernet frame type
85 * hwaddr -- if non-NULL, set to the hardware address
87 * A raw socket for talking to the Ethernet card. Exits on error.
89 * Opens a raw Ethernet socket
90 ***********************************************************************/
92 openInterface(char const *ifname, UINT16_t type, unsigned char *hwaddr)
99 #ifdef HAVE_STRUCT_SOCKADDR_LL
100 struct sockaddr_ll sa;
105 memset(&sa, 0, sizeof(sa));
107 #ifdef HAVE_STRUCT_SOCKADDR_LL
115 if ((fd = socket(domain, stype, htons(type))) < 0) {
116 /* Give a more helpful message for the common error case */
117 if (errno == EPERM) {
118 fatal("Cannot create raw socket -- pppoe must be run as root.");
120 error("Can't open socket for pppoe: %m");
124 if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &optval, sizeof(optval)) < 0) {
125 error("Can't set socket options for pppoe: %m");
130 /* Fill in hardware address */
132 strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
133 if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0) {
134 error("Can't get hardware address for %s: %m", ifname);
138 memcpy(hwaddr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
140 if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
141 warn("Interface %.16s is not Ethernet", ifname);
144 if (NOT_UNICAST(hwaddr)) {
145 fatal("Can't use interface %.16s: it has broadcast/multicast MAC address",
150 /* Sanity check on MTU */
151 strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
152 if (ioctl(fd, SIOCGIFMTU, &ifr) < 0) {
153 error("Can't get MTU for %s: %m", ifname);
154 } else if (ifr.ifr_mtu < ETH_DATA_LEN) {
155 error("Interface %.16s has MTU of %d -- should be at least %d.",
156 ifname, ifr.ifr_mtu, ETH_DATA_LEN);
157 error("This may cause serious connection problems.");
160 #ifdef HAVE_STRUCT_SOCKADDR_LL
161 /* Get interface index */
162 sa.sll_family = AF_PACKET;
163 sa.sll_protocol = htons(type);
165 strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
166 if (ioctl(fd, SIOCGIFINDEX, &ifr) < 0) {
167 error("Could not get interface index for %s: %m", ifname);
171 sa.sll_ifindex = ifr.ifr_ifindex;
174 strcpy(sa.sa_data, ifname);
177 /* We're only interested in packets on specified interface */
178 if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
179 error("Failed to bind to interface %s: %m", ifname);
188 /***********************************************************************
189 *%FUNCTION: sendPacket
191 * sock -- socket to send to
192 * pkt -- the packet to transmit
193 * size -- size of packet (in bytes)
195 * 0 on success; -1 on failure
198 ***********************************************************************/
200 sendPacket(PPPoEConnection *conn, int sock, PPPoEPacket *pkt, int size)
205 pppoe_log_packet("Send ", pkt);
206 #if defined(HAVE_STRUCT_SOCKADDR_LL)
207 err = send(sock, pkt, size, 0);
211 strcpy(sa.sa_data, conn->ifName);
212 err = sendto(sock, pkt, size, 0, &sa, sizeof(sa));
215 error("error sending pppoe packet: %m");
221 /***********************************************************************
222 *%FUNCTION: receivePacket
224 * sock -- socket to read from
225 * pkt -- place to store the received packet
226 * size -- set to size of packet in bytes
228 * >= 0 if all OK; < 0 if error
231 ***********************************************************************/
233 receivePacket(int sock, PPPoEPacket *pkt, int *size)
235 if ((*size = recv(sock, pkt, sizeof(PPPoEPacket), 0)) < 0) {
236 error("error receiving pppoe packet: %m");
240 pppoe_log_packet("Recv ", pkt);