Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Linux/net/netrom/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 6 kB image not shown  

Quelle  nr_in.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0-or-later
/*
 *
 * Copyright Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
 * Copyright Darryl Miles G7LED (dlm@g7led.demon.co.uk)
 */

#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
#include <linux/in.h>
#include <linux/kernel.h>
#include <linux/timer.h>
#include <linux/string.h>
#include <linux/sockios.h>
#include <linux/net.h>
#include <linux/slab.h>
#include <net/ax25.h>
#include <linux/inet.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <net/sock.h>
#include <net/tcp_states.h>
#include <linux/uaccess.h>
#include <linux/fcntl.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <net/netrom.h>

static int nr_queue_rx_frame(struct sock *sk, struct sk_buff *skb, int more)
{
 struct sk_buff *skbo, *skbn = skb;
 struct nr_sock *nr = nr_sk(sk);

 skb_pull(skb, NR_NETWORK_LEN + NR_TRANSPORT_LEN);

 nr_start_idletimer(sk);

 if (more) {
  nr->fraglen += skb->len;
  skb_queue_tail(&nr->frag_queue, skb);
  return 0;
 }

 if (!more && nr->fraglen > 0) { /* End of fragment */
  nr->fraglen += skb->len;
  skb_queue_tail(&nr->frag_queue, skb);

  if ((skbn = alloc_skb(nr->fraglen, GFP_ATOMIC)) == NULL)
   return 1;

  skb_reset_transport_header(skbn);

  while ((skbo = skb_dequeue(&nr->frag_queue)) != NULL) {
   skb_copy_from_linear_data(skbo,
        skb_put(skbn, skbo->len),
        skbo->len);
   kfree_skb(skbo);
  }

  nr->fraglen = 0;
 }

 return sock_queue_rcv_skb(sk, skbn);
}

/*
 * State machine for state 1, Awaiting Connection State.
 * The handling of the timer(s) is in file nr_timer.c.
 * Handling of state 0 and connection release is in netrom.c.
 */

static int nr_state1_machine(struct sock *sk, struct sk_buff *skb,
 int frametype)
{
 switch (frametype) {
 case NR_CONNACK: {
  struct nr_sock *nr = nr_sk(sk);

  nr_stop_t1timer(sk);
  nr_start_idletimer(sk);
  nr->your_index = skb->data[17];
  nr->your_id    = skb->data[18];
  nr->vs        = 0;
  nr->va        = 0;
  nr->vr        = 0;
  nr->vl        = 0;
  nr->state      = NR_STATE_3;
  nr->n2count    = 0;
  nr->window     = skb->data[20];
  sk->sk_state   = TCP_ESTABLISHED;
  if (!sock_flag(sk, SOCK_DEAD))
   sk->sk_state_change(sk);
  break;
 }

 case NR_CONNACK | NR_CHOKE_FLAG:
  nr_disconnect(sk, ECONNREFUSED);
  break;

 case NR_RESET:
  if (READ_ONCE(sysctl_netrom_reset_circuit))
   nr_disconnect(sk, ECONNRESET);
  break;

 default:
  break;
 }
 return 0;
}

/*
 * State machine for state 2, Awaiting Release State.
 * The handling of the timer(s) is in file nr_timer.c
 * Handling of state 0 and connection release is in netrom.c.
 */

static int nr_state2_machine(struct sock *sk, struct sk_buff *skb,
 int frametype)
{
 switch (frametype) {
 case NR_CONNACK | NR_CHOKE_FLAG:
  nr_disconnect(sk, ECONNRESET);
  break;

 case NR_DISCREQ:
  nr_write_internal(sk, NR_DISCACK);
  fallthrough;
 case NR_DISCACK:
  nr_disconnect(sk, 0);
  break;

 case NR_RESET:
  if (READ_ONCE(sysctl_netrom_reset_circuit))
   nr_disconnect(sk, ECONNRESET);
  break;

 default:
  break;
 }
 return 0;
}

/*
 * State machine for state 3, Connected State.
 * The handling of the timer(s) is in file nr_timer.c
 * Handling of state 0 and connection release is in netrom.c.
 */

static int nr_state3_machine(struct sock *sk, struct sk_buff *skb, int frametype)
{
 struct nr_sock *nrom = nr_sk(sk);
 struct sk_buff_head temp_queue;
 struct sk_buff *skbn;
 unsigned short save_vr;
 unsigned short nr, ns;
 int queued = 0;

 nr = skb->data[18];

 switch (frametype) {
 case NR_CONNREQ:
  nr_write_internal(sk, NR_CONNACK);
  break;

 case NR_DISCREQ:
  nr_write_internal(sk, NR_DISCACK);
  nr_disconnect(sk, 0);
  break;

 case NR_CONNACK | NR_CHOKE_FLAG:
 case NR_DISCACK:
  nr_disconnect(sk, ECONNRESET);
  break;

 case NR_INFOACK:
 case NR_INFOACK | NR_CHOKE_FLAG:
 case NR_INFOACK | NR_NAK_FLAG:
 case NR_INFOACK | NR_NAK_FLAG | NR_CHOKE_FLAG:
  if (frametype & NR_CHOKE_FLAG) {
   nrom->condition |= NR_COND_PEER_RX_BUSY;
   nr_start_t4timer(sk);
  } else {
   nrom->condition &= ~NR_COND_PEER_RX_BUSY;
   nr_stop_t4timer(sk);
  }
  if (!nr_validate_nr(sk, nr)) {
   break;
  }
  if (frametype & NR_NAK_FLAG) {
   nr_frames_acked(sk, nr);
   nr_send_nak_frame(sk);
  } else {
   if (nrom->condition & NR_COND_PEER_RX_BUSY) {
    nr_frames_acked(sk, nr);
   } else {
    nr_check_iframes_acked(sk, nr);
   }
  }
  break;

 case NR_INFO:
 case NR_INFO | NR_NAK_FLAG:
 case NR_INFO | NR_CHOKE_FLAG:
 case NR_INFO | NR_MORE_FLAG:
 case NR_INFO | NR_NAK_FLAG | NR_CHOKE_FLAG:
 case NR_INFO | NR_CHOKE_FLAG | NR_MORE_FLAG:
 case NR_INFO | NR_NAK_FLAG | NR_MORE_FLAG:
 case NR_INFO | NR_NAK_FLAG | NR_CHOKE_FLAG | NR_MORE_FLAG:
  if (frametype & NR_CHOKE_FLAG) {
   nrom->condition |= NR_COND_PEER_RX_BUSY;
   nr_start_t4timer(sk);
  } else {
   nrom->condition &= ~NR_COND_PEER_RX_BUSY;
   nr_stop_t4timer(sk);
  }
  if (nr_validate_nr(sk, nr)) {
   if (frametype & NR_NAK_FLAG) {
    nr_frames_acked(sk, nr);
    nr_send_nak_frame(sk);
   } else {
    if (nrom->condition & NR_COND_PEER_RX_BUSY) {
     nr_frames_acked(sk, nr);
    } else {
     nr_check_iframes_acked(sk, nr);
    }
   }
  }
  queued = 1;
  skb_queue_head(&nrom->reseq_queue, skb);
  if (nrom->condition & NR_COND_OWN_RX_BUSY)
   break;
  skb_queue_head_init(&temp_queue);
  do {
   save_vr = nrom->vr;
   while ((skbn = skb_dequeue(&nrom->reseq_queue)) != NULL) {
    ns = skbn->data[17];
    if (ns == nrom->vr) {
     if (nr_queue_rx_frame(sk, skbn, frametype & NR_MORE_FLAG) == 0) {
      nrom->vr = (nrom->vr + 1) % NR_MODULUS;
     } else {
      nrom->condition |= NR_COND_OWN_RX_BUSY;
      skb_queue_tail(&temp_queue, skbn);
     }
    } else if (nr_in_rx_window(sk, ns)) {
     skb_queue_tail(&temp_queue, skbn);
    } else {
     kfree_skb(skbn);
    }
   }
   while ((skbn = skb_dequeue(&temp_queue)) != NULL) {
    skb_queue_tail(&nrom->reseq_queue, skbn);
   }
  } while (save_vr != nrom->vr);
  /*
 * Window is full, ack it immediately.
 */

  if (((nrom->vl + nrom->window) % NR_MODULUS) == nrom->vr) {
   nr_enquiry_response(sk);
  } else {
   if (!(nrom->condition & NR_COND_ACK_PENDING)) {
    nrom->condition |= NR_COND_ACK_PENDING;
    nr_start_t2timer(sk);
   }
  }
  break;

 case NR_RESET:
  if (READ_ONCE(sysctl_netrom_reset_circuit))
   nr_disconnect(sk, ECONNRESET);
  break;

 default:
  break;
 }
 return queued;
}

/* 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;
}

Messung V0.5
C=98 H=98 G=97

¤ Dauer der Verarbeitung: 0.4 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.