/* * This routine purges all of the queues of frames.
*/ void rose_clear_queues(struct sock *sk)
{
skb_queue_purge(&sk->sk_write_queue);
skb_queue_purge(&rose_sk(sk)->ack_queue);
}
/* * This routine purges the input queue of those frames that have been * acknowledged. This replaces the boxes labelled "V(a) <- N(r)" on the * SDL diagram.
*/ void rose_frames_acked(struct sock *sk, unsignedshort nr)
{ struct sk_buff *skb; struct rose_sock *rose = rose_sk(sk);
/* * Remove all the ack-ed frames from the ack queue.
*/ if (rose->va != nr) { while (skb_peek(&rose->ack_queue) != NULL && rose->va != nr) {
skb = skb_dequeue(&rose->ack_queue);
kfree_skb(skb);
rose->va = (rose->va + 1) % ROSE_MODULUS;
}
}
}
/* * Requeue all the un-ack-ed frames on the output queue to be picked * up by rose_kick. This arrangement handles the possibility of an * empty output queue.
*/ while ((skb = skb_dequeue(&rose_sk(sk)->ack_queue)) != NULL) { if (skb_prev == NULL)
skb_queue_head(&sk->sk_write_queue, skb); else
skb_append(skb_prev, skb, &sk->sk_write_queue);
skb_prev = skb;
}
}
/* * Validate that the value of nr is between va and vs. Return true or * false for testing.
*/ int rose_validate_nr(struct sock *sk, unsignedshort nr)
{ struct rose_sock *rose = rose_sk(sk); unsignedshort vc = rose->va;
while (vc != rose->vs) { if (nr == vc) return 1;
vc = (vc + 1) % ROSE_MODULUS;
}
return nr == rose->vs;
}
/* * This routine is called when the packet layer internally generates a * control frame.
*/ void rose_write_internal(struct sock *sk, int frametype)
{ struct rose_sock *rose = rose_sk(sk); struct sk_buff *skb; unsignedchar *dptr; unsignedchar lci1, lci2; int maxfaclen = 0; int len, faclen; int reserve;
reserve = AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + 1;
len = ROSE_MIN_LEN;
switch (frametype) { case ROSE_CALL_REQUEST:
len += 1 + ROSE_ADDR_LEN + ROSE_ADDR_LEN;
maxfaclen = 256; break; case ROSE_CALL_ACCEPTED: case ROSE_CLEAR_REQUEST: case ROSE_RESET_REQUEST:
len += 2; break;
}
skb = alloc_skb(reserve + len + maxfaclen, GFP_ATOMIC); if (!skb) return;
/* * Space for AX.25 header and PID.
*/
skb_reserve(skb, reserve);
int rose_decode(struct sk_buff *skb, int *ns, int *nr, int *q, int *d, int *m)
{ unsignedchar *frame;
frame = skb->data;
*ns = *nr = *q = *d = *m = 0;
switch (frame[2]) { case ROSE_CALL_REQUEST: case ROSE_CALL_ACCEPTED: case ROSE_CLEAR_REQUEST: case ROSE_CLEAR_CONFIRMATION: case ROSE_RESET_REQUEST: case ROSE_RESET_CONFIRMATION: return frame[2]; default: break;
}
staticint rose_parse_national(unsignedchar *p, struct rose_facilities_struct *facilities, int len)
{ unsignedchar *pt; unsignedchar l, lg, n = 0; int fac_national_digis_received = 0;
do { switch (*p & 0xC0) { case 0x00: if (len < 2) return -1;
p += 2;
n += 2;
len -= 2; break;
case 0x40: if (len < 3) return -1; if (*p == FAC_NATIONAL_RAND)
facilities->rand = ((p[1] << 8) & 0xFF00) + ((p[2] << 0) & 0x00FF);
p += 3;
n += 3;
len -= 3; break;
case 0x80: if (len < 4) return -1;
p += 4;
n += 4;
len -= 4; break;
case 0xC0: if (len < 2) return -1;
l = p[1]; if (len < 2 + l) return -1; if (*p == FAC_NATIONAL_DEST_DIGI) { if (!fac_national_digis_received) { if (l < AX25_ADDR_LEN) return -1;
memcpy(&facilities->source_digis[0], p + 2, AX25_ADDR_LEN);
facilities->source_ndigis = 1;
}
} elseif (*p == FAC_NATIONAL_SRC_DIGI) { if (!fac_national_digis_received) { if (l < AX25_ADDR_LEN) return -1;
memcpy(&facilities->dest_digis[0], p + 2, AX25_ADDR_LEN);
facilities->dest_ndigis = 1;
}
} elseif (*p == FAC_NATIONAL_FAIL_CALL) { if (l < AX25_ADDR_LEN) return -1;
memcpy(&facilities->fail_call, p + 2, AX25_ADDR_LEN);
} elseif (*p == FAC_NATIONAL_FAIL_ADD) { if (l < 1 + ROSE_ADDR_LEN) return -1;
memcpy(&facilities->fail_addr, p + 3, ROSE_ADDR_LEN);
} elseif (*p == FAC_NATIONAL_DIGIS) { if (l % AX25_ADDR_LEN) return -1;
fac_national_digis_received = 1;
facilities->source_ndigis = 0;
facilities->dest_ndigis = 0; for (pt = p + 2, lg = 0 ; lg < l ; pt += AX25_ADDR_LEN, lg += AX25_ADDR_LEN) { if (pt[6] & AX25_HBIT) { if (facilities->dest_ndigis >= ROSE_MAX_DIGIS) return -1;
memcpy(&facilities->dest_digis[facilities->dest_ndigis++], pt, AX25_ADDR_LEN);
} else { if (facilities->source_ndigis >= ROSE_MAX_DIGIS) return -1;
memcpy(&facilities->source_digis[facilities->source_ndigis++], pt, AX25_ADDR_LEN);
}
}
}
p += l + 2;
n += l + 2;
len -= l + 2; break;
}
} while (*p != 0x00 && len > 0);
return n;
}
staticint rose_parse_ccitt(unsignedchar *p, struct rose_facilities_struct *facilities, int len)
{ unsignedchar l, n = 0; char callsign[11];
do { switch (*p & 0xC0) { case 0x00: if (len < 2) return -1;
p += 2;
n += 2;
len -= 2; break;
case 0x40: if (len < 3) return -1;
p += 3;
n += 3;
len -= 3; break;
case 0x80: if (len < 4) return -1;
p += 4;
n += 4;
len -= 4; break;
case 0xC0: if (len < 2) return -1;
l = p[1];
/* Prevent overflows*/ if (l < 10 || l > 20) return -1;
if (*p == FAC_CCITT_DEST_NSAP) {
memcpy(&facilities->source_addr, p + 7, ROSE_ADDR_LEN);
memcpy(callsign, p + 12, l - 10);
callsign[l - 10] = '\0';
asc2ax(&facilities->source_call, callsign);
} if (*p == FAC_CCITT_SRC_NSAP) {
memcpy(&facilities->dest_addr, p + 7, ROSE_ADDR_LEN);
memcpy(callsign, p + 12, l - 10);
callsign[l - 10] = '\0';
asc2ax(&facilities->dest_call, callsign);
}
p += l + 2;
n += l + 2;
len -= l + 2; break;
}
} while (*p != 0x00 && len > 0);
return n;
}
int rose_parse_facilities(unsignedchar *p, unsigned packet_len, struct rose_facilities_struct *facilities)
{ int facilities_len, len;
facilities_len = *p++;
if (facilities_len == 0 || (unsignedint)facilities_len > packet_len) return 0;
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.