/* * setup {@link ::_l2tp_ctrl L2TP LNS control connection} instance */ static void l2tp_ctrl_reload(l2tp_ctrl *_this) { _this->data_use_seq = L2TP_CTRL_CONF(_this)->data_use_seq; if (L2TP_CTRL_CONF(_this)->hello_interval != 0) _this->hello_interval = L2TP_CTRL_CONF(_this)->hello_interval; if (L2TP_CTRL_CONF(_this)->hello_timeout != 0) _this->hello_timeout = L2TP_CTRL_CONF(_this)->hello_timeout; }
/* 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 L2TP data message */ static int l2tp_call_send_data_packet(l2tp_call *_this, bytebuffer *buffer) { int rval; struct l2tp_header *hdr; bytebuffer_flip(buffer); hdr = (struct l2tp_header *)bytebuffer_pointer(buffer); memset(hdr, 0, sizeof(*hdr) - 4); /* Nr, NS are option */ hdr->t = 0; hdr->ver = L2TP_HEADER_VERSION_RFC2661; hdr->l = 1; hdr->length = htons(bytebuffer_remaining(buffer)); hdr->tunnel_id = htons(_this->ctrl->peer_tunnel_id); hdr->session_id = htons(_this->peer_session_id); if (_this->use_seq) { hdr->s = 1; hdr->ns = htons(_this->snd_nxt++); hdr->nr = htons(_this->rcv_nxt); } if (L2TP_CTRL_CONF(_this->ctrl)->data_out_pktdump != 0) { l2tpd_log(_this->ctrl->l2tpd, LOG_DEBUG, "ctrl=%u call=%u L2TP Data output packet dump", _this->ctrl->id, _this->id); show_hd(debug_get_debugfp(), bytebuffer_pointer(buffer), bytebuffer_remaining(buffer)); } if ((rval = l2tp_ctrl_send(_this->ctrl, bytebuffer_pointer(buffer), bytebuffer_remaining(buffer))) < 0) { L2TP_CALL_DBG((_this, LOG_DEBUG, "sendto() failed: %m")); } return (rval == bytebuffer_remaining(buffer))? 0 : 1; }
/* bind ppp */ static int l2tp_call_bind_ppp(l2tp_call *_this, dialin_proxy_info *dpi) { int code, errcode; npppd_ppp *ppp; code = L2TP_CDN_RCODE_BUSY; errcode = 0; ppp = NULL; if ((ppp = ppp_create()) == NULL) goto fail; ASSERT(_this->ppp == NULL); if (_this->ppp != NULL) return -1; _this->ppp = ppp; ppp->tunnel_type = NPPPD_TUNNEL_L2TP; ppp->phy_context = _this; ppp->send_packet = l2tp_call_ppp_output; ppp->phy_close = l2tp_call_closed_by_ppp; strlcpy(ppp->phy_label, L2TP_CTRL_LISTENER_TUN_NAME(_this->ctrl), sizeof(ppp->phy_label)); L2TP_CALL_ASSERT(sizeof(ppp->phy_info) >= _this->ctrl->peer.ss_len); memcpy(&ppp->phy_info, &_this->ctrl->peer, MIN(sizeof(ppp->phy_info), _this->ctrl->peer.ss_len)); strlcpy(ppp->calling_number, _this->calling_number, sizeof(ppp->calling_number)); if (ppp_init(npppd_get_npppd(), ppp) != 0) { l2tp_call_log(_this, LOG_ERR, "failed binding ppp"); goto fail; } l2tp_call_log(_this, LOG_NOTICE, "logtype=PPPBind ppp=%d", ppp->id); if (DIALIN_PROXY_IS_REQUESTED(dpi)) { if (!L2TP_CTRL_CONF(_this->ctrl)->accept_dialin) { l2tp_call_log(_this, LOG_ERR, "'accept_dialin' is 'false' in the setting."); code = L2TP_CDN_RCODE_ERROR_CODE; errcode = L2TP_ECODE_INVALID_MESSAGE; goto fail; } if (ppp_dialin_proxy_prepare(ppp, dpi) != 0) { code = L2TP_CDN_RCODE_TEMP_NOT_AVALIABLE; goto fail; } } ppp_start(ppp); return 0; fail: if (ppp != NULL) ppp_destroy(ppp); _this->ppp = NULL; l2tp_call_disconnect(_this, code, 0, NULL, NULL, 0); return 1; }
/* * Terminate the control connection * * <p> * please specify an appropriate value to result( >0 ) for * StopCCN ResultCode AVP, when to sent Active Close (which * require StopCCN sent).</p> * <p> * When the return value of this function is zero, the _this * is already released. The lt2p_ctrl process that was bound to it * could not contine. * When the return value of this function is one, the timer * is reset.</p> * * @return return 0 if terminate process was completed. */ int l2tp_ctrl_stop(l2tp_ctrl *_this, int result) { int i; l2tpd *_l2tpd; L2TP_CTRL_ASSERT(_this != NULL); switch (_this->state) { case L2TP_CTRL_STATE_ESTABLISHED: _this->state = L2TP_CTRL_STATE_CLEANUP_WAIT; if (result > 0) { _this->active_closing = result; l2tp_ctrl_send_disconnect_notify(_this); break; } goto cleanup; default: l2tp_ctrl_log(_this, LOG_DEBUG, "%s() unexpected state=%s", __func__, l2tp_ctrl_state_string(_this)); /* FALLTHROUGH */ case L2TP_CTRL_STATE_WAIT_CTL_CONN: /* FALLTHROUGH */ case L2TP_CTRL_STATE_CLEANUP_WAIT: cleanup: if (slist_length(&_this->call_list) != 0) { if (l2tp_ctrl_disconnect_all_calls(_this, 1) > 0) break; } #if 0 if (L2TP_CTRL_CONF(_this)e_ipsec_sa != 0) l2tp_ctrl_purge_ipsec_sa(_this); #endif l2tp_ctrl_log(_this, LOG_NOTICE, "logtype=Finished"); evtimer_del(&_this->ev_timeout); /* free send buffer */ if (_this->snd_buffers != NULL) { for (i = 0; i < _this->winsz; i++) bytebuffer_destroy(_this->snd_buffers[i]); free(_this->snd_buffers); _this->snd_buffers = NULL; } if (_this->zlb_buffer != NULL) { bytebuffer_destroy(_this->zlb_buffer); _this->zlb_buffer = NULL; } /* free l2tp_call */ l2tp_ctrl_destroy_all_calls(_this); slist_fini(&_this->call_list); l2tpd_remove_ctrl(_this->l2tpd, _this->tunnel_id); _l2tpd = _this->l2tpd; l2tp_ctrl_destroy(_this); l2tpd_ctrl_finished_notify(_l2tpd); return 0; /* stopped */ } l2tp_ctrl_reset_timeout(_this); return 1; }
/* * send SCCRP */ static void l2tp_ctrl_send_SCCRP(l2tp_ctrl *_this) { int len; struct l2tp_avp *avp; char buf[L2TP_AVP_MAXSIZ], hbuf[HOST_NAME_MAX+1]; const char *val; bytebuffer *bytebuf; if ((bytebuf = l2tp_ctrl_prepare_snd_buffer(_this, 1)) == NULL) { l2tp_ctrl_log(_this, LOG_ERR, "sending SCCRP failed: no buffer."); return; } avp = (struct l2tp_avp *)buf; /* Message Type = SCCRP */ memset(avp, 0, sizeof(*avp)); avp->is_mandatory = 1; avp->attr_type = L2TP_AVP_TYPE_MESSAGE_TYPE; avp_set_val16(avp, L2TP_AVP_MESSAGE_TYPE_SCCRP); bytebuf_add_avp(bytebuf, avp, 2); /* Protocol Version = 1.0 */ memset(avp, 0, sizeof(*avp)); avp->is_mandatory = 1; avp->attr_type = L2TP_AVP_TYPE_PROTOCOL_VERSION; avp->attr_value[0] = L2TP_RFC2661_VERSION; avp->attr_value[1] = L2TP_RFC2661_REVISION; bytebuf_add_avp(bytebuf, avp, 2); /* Framing Capability = Async */ memset(avp, 0, sizeof(*avp)); avp->is_mandatory = 1; avp->attr_type = L2TP_AVP_TYPE_FRAMING_CAPABILITIES; avp_set_val32(avp, L2TP_FRAMING_CAP_FLAGS_SYNC); bytebuf_add_avp(bytebuf, avp, 4); /* Host Name */ memset(avp, 0, sizeof(*avp)); avp->is_mandatory = 1; avp->attr_type = L2TP_AVP_TYPE_HOST_NAME; if ((val = L2TP_CTRL_CONF(_this)->hostname) == NULL) { gethostname(hbuf, sizeof(hbuf)); val = hbuf; } len = strlen(val); memcpy(avp->attr_value, val, len); bytebuf_add_avp(bytebuf, avp, len); /* Assigned Tunnel Id */ memset(avp, 0, sizeof(*avp)); avp->is_mandatory = 1; avp->attr_type = L2TP_AVP_TYPE_ASSINGED_TUNNEL_ID; avp_set_val16(avp, _this->tunnel_id); bytebuf_add_avp(bytebuf, avp, 2); /* Bearer Capability * This implementation never act as LAC. * memset(avp, 0, sizeof(*avp)); avp->is_mandatory = 1; avp->attr_type = L2TP_AVP_TYPE_BEARER_CAPABILITIES; avp_set_val32(avp, 0); bytebuf_add_avp(bytebuf, avp, 4); */ /* Firmware Revision */ memset(avp, 0, sizeof(*avp)); avp->is_mandatory = 0; avp->attr_type = L2TP_AVP_TYPE_FIRMWARE_REVISION; avp->attr_value[0] = MAJOR_VERSION; avp->attr_value[1] = MINOR_VERSION; bytebuf_add_avp(bytebuf, avp, 2); /* Vendor Name */ if ((val = L2TP_CTRL_CONF(_this)->vendor_name) != NULL) { memset(avp, 0, sizeof(*avp)); avp->is_mandatory = 0; avp->attr_type = L2TP_AVP_TYPE_VENDOR_NAME; len = strlen(val); memcpy(avp->attr_value, val, len); bytebuf_add_avp(bytebuf, avp, len); } /* Window Size */ memset(avp, 0, sizeof(*avp)); avp->is_mandatory = 1; avp->attr_type = L2TP_AVP_TYPE_RECV_WINDOW_SIZE; avp_set_val16(avp, _this->winsz); bytebuf_add_avp(bytebuf, avp, 2); if ((l2tp_ctrl_send_packet(_this, 0, bytebuf)) != 0) { l2tp_ctrl_log(_this, LOG_ERR, "sending SCCRP failed"); l2tp_ctrl_stop(_this, L2TP_STOP_CCN_RCODE_GENERAL); return; } l2tp_ctrl_log(_this, LOG_INFO, "SendSCCRP"); }