/* Some route implementation which has "PPTP pass-through" function * will discard 1723/tcp packet between PAC and PNS, when it recognize * SLI from PAC. (for example, FLASHWAVE by Fujitsu). * * To avoid avobe situation, npppd send well-known SLI only. */ static int pptp_call_send_SLI(pptp_call *_this) { int lpkt; struct pptp_sli *sli; sli = bytebuffer_pointer(_this->ctrl->send_buf); lpkt = bytebuffer_remaining(_this->ctrl->send_buf); if (lpkt < sizeof(struct pptp_sli)) { pptp_call_log(_this, LOG_ERR, "SendOCRP failed: No buffer space available"); return -1; } memset(sli, 0, sizeof(struct pptp_sli)); pptp_init_header(&sli->header, sizeof(struct pptp_sli), PPTP_CTRL_MES_CODE_SLI); sli->peers_call_id = _this->id; sli->send_accm = 0xffffffff; sli->recv_accm = 0xffffffff; _this->last_io = get_monosec(); pptp_call_log(_this, LOG_INFO, "SendSLI accm=%08x:%08x", sli->send_accm, sli->recv_accm); sli->peers_call_id = htons(sli->peers_call_id); sli->send_accm = htonl(sli->send_accm); sli->recv_accm = htonl(sli->recv_accm); pptp_ctrl_output(_this->ctrl, NULL, sizeof(struct pptp_sli)); return 0; }
int pptp_call_init(pptp_call *_this, pptp_ctrl *ctrl) { memset(_this, 0, sizeof(pptp_call)); _this->ctrl = ctrl; _this->maxwinsz = PPTP_CALL_DEFAULT_MAXWINSZ; _this->winsz = RUPDIV(_this->maxwinsz, 2); _this->last_io = get_monosec(); _this->snd_nxt = 1; return 0; }
/* send control packet */ int l2tp_ctrl_send_packet(l2tp_ctrl *_this, int call_id, bytebuffer *bytebuf) { struct l2tp_header *hdr; int rval; time_t curr_time; curr_time = get_monosec(); bytebuffer_flip(bytebuf); hdr = (struct l2tp_header *)bytebuffer_pointer(bytebuf); memset(hdr, 0, sizeof(*hdr)); hdr->t = 1; hdr->ver = L2TP_HEADER_VERSION_RFC2661; hdr->l = 1; hdr->length = htons(bytebuffer_remaining(bytebuf)); hdr->tunnel_id = htons(_this->peer_tunnel_id); hdr->session_id = htons(call_id); hdr->s = 1; hdr->ns = htons(_this->snd_nxt); hdr->nr = htons(_this->rcv_nxt); if (bytebuffer_remaining(bytebuf) > sizeof(struct l2tp_header)) /* Not ZLB */ _this->snd_nxt++; L2TP_CTRL_DBG((_this, DEBUG_LEVEL_2, "SEND C ns=%u nr=%u snd_nxt=%u snd_una=%u rcv_nxt=%u ", ntohs(hdr->ns), htons(hdr->nr), _this->snd_nxt, _this->snd_una, _this->rcv_nxt)); if (L2TP_CTRL_CONF(_this)->ctrl_out_pktdump != 0) { l2tpd_log(_this->l2tpd, LOG_DEBUG, "L2TP Control output packet dump"); show_hd(debug_get_debugfp(), bytebuffer_pointer(bytebuf), bytebuffer_remaining(bytebuf)); } if ((rval = l2tp_ctrl_send(_this, bytebuffer_pointer(bytebuf), bytebuffer_remaining(bytebuf))) < 0) { L2TP_CTRL_DBG((_this, LOG_DEBUG, "sendto() failed: %m")); } _this->last_snd_ctrl = curr_time; return (rval == bytebuffer_remaining(bytebuf))? 0 : 1; }
/* Send Outgoing-Call-Reply */ static int pptp_call_send_OCRP(pptp_call *_this, int result, int error, int cause) { int lpkt; struct pptp_ocrp *ocrp; char logbuf[512]; ocrp = bytebuffer_pointer(_this->ctrl->send_buf); lpkt = bytebuffer_remaining(_this->ctrl->send_buf); if (lpkt < sizeof(struct pptp_ocrp)) { pptp_call_log(_this, LOG_ERR, "SendOCRP failed: No buffer space available"); return -1; } memset(ocrp, 0, sizeof(struct pptp_ocrp)); pptp_init_header(&ocrp->header, sizeof(struct pptp_ocrp), PPTP_CTRL_MES_CODE_OCRP); ocrp->call_id = _this->id; ocrp->peers_call_id = _this->peers_call_id; ocrp->result_code = result; ocrp->error_code = error; ocrp->cause_code = cause; ocrp->connect_speed = PPTP_CALL_CONNECT_SPEED; ocrp->recv_winsz = _this->maxwinsz; ocrp->packet_proccessing_delay = PPTP_CALL_INITIAL_PPD; ocrp->physical_channel_id = _this->id; pptp_call_OCRP_string(ocrp, logbuf, sizeof(logbuf)); pptp_call_log(_this, LOG_INFO, "SendOCRP %s", logbuf); ocrp->call_id = htons(ocrp->call_id); ocrp->peers_call_id = htons(ocrp->peers_call_id); ocrp->cause_code = htons(ocrp->cause_code); ocrp->connect_speed = htons(ocrp->connect_speed); ocrp->recv_winsz = htons(ocrp->recv_winsz); ocrp->packet_proccessing_delay = htons(ocrp->packet_proccessing_delay); ocrp->physical_channel_id = htonl(ocrp->physical_channel_id); _this->last_io = get_monosec(); pptp_ctrl_output(_this->ctrl, NULL, sizeof(struct pptp_ocrp)); return 0; }
/** This function is called when IPCP is opened */ void ppp_ipcp_opened(npppd_ppp *_this) { time_t curr_time; curr_time = get_monosec(); npppd_set_ip_enabled(_this->pppd, _this, 1); if (_this->logged_acct_start == 0) { char label[512], ipstr[64]; ppp_set_tunnel_label(_this, label, sizeof(label)); strlcpy(ipstr, " ip=", sizeof(ipstr)); strlcat(ipstr, inet_ntoa(_this->ppp_framed_ip_address), sizeof(ipstr)); if (_this->ppp_framed_ip_netmask.s_addr != 0xffffffffL) { strlcat(ipstr, ":", sizeof(ipstr)); strlcat(ipstr, inet_ntoa(_this->ppp_framed_ip_netmask), sizeof(ipstr)); } ppp_log(_this, LOG_NOTICE, "logtype=TUNNELSTART user=\"%s\" duration=%lusec layer2=%s " "layer2from=%s auth=%s %s iface=%s%s", _this->username[0]? _this->username : "******", (long)(curr_time - _this->start_monotime), _this->phy_label, label, _this->username[0]? ppp_peer_auth_string(_this) : "none", ipstr, npppd_ppp_get_iface_name(_this->pppd, _this), (_this->lcp.dialin_proxy != 0)? " dialin_proxy=yes" : "" ); #ifdef USE_NPPPD_RADIUS npppd_ppp_radius_acct_start(_this->pppd, _this); #endif _this->logged_acct_start = 1; ppp_reset_idle_timeout(_this); } #ifdef USE_NPPPD_PIPEX ppp_on_network_pipex(_this); #endif }
/** * Start the npppd_ppp. * Set npppd_ppp#phy_context, npppd_ppp#send_packet, npppd_ppp#phy_close and * npppd_ppp#phy_info before call this function. */ void ppp_start(npppd_ppp *_this) { char label[512]; PPP_ASSERT(_this != NULL); PPP_ASSERT(_this->recv_packet != NULL); PPP_ASSERT(_this->send_packet != NULL); PPP_ASSERT(_this->phy_close != NULL); _this->start_time = time(NULL); _this->start_monotime = get_monosec(); /* log the lower layer information */ ppp_set_tunnel_label(_this, label, sizeof(label)); ppp_log(_this, LOG_INFO, "logtype=Started tunnel=%s(%s)", _this->phy_label, label); lcp_lowerup(&_this->lcp); }
/* Send Call-Disconnect-Notify */ static void pptp_call_send_CDN(pptp_call *_this, int result, int error, int cause, const char *statistics) { int lpkt; struct pptp_cdn *cdn; cdn = bytebuffer_pointer(_this->ctrl->send_buf); lpkt = bytebuffer_remaining(_this->ctrl->send_buf); if (lpkt < sizeof(struct pptp_cdn)) { pptp_call_log(_this, LOG_ERR, "SendCCR failed: No buffer space available"); return; } memset(cdn, 0, sizeof(struct pptp_cdn)); pptp_init_header(&cdn->header, sizeof(struct pptp_cdn), PPTP_CTRL_MES_CODE_CDN); cdn->call_id = _this->id; cdn->result_code = result; cdn->error_code = error; cdn->cause_code = cause; if (statistics != NULL) strlcpy(cdn->statistics, statistics, sizeof(cdn->statistics)); pptp_call_log(_this, LOG_INFO, "SendCDN " "call_id=%u result=%s(%d) error=%s(%d) cause=%d statistics=%s", cdn->call_id, pptp_CDN_result_string(cdn->result_code), cdn->result_code, pptp_general_error_string(cdn->error_code), cdn->error_code, cdn->cause_code, (statistics == NULL)? "(none)" : (char *)cdn->statistics); cdn->call_id = htons(cdn->call_id); cdn->cause_code = htons(cdn->cause_code); _this->last_io = get_monosec(); pptp_ctrl_output(_this->ctrl, NULL, sizeof(struct pptp_cdn)); }
/* Receive packet */ void l2tp_ctrl_input(l2tpd *_this, int listener_index, struct sockaddr *peer, struct sockaddr *sock, void *nat_t_ctx, u_char *pkt, int pktlen) { int i, len, offsiz, reqlen, is_ctrl; uint16_t mestype; struct l2tp_avp *avp, *avp0; l2tp_ctrl *ctrl; l2tp_call *call; char buf[L2TP_AVP_MAXSIZ], errmsg[256]; time_t curr_time; u_char *pkt0; struct l2tp_header hdr; char hbuf[NI_MAXHOST + NI_MAXSERV + 16]; ctrl = NULL; curr_time = get_monosec(); pkt0 = pkt; L2TP_CTRL_ASSERT(peer->sa_family == sock->sa_family); L2TP_CTRL_ASSERT(peer->sa_family == AF_INET || peer->sa_family == AF_INET6) /* * Parse L2TP Header */ memset(&hdr, 0, sizeof(hdr)); if (pktlen < 2) { snprintf(errmsg, sizeof(errmsg), "a short packet. " "length=%d", pktlen); goto bad_packet; } memcpy(&hdr, pkt, 2); pkt += 2; if (hdr.ver != L2TP_HEADER_VERSION_RFC2661) { /* XXX: only RFC2661 is supported */ snprintf(errmsg, sizeof(errmsg), "Unsupported version at header = %d", hdr.ver); goto bad_packet; } is_ctrl = (hdr.t != 0)? 1 : 0; /* calc required length */ reqlen = 6; /* for Flags, Tunnel-Id, Session-Id field */ if (hdr.l) reqlen += 2; /* for Length field (opt) */ if (hdr.s) reqlen += 4; /* for Ns, Nr field (opt) */ if (hdr.o) reqlen += 2; /* for Offset Size field (opt) */ if (reqlen > pktlen) { snprintf(errmsg, sizeof(errmsg), "a short packet. length=%d", pktlen); goto bad_packet; } if (hdr.l != 0) { GETSHORT(hdr.length, pkt); if (hdr.length > pktlen) { snprintf(errmsg, sizeof(errmsg), "Actual packet size is smaller than the length " "field %d < %d", pktlen, hdr.length); goto bad_packet; } pktlen = hdr.length; /* remove trailing trash */ } GETSHORT(hdr.tunnel_id, pkt); GETSHORT(hdr.session_id, pkt); if (hdr.s != 0) { GETSHORT(hdr.ns, pkt); GETSHORT(hdr.nr, pkt); } if (hdr.o != 0) { GETSHORT(offsiz, pkt); if (pktlen < offsiz) { snprintf(errmsg, sizeof(errmsg), "offset field is bigger than remaining packet " "length %d > %d", offsiz, pktlen); goto bad_packet; } pkt += offsiz; } L2TP_CTRL_ASSERT(pkt - pkt0 == reqlen); pktlen -= (pkt - pkt0); /* cut down the length of header */ ctrl = NULL; memset(buf, 0, sizeof(buf)); mestype = 0; avp = NULL; if (is_ctrl) { avp0 = (struct l2tp_avp *)buf; avp = avp_find_message_type_avp(avp0, pkt, pktlen); if (avp != NULL) mestype = avp->attr_value[0] << 8 | avp->attr_value[1]; } ctrl = l2tpd_get_ctrl(_this, hdr.tunnel_id); if (ctrl == NULL) { /* new control */ if (!is_ctrl) { snprintf(errmsg, sizeof(errmsg), "bad data message: tunnelId=%d is not " "found.", hdr.tunnel_id); goto bad_packet; } if (mestype != L2TP_AVP_MESSAGE_TYPE_SCCRQ) { snprintf(errmsg, sizeof(errmsg), "bad control message: tunnelId=%d is not " "found. mestype=%s", hdr.tunnel_id, avp_mes_type_string(mestype)); goto bad_packet; } if ((ctrl = l2tp_ctrl_create()) == NULL) { l2tp_ctrl_log(ctrl, LOG_ERR, "l2tp_ctrl_create() failed: %m"); goto fail; } if (l2tp_ctrl_init(ctrl, _this, peer, sock, nat_t_ctx) != 0) { l2tp_ctrl_log(ctrl, LOG_ERR, "l2tp_ctrl_start() failed: %m"); goto fail; } ctrl->listener_index = listener_index; l2tp_ctrl_reload(ctrl); } else { /* * treat as an error if src address and port is not * match. (because it is potentially DoS attach) */ int notmatch = 0; if (ctrl->peer.ss_family != peer->sa_family) notmatch = 1; else if (peer->sa_family == AF_INET) { if (SIN(peer)->sin_addr.s_addr != SIN(&ctrl->peer)->sin_addr.s_addr || SIN(peer)->sin_port != SIN(&ctrl->peer)->sin_port) notmatch = 1; } else if (peer->sa_family == AF_INET6) { if (!IN6_ARE_ADDR_EQUAL(&(SIN6(peer)->sin6_addr), &(SIN6(&ctrl->peer)->sin6_addr)) || SIN6(peer)->sin6_port != SIN6(&ctrl->peer)->sin6_port) notmatch = 1; } if (notmatch) { snprintf(errmsg, sizeof(errmsg), "tunnelId=%u is already assigned for %s", hdr.tunnel_id, addrport_tostring( (struct sockaddr *)&ctrl->peer, ctrl->peer.ss_len, hbuf, sizeof(hbuf))); goto bad_packet; } } ctrl->last_rcv = curr_time; call = NULL; if (hdr.session_id != 0) { /* search l2tp_call by Session ID */ /* linear search is enough for this purpose */ len = slist_length(&ctrl->call_list); for (i = 0; i < len; i++) { call = slist_get(&ctrl->call_list, i); if (call->session_id == hdr.session_id) break; call = NULL; } } if (!is_ctrl) { int delayed = 0; /* L2TP data */ if (ctrl->state != L2TP_CTRL_STATE_ESTABLISHED) { l2tp_ctrl_log(ctrl, LOG_WARNING, "Received Data packet in '%s'", l2tp_ctrl_state_string(ctrl)); goto fail; } if (call == NULL) { l2tp_ctrl_log(ctrl, LOG_WARNING, "Received a data packet but it has no call. " "session_id=%u", hdr.session_id); goto fail; } L2TP_CTRL_DBG((ctrl, DEBUG_LEVEL_2, "call=%u RECV ns=%u nr=%u snd_nxt=%u rcv_nxt=%u len=%d", call->id, hdr.ns, hdr.nr, call->snd_nxt, call->rcv_nxt, pktlen)); if (call->state != L2TP_CALL_STATE_ESTABLISHED){ l2tp_ctrl_log(ctrl, LOG_WARNING, "Received a data packet but call is not " "established"); goto fail; } if (hdr.s != 0) { if (SEQ_LT(hdr.ns, call->rcv_nxt)) { if (SEQ_LT(hdr.ns, call->rcv_nxt - L2TP_CALL_DELAY_LIMIT)) { /* sequence number seems to be delayed */ /* XXX: need to log? */ L2TP_CTRL_DBG((ctrl, LOG_DEBUG, "receive a out of sequence " "data packet: %u < %u.", hdr.ns, call->rcv_nxt)); return; } delayed = 1; } else { call->rcv_nxt = hdr.ns + 1; } } l2tp_call_ppp_input(call, pkt, pktlen, delayed); return; } if (hdr.s != 0) { L2TP_CTRL_DBG((ctrl, DEBUG_LEVEL_2, "RECV %s ns=%u nr=%u snd_nxt=%u snd_una=%u rcv_nxt=%u " "len=%d", (is_ctrl)? "C" : "", hdr.ns, hdr.nr, ctrl->snd_nxt, ctrl->snd_una, ctrl->rcv_nxt, pktlen)); if (pktlen <= 0) l2tp_ctrl_log(ctrl, LOG_INFO, "RecvZLB"); if (SEQ_GT(hdr.nr, ctrl->snd_una)) { if (hdr.nr == ctrl->snd_nxt || SEQ_LT(hdr.nr, ctrl->snd_nxt)) ctrl->snd_una = hdr.nr; else { l2tp_ctrl_log(ctrl, LOG_INFO, "Received message has bad Nr field: " "%u < %u.", hdr.ns, ctrl->snd_nxt); /* XXX Drop with ZLB? */ goto fail; } } if (l2tp_ctrl_txwin_size(ctrl) <= 0) { /* no waiting ack */ if (ctrl->hello_wait_ack != 0) { /* * Reset Hello state, as an ack for the Hello * is recived. */ ctrl->hello_wait_ack = 0; ctrl->hello_io_time = curr_time; } switch (ctrl->state) { case L2TP_CTRL_STATE_CLEANUP_WAIT: l2tp_ctrl_stop(ctrl, 0); return; } } if (hdr.ns != ctrl->rcv_nxt) { /* there are remaining packet */ if (l2tp_ctrl_resend_una_packets(ctrl) <= 0) { /* resend or sent ZLB */ l2tp_ctrl_send_ZLB(ctrl); } #ifdef L2TP_CTRL_DEBUG if (pktlen != 0) { /* not ZLB */ L2TP_CTRL_DBG((ctrl, LOG_DEBUG, "receive out of sequence %u must be %u. " "mestype=%s", hdr.ns, ctrl->rcv_nxt, avp_mes_type_string(mestype))); } #endif return; } if (pktlen <= 0) return; /* ZLB */ if (l2tp_ctrl_txwin_is_full(ctrl)) { L2TP_CTRL_DBG((ctrl, LOG_DEBUG, "Received message cannot be handled. " "Transmission window is full.")); l2tp_ctrl_send_ZLB(ctrl); return; } ctrl->rcv_nxt++; if (avp == NULL) { l2tpd_log(_this, LOG_WARNING, "bad control message: no message-type AVP."); goto fail; } } /* * state machine (RFC2661 pp. 56-57) */ switch (ctrl->state) { case L2TP_CTRL_STATE_IDLE: switch (mestype) { case L2TP_AVP_MESSAGE_TYPE_SCCRQ: if (l2tp_ctrl_recv_SCCRQ(ctrl, pkt, pktlen, _this, peer) == 0) { /* acceptable */ l2tp_ctrl_send_SCCRP(ctrl); ctrl->state = L2TP_CTRL_STATE_WAIT_CTL_CONN; return; } /* * in case un-acceptable, it was already processed * at l2tcp_ctrl_recv_SCCRQ */ return; case L2TP_AVP_MESSAGE_TYPE_SCCRP: /* * RFC specifies that sent of StopCCN in the state, * However as this implementation only support Passive * open, this packet will not received. */ /* FALLTHROUGH */ case L2TP_AVP_MESSAGE_TYPE_SCCCN: default: break; } goto fsm_fail; case L2TP_CTRL_STATE_WAIT_CTL_CONN: /* Wait-Ctl-Conn */ switch (mestype) { case L2TP_AVP_MESSAGE_TYPE_SCCCN: l2tp_ctrl_log(ctrl, LOG_INFO, "RecvSCCN"); if (l2tp_ctrl_send_ZLB(ctrl) == 0) { ctrl->state = L2TP_CTRL_STATE_ESTABLISHED; } return; case L2TP_AVP_MESSAGE_TYPE_StopCCN: goto receive_stop_ccn; case L2TP_AVP_MESSAGE_TYPE_SCCRQ: case L2TP_AVP_MESSAGE_TYPE_SCCRP: default: break; } break; /* fsm_fail */ case L2TP_CTRL_STATE_ESTABLISHED: /* Established */ switch (mestype) { case L2TP_AVP_MESSAGE_TYPE_SCCCN: case L2TP_AVP_MESSAGE_TYPE_SCCRQ: case L2TP_AVP_MESSAGE_TYPE_SCCRP: break; receive_stop_ccn: case L2TP_AVP_MESSAGE_TYPE_StopCCN: if (l2tp_ctrl_recv_StopCCN(ctrl, pkt, pktlen) == 0) { if (l2tp_ctrl_resend_una_packets(ctrl) <= 0) l2tp_ctrl_send_ZLB(ctrl); l2tp_ctrl_stop(ctrl, 0); return; } l2tp_ctrl_log(ctrl, LOG_ERR, "Received bad StopCCN"); l2tp_ctrl_send_ZLB(ctrl); l2tp_ctrl_stop(ctrl, 0); return; case L2TP_AVP_MESSAGE_TYPE_HELLO: if (l2tp_ctrl_resend_una_packets(ctrl) <= 0) l2tp_ctrl_send_ZLB(ctrl); return; case L2TP_AVP_MESSAGE_TYPE_CDN: case L2TP_AVP_MESSAGE_TYPE_ICRP: case L2TP_AVP_MESSAGE_TYPE_ICCN: if (call == NULL) { l2tp_ctrl_log(ctrl, LOG_INFO, "Unknown call message: %s", avp_mes_type_string(mestype)); goto fail; } /* FALLTHROUGH */ case L2TP_AVP_MESSAGE_TYPE_ICRQ: l2tp_call_recv_packet(ctrl, call, mestype, pkt, pktlen); return; default: break; } break; /* fsm_fail */ case L2TP_CTRL_STATE_CLEANUP_WAIT: if (mestype == L2TP_AVP_MESSAGE_TYPE_StopCCN) { /* * We left ESTABLISHED state, but the peer sent StopCCN. */ goto receive_stop_ccn; } break; /* fsm_fail */ } fsm_fail: /* state machine error */ l2tp_ctrl_log(ctrl, LOG_WARNING, "Received %s in '%s' state", avp_mes_type_string(mestype), l2tp_ctrl_state_string(ctrl)); l2tp_ctrl_stop(ctrl, L2TP_STOP_CCN_RCODE_FSM_ERROR); return; fail: if (ctrl != NULL && mestype != 0) { l2tp_ctrl_log(ctrl, LOG_WARNING, "Received %s in '%s' state", avp_mes_type_string(mestype), l2tp_ctrl_state_string(ctrl)); l2tp_ctrl_stop(ctrl, L2TP_STOP_CCN_RCODE_GENERAL_ERROR); } return; bad_packet: l2tpd_log(_this, LOG_INFO, "Received from=%s: %s", addrport_tostring(peer, peer->sa_len, hbuf, sizeof(hbuf)), errmsg); return; }
/* timeout processing */ static void l2tp_ctrl_timeout(int fd, short evtype, void *ctx) { int next_timeout, need_resend; time_t curr_time; l2tp_ctrl *_this; l2tp_call *call; /* * the timer must be reset, when leave this function. * MEMO: l2tp_ctrl_stop() will reset the timer in it. * and please remember that the l2tp_ctrl_stop() may free _this. */ _this = ctx; L2TP_CTRL_ASSERT(_this != NULL); curr_time = get_monosec(); next_timeout = 2; need_resend = 0; if (l2tp_ctrl_txwin_size(_this) > 0) { if (_this->state == L2TP_CTRL_STATE_ESTABLISHED) { if (_this->hello_wait_ack != 0) { /* wait Hello reply */ if (curr_time - _this->hello_io_time >= _this->hello_timeout) { l2tp_ctrl_log(_this, LOG_NOTICE, "timeout waiting ack for hello " "packets."); l2tp_ctrl_stop(_this, L2TP_STOP_CCN_RCODE_GENERAL); return; } } } else if (curr_time - _this->last_snd_ctrl >= L2TP_CTRL_CTRL_PKT_TIMEOUT) { l2tp_ctrl_log(_this, LOG_NOTICE, "timeout waiting ack for ctrl packets."); l2tp_ctrl_stop(_this, L2TP_STOP_CCN_RCODE_GENERAL); return; } need_resend = 1; } else { for (slist_itr_first(&_this->call_list); slist_itr_has_next(&_this->call_list);) { call = slist_itr_next(&_this->call_list); if (call->state == L2TP_CALL_STATE_CLEANUP_WAIT) { l2tp_call_destroy(call, 1); slist_itr_remove(&_this->call_list); } } } switch (_this->state) { case L2TP_CTRL_STATE_IDLE: /* * idle: * XXX: never happen in current implementation */ l2tp_ctrl_log(_this, LOG_ERR, "Internal error, timeout on illegal state=idle"); l2tp_ctrl_stop(_this, L2TP_STOP_CCN_RCODE_GENERAL); break; case L2TP_CTRL_STATE_WAIT_CTL_CONN: /* * wait-ctrl-conn: * if there is no ack for SCCRP, the peer will * resend SCCRQ. however this implementation can * not recognize that the SCCRQ was resent or not. * Therefore, never resent from this side. */ need_resend = 0; break; case L2TP_CTRL_STATE_ESTABLISHED: if (slist_length(&_this->call_list) == 0 && curr_time - _this->last_snd_ctrl >= L2TP_CTRL_WAIT_CALL_TIMEOUT) { if (_this->ncalls == 0) /* fail to receive first call */ l2tp_ctrl_log(_this, LOG_WARNING, "timeout waiting call"); l2tp_ctrl_stop(_this, L2TP_STOP_CCN_RCODE_GENERAL); return; } if (_this->hello_wait_ack == 0 && _this->hello_interval > 0) { /* send Hello */ if (curr_time - _this->hello_interval >= _this->hello_io_time) { if (l2tp_ctrl_send_HELLO(_this) == 0) /* success */ _this->hello_wait_ack = 1; _this->hello_io_time = curr_time; need_resend = 0; } } break; case L2TP_CTRL_STATE_CLEANUP_WAIT: if (curr_time - _this->last_snd_ctrl >= L2TP_CTRL_CLEANUP_WAIT_TIME) { l2tp_ctrl_log(_this, LOG_NOTICE, "Cleanup timeout state=%d", _this->state); l2tp_ctrl_stop(_this, 0); return; } if (_this->active_closing != 0) l2tp_ctrl_send_disconnect_notify(_this); break; default: l2tp_ctrl_log(_this, LOG_ERR, "Internal error, timeout on illegal state=%d", _this->state); l2tp_ctrl_stop(_this, L2TP_STOP_CCN_RCODE_GENERAL); return; } /* resend if required */ if (need_resend) l2tp_ctrl_resend_una_packets(_this); l2tp_ctrl_reset_timeout(_this); }
/** * initialize and startup of {@link ::_l2tp_ctrl L2TP LNS control connection} * instance */ static int l2tp_ctrl_init(l2tp_ctrl *_this, l2tpd *_l2tpd, struct sockaddr *peer, struct sockaddr *sock, void *nat_t_ctx) { int tunid, i; bytebuffer *bytebuf; time_t curr_time; memset(_this, 0, sizeof(l2tp_ctrl)); curr_time = get_monosec(); _this->l2tpd = _l2tpd; _this->state = L2TP_CTRL_STATE_IDLE; _this->last_snd_ctrl = curr_time; slist_init(&_this->call_list); /* seek a free tunnel ID */ i = 0; _this->id = ++l2tp_ctrl_id_seq; for (i = 0, tunid = _this->id; ; i++, tunid++) { tunid &= 0xffff; _this->tunnel_id = l2tp_ctrl_id_seq & 0xffff; if (tunid == 0) continue; if (l2tpd_get_ctrl(_l2tpd, tunid) == NULL) break; if (i > 80000) { /* this must be happen, just log it. */ l2tpd_log(_l2tpd, LOG_ERR, "Too many l2tp controls"); return -1; } } _this->tunnel_id = tunid; L2TP_CTRL_ASSERT(peer != NULL); L2TP_CTRL_ASSERT(sock != NULL); memcpy(&_this->peer, peer, peer->sa_len); memcpy(&_this->sock, sock, sock->sa_len); /* prepare send buffer */ _this->winsz = L2TPD_DEFAULT_SEND_WINSZ; if ((_this->snd_buffers = calloc(_this->winsz, sizeof(bytebuffer *))) == NULL) { l2tpd_log(_l2tpd, LOG_ERR, "calloc() failed in %s(): %m", __func__); goto fail; } for (i = 0; i < _this->winsz; i++) { if ((bytebuf = bytebuffer_create(L2TPD_SND_BUFSIZ)) == NULL) { l2tpd_log(_l2tpd, LOG_ERR, "bytebuffer_create() failed in %s(): %m", __func__); goto fail; } _this->snd_buffers[i] = bytebuf; } if ((_this->zlb_buffer = bytebuffer_create(sizeof(struct l2tp_header) + 128)) == NULL) { l2tpd_log(_l2tpd, LOG_ERR, "bytebuffer_create() failed in %s(): %m", __func__); goto fail; } #if defined(USE_LIBSOCKUTIL) || defined(USE_SA_COOKIE) if (nat_t_ctx != NULL) { if ((_this->sa_cookie = malloc( sizeof(struct in_ipsec_sa_cookie))) != NULL) { *(struct in_ipsec_sa_cookie *)_this->sa_cookie = *(struct in_ipsec_sa_cookie *)nat_t_ctx; } else { l2tpd_log(_l2tpd, LOG_ERR, "creating sa_cookie failed: %m"); goto fail; } } #endif _this->hello_interval = L2TP_CTRL_DEFAULT_HELLO_INTERVAL; _this->hello_timeout = L2TP_CTRL_DEFAULT_HELLO_TIMEOUT; _this->hello_io_time = curr_time; /* initialize timeout timer */ l2tp_ctrl_reset_timeout(_this); /* register l2tp context */ l2tpd_add_ctrl(_l2tpd, _this); return 0; fail: l2tp_ctrl_stop(_this, 0); return -1; }
void pptp_call_input(pptp_call *_this, int mes_type, u_char *pkt, int lpkt) { PPTP_CALL_ASSERT(_this != NULL); PPTP_CALL_ASSERT(pkt != NULL); PPTP_CALL_ASSERT(lpkt >= 4); _this->last_io = get_monosec(); switch (mes_type) { case PPTP_CTRL_MES_CODE_OCRQ: if (_this->state != PPTP_CALL_STATE_IDLE) { pptp_call_send_OCRP(_this, PPTP_OCRP_RESULT_GENERIC_ERROR, PPTP_ERROR_BAD_CALL, 0); goto bad_state; } if (pptp_call_recv_OCRQ(_this, pkt, lpkt) != 0) { pptp_call_send_OCRP(_this, PPTP_OCRP_RESULT_GENERIC_ERROR, PPTP_ERROR_BAD_CALL, 0); return; } if (pptpd_assign_call(_this->ctrl->pptpd, _this) != 0) { pptp_call_send_OCRP(_this, PPTP_OCRP_RESULT_BUSY, PPTP_ERROR_NONE, 0); return; } if (pptp_call_send_OCRP(_this, PPTP_OCRP_RESULT_CONNECTED, PPTP_ERROR_NONE, 0) != 0) { pptp_call_disconnect(_this, PPTP_CDN_RESULT_GENRIC_ERROR, PPTP_ERROR_PAC_ERROR, NULL); return; } if (pptp_call_start(_this) != 0) { pptp_call_disconnect(_this, PPTP_CDN_RESULT_GENRIC_ERROR, PPTP_ERROR_PAC_ERROR, NULL); return; } _this->state = PPTP_CALL_STATE_ESTABLISHED; break; case PPTP_CTRL_MES_CODE_SLI: if (pptp_call_recv_SLI(_this, pkt, lpkt) != 0) { return; } return; case PPTP_CTRL_MES_CODE_CCR: pptp_call_recv_CCR(_this, pkt, lpkt); if (_this->state == PPTP_CALL_STATE_ESTABLISHED) { pptp_call_disconnect(_this, PPTP_CDN_RESULT_REQUEST, PPTP_ERROR_NONE, NULL); } else { pptp_call_disconnect(_this, 0, 0, NULL); if (_this->state != PPTP_CALL_STATE_CLEANUP_WAIT) goto bad_state; } return; default: pptp_call_log(_this, LOG_WARNING, "Unhandled control message type=%s(%d)", pptp_ctrl_mes_type_string(mes_type), mes_type); } return; bad_state: pptp_call_log(_this, LOG_WARNING, "Received control message %s(%d) in bad state=%s", pptp_ctrl_mes_type_string(mes_type), mes_type, pptp_call_state_string(_this->state)); }
static void ppp_stop0(npppd_ppp *_this) { char mppe_str[BUFSIZ]; char label[512]; #ifdef USE_NPPPD_RADIUS ppp_set_radius_terminate_cause(_this, RADIUS_TERMNATE_CAUSE_NAS_ERROR); #endif ppp_set_disconnect_cause(_this, PPP_DISCON_NORMAL, 0, 1 /* by local */, NULL); _this->end_monotime = get_monosec(); if (_this->phy_close != NULL) _this->phy_close(_this); _this->phy_close = NULL; /* * NAT/Blackhole detection for PPTP(GRE) */ if (_this->lcp.dialin_proxy != 0 && _this->lcp.dialin_proxy_lcp_renegotiation == 0) { /* No LCP packets on dialin proxy without LCP renegotiation */ } else if (_this->lcp.recv_ress == 0) { /* No responses */ if (_this->lcp.recv_reqs == 0) /* No requests */ ppp_log(_this, LOG_WARNING, "no PPP frames from the " "peer. router/NAT issue? (may have filtered out)"); else ppp_log(_this, LOG_WARNING, "my PPP frames may not " "have arrived at the peer. router/NAT issue? (may " "be the only-first-person problem)"); } #ifdef USE_NPPPD_PIPEX if (npppd_ppp_pipex_disable(_this->pppd, _this) != 0) ppp_log(_this, LOG_ERR, "npppd_ppp_pipex_disable() failed: %m"); #endif ppp_set_tunnel_label(_this, label, sizeof(label)); #ifdef USE_NPPPD_MPPE if (_this->mppe_started) { snprintf(mppe_str, sizeof(mppe_str), "mppe=yes mppe_in=%dbits,%s mppe_out=%dbits,%s", _this->mppe.recv.keybits, (_this->mppe.recv.stateless)? "stateless" : "stateful", _this->mppe.send.keybits, (_this->mppe.send.stateless)? "stateless" : "stateful"); } else #endif snprintf(mppe_str, sizeof(mppe_str), "mppe=no"); ppp_log(_this, LOG_NOTICE, "logtype=TUNNELUSAGE user=\"%s\" duration=%ldsec layer2=%s " "layer2from=%s auth=%s data_in=%llubytes,%upackets " "data_out=%llubytes,%upackets error_in=%u error_out=%u %s " "iface=%s", _this->username[0]? _this->username : "******", (long)(_this->end_monotime - _this->start_monotime), _this->phy_label, label, _this->username[0]? ppp_peer_auth_string(_this) : "none", (unsigned long long)_this->ibytes, _this->ipackets, (unsigned long long)_this->obytes, _this->opackets, _this->ierrors, _this->oerrors, mppe_str, npppd_ppp_get_iface_name(_this->pppd, _this)); #ifdef USE_NPPPD_RADIUS npppd_ppp_radius_acct_stop(_this->pppd, _this); #endif npppd_ppp_unbind_iface(_this->pppd, _this); #ifdef USE_NPPPD_MPPE mppe_fini(&_this->mppe); #endif evtimer_del(&_this->idle_event); npppd_release_ip(_this->pppd, _this); ppp_destroy(_this); }