Ejemplo n.º 1
0
/* Higher level upcall for a LAPB frame - called with sk locked */
int nr_process_rx_frame(struct sock *sk, struct sk_buff *skb)
{
	struct nr_sock *nr = nr_sk(sk);
	int queued = 0, frametype;

	if (nr->state == NR_STATE_0)
		return 0;

	frametype = skb->data[19];

	switch (nr->state) {
	case NR_STATE_1:
		queued = nr_state1_machine(sk, skb, frametype);
		break;
	case NR_STATE_2:
		queued = nr_state2_machine(sk, skb, frametype);
		break;
	case NR_STATE_3:
		queued = nr_state3_machine(sk, skb, frametype);
		break;
	}

	nr_kick(sk);

	return queued;
}
Ejemplo n.º 2
0
void nr_output(struct sock *sk, struct sk_buff *skb)
{
	struct sk_buff *skbn;
	unsigned char transport[NR_TRANSPORT_LEN];
	int err, frontlen, len;

	if (skb->len - NR_TRANSPORT_LEN > NR_MAX_PACKET_SIZE) {
		/* Save a copy of the Transport Header */
		skb_copy_from_linear_data(skb, transport, NR_TRANSPORT_LEN);
		skb_pull(skb, NR_TRANSPORT_LEN);

		frontlen = skb_headroom(skb);

		while (skb->len > 0) {
			if ((skbn = sock_alloc_send_skb(sk, frontlen + NR_MAX_PACKET_SIZE, 0, &err)) == NULL)
				return;

			skb_reserve(skbn, frontlen);

			len = (NR_MAX_PACKET_SIZE > skb->len) ? skb->len : NR_MAX_PACKET_SIZE;

			/* Copy the user data */
			skb_copy_from_linear_data(skb, skb_put(skbn, len), len);
			skb_pull(skb, len);

			/* Duplicate the Transport Header */
			skb_push(skbn, NR_TRANSPORT_LEN);
			skb_copy_to_linear_data(skbn, transport,
						NR_TRANSPORT_LEN);
			if (skb->len > 0)
				skbn->data[4] |= NR_MORE_FLAG;

			skb_queue_tail(&sk->sk_write_queue, skbn); /* Throw it on the queue */
		}

		kfree_skb(skb);
	} else {
		skb_queue_tail(&sk->sk_write_queue, skb);		/* Throw it on the queue */
	}

	nr_kick(sk);
}
Ejemplo n.º 3
0
/*
 *	NET/ROM TIMER 
 *
 *	This routine is called every 100ms. Decrement timer by this
 *	amount - if expired then process the event.
 */
static void nr_timer(unsigned long param)
{
	struct sock *sk = (struct sock *)param;

	switch (sk->protinfo.nr->state) {
		case NR_STATE_0:
			/* Magic here: If we listen() and a new link dies before it
			   is accepted() it isn't 'dead' so doesn't get removed. */
			if (sk->destroy || (sk->state == TCP_LISTEN && sk->dead)) {
				del_timer(&sk->timer);
				nr_destroy_socket(sk);
				return;
			}
			break;

		case NR_STATE_3:
			/*
			 * Check for the state of the receive buffer.
			 */
			if (sk->rmem_alloc < (sk->rcvbuf / 2) && (sk->protinfo.nr->condition & NR_COND_OWN_RX_BUSY)) {
				sk->protinfo.nr->condition &= ~NR_COND_OWN_RX_BUSY;
				sk->protinfo.nr->condition &= ~NR_COND_ACK_PENDING;
				sk->protinfo.nr->vl         = sk->protinfo.nr->vr;
				nr_write_internal(sk, NR_INFOACK);
				break;
			}
			/*
			 * Check for frames to transmit.
			 */
			nr_kick(sk);
			break;

		default:
			break;
	}

	if (sk->protinfo.nr->t2timer > 0 && --sk->protinfo.nr->t2timer == 0) {
		if (sk->protinfo.nr->state == NR_STATE_3) {
			if (sk->protinfo.nr->condition & NR_COND_ACK_PENDING) {
				sk->protinfo.nr->condition &= ~NR_COND_ACK_PENDING;
				nr_enquiry_response(sk);
			}
		}
	}

	if (sk->protinfo.nr->t4timer > 0 && --sk->protinfo.nr->t4timer == 0) {
		sk->protinfo.nr->condition &= ~NR_COND_PEER_RX_BUSY;
	}

	if (sk->protinfo.nr->t1timer == 0 || --sk->protinfo.nr->t1timer > 0) {
		nr_set_timer(sk);
		return;
	}

	switch (sk->protinfo.nr->state) {
		case NR_STATE_1: 
			if (sk->protinfo.nr->n2count == sk->protinfo.nr->n2) {
				nr_clear_queues(sk);
				sk->protinfo.nr->state = NR_STATE_0;
				sk->state              = TCP_CLOSE;
				sk->err                = ETIMEDOUT;
				sk->shutdown          |= SEND_SHUTDOWN;
				if (!sk->dead)
					sk->state_change(sk);
				sk->dead               = 1;
			} else {
				sk->protinfo.nr->n2count++;
				nr_write_internal(sk, NR_CONNREQ);
			}
			break;

		case NR_STATE_2:
			if (sk->protinfo.nr->n2count == sk->protinfo.nr->n2) {
				nr_clear_queues(sk);
				sk->protinfo.nr->state = NR_STATE_0;
				sk->state              = TCP_CLOSE;
				sk->err                = ETIMEDOUT;
				sk->shutdown          |= SEND_SHUTDOWN;
				if (!sk->dead)
					sk->state_change(sk);
				sk->dead               = 1;
			} else {
				sk->protinfo.nr->n2count++;
				nr_write_internal(sk, NR_DISCREQ);
			}
			break;

		case NR_STATE_3:
			if (sk->protinfo.nr->n2count == sk->protinfo.nr->n2) {
				nr_clear_queues(sk);
				sk->protinfo.nr->state = NR_STATE_0;
				sk->state              = TCP_CLOSE;
				sk->err                = ETIMEDOUT;
				sk->shutdown          |= SEND_SHUTDOWN;
				if (!sk->dead)
					sk->state_change(sk);
				sk->dead               = 1;
			} else {
				sk->protinfo.nr->n2count++;
				nr_requeue_frames(sk);
			}
			break;
	}

	sk->protinfo.nr->t1timer = sk->protinfo.nr->t1;

	nr_set_timer(sk);
}