Exemplo n.º 1
0
/*
 *	State machine for state 2, Awaiting Release State.
 *	The handling of the timer(s) is in file lapb_timer.c
 */
static void lapb_state2_machine(struct lapb_cb *lapb, struct sk_buff *skb,
				struct lapb_frame *frame)
{
	switch (frame->type) {
	case LAPB_SABM:
	case LAPB_SABME:
		lapb_dbg(1, "(%p) S2 RX {SABM,SABME}(%d)\n",
			 lapb->dev, frame->pf);
		lapb_dbg(1, "(%p) S2 TX DM(%d)\n", lapb->dev, frame->pf);
		lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE);
		break;

	case LAPB_DISC:
		lapb_dbg(1, "(%p) S2 RX DISC(%d)\n", lapb->dev, frame->pf);
		lapb_dbg(1, "(%p) S2 TX UA(%d)\n", lapb->dev, frame->pf);
		lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE);
		break;

	case LAPB_UA:
		lapb_dbg(1, "(%p) S2 RX UA(%d)\n", lapb->dev, frame->pf);
		if (frame->pf) {
			lapb_dbg(0, "(%p) S2 -> S0\n", lapb->dev);
			lapb->state = LAPB_STATE_0;
			lapb_start_t1timer(lapb);
			lapb_stop_t2timer(lapb);
			lapb_disconnect_confirmation(lapb, LAPB_OK);
		}
		break;

	case LAPB_DM:
		lapb_dbg(1, "(%p) S2 RX DM(%d)\n", lapb->dev, frame->pf);
		if (frame->pf) {
			lapb_dbg(0, "(%p) S2 -> S0\n", lapb->dev);
			lapb->state = LAPB_STATE_0;
			lapb_start_t1timer(lapb);
			lapb_stop_t2timer(lapb);
			lapb_disconnect_confirmation(lapb, LAPB_NOTCONNECTED);
		}
		break;

	case LAPB_I:
	case LAPB_REJ:
	case LAPB_RNR:
	case LAPB_RR:
		lapb_dbg(1, "(%p) S2 RX {I,REJ,RNR,RR}(%d)\n",
		       lapb->dev, frame->pf);
		lapb_dbg(1, "(%p) S2 RX DM(%d)\n", lapb->dev, frame->pf);
		if (frame->pf)
			lapb_send_control(lapb, LAPB_DM, frame->pf,
					  LAPB_RESPONSE);
		break;
	}

	kfree_skb(skb);
}
Exemplo n.º 2
0
/*
 *  This procedure is passed a buffer descriptor for an iframe. It builds
 *  the rest of the control part of the frame and then writes it out.
 */
static void lapb_send_iframe(struct lapb_cb *lapb, struct sk_buff *skb, int poll_bit)
{
	unsigned char *frame;

	if (!skb)
		return;

	if (lapb->mode & LAPB_EXTENDED) {
		frame = skb_push(skb, 2);

		frame[0] = LAPB_I;
		frame[0] |= lapb->vs << 1;
		frame[1] = poll_bit ? LAPB_EPF : 0;
		frame[1] |= lapb->vr << 1;
	} else {
		frame = skb_push(skb, 1);

		*frame = LAPB_I;
		*frame |= poll_bit ? LAPB_SPF : 0;
		*frame |= lapb->vr << 5;
		*frame |= lapb->vs << 1;
	}

	lapb_dbg(1, "(%p) S%d TX I(%d) S%d R%d\n",
		 lapb->dev, lapb->state, poll_bit, lapb->vs, lapb->vr);

	lapb_transmit_buffer(lapb, skb, LAPB_COMMAND);
}
Exemplo n.º 3
0
void lapb_establish_data_link(struct lapb_cb *lapb)
{
	lapb->condition = 0x00;
	lapb->n2count   = 0;

	if (lapb->mode & LAPB_EXTENDED) {
		lapb_dbg(1, "(%p) S%d TX SABME(1)\n", lapb->dev, lapb->state);
		lapb_send_control(lapb, LAPB_SABME, LAPB_POLLON, LAPB_COMMAND);
	} else {
		lapb_dbg(1, "(%p) S%d TX SABM(1)\n", lapb->dev, lapb->state);
		lapb_send_control(lapb, LAPB_SABM, LAPB_POLLON, LAPB_COMMAND);
	}

	lapb_start_t1timer(lapb);
	lapb_stop_t2timer(lapb);
}
Exemplo n.º 4
0
/*
 *	State machine for state 4, Frame Reject State.
 *	The handling of the timer(s) is in file lapb_timer.c.
 */
static void lapb_state4_machine(struct lapb_cb *lapb, struct sk_buff *skb,
				struct lapb_frame *frame)
{
	switch (frame->type) {
	case LAPB_SABM:
		lapb_dbg(1, "(%p) S4 RX SABM(%d)\n", lapb->dev, frame->pf);
		if (lapb->mode & LAPB_EXTENDED) {
			lapb_dbg(1, "(%p) S4 TX DM(%d)\n",
				 lapb->dev, frame->pf);
			lapb_send_control(lapb, LAPB_DM, frame->pf,
					  LAPB_RESPONSE);
		} else {
			lapb_dbg(1, "(%p) S4 TX UA(%d)\n",
				 lapb->dev, frame->pf);
			lapb_dbg(0, "(%p) S4 -> S3\n", lapb->dev);
			lapb_send_control(lapb, LAPB_UA, frame->pf,
					  LAPB_RESPONSE);
			lapb_stop_t1timer(lapb);
			lapb_stop_t2timer(lapb);
			lapb->state     = LAPB_STATE_3;
			lapb->condition = 0x00;
			lapb->n2count   = 0;
			lapb->vs        = 0;
			lapb->vr        = 0;
			lapb->va        = 0;
			lapb_connect_indication(lapb, LAPB_OK);
		}
		break;

	case LAPB_SABME:
		lapb_dbg(1, "(%p) S4 RX SABME(%d)\n", lapb->dev, frame->pf);
		if (lapb->mode & LAPB_EXTENDED) {
			lapb_dbg(1, "(%p) S4 TX UA(%d)\n",
				 lapb->dev, frame->pf);
			lapb_dbg(0, "(%p) S4 -> S3\n", lapb->dev);
			lapb_send_control(lapb, LAPB_UA, frame->pf,
					  LAPB_RESPONSE);
			lapb_stop_t1timer(lapb);
			lapb_stop_t2timer(lapb);
			lapb->state     = LAPB_STATE_3;
			lapb->condition = 0x00;
			lapb->n2count   = 0;
			lapb->vs        = 0;
			lapb->vr        = 0;
			lapb->va        = 0;
			lapb_connect_indication(lapb, LAPB_OK);
		} else {
			lapb_dbg(1, "(%p) S4 TX DM(%d)\n",
				 lapb->dev, frame->pf);
			lapb_send_control(lapb, LAPB_DM, frame->pf,
					  LAPB_RESPONSE);
		}
		break;
	}

	kfree_skb(skb);
}
Exemplo n.º 5
0
void lapb_timeout_response(struct lapb_cb *lapb)
{
	lapb_dbg(1, "(%p) S%d TX RR(0) R%d\n",
		 lapb->dev, lapb->state, lapb->vr);
	lapb_send_control(lapb, LAPB_RR, LAPB_POLLOFF, LAPB_RESPONSE);

	lapb->condition &= ~LAPB_ACK_PENDING_CONDITION;
}
Exemplo n.º 6
0
void lapb_transmit_buffer(struct lapb_cb *lapb, struct sk_buff *skb, int type)
{
	unsigned char *ptr;

	ptr = skb_push(skb, 1);

	if (lapb->mode & LAPB_MLP) {
		if (lapb->mode & LAPB_DCE) {
			if (type == LAPB_COMMAND)
				*ptr = LAPB_ADDR_C;
			if (type == LAPB_RESPONSE)
				*ptr = LAPB_ADDR_D;
		} else {
			if (type == LAPB_COMMAND)
				*ptr = LAPB_ADDR_D;
			if (type == LAPB_RESPONSE)
				*ptr = LAPB_ADDR_C;
		}
	} else {
		if (lapb->mode & LAPB_DCE) {
			if (type == LAPB_COMMAND)
				*ptr = LAPB_ADDR_A;
			if (type == LAPB_RESPONSE)
				*ptr = LAPB_ADDR_B;
		} else {
			if (type == LAPB_COMMAND)
				*ptr = LAPB_ADDR_B;
			if (type == LAPB_RESPONSE)
				*ptr = LAPB_ADDR_A;
		}
	}

	lapb_dbg(2, "(%p) S%d TX %02X %02X %02X\n",
		 lapb->dev, lapb->state,
		 skb->data[0], skb->data[1], skb->data[2]);

	if (!lapb_data_transmit(lapb, skb))
		kfree_skb(skb);
}
Exemplo n.º 7
0
/*
 *	State machine for state 3, Connected State.
 *	The handling of the timer(s) is in file lapb_timer.c
 */
static void lapb_state3_machine(struct lapb_cb *lapb, struct sk_buff *skb,
				struct lapb_frame *frame)
{
	int queued = 0;
	int modulus = (lapb->mode & LAPB_EXTENDED) ? LAPB_EMODULUS :
						     LAPB_SMODULUS;

	switch (frame->type) {
	case LAPB_SABM:
		lapb_dbg(1, "(%p) S3 RX SABM(%d)\n", lapb->dev, frame->pf);
		if (lapb->mode & LAPB_EXTENDED) {
			lapb_dbg(1, "(%p) S3 TX DM(%d)\n",
				 lapb->dev, frame->pf);
			lapb_send_control(lapb, LAPB_DM, frame->pf,
					  LAPB_RESPONSE);
		} else {
			lapb_dbg(1, "(%p) S3 TX UA(%d)\n",
				 lapb->dev, frame->pf);
			lapb_send_control(lapb, LAPB_UA, frame->pf,
					  LAPB_RESPONSE);
			lapb_stop_t1timer(lapb);
			lapb_stop_t2timer(lapb);
			lapb->condition = 0x00;
			lapb->n2count   = 0;
			lapb->vs        = 0;
			lapb->vr        = 0;
			lapb->va        = 0;
			lapb_requeue_frames(lapb);
		}
		break;

	case LAPB_SABME:
		lapb_dbg(1, "(%p) S3 RX SABME(%d)\n", lapb->dev, frame->pf);
		if (lapb->mode & LAPB_EXTENDED) {
			lapb_dbg(1, "(%p) S3 TX UA(%d)\n",
				 lapb->dev, frame->pf);
			lapb_send_control(lapb, LAPB_UA, frame->pf,
					  LAPB_RESPONSE);
			lapb_stop_t1timer(lapb);
			lapb_stop_t2timer(lapb);
			lapb->condition = 0x00;
			lapb->n2count   = 0;
			lapb->vs        = 0;
			lapb->vr        = 0;
			lapb->va        = 0;
			lapb_requeue_frames(lapb);
		} else {
			lapb_dbg(1, "(%p) S3 TX DM(%d)\n",
				 lapb->dev, frame->pf);
			lapb_send_control(lapb, LAPB_DM, frame->pf,
					  LAPB_RESPONSE);
		}
		break;

	case LAPB_DISC:
		lapb_dbg(1, "(%p) S3 RX DISC(%d)\n", lapb->dev, frame->pf);
		lapb_dbg(0, "(%p) S3 -> S0\n", lapb->dev);
		lapb_clear_queues(lapb);
		lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE);
		lapb_start_t1timer(lapb);
		lapb_stop_t2timer(lapb);
		lapb->state = LAPB_STATE_0;
		lapb_disconnect_indication(lapb, LAPB_OK);
		break;

	case LAPB_DM:
		lapb_dbg(1, "(%p) S3 RX DM(%d)\n", lapb->dev, frame->pf);
		lapb_dbg(0, "(%p) S3 -> S0\n", lapb->dev);
		lapb_clear_queues(lapb);
		lapb->state = LAPB_STATE_0;
		lapb_start_t1timer(lapb);
		lapb_stop_t2timer(lapb);
		lapb_disconnect_indication(lapb, LAPB_NOTCONNECTED);
		break;

	case LAPB_RNR:
		lapb_dbg(1, "(%p) S3 RX RNR(%d) R%d\n",
			 lapb->dev, frame->pf, frame->nr);
		lapb->condition |= LAPB_PEER_RX_BUSY_CONDITION;
		lapb_check_need_response(lapb, frame->cr, frame->pf);
		if (lapb_validate_nr(lapb, frame->nr)) {
			lapb_check_iframes_acked(lapb, frame->nr);
		} else {
			lapb->frmr_data = *frame;
			lapb->frmr_type = LAPB_FRMR_Z;
			lapb_transmit_frmr(lapb);
			lapb_dbg(0, "(%p) S3 -> S4\n", lapb->dev);
			lapb_start_t1timer(lapb);
			lapb_stop_t2timer(lapb);
			lapb->state   = LAPB_STATE_4;
			lapb->n2count = 0;
		}
		break;

	case LAPB_RR:
		lapb_dbg(1, "(%p) S3 RX RR(%d) R%d\n",
			 lapb->dev, frame->pf, frame->nr);
		lapb->condition &= ~LAPB_PEER_RX_BUSY_CONDITION;
		lapb_check_need_response(lapb, frame->cr, frame->pf);
		if (lapb_validate_nr(lapb, frame->nr)) {
			lapb_check_iframes_acked(lapb, frame->nr);
		} else {
			lapb->frmr_data = *frame;
			lapb->frmr_type = LAPB_FRMR_Z;
			lapb_transmit_frmr(lapb);
			lapb_dbg(0, "(%p) S3 -> S4\n", lapb->dev);
			lapb_start_t1timer(lapb);
			lapb_stop_t2timer(lapb);
			lapb->state   = LAPB_STATE_4;
			lapb->n2count = 0;
		}
		break;

	case LAPB_REJ:
		lapb_dbg(1, "(%p) S3 RX REJ(%d) R%d\n",
			 lapb->dev, frame->pf, frame->nr);
		lapb->condition &= ~LAPB_PEER_RX_BUSY_CONDITION;
		lapb_check_need_response(lapb, frame->cr, frame->pf);
		if (lapb_validate_nr(lapb, frame->nr)) {
			lapb_frames_acked(lapb, frame->nr);
			lapb_stop_t1timer(lapb);
			lapb->n2count = 0;
			lapb_requeue_frames(lapb);
		} else {
			lapb->frmr_data = *frame;
			lapb->frmr_type = LAPB_FRMR_Z;
			lapb_transmit_frmr(lapb);
			lapb_dbg(0, "(%p) S3 -> S4\n", lapb->dev);
			lapb_start_t1timer(lapb);
			lapb_stop_t2timer(lapb);
			lapb->state   = LAPB_STATE_4;
			lapb->n2count = 0;
		}
		break;

	case LAPB_I:
		lapb_dbg(1, "(%p) S3 RX I(%d) S%d R%d\n",
			 lapb->dev, frame->pf, frame->ns, frame->nr);
		if (!lapb_validate_nr(lapb, frame->nr)) {
			lapb->frmr_data = *frame;
			lapb->frmr_type = LAPB_FRMR_Z;
			lapb_transmit_frmr(lapb);
			lapb_dbg(0, "(%p) S3 -> S4\n", lapb->dev);
			lapb_start_t1timer(lapb);
			lapb_stop_t2timer(lapb);
			lapb->state   = LAPB_STATE_4;
			lapb->n2count = 0;
			break;
		}
		if (lapb->condition & LAPB_PEER_RX_BUSY_CONDITION)
			lapb_frames_acked(lapb, frame->nr);
		else
			lapb_check_iframes_acked(lapb, frame->nr);

		if (frame->ns == lapb->vr) {
			int cn;
			cn = lapb_data_indication(lapb, skb);
			queued = 1;
			/*
			 * If upper layer has dropped the frame, we
			 * basically ignore any further protocol
			 * processing. This will cause the peer
			 * to re-transmit the frame later like
			 * a frame lost on the wire.
			 */
			if (cn == NET_RX_DROP) {
				pr_debug("rx congestion\n");
				break;
			}
			lapb->vr = (lapb->vr + 1) % modulus;
			lapb->condition &= ~LAPB_REJECT_CONDITION;
			if (frame->pf)
				lapb_enquiry_response(lapb);
			else {
				if (!(lapb->condition &
				      LAPB_ACK_PENDING_CONDITION)) {
					lapb->condition |= LAPB_ACK_PENDING_CONDITION;
					lapb_start_t2timer(lapb);
				}
			}
		} else {
			if (lapb->condition & LAPB_REJECT_CONDITION) {
				if (frame->pf)
					lapb_enquiry_response(lapb);
			} else {
				lapb_dbg(1, "(%p) S3 TX REJ(%d) R%d\n",
					 lapb->dev, frame->pf, lapb->vr);
				lapb->condition |= LAPB_REJECT_CONDITION;
				lapb_send_control(lapb, LAPB_REJ, frame->pf,
						  LAPB_RESPONSE);
				lapb->condition &= ~LAPB_ACK_PENDING_CONDITION;
			}
		}
		break;

	case LAPB_FRMR:
		lapb_dbg(1, "(%p) S3 RX FRMR(%d) %5ph\n",
			 lapb->dev, frame->pf,
			 skb->data);
		lapb_establish_data_link(lapb);
		lapb_dbg(0, "(%p) S3 -> S1\n", lapb->dev);
		lapb_requeue_frames(lapb);
		lapb->state = LAPB_STATE_1;
		break;

	case LAPB_ILLEGAL:
		lapb_dbg(1, "(%p) S3 RX ILLEGAL(%d)\n", lapb->dev, frame->pf);
		lapb->frmr_data = *frame;
		lapb->frmr_type = LAPB_FRMR_W;
		lapb_transmit_frmr(lapb);
		lapb_dbg(0, "(%p) S3 -> S4\n", lapb->dev);
		lapb_start_t1timer(lapb);
		lapb_stop_t2timer(lapb);
		lapb->state   = LAPB_STATE_4;
		lapb->n2count = 0;
		break;
	}

	if (!queued)
		kfree_skb(skb);
}
Exemplo n.º 8
0
/*
 *	This routine is the centralised routine for parsing the control
 *	information for the different frame formats.
 */
int lapb_decode(struct lapb_cb *lapb, struct sk_buff *skb,
		struct lapb_frame *frame)
{
	frame->type = LAPB_ILLEGAL;

	lapb_dbg(2, "(%p) S%d RX %3ph\n", lapb->dev, lapb->state, skb->data);

	/* We always need to look at 2 bytes, sometimes we need
	 * to look at 3 and those cases are handled below.
	 */
	if (!pskb_may_pull(skb, 2))
		return -1;

	if (lapb->mode & LAPB_MLP) {
		if (lapb->mode & LAPB_DCE) {
			if (skb->data[0] == LAPB_ADDR_D)
				frame->cr = LAPB_COMMAND;
			if (skb->data[0] == LAPB_ADDR_C)
				frame->cr = LAPB_RESPONSE;
		} else {
			if (skb->data[0] == LAPB_ADDR_C)
				frame->cr = LAPB_COMMAND;
			if (skb->data[0] == LAPB_ADDR_D)
				frame->cr = LAPB_RESPONSE;
		}
	} else {
		if (lapb->mode & LAPB_DCE) {
			if (skb->data[0] == LAPB_ADDR_B)
				frame->cr = LAPB_COMMAND;
			if (skb->data[0] == LAPB_ADDR_A)
				frame->cr = LAPB_RESPONSE;
		} else {
			if (skb->data[0] == LAPB_ADDR_A)
				frame->cr = LAPB_COMMAND;
			if (skb->data[0] == LAPB_ADDR_B)
				frame->cr = LAPB_RESPONSE;
		}
	}

	skb_pull(skb, 1);

	if (lapb->mode & LAPB_EXTENDED) {
		if (!(skb->data[0] & LAPB_S)) {
			if (!pskb_may_pull(skb, 2))
				return -1;
			/*
			 * I frame - carries NR/NS/PF
			 */
			frame->type       = LAPB_I;
			frame->ns         = (skb->data[0] >> 1) & 0x7F;
			frame->nr         = (skb->data[1] >> 1) & 0x7F;
			frame->pf         = skb->data[1] & LAPB_EPF;
			frame->control[0] = skb->data[0];
			frame->control[1] = skb->data[1];
			skb_pull(skb, 2);
		} else if ((skb->data[0] & LAPB_U) == 1) {
			if (!pskb_may_pull(skb, 2))
				return -1;
			/*
			 * S frame - take out PF/NR
			 */
			frame->type       = skb->data[0] & 0x0F;
			frame->nr         = (skb->data[1] >> 1) & 0x7F;
			frame->pf         = skb->data[1] & LAPB_EPF;
			frame->control[0] = skb->data[0];
			frame->control[1] = skb->data[1];
			skb_pull(skb, 2);
		} else if ((skb->data[0] & LAPB_U) == 3) {