int llc_conn_ev_local_busy_cleared(struct sock *sk, struct sk_buff *skb)
{
	struct llc_conn_state_ev *ev = llc_conn_ev(skb);

	return ev->type == LLC_CONN_EV_TYPE_SIMPLE &&
	       ev->prim_type == LLC_CONN_EV_LOCAL_BUSY_CLEARED ? 0 : 1;
}
示例#2
0
文件: llc_if.c 项目: 274914765/C
/**
 *    llc_send_disc - Called by upper layer to close a connection
 *    @sk: connection to be closed
 *
 *    Upper layer calls this when it wants to close an established LLC
 *    connection with a remote machine. This function packages a proper event
 *    and sends it to connection component state machine. Returns 0 for
 *    success, 1 otherwise.
 */
int llc_send_disc(struct sock *sk)
{
    u16 rc = 1;
    struct llc_conn_state_ev *ev;
    struct sk_buff *skb;

    sock_hold(sk);
    if (sk->sk_type != SOCK_STREAM || sk->sk_state != TCP_ESTABLISHED ||
        llc_sk(sk)->state == LLC_CONN_STATE_ADM ||
        llc_sk(sk)->state == LLC_CONN_OUT_OF_SVC)
        goto out;
    /*
     * Postpone unassigning the connection from its SAP and returning the
     * connection until all ACTIONs have been completely executed
     */
    skb = alloc_skb(0, GFP_ATOMIC);
    if (!skb)
        goto out;
    skb_set_owner_w(skb, sk);
    sk->sk_state  = TCP_CLOSING;
    ev          = llc_conn_ev(skb);
    ev->type      = LLC_CONN_EV_TYPE_PRIM;
    ev->prim      = LLC_DISC_PRIM;
    ev->prim_type = LLC_PRIM_TYPE_REQ;
    rc = llc_conn_state_process(sk, skb);
out:
    sock_put(sk);
    return rc;
}
示例#3
0
static int llc_conn_ac_data_confirm(struct sock *sk, struct sk_buff *skb)
{
	struct llc_conn_state_ev *ev = llc_conn_ev(skb);

	ev->cfm_prim = LLC_DATA_PRIM;
	return 0;
}
int llc_conn_ev_qlfy_set_status_received(struct sock *sk, struct sk_buff *skb)
{
	struct llc_conn_state_ev *ev = llc_conn_ev(skb);

	ev->status = LLC_STATUS_RECEIVED;
	return 0;
}
int llc_conn_ev_local_busy_detected(struct sock *sk, struct sk_buff *skb)
{
	const struct llc_conn_state_ev *ev = llc_conn_ev(skb);

	return ev->type == LLC_CONN_EV_TYPE_SIMPLE &&
	       ev->prim_type == LLC_CONN_EV_LOCAL_BUSY_DETECTED ? 0 : 1;
}
int llc_conn_ev_data_req(struct sock *sk, struct sk_buff *skb)
{
	const struct llc_conn_state_ev *ev = llc_conn_ev(skb);

	return ev->prim == LLC_DATA_PRIM &&
	       ev->prim_type == LLC_PRIM_TYPE_REQ ? 0 : 1;
}
示例#7
0
int llc_conn_ac_disc_ind(struct sock *sk, struct sk_buff *skb)
{
	struct llc_conn_state_ev *ev = llc_conn_ev(skb);
	u8 reason = 0;
	int rc = 0;

	if (ev->type == LLC_CONN_EV_TYPE_PDU) {
		struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);

		if (LLC_PDU_IS_RSP(pdu) &&
		    LLC_PDU_TYPE_IS_U(pdu) &&
		    LLC_U_PDU_RSP(pdu) == LLC_2_PDU_RSP_DM)
			reason = LLC_DISC_REASON_RX_DM_RSP_PDU;
		else if (LLC_PDU_IS_CMD(pdu) &&
			   LLC_PDU_TYPE_IS_U(pdu) &&
			   LLC_U_PDU_CMD(pdu) == LLC_2_PDU_CMD_DISC)
			reason = LLC_DISC_REASON_RX_DISC_CMD_PDU;
	} else if (ev->type == LLC_CONN_EV_TYPE_ACK_TMR)
		reason = LLC_DISC_REASON_ACK_TMR_EXP;
	else
		rc = -EINVAL;
	if (!rc) {
		ev->reason   = reason;
		ev->ind_prim = LLC_DISC_PRIM;
	}
	return rc;
}
示例#8
0
/**
 *	llc_build_and_send_pkt - Connection data sending for upper layers.
 *	@sk: connection
 *	@skb: packet to send
 *
 *	This function is called when upper layer wants to send data using
 *	connection oriented communication mode. During sending data, connection
 *	will be locked and received frames and expired timers will be queued.
 *	Returns 0 for success, -ECONNABORTED when the connection already
 *	closed and -EBUSY when sending data is not permitted in this state or
 *	LLC has send an I pdu with p bit set to 1 and is waiting for it's
 *	response.
 */
int llc_build_and_send_pkt(struct sock *sk, struct sk_buff *skb)
{
	struct llc_conn_state_ev *ev;
	int rc = -ECONNABORTED;
	struct llc_opt *llc = llc_sk(sk);

	if (llc->state == LLC_CONN_STATE_ADM)
		goto out;
	rc = -EBUSY;
	if (llc_data_accept_state(llc->state)) { /* data_conn_refuse */
		llc->failed_data_req = 1;
		goto out;
	}
	if (llc->p_flag) {
		llc->failed_data_req = 1;
		goto out;
	}
	ev = llc_conn_ev(skb);
	ev->type      = LLC_CONN_EV_TYPE_PRIM;
	ev->prim      = LLC_DATA_PRIM;
	ev->prim_type = LLC_PRIM_TYPE_REQ;
	skb->dev      = llc->dev;
	rc = llc_conn_state_process(sk, skb);
out:
	return rc;
}
int llc_conn_ev_qlfy_set_status_impossible(struct sock *sk, struct sk_buff *skb)
{
	struct llc_conn_state_ev *ev = llc_conn_ev(skb);

	ev->status = LLC_STATUS_IMPOSSIBLE;
	return 0;
}
int llc_conn_ev_qlfy_set_status_failed(struct sock *sk, struct sk_buff *skb)
{
	struct llc_conn_state_ev *ev = llc_conn_ev(skb);

	ev->status = LLC_STATUS_FAILED;
	return 0;
}
int llc_conn_ev_tx_buffer_full(struct sock *sk, struct sk_buff *skb)
{
	struct llc_conn_state_ev *ev = llc_conn_ev(skb);

	return ev->type == LLC_CONN_EV_TYPE_SIMPLE &&
	       ev->prim_type == LLC_CONN_EV_TX_BUFF_FULL ? 0 : 1;
}
int llc_conn_ev_qlfy_set_status_disc(struct sock *sk, struct sk_buff *skb)
{
	struct llc_conn_state_ev *ev = llc_conn_ev(skb);

	ev->status = LLC_STATUS_DISC;
	return 0;
}
示例#13
0
/**
 *	llc_establish_connection - Called by upper layer to establish a conn
 *	@sk: connection
 *	@lmac: local mac address
 *	@dmac: destination mac address
 *	@dsap: destination sap
 *
 *	Upper layer calls this to establish an LLC connection with a remote
 *	machine. This function packages a proper event and sends it connection
 *	component state machine. Success or failure of connection
 *	establishment will inform to upper layer via calling it's confirm
 *	function and passing proper information.
 */
int llc_establish_connection(struct sock *sk, u8 *lmac, u8 *dmac, u8 dsap)
{
	int rc = -EISCONN;
	struct llc_addr laddr, daddr;
	struct sk_buff *skb;
	struct llc_opt *llc = llc_sk(sk);
	struct sock *existing;

	laddr.lsap = llc->sap->laddr.lsap;
	daddr.lsap = dsap;
	memcpy(daddr.mac, dmac, sizeof(daddr.mac));
	memcpy(laddr.mac, lmac, sizeof(laddr.mac));
	existing = llc_lookup_established(llc->sap, &daddr, &laddr);
	if (existing) {
		if (existing->sk_state == TCP_ESTABLISHED) {
			sk = existing;
			goto out_put;
		} else
			sock_put(existing);
	}
	sock_hold(sk);
	rc = -ENOMEM;
	skb = alloc_skb(0, GFP_ATOMIC);
	if (skb) {
		struct llc_conn_state_ev *ev = llc_conn_ev(skb);

		ev->type      = LLC_CONN_EV_TYPE_PRIM;
		ev->prim      = LLC_CONN_PRIM;
		ev->prim_type = LLC_PRIM_TYPE_REQ;
		rc = llc_conn_state_process(sk, skb);
	}
out_put:
	sock_put(sk);
	return rc;
}
int llc_conn_ev_qlfy_set_status_conflict(struct sock *sk, struct sk_buff *skb)
{
	struct llc_conn_state_ev *ev = llc_conn_ev(skb);

	ev->status = LLC_STATUS_CONFLICT;
	return 0;
}
int llc_conn_ev_conn_req(struct sock *sk, struct sk_buff *skb)
{
	struct llc_conn_state_ev *ev = llc_conn_ev(skb);

	return ev->prim == LLC_CONN_PRIM &&
	       ev->prim_type == LLC_PRIM_TYPE_REQ ? 0 : 1;
}
int llc_conn_ev_rst_resp(struct sock *sk, struct sk_buff *skb)
{
	struct llc_conn_state_ev *ev = llc_conn_ev(skb);

	return ev->prim == LLC_RESET_PRIM &&
	       ev->prim_type == LLC_PRIM_TYPE_RESP ? 0 : 1;
}
int llc_conn_ev_qlfy_set_status_refuse(struct sock *sk, struct sk_buff *skb)
{
	struct llc_conn_state_ev *ev = llc_conn_ev(skb);

	ev->status = LLC_STATUS_REFUSE;
	return 0;
}
示例#18
0
int llc_conn_ac_conn_ind(struct sock *sk, struct sk_buff *skb)
{
	struct llc_conn_state_ev *ev = llc_conn_ev(skb);

	ev->ind_prim = LLC_CONN_PRIM;
	return 0;
}
int llc_conn_ev_qlfy_set_status_rst_done(struct sock *sk, struct sk_buff *skb)
{
	struct llc_conn_state_ev *ev = llc_conn_ev(skb);

	ev->status = LLC_STATUS_RESET_DONE;
	return 0;
}
示例#20
0
/**
 *	llc_conn_rcv - sends received pdus to the connection state machine
 *	@sk: current connection structure.
 *	@skb: received frame.
 *
 *	Sends received pdus to the connection state machine.
 */
static int llc_conn_rcv(struct sock* sk, struct sk_buff *skb)
{
	struct llc_conn_state_ev *ev = llc_conn_ev(skb);

	ev->type   = LLC_CONN_EV_TYPE_PDU;
	ev->reason = 0;
	return llc_conn_state_process(sk, skb);
}
int llc_conn_ev_qlfy_set_status_remote_busy(struct sock *sk,
					    struct sk_buff *skb)
{
	struct llc_conn_state_ev *ev = llc_conn_ev(skb);

	ev->status = LLC_STATUS_REMOTE_BUSY;
	return 0;
}
示例#22
0
int llc_conn_ac_rst_confirm(struct sock *sk, struct sk_buff *skb)
{
	struct llc_conn_state_ev *ev = llc_conn_ev(skb);

	ev->reason   = 0;
	ev->cfm_prim = LLC_RESET_PRIM;
	return 0;
}
示例#23
0
int llc_conn_ac_disc_confirm(struct sock *sk, struct sk_buff *skb)
{
	struct llc_conn_state_ev *ev = llc_conn_ev(skb);

	ev->reason   = ev->status;
	ev->cfm_prim = LLC_DISC_PRIM;
	return 0;
}
int llc_conn_ev_any_tmr_exp(struct sock *sk, struct sk_buff *skb)
{
	struct llc_conn_state_ev *ev = llc_conn_ev(skb);

	return ev->type == LLC_CONN_EV_TYPE_P_TMR ||
	       ev->type == LLC_CONN_EV_TYPE_ACK_TMR ||
	       ev->type == LLC_CONN_EV_TYPE_REJ_TMR ||
	       ev->type == LLC_CONN_EV_TYPE_BUSY_TMR ? 0 : 1;
}
示例#25
0
static void llc_conn_tmr_common_cb(unsigned long timeout_data, u8 type)
{
	struct sock *sk = (struct sock *)timeout_data;
	struct sk_buff *skb = alloc_skb(0, GFP_ATOMIC);

	bh_lock_sock(sk);
	if (skb) {
		struct llc_conn_state_ev *ev = llc_conn_ev(skb);

		skb_set_owner_r(skb, sk);
		ev->type = type;
		llc_process_tmr_ev(sk, skb);
	}
	bh_unlock_sock(sk);
}
void llc_conn_rej_tmr_cb(unsigned long timeout_data)
{
	struct sock *sk = (struct sock *)timeout_data;
	struct sk_buff *skb = alloc_skb(0, GFP_ATOMIC);

	bh_lock_sock(sk);
	if (skb) {
		struct llc_conn_state_ev *ev = llc_conn_ev(skb);

		skb->sk  = sk;
		ev->type = LLC_CONN_EV_TYPE_REJ_TMR;
		llc_process_tmr_ev(sk, skb);
	}
	bh_unlock_sock(sk);
}
int llc_conn_ac_rst_ind(struct sock *sk, struct sk_buff *skb)
{
	u8 reason = 0;
	int rc = 1;
	struct llc_conn_state_ev *ev = llc_conn_ev(skb);
	struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
	struct llc_opt *llc = llc_sk(sk);

	switch (ev->type) {
	case LLC_CONN_EV_TYPE_PDU:
		if (LLC_PDU_IS_RSP(pdu) &&
		    LLC_PDU_TYPE_IS_U(pdu) &&
		    LLC_U_PDU_RSP(pdu) == LLC_2_PDU_RSP_FRMR) {
			reason = LLC_RESET_REASON_LOCAL;
			rc = 0;
		} else if (LLC_PDU_IS_CMD(pdu) &&
			   LLC_PDU_TYPE_IS_U(pdu) &&
			   LLC_U_PDU_CMD(pdu) == LLC_2_PDU_CMD_SABME) {
			reason = LLC_RESET_REASON_REMOTE;
			rc = 0;
		} else {
			reason = 0;
			rc  = 1;
		}
		break;
	case LLC_CONN_EV_TYPE_ACK_TMR:
	case LLC_CONN_EV_TYPE_P_TMR:
	case LLC_CONN_EV_TYPE_REJ_TMR:
	case LLC_CONN_EV_TYPE_BUSY_TMR:
		if (llc->retry_count > llc->n2) {
			reason = LLC_RESET_REASON_LOCAL;
			rc = 0;
		} else
			rc = 1;
		break;
	}
	if (!rc) {
		ev->reason   = reason;
		ev->ind_prim = LLC_RESET_PRIM;
	}
	return rc;
}
int llc_conn_ac_conn_ind(struct sock *sk, struct sk_buff *skb)
{
	int rc = -ENOTCONN;
	u8 dsap;
	struct llc_sap *sap;

	llc_pdu_decode_dsap(skb, &dsap);
	sap = llc_sap_find(dsap);
	if (sap) {
		struct llc_conn_state_ev *ev = llc_conn_ev(skb);
		struct llc_opt *llc = llc_sk(sk);

		llc_pdu_decode_sa(skb, llc->daddr.mac);
		llc_pdu_decode_da(skb, llc->laddr.mac);
		llc->dev = skb->dev;
		ev->ind_prim = LLC_CONN_PRIM;
		rc = 0;
	}
	return rc;
}
示例#29
0
/**
 *	llc_qualify_conn_ev - finds transition for event
 *	@sk: connection
 *	@skb: happened event
 *
 *	This function finds transition that matches with happened event.
 *	Returns pointer to found transition on success, %NULL otherwise.
 */
static struct llc_conn_state_trans *llc_qualify_conn_ev(struct sock *sk,
							struct sk_buff *skb)
{
	struct llc_conn_state_trans **next_trans;
	llc_conn_ev_qfyr_t *next_qualifier;
	struct llc_conn_state_ev *ev = llc_conn_ev(skb);
	struct llc_sock *llc = llc_sk(sk);
	struct llc_conn_state *curr_state =
					&llc_conn_state_table[llc->state - 1];

	/* search thru events for this state until
	 * list exhausted or until no more
	 */
	for (next_trans = curr_state->transitions +
		llc_find_offset(llc->state - 1, ev->type);
	     (*next_trans)->ev; next_trans++) {
		if (!((*next_trans)->ev)(sk, skb)) {
			/* got POSSIBLE event match; the event may require
			 * qualification based on the values of a number of
			 * state flags; if all qualifications are met (i.e.,
			 * if all qualifying functions return success, or 0,
			 * then this is THE event we're looking for
			 */
			for (next_qualifier = (*next_trans)->ev_qualifiers;
			     next_qualifier && *next_qualifier &&
			     !(*next_qualifier)(sk, skb); next_qualifier++)
				/* nothing */;
			if (!next_qualifier || !*next_qualifier)
				/* all qualifiers executed successfully; this is
				 * our transition; return it so we can perform
				 * the associated actions & change the state
				 */
				return *next_trans;
		}
	}
	return NULL;
}
static struct llc_conn_state_trans *llc_qualify_conn_ev(struct sock *sk,
							struct sk_buff *skb)
{
	struct llc_conn_state_trans **next_trans;
	llc_conn_ev_qfyr_t *next_qualifier;
	struct llc_conn_state_ev *ev = llc_conn_ev(skb);
	struct llc_sock *llc = llc_sk(sk);
	struct llc_conn_state *curr_state =
					&llc_conn_state_table[llc->state - 1];

	for (next_trans = curr_state->transitions +
		llc_find_offset(llc->state - 1, ev->type);
	     (*next_trans)->ev; next_trans++) {
		if (!((*next_trans)->ev)(sk, skb)) {
			for (next_qualifier = (*next_trans)->ev_qualifiers;
			     next_qualifier && *next_qualifier &&
			     !(*next_qualifier)(sk, skb); next_qualifier++)
				;
			if (!next_qualifier || !*next_qualifier)
				return *next_trans;
		}
	}
	return NULL;
}