static int l2tp_statusfile_file_delete(const char *root, const char *parent, const char *name)
{
	int result;
	char filename[256];

	if (root == NULL) {
		if (name != NULL) {
			sprintf(filename, "%s/%s", parent, name);
		} else if (parent != NULL) {
			strcpy(filename, parent);
		} else {
			strcpy(filename, L2TP_STATUSFILE_DIR);
		}
	} else {
		if (name != NULL) {
			sprintf(filename, "%s/%s/%s", root, parent, name);
		} else if (parent != NULL) {
			sprintf(filename, "%s/%s", root, parent);
		} else {
			strcpy(filename, root);
		}
	}

	L2TP_DEBUG(L2TP_FUNC, "FUNC: unlink(%s)", filename);
#if 0
	result = 0;
#else
	result = unlink(filename);
#endif
	if (result < 0) {
		result = -errno;
	}

	return result;
}
Exemple #2
0
void l2tp_pkt_free(struct l2tp_packet *pkt)
{
	int buf;

	L2TP_DEBUG(L2TP_DATA, "%s: pkt=%p, msg=%d tid=%hu sid=%hu ns=%hu nr=%hu", __func__,
		   pkt, pkt->msg_type, pkt->tunnel_id, pkt->session_id, pkt->nr, pkt->ns);

	if (pkt->num_bufs > 0) {
		for (buf = 0; buf < pkt->num_bufs; buf++) {
			if (pkt->iov[buf].iov_base != NULL) {
#ifdef DEBUG
				if (pkt->iov[buf].iov_len == 0) {
					l2tp_log(LOG_ERR, "Freeing zero length buffer %p, index %d?", 
						 pkt->iov[buf].iov_base, buf);
				}
				USL_POISON_MEMORY(pkt->iov[buf].iov_base, 0xe8, pkt->iov[buf].iov_len);
#endif
				free(pkt->iov[buf].iov_base);
			} else {
				break;
			}
		}
	}

	USL_POISON_MEMORY(pkt, 0xe7, sizeof(*pkt));
	free(pkt);
}
static int l2tp_statusfile_session_deleted_ind(struct l2tp_session const *session, uint16_t tunnel_id, uint16_t session_id)
{
	int result;
	char name[32];
	char dir[32];

	if (l2tp_old_session_deleted_hook != NULL) {
		result = (*l2tp_old_session_deleted_hook)(session, tunnel_id, session_id);
		if (result < 0) {
			goto out;
		}
	}

	sprintf(&dir[0], "%hu/sessions", tunnel_id);
	sprintf(&name[0], "%hu/sessions/%hu", tunnel_id, session_id);
	result = l2tp_statusfile_dir_delete(L2TP_STATUSFILE_DIR, "tunnels", name, 1);
	(void) l2tp_statusfile_dir_delete(L2TP_STATUSFILE_DIR, "tunnels", dir, 0); 

	if (result < 0) {
		L2TP_DEBUG(L2TP_FUNC, "%s: result=%d", __func__, result);
	}

out:
	return result;
}
static int l2tp_statusfile_peer_deleted_ind(struct in_addr src, struct in_addr dest)
{
	int result;
	char name[32];
	char srcip[16];
	char destip[16];
	char *ip;

	if (l2tp_old_peer_deleted_hook != NULL) {
		result = (*l2tp_old_peer_deleted_hook)(src, dest);
		if (result < 0) {
			goto out;
		}
	}

	ip = inet_ntoa(src);
	strcpy(&srcip[0], ip);
	ip = inet_ntoa(dest);
	strcpy(&destip[0], ip);
	sprintf(&name[0], "%s-%s", srcip, destip);
	result = l2tp_statusfile_file_delete(L2TP_STATUSFILE_DIR, "peers", name);
	(void) l2tp_statusfile_dir_delete(L2TP_STATUSFILE_DIR, "peers", NULL, 0); 

	if (result < 0) {
		L2TP_DEBUG(L2TP_FUNC, "%s: result=%d", __func__, result);
	}

out:
	return result;
}
Exemple #5
0
static void l2tp_cleanup(void)
{
    pid_t pid;

    pid = getpid();
    if (pid != l2tp_my_pid) {
        L2TP_DEBUG(L2TP_FUNC, "%s: not main pid so returning now", __FUNCTION__);
        return;
    }

    l2tp_log(LOG_INFO, "Cleaning up before exiting");

    usl_signal_notifier_remove(l2tp_signal_handler, NULL);

    /* Cleanup all resources */
    l2tp_api_cleanup();
    l2tp_net_cleanup();
    l2tp_avp_cleanup();
    l2tp_ppp_cleanup();
    l2tp_session_cleanup();
    l2tp_xprt_cleanup();
    l2tp_tunnel_cleanup();
    l2tp_peer_cleanup();

    usl_timer_cleanup();
    usl_fd_cleanup();
    usl_signal_cleanup();
    usl_pid_cleanup();

    if (l2tp_rand_fd != 0) {
        close(l2tp_rand_fd);
    }

    L2TP_DEBUG(L2TP_FUNC, "%s: done", __FUNCTION__);

#ifdef L2TP_DMALLOC
    dmalloc_log_changed(l2tp_dmalloc_mark, 1, 0, 1);
    // dmalloc_log_unfreed();
    // dmalloc_log_stats();
    // dmalloc_log_heap_map();
#endif

    /* Remove pid file */
    unlink(L2TP_PID_FILENAME);
}
Exemple #6
0
static int l2tp_parse_args(int argc, char **argv)
{
    int opt;
    int result = 0;
    int plugin_loaded = 0;

    while((opt = getopt(argc, argv, "p:d:u:L:fRDh")) != -1) {
        switch(opt) {
        case 'h':
            usage(argv, 0);
            break;
        case 'f':
            l2tp_opt_nodaemon = 1;
            break;
#ifdef DEBUG
        case 'D':
            l2tp_opt_debug = 1;
            break;
#endif
        case 'd':
            l2tp_opt_trace_flags = l2tp_parse_debug_mask(optarg);
            break;
        case 'p':
            if (l2tp_plugin_load(optarg) < 0) {
                exit(1);
            }
            plugin_loaded = 1;
            break;
        case 'R':
            l2tp_opt_remote_rpc = 1;
            break;
        case 'L':
            l2tp_opt_log_facility = l2tp_parse_log_facility(optarg);
            if (l2tp_opt_log_facility < 0) {
                result = -EINVAL;
            }
            break;
        case 'u':
            sscanf(optarg, "%d", &l2tp_opt_udp_port);
            L2TP_DEBUG(L2TP_API, "Using port %d", l2tp_opt_udp_port);
            break;
        default:
            usage(argv, 1);
        }
    }

    /* Load ppp_unix plugin if no other plugin is requested */
    if (!plugin_loaded) {
        if (l2tp_plugin_load("ppp_unix.so") < 0) {
            exit(1);
        }
    }

    return result;
}
static FILE *l2tp_statusfile_file_create(const char *parent, const char *name)
{
	char filename[256];
	FILE *file;

	if (name != NULL) {
		sprintf(filename, L2TP_STATUSFILE_DIR "/%s/%s", parent, name);
	} else {
		sprintf(filename, L2TP_STATUSFILE_DIR "/%s", parent);
	}

	L2TP_DEBUG(L2TP_FUNC, "FUNC: creat(%s)", filename);
	file = fopen(filename, "w+");

	return file;
}
Exemple #8
0
static void l2tp_init(void)
{
    l2tp_log(LOG_INFO, "started");
#ifdef L2TP_DMALLOC
    /* dmalloc debug options are set in the environment. However,
     * certain options cause problems to this application. We
     * therefore ensure that the troublesome options are disabled,
     * regardless of the user's settings.  The disabled options
     * are: alloc-blank, free-blank, force-linear.  If these
     * options are enabled, it causes strange problems in the
     * generated RPC code.
     */
    dmalloc_debug(dmalloc_debug_current() & 0xff5dffff);
    l2tp_dmalloc_mark = dmalloc_mark();
    if (getenv("DMALLOC_OPTIONS") != NULL) {
        l2tp_log(LOG_WARNING, "DMALLOC debugging enabled");
    }
#endif
    l2tp_my_pid = getpid();

    atexit(l2tp_cleanup);
    L2TP_DEBUG(L2TP_FUNC, "%s (%s %s): trace flags = %08lx", __FUNCTION__, __DATE__, __TIME__, l2tp_opt_trace_flags);
    usl_set_debug(l2tp_opt_debug, l2tp_system_log);

    usl_signal_terminate_hook = l2tp_die;
    usl_signal_init();
    usl_fd_init();
    usl_timer_init();
    usl_pid_init();
    l2tp_net_init();

    l2tp_rand_fd = open("/dev/random", O_RDONLY);
    if (l2tp_rand_fd < 0) {
        fprintf(stderr, "No /dev/random device found. Exiting.\n");
        exit(1);
    }

    usl_signal_notifier_add(l2tp_signal_handler, NULL);

    l2tp_avp_init();
    l2tp_peer_init();
    l2tp_api_init();
    l2tp_xprt_init();
    l2tp_tunnel_init();
    l2tp_session_init();
    l2tp_ppp_init();
}
static inline void l2tp_net_parse_header(struct l2tp_packet *pkt, uint16_t *ver, int *is_data, int *has_seq, void **payload)
{
	struct l2tp_control_hdr* hdr = pkt->buf[0].data;

	uint16_t offset = 0;
	uint16_t dlen = 0;
	uint16_t *optval = (uint16_t *) &hdr->data;

	*ver = (uint16_t) hdr->ver;
	if (hdr->t_bit) {
		*is_data = 0;
	} else {
		*is_data = 1;
	}
	if (hdr->l_bit) {
		dlen = ntohs(*optval);
		optval++;
	}
	pkt->tunnel_id = ntohs(*optval);
	optval++;
	pkt->session_id = ntohs(*optval);
	optval++;
	if (hdr->s_bit) {
		pkt->ns = ntohs(*optval);
		optval++;
		pkt->nr = ntohs(*optval);
		optval++;
		*has_seq = 1;
	} else {
		*has_seq = 0;
	}
	if (hdr->o_bit) {
		offset = ntohs(*optval);
		optval++;
	}
	*payload = ((void *) optval) + offset;
	if (hdr->l_bit) {
		pkt->avp_len = dlen - (((void *) optval) - ((void *) hdr));
	} else {
		pkt->avp_len = 0;
	}
	pkt->avp_offset = ((void *) *payload) - ((void *) hdr);

	L2TP_DEBUG(L2TP_XPRT, "%s: ver=%hu data=%d tid=%hu sid=%hu nr=%hu ns=%hu seq=%d offs=%hu len=%hu", __FUNCTION__, 
		    *ver, *is_data, pkt->tunnel_id, pkt->session_id,
		    pkt->nr, pkt->ns, *has_seq, offset, pkt->avp_len);
}
Exemple #10
0
static int l2tp_statusfile_session_created_ind(struct l2tp_session const *session, uint16_t tunnel_id, uint16_t session_id)
{
	int result = 0;
	char name[32];
	char dir1[32];
	char dir2[32];
	FILE *file;
	struct l2tp_api_session_msg_data sess;
	optstring tunnel_name = { 0, };
	optstring session_name = { 0, };
	
	if (l2tp_old_session_created_hook != NULL) {
		result = (*l2tp_old_session_created_hook)(session, tunnel_id, session_id);
		if (result < 0) {
			goto out;
		}
	}

	sprintf(&dir1[0], "tunnels/%hu", tunnel_id);
	sprintf(&dir2[0], "tunnels/%hu/sessions", tunnel_id);
	sprintf(&name[0], "tunnels/%hu/sessions/%hu", tunnel_id, session_id);
	(void) l2tp_statusfile_dir_create("tunnels", NULL); 
	(void) l2tp_statusfile_dir_create(dir1, NULL); 
	(void) l2tp_statusfile_dir_create(dir2, NULL); 
	(void) l2tp_statusfile_dir_create(name, NULL);
	file = l2tp_statusfile_file_create(name, "status");

	if (file == NULL) {
		result = -errno;
		L2TP_DEBUG(L2TP_FUNC, "%s: result=%d", __func__, result);
	}

	memset(&sess, 0, sizeof(sess));
	if (l2tp_session_get_1_svc(tunnel_id, tunnel_name, session_id, session_name, &sess, NULL)) {
		l2tp_show_session(file, &sess);
	}

	fclose(file);

out:
	return result;
}
Exemple #11
0
static int l2tp_statusfile_peer_created_ind(struct in_addr src, struct in_addr dest)
{
	int result = 0;
	char name[32];
	char srcip[16];
	char destip[16];
	FILE *file;
	char *ip;
	struct l2tp_api_peer_msg_data peer;
	struct l2tp_api_ip_addr peer_addr = { src.s_addr, };
	struct l2tp_api_ip_addr local_addr = { dest.s_addr, };
	
	if (l2tp_old_peer_created_hook != NULL) {
		result = (*l2tp_old_peer_created_hook)(src, dest);
		if (result < 0) {
			goto out;
		}
	}

	ip = inet_ntoa(src);
	strcpy(&srcip[0], ip);
	ip = inet_ntoa(dest);
	strcpy(&destip[0], ip);
	sprintf(&name[0], "%s-%s", srcip, destip);
	(void) l2tp_statusfile_dir_create("peers", NULL); 
	file = l2tp_statusfile_file_create("peers", name);

	if (file == NULL) {
		result = -errno;
		L2TP_DEBUG(L2TP_FUNC, "%s: result=%d", __func__, result);
	}

	memset(&peer, 0, sizeof(peer));
	if (l2tp_peer_get_1_svc(local_addr, peer_addr, &peer, NULL)) {
		l2tp_show_peer(file, &peer);
	}

	fclose(file);

out:
	return result;
}
Exemple #12
0
static int l2tp_statusfile_tunnel_down_ind(uint16_t tunnel_id)
{
	int result;

	if (l2tp_old_tunnel_down_hook != NULL) {
		result = (*l2tp_old_tunnel_down_hook)(tunnel_id);
		if (result < 0) {
			goto out;
		}
	}

	(void) l2tp_statusfile_tunnel_deleted_ind(tunnel_id);
	result = l2tp_statusfile_tunnel_created_ind(tunnel_id);

	if (result < 0) {
		L2TP_DEBUG(L2TP_FUNC, "%s: result=%d", __func__, result);
	}

out:
	return result;
}
Exemple #13
0
static int l2tp_statusfile_session_down_ind(struct l2tp_session const *session, uint16_t tunnel_id, uint16_t session_id)
{
	int result;

	if (l2tp_old_session_down_hook != NULL) {
		result = (*l2tp_old_session_down_hook)(session, tunnel_id, session_id);
		if (result < 0) {
			goto out;
		}
	}

	(void) l2tp_statusfile_session_deleted_ind(session, tunnel_id, session_id);
	result = l2tp_statusfile_session_created_ind(session, tunnel_id, session_id);

	if (result < 0) {
		L2TP_DEBUG(L2TP_FUNC, "%s: result=%d", __func__, result);
	}

out:
	return result;
}
Exemple #14
0
static int l2tp_statusfile_tunnel_deleted_ind(uint16_t tunnel_id)
{
	int result;
	char name[16];

	if (l2tp_old_tunnel_deleted_hook != NULL) {
		result = (*l2tp_old_tunnel_deleted_hook)(tunnel_id);
		if (result < 0) {
			goto out;
		}
	}

	sprintf(&name[0], "%hu", tunnel_id);
	result = l2tp_statusfile_dir_delete(L2TP_STATUSFILE_DIR, "tunnels", name, 1);
	(void) l2tp_statusfile_dir_delete(L2TP_STATUSFILE_DIR, "tunnels", NULL, 0); 

	if (result < 0) {
		L2TP_DEBUG(L2TP_FUNC, "%s: result=%d", __func__, result);
	}

out:
	return result;
}
Exemple #15
0
static int l2tp_statusfile_dir_create(const char *parent, const char *name)
{
	int result;
	char dirname[256];

	if (name != NULL) {
		sprintf(dirname, L2TP_STATUSFILE_DIR "/%s/%s", parent, name);
	} else if (parent != NULL) {
		sprintf(dirname, L2TP_STATUSFILE_DIR "/%s", parent);
	} else {
		strcpy(dirname, L2TP_STATUSFILE_DIR);
	}
	
	L2TP_DEBUG(L2TP_FUNC, "FUNC: mkdir(%s)", dirname);
	result = mkdir(dirname, 0755);
	if (result < 0) {
		result = -errno;
	}
	if (result == -EEXIST) {
		result = 0;
	}

	return result;
}
Exemple #16
0
static int l2tp_statusfile_tunnel_created_ind(uint16_t tunnel_id)
{
	int result = 0;
	char name[16];
	char dir[32];
	FILE *file;
	struct l2tp_api_tunnel_msg_data tunnel;
	optstring tunnel_name = { 0, };

	if (l2tp_old_tunnel_created_hook != NULL) {
		result = (*l2tp_old_tunnel_created_hook)(tunnel_id);
		if (result < 0) {
			goto out;
		}
	}

	sprintf(&name[0], "%hu", tunnel_id);
	sprintf(&dir[0], "tunnels/%hu", tunnel_id);
	(void) l2tp_statusfile_dir_create("tunnels", NULL); 
	(void) l2tp_statusfile_dir_create("tunnels", name); 
	file = l2tp_statusfile_file_create(dir, "status");

	if (file == NULL) {
		result = -errno;
		L2TP_DEBUG(L2TP_FUNC, "%s: result=%d", __func__, result);
		goto out;
	}

	memset(&tunnel, 0, sizeof(tunnel));
	if (l2tp_tunnel_get_1_svc(tunnel_id, tunnel_name, &tunnel, NULL)) {
		l2tp_show_tunnel(file, &tunnel, 1, 0);
	}
	fclose(file);
out:
	return result;
}
Exemple #17
0
static void l2tp_net_recv_core(int fd, struct sockaddr_in const *from, struct msghdr *msg, int recv_len, struct in_pktinfo *ipi)
{
	int result = -EBADMSG;
	struct l2tp_peer *peer = NULL;
	struct l2tp_tunnel *tunnel = NULL;
	char *peer_host_name = NULL;
	struct l2tp_packet *pkt = NULL;
	int frag;
	uint16_t ver;
	int is_data;
	int has_seq;
	void *payload;
	uint16_t msg_type;

	if (recv_len < L2TP_MIN_FRAME_LEN) {
		l2tp_stats.short_frames++;
		goto out;
	}

	/* Allocate a pkt to hold info about this packet. 
	 * Once we've done this, there's no need to use the struct msghdr.
	 */
	pkt = l2tp_pkt_alloc(msg->msg_iovlen);
	if (pkt == NULL) {
		result = -ENOMEM;
		l2tp_stats.no_control_frame_resources++;
		goto out;
	}
	for (frag = 0; frag < msg->msg_iovlen; frag++) {
		pkt->buf[frag].data = msg->msg_iov[frag].iov_base;
		pkt->buf[frag].data_len = MIN(recv_len, msg->msg_iov[frag].iov_len);
	}
	pkt->total_len = recv_len;

	/* Parse the L2TP packet header */
	l2tp_net_parse_header(pkt, &ver, &is_data, &has_seq, &payload);
	if (ver != 2) {
		l2tp_stats.wrong_version_frames++;
		goto out;
	}

	/* If this is a data frame, return now. This should be handled by
	 * the kernel's L2TP code.
	 */
	if (is_data) {
		l2tp_stats.unexpected_data_frames++;
		goto out;
	}

#ifdef L2TP_TEST
	if (l2tp_test_is_fake_rx_drop(pkt->tunnel_id, pkt->session_id)) {
		L2TP_DEBUG(L2TP_DATA, "%s: fake rx drop: tid=%hu/%hu, len=%d", __FUNCTION__,
			   pkt->tunnel_id, pkt->session_id, recv_len);
		goto out;
	}
#endif /* L2TP_TEST */

	L2TP_DEBUG(L2TP_PROTOCOL, "%s: received len %d tunl %hu ses %hu, from fd %d", __FUNCTION__,
		   recv_len, pkt->tunnel_id, pkt->session_id, fd);
	if (pkt->avp_len > 0) {
		/* Don't count ZLBs as received frames */
		l2tp_stats.total_rcvd_control_frames++;
	}
	if ((pkt->avp_offset + pkt->avp_len) > recv_len) {
		l2tp_stats.bad_rcvd_frames++;
		goto out;
	}

	/* If tunnel_id non-zero, find tunnel context by id and if not found, discard the frame.
	 * If tunnel_id is zero, pre-parse the L2TP packet looking for a HOSTNAME attribute
	 * which is mandatory for all messages when tunnel_id is zero. Use the name there
	 * to locate the peer profile, then create the tunnel context.
	 */
	if (pkt->tunnel_id != 0) {
		/* Simple case - tunnel_id non-zero. If we can't find a tunnel context, bail */
		tunnel = l2tp_tunnel_find_by_id(pkt->tunnel_id);
		if (tunnel == NULL) {
			l2tp_stats.no_matching_tunnel_id_discards++;
			goto out;
		}
		peer = l2tp_tunnel_get_peer(tunnel);
	} else {
		/* Complicated case - tunnel_id zero. Since we support incoming L2TP tunnel
		 * setup requests, we must create internal contexts in order to handle the
		 * request. However, we should only do this for SCCRQ messages...
		 */
		struct l2tp_peer_profile *peer_profile;

		result = l2tp_avp_preparse(payload, pkt->avp_len, &peer_host_name, &msg_type);
		if (result < 0) {
			if (result != -ENOMEM) {
				if (from != NULL) {
					L2TP_DEBUG(L2TP_PROTOCOL, "%s: dropping non-SCCRQ from %x/%hu on fd %d", __FUNCTION__, 
						   ntohl(from->sin_addr.s_addr), ntohs(from->sin_port), fd);
				} else {
					L2TP_DEBUG(L2TP_PROTOCOL, "%s: dropping non-SCCRQ on fd %d", __FUNCTION__, fd);
				}
				l2tp_stats.no_matching_tunnel_id_discards++;
			}
			goto out;
		}

		/* Find a peer profile. Since this tunnel is being created by remote request, an explicit
		 * peer profile name cannot be specified by the remote peer. So we use the HOST_NAME AVP
		 * to select it. If a peer profile with that name does not exist, try to find a profile
		 * that matches the source IP address. Otherwise, we use the default profile.
		 */
		peer_profile = l2tp_peer_profile_find(peer_host_name);
		if (peer_profile == NULL) {
			peer_profile = l2tp_peer_profile_find_by_addr(from->sin_addr);
			if (peer_profile == NULL) {
				peer_profile = l2tp_peer_profile_find(L2TP_API_PEER_PROFILE_DEFAULT_PROFILE_NAME);
			}
		}
		L2TP_DEBUG(L2TP_PROTOCOL, "%s: using peer profile %s for %s (%x/%hu) on fd %d", __FUNCTION__, 
			   peer_profile->profile_name, peer_host_name, ntohl(from->sin_addr.s_addr), ntohs(from->sin_port), fd);

		/* Register a new peer context and record his addr */
		if (ipi != NULL) {
			peer = l2tp_peer_find(&ipi->ipi_addr, &from->sin_addr);
			if (peer == NULL) {
				peer = l2tp_peer_alloc(ipi->ipi_addr, from->sin_addr);
				if (peer == NULL) {
					result = -ENOMEM;
					l2tp_stats.no_control_frame_resources++;
					goto out;
				}
			}
			l2tp_peer_inc_use_count(peer);
		}

		if (l2tp_opt_trace_flags & L2TP_PROTOCOL) {
			l2tp_log(LOG_DEBUG, "PROTO: Creating new tunnel context with profile '%s' for %s (%x/%hu)",
				 peer_profile->default_tunnel_profile_name, peer_host_name, ntohl(from->sin_addr.s_addr), ntohs(from->sin_port));
		}

		tunnel = l2tp_tunnel_alloc(0, peer_profile->default_tunnel_profile_name, peer_profile->profile_name, 0, &result);
		if (tunnel == NULL) {
			if (result == -ENOMEM) {
				l2tp_stats.no_control_frame_resources++;
			}
			goto out_unlink_peer;
		}
		l2tp_tunnel_link(tunnel);
		result = l2tp_tunnel_xprt_create(peer, tunnel, from);
		if (result < 0) {
			if (result == -ENOMEM) {
				l2tp_stats.no_control_frame_resources++;
			}
			goto out_unlink_tunnel;
		}

		/* Give plugins visibility of tunnel created */
		if (l2tp_tunnel_created_hook != NULL) {
			result = (*l2tp_tunnel_created_hook)(l2tp_tunnel_peer_id(tunnel));
			if (result < 0) {
				goto out_unlink_tunnel;
			}
		}
	}

	BUG_TRAP(tunnel == NULL);

	if (!l2tp_tunnel_is_fd_connected(tunnel)) {
		if (from == NULL) {
			from = l2tp_tunnel_get_peer_addr(tunnel);
		}
		result = l2tp_net_connect_socket(l2tp_tunnel_get_fd(tunnel), from, peer, tunnel);
		if (result < 0) {
			l2tp_stats.socket_errors++;
			goto out_unlink_tunnel;
		}
	}

	l2tp_tunnel_inc_use_count(tunnel);
	result = l2tp_xprt_recv(l2tp_tunnel_get_xprt(tunnel), pkt);
	l2tp_tunnel_dec_use_count(tunnel);

out:
	/* l2tp_xprt_recv() consumes msg only if it returns 0 */
	if (result < 0) {
		if (pkt == NULL) {
			for (frag = 0; frag < msg->msg_iovlen; frag++) {
				if (msg->msg_iov[frag].iov_base != NULL) {
					free(msg->msg_iov[frag].iov_base);
				}
			}
		} else {
			l2tp_pkt_free(pkt);
		}
	}

	/* This might have been allocated by l2tp_avp_preparse() */
	if (peer_host_name != NULL) {
		free(peer_host_name);
	}

	return;

out_unlink_tunnel:
	l2tp_tunnel_dec_use_count(tunnel);
out_unlink_peer:
	l2tp_peer_dec_use_count(peer);

	l2tp_stats.tunnel_setup_failures++;
	
	goto out;
}
Exemple #18
0
static int l2tp_statusfile_dir_delete(const char *root, const char *parent, const char *name, int recursive)
{
	int result;
	char dirname[256];
	char filename[256];
	DIR *dir;
	struct dirent *entry;
	struct stat statbuf;

	if (root == NULL) {
		if (name != NULL) {
			sprintf(dirname, "%s/%s", parent, name);
		} else if (parent != NULL) {
			strcpy(dirname, parent);
		} else {
			strcpy(dirname, L2TP_STATUSFILE_DIR);
		}
	} else {
		if (name != NULL) {
			sprintf(dirname, "%s/%s/%s", root, parent, name);
		} else if (parent != NULL) {
			sprintf(dirname, "%s/%s", root, parent);
		} else {
			strcpy(dirname, root);
		}
	}

	if (recursive) {
		dir = opendir(dirname);
		if (dir == NULL) {
			result = -errno;
			goto out;
		}

		while ((entry = readdir(dir)) != NULL) {
			if ((strcmp(entry->d_name, ".") == 0) ||
			    (strcmp(entry->d_name, "..") == 0)) {
				continue;
			}
			sprintf(filename, "%s/%s", dirname, entry->d_name);
			result = stat(filename, &statbuf);
			if (result < 0) {
				continue;
			}
			if (S_ISDIR(statbuf.st_mode)) {
				(void) l2tp_statusfile_dir_delete(NULL, dirname, entry->d_name, recursive);
			} else {
				(void) l2tp_statusfile_file_delete(NULL, dirname, entry->d_name);
			}
		}
		L2TP_DEBUG(L2TP_FUNC, "FUNC: rmdir(%s)", dirname);
#if 0
		result = 0;
#else
		result = rmdir(dirname);
#endif
		closedir(dir);
	} else {
		L2TP_DEBUG(L2TP_FUNC, "FUNC: rmdir(%s)", dirname);
#if 0
		result = 0;
#else
		result = rmdir(dirname);
#endif
	}

out:
	return result;
}