#include "selectops.h" #include "link.h" #include #include #define ETH_P_PPPoE_DISC 0x8863 #define ETH_P_PPPoE_SESN 0x8864 #define PPPoE_CODE_DATA 0x00 #define PPPoE_CODE_PADI 0x09 #define PPPoE_CODE_PADO 0x07 #define PPPoE_CODE_PADR 0x19 #define PPPoE_CODE_PADS 0x65 #define PPPoE_CODE_PADT 0xa7 #define PPPoE_TAG_END_OF_LIST 0x0000 #define PPPoE_TAG_SERVICE_NAME 0x0101 #define PPPoE_TAG_AC_NAME 0x0102 #define PPPoE_TAG_HOST_UNIQ 0x0103 #define PPPoE_TAG_AC_COOKIE 0x0104 #define PPPoE_TAG_VENDOR_SPECIFIC 0x0105 #define PPPoE_TAG_RELAY_SESSION_ID 0x0110 #define PPPoE_TAG_SERVICE_NAME_ERROR 0x0201 #define PPPoE_TAG_AC_SYSTEM_ERROR 0x0202 #define PPPoE_TAG_GENERIC_ERROR 0x0203 struct pppoehdr { unsigned char dst_addr[6]; unsigned char src_addr[6]; unsigned short ether_type; unsigned char vertype; unsigned char code; unsigned short sesn_id; unsigned short length; } __attribute__((packed)); class pppoed; class pppoe_session : public CLink, public CTimer { pppoed *parent; public: u16 session_id; u8 peer_mac[6]; /* We need to default to a 1492 MTU for PPPoE sessions, otherwise * LCP won't converge with a DLink WBR-2310 router. */ virtual unsigned DefaultMRU(void) { return 1492; } channel_t ch; pppoe_session(u8 *mac, u16 id, pppoed *pppoed); pppoe_session(channel_t *ch); ~pppoe_session(); void pppoe_input(u8 *buf, int len); int HardOutput(CPppPacket *pkt, int pri = 0); void HardHangup(void); friend pppoe_session *find_idle_session(u8 *mac_addr, u16 id, pppoed *pppoed); #define BPPPOE_MULTIHOP_IDLE_INTERVAL (1*60*100) // 1 minute virtual void TimerExpired(void); // Use for checking idle time }; class relay_session_t : public CTimer { public: pppoed *m_relay; pppoed *m_pppoed; relay_session_t *m_next; u8 *m_tag; u16 m_tag_len; u8 m_client_mac[6]; u8 m_server_mac[6]; struct timespec m_access_time; const char *m_state; void update_access_time(void) { if (clock_gettime(CLOCK_MONOTONIC, &m_access_time)) *(char *)0 = 0; Stop(); Start(120 * 100); // 120s timeout } long get_idle_time(void) { struct timespec now; if (clock_gettime(CLOCK_MONOTONIC, &now)) *(char *)0 = 0; long secs = now.tv_sec - m_access_time.tv_sec; return secs; } relay_session_t() { m_relay = NULL; m_pppoed = NULL; m_next = NULL; m_tag = NULL; m_tag_len = 0; memset(m_client_mac, 0xff, 6); memset(m_server_mac, 0xff, 6); update_access_time(); m_state = "new"; Start(120 * 100); // 120s timeout } ~relay_session_t() { if (m_tag) free(m_tag); } virtual void TimerExpired(void); }; class bvirt_ns_t; class pppoed : public SelectEventHandler { friend int pppoe_session::HardOutput(CPppPacket *pkt, int pri = 0); friend void pppoe_session::HardHangup(void); friend void bpppoe_del(ctrlfd_t *cfd, char *str); friend void bpppoe_show_relay(ctrlfd_t *cfd); friend void relay_session_t::TimerExpired(void); pppoed *m_next, **m_prevp, *m_prev; int pppoed_disc_fd; int pppoed_sesn_fd; u8 our_addr[6]; u16 last_session_id; bvirt_ns_t *m_netns; const char *ac_name; int ac_name_len; pppoed *m_relay; relay_session_t *m_relay_session_list; relay_session_t *lookup_relay_session_by_tag(u8 *tag, u16 tag_len); relay_session_t *lookup_relay_session_by_client_mac(u8 *mac); void relay_padi(pppoed *src, struct pppoehdr *h, u8 *tag, u16 tag_len); void relay_pado(relay_session_t *relay_sesn, struct pppoehdr *h); void relay_padr(relay_session_t *relay_sesn, struct pppoehdr *h); pppoe_session *sessions[65536]; u16 alloc_sesn_id(unsigned char *mac_addr); void send_padi(pppoed *src, struct pppoehdr *h); /* Only in relay mode */ void send_pado(struct pppoehdr *h); void send_pads(struct pppoehdr *h); public: char pppoed_dev_name[16]; int m_relay_mode; void send_padt(u16 session_id, u8 *our_addr, u8 *peer_addr); struct sockaddr sa; pppoed(const char *dev_name, int disc_fd, char *addr, bvirt_ns_t *netns, int relay_mode); ~pppoed(); void setup_sesn_sk(int sk); void setup_relay(pppoed *relay); void SelectEvent(int fd, SelectEventType event); void remove_session(pppoe_session *s, u16 idx); void set_ac_name(const char *name) { if (ac_name) free((void*)ac_name); ac_name = strdup(name); ac_name_len = strlen(ac_name); } int pppoed_sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dst, socklen_t addrlen); void show_running_config(ctrlfd_t *cfd, int verbose); friend void show_pppoed_list(ctrlfd_t *cfd, int verbose); friend pppoed *find_pppoed(bvirt_ns_t *netns, char *devname); };