1*2874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds *
41da177e4SLinus Torvalds * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
51da177e4SLinus Torvalds */
61da177e4SLinus Torvalds #include <linux/errno.h>
71da177e4SLinus Torvalds #include <linux/types.h>
81da177e4SLinus Torvalds #include <linux/socket.h>
91da177e4SLinus Torvalds #include <linux/in.h>
101da177e4SLinus Torvalds #include <linux/kernel.h>
111da177e4SLinus Torvalds #include <linux/timer.h>
121da177e4SLinus Torvalds #include <linux/string.h>
131da177e4SLinus Torvalds #include <linux/sockios.h>
141da177e4SLinus Torvalds #include <linux/net.h>
155a0e3ad6STejun Heo #include <linux/slab.h>
161da177e4SLinus Torvalds #include <net/ax25.h>
171da177e4SLinus Torvalds #include <linux/inet.h>
181da177e4SLinus Torvalds #include <linux/netdevice.h>
191da177e4SLinus Torvalds #include <linux/skbuff.h>
201da177e4SLinus Torvalds #include <net/sock.h>
21c752f073SArnaldo Carvalho de Melo #include <net/tcp_states.h>
221da177e4SLinus Torvalds #include <linux/fcntl.h>
231da177e4SLinus Torvalds #include <linux/mm.h>
241da177e4SLinus Torvalds #include <linux/interrupt.h>
251da177e4SLinus Torvalds #include <net/rose.h>
261da177e4SLinus Torvalds
271da177e4SLinus Torvalds static int rose_create_facilities(unsigned char *buffer, struct rose_sock *rose);
281da177e4SLinus Torvalds
291da177e4SLinus Torvalds /*
301da177e4SLinus Torvalds * This routine purges all of the queues of frames.
311da177e4SLinus Torvalds */
rose_clear_queues(struct sock * sk)321da177e4SLinus Torvalds void rose_clear_queues(struct sock *sk)
331da177e4SLinus Torvalds {
341da177e4SLinus Torvalds skb_queue_purge(&sk->sk_write_queue);
351da177e4SLinus Torvalds skb_queue_purge(&rose_sk(sk)->ack_queue);
361da177e4SLinus Torvalds }
371da177e4SLinus Torvalds
381da177e4SLinus Torvalds /*
391da177e4SLinus Torvalds * This routine purges the input queue of those frames that have been
401da177e4SLinus Torvalds * acknowledged. This replaces the boxes labelled "V(a) <- N(r)" on the
411da177e4SLinus Torvalds * SDL diagram.
421da177e4SLinus Torvalds */
rose_frames_acked(struct sock * sk,unsigned short nr)431da177e4SLinus Torvalds void rose_frames_acked(struct sock *sk, unsigned short nr)
441da177e4SLinus Torvalds {
451da177e4SLinus Torvalds struct sk_buff *skb;
461da177e4SLinus Torvalds struct rose_sock *rose = rose_sk(sk);
471da177e4SLinus Torvalds
481da177e4SLinus Torvalds /*
491da177e4SLinus Torvalds * Remove all the ack-ed frames from the ack queue.
501da177e4SLinus Torvalds */
511da177e4SLinus Torvalds if (rose->va != nr) {
521da177e4SLinus Torvalds while (skb_peek(&rose->ack_queue) != NULL && rose->va != nr) {
531da177e4SLinus Torvalds skb = skb_dequeue(&rose->ack_queue);
541da177e4SLinus Torvalds kfree_skb(skb);
551da177e4SLinus Torvalds rose->va = (rose->va + 1) % ROSE_MODULUS;
561da177e4SLinus Torvalds }
571da177e4SLinus Torvalds }
581da177e4SLinus Torvalds }
591da177e4SLinus Torvalds
rose_requeue_frames(struct sock * sk)601da177e4SLinus Torvalds void rose_requeue_frames(struct sock *sk)
611da177e4SLinus Torvalds {
621da177e4SLinus Torvalds struct sk_buff *skb, *skb_prev = NULL;
631da177e4SLinus Torvalds
641da177e4SLinus Torvalds /*
651da177e4SLinus Torvalds * Requeue all the un-ack-ed frames on the output queue to be picked
661da177e4SLinus Torvalds * up by rose_kick. This arrangement handles the possibility of an
671da177e4SLinus Torvalds * empty output queue.
681da177e4SLinus Torvalds */
691da177e4SLinus Torvalds while ((skb = skb_dequeue(&rose_sk(sk)->ack_queue)) != NULL) {
701da177e4SLinus Torvalds if (skb_prev == NULL)
711da177e4SLinus Torvalds skb_queue_head(&sk->sk_write_queue, skb);
721da177e4SLinus Torvalds else
738728b834SDavid S. Miller skb_append(skb_prev, skb, &sk->sk_write_queue);
741da177e4SLinus Torvalds skb_prev = skb;
751da177e4SLinus Torvalds }
761da177e4SLinus Torvalds }
771da177e4SLinus Torvalds
781da177e4SLinus Torvalds /*
791da177e4SLinus Torvalds * Validate that the value of nr is between va and vs. Return true or
801da177e4SLinus Torvalds * false for testing.
811da177e4SLinus Torvalds */
rose_validate_nr(struct sock * sk,unsigned short nr)821da177e4SLinus Torvalds int rose_validate_nr(struct sock *sk, unsigned short nr)
831da177e4SLinus Torvalds {
841da177e4SLinus Torvalds struct rose_sock *rose = rose_sk(sk);
851da177e4SLinus Torvalds unsigned short vc = rose->va;
861da177e4SLinus Torvalds
871da177e4SLinus Torvalds while (vc != rose->vs) {
881da177e4SLinus Torvalds if (nr == vc) return 1;
891da177e4SLinus Torvalds vc = (vc + 1) % ROSE_MODULUS;
901da177e4SLinus Torvalds }
911da177e4SLinus Torvalds
921da177e4SLinus Torvalds return nr == rose->vs;
931da177e4SLinus Torvalds }
941da177e4SLinus Torvalds
951da177e4SLinus Torvalds /*
961da177e4SLinus Torvalds * This routine is called when the packet layer internally generates a
971da177e4SLinus Torvalds * control frame.
981da177e4SLinus Torvalds */
rose_write_internal(struct sock * sk,int frametype)991da177e4SLinus Torvalds void rose_write_internal(struct sock *sk, int frametype)
1001da177e4SLinus Torvalds {
1011da177e4SLinus Torvalds struct rose_sock *rose = rose_sk(sk);
1021da177e4SLinus Torvalds struct sk_buff *skb;
1031da177e4SLinus Torvalds unsigned char *dptr;
1041da177e4SLinus Torvalds unsigned char lci1, lci2;
105e5dcc0c3SEric Dumazet int maxfaclen = 0;
106e5dcc0c3SEric Dumazet int len, faclen;
107e5dcc0c3SEric Dumazet int reserve;
1081da177e4SLinus Torvalds
109e5dcc0c3SEric Dumazet reserve = AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + 1;
110e5dcc0c3SEric Dumazet len = ROSE_MIN_LEN;
1111da177e4SLinus Torvalds
1121da177e4SLinus Torvalds switch (frametype) {
1131da177e4SLinus Torvalds case ROSE_CALL_REQUEST:
1141da177e4SLinus Torvalds len += 1 + ROSE_ADDR_LEN + ROSE_ADDR_LEN;
115e5dcc0c3SEric Dumazet maxfaclen = 256;
1161da177e4SLinus Torvalds break;
1171da177e4SLinus Torvalds case ROSE_CALL_ACCEPTED:
1181da177e4SLinus Torvalds case ROSE_CLEAR_REQUEST:
1191da177e4SLinus Torvalds case ROSE_RESET_REQUEST:
1201da177e4SLinus Torvalds len += 2;
1211da177e4SLinus Torvalds break;
1221da177e4SLinus Torvalds }
1231da177e4SLinus Torvalds
124e5dcc0c3SEric Dumazet skb = alloc_skb(reserve + len + maxfaclen, GFP_ATOMIC);
125e5dcc0c3SEric Dumazet if (!skb)
1261da177e4SLinus Torvalds return;
1271da177e4SLinus Torvalds
1281da177e4SLinus Torvalds /*
1291da177e4SLinus Torvalds * Space for AX.25 header and PID.
1301da177e4SLinus Torvalds */
131e5dcc0c3SEric Dumazet skb_reserve(skb, reserve);
1321da177e4SLinus Torvalds
133e5dcc0c3SEric Dumazet dptr = skb_put(skb, len);
1341da177e4SLinus Torvalds
1351da177e4SLinus Torvalds lci1 = (rose->lci >> 8) & 0x0F;
1361da177e4SLinus Torvalds lci2 = (rose->lci >> 0) & 0xFF;
1371da177e4SLinus Torvalds
1381da177e4SLinus Torvalds switch (frametype) {
1391da177e4SLinus Torvalds case ROSE_CALL_REQUEST:
1401da177e4SLinus Torvalds *dptr++ = ROSE_GFI | lci1;
1411da177e4SLinus Torvalds *dptr++ = lci2;
1421da177e4SLinus Torvalds *dptr++ = frametype;
143e0bccd31SBen Hutchings *dptr++ = ROSE_CALL_REQ_ADDR_LEN_VAL;
1441da177e4SLinus Torvalds memcpy(dptr, &rose->dest_addr, ROSE_ADDR_LEN);
1451da177e4SLinus Torvalds dptr += ROSE_ADDR_LEN;
1461da177e4SLinus Torvalds memcpy(dptr, &rose->source_addr, ROSE_ADDR_LEN);
1471da177e4SLinus Torvalds dptr += ROSE_ADDR_LEN;
148e5dcc0c3SEric Dumazet faclen = rose_create_facilities(dptr, rose);
149e5dcc0c3SEric Dumazet skb_put(skb, faclen);
1501da177e4SLinus Torvalds dptr += faclen;
1511da177e4SLinus Torvalds break;
1521da177e4SLinus Torvalds
1531da177e4SLinus Torvalds case ROSE_CALL_ACCEPTED:
1541da177e4SLinus Torvalds *dptr++ = ROSE_GFI | lci1;
1551da177e4SLinus Torvalds *dptr++ = lci2;
1561da177e4SLinus Torvalds *dptr++ = frametype;
1571da177e4SLinus Torvalds *dptr++ = 0x00; /* Address length */
1581da177e4SLinus Torvalds *dptr++ = 0; /* Facilities length */
1591da177e4SLinus Torvalds break;
1601da177e4SLinus Torvalds
1611da177e4SLinus Torvalds case ROSE_CLEAR_REQUEST:
1621da177e4SLinus Torvalds *dptr++ = ROSE_GFI | lci1;
1631da177e4SLinus Torvalds *dptr++ = lci2;
1641da177e4SLinus Torvalds *dptr++ = frametype;
1651da177e4SLinus Torvalds *dptr++ = rose->cause;
1661da177e4SLinus Torvalds *dptr++ = rose->diagnostic;
1671da177e4SLinus Torvalds break;
1681da177e4SLinus Torvalds
1691da177e4SLinus Torvalds case ROSE_RESET_REQUEST:
1701da177e4SLinus Torvalds *dptr++ = ROSE_GFI | lci1;
1711da177e4SLinus Torvalds *dptr++ = lci2;
1721da177e4SLinus Torvalds *dptr++ = frametype;
1731da177e4SLinus Torvalds *dptr++ = ROSE_DTE_ORIGINATED;
1741da177e4SLinus Torvalds *dptr++ = 0;
1751da177e4SLinus Torvalds break;
1761da177e4SLinus Torvalds
1771da177e4SLinus Torvalds case ROSE_RR:
1781da177e4SLinus Torvalds case ROSE_RNR:
1791da177e4SLinus Torvalds *dptr++ = ROSE_GFI | lci1;
1801da177e4SLinus Torvalds *dptr++ = lci2;
1811da177e4SLinus Torvalds *dptr = frametype;
1821da177e4SLinus Torvalds *dptr++ |= (rose->vr << 5) & 0xE0;
1831da177e4SLinus Torvalds break;
1841da177e4SLinus Torvalds
1851da177e4SLinus Torvalds case ROSE_CLEAR_CONFIRMATION:
1861da177e4SLinus Torvalds case ROSE_RESET_CONFIRMATION:
1871da177e4SLinus Torvalds *dptr++ = ROSE_GFI | lci1;
1881da177e4SLinus Torvalds *dptr++ = lci2;
1891da177e4SLinus Torvalds *dptr++ = frametype;
1901da177e4SLinus Torvalds break;
1911da177e4SLinus Torvalds
1921da177e4SLinus Torvalds default:
1931da177e4SLinus Torvalds printk(KERN_ERR "ROSE: rose_write_internal - invalid frametype %02X\n", frametype);
1941da177e4SLinus Torvalds kfree_skb(skb);
1951da177e4SLinus Torvalds return;
1961da177e4SLinus Torvalds }
1971da177e4SLinus Torvalds
1981da177e4SLinus Torvalds rose_transmit_link(skb, rose->neighbour);
1991da177e4SLinus Torvalds }
2001da177e4SLinus Torvalds
rose_decode(struct sk_buff * skb,int * ns,int * nr,int * q,int * d,int * m)2011da177e4SLinus Torvalds int rose_decode(struct sk_buff *skb, int *ns, int *nr, int *q, int *d, int *m)
2021da177e4SLinus Torvalds {
2031da177e4SLinus Torvalds unsigned char *frame;
2041da177e4SLinus Torvalds
2051da177e4SLinus Torvalds frame = skb->data;
2061da177e4SLinus Torvalds
2071da177e4SLinus Torvalds *ns = *nr = *q = *d = *m = 0;
2081da177e4SLinus Torvalds
2091da177e4SLinus Torvalds switch (frame[2]) {
2101da177e4SLinus Torvalds case ROSE_CALL_REQUEST:
2111da177e4SLinus Torvalds case ROSE_CALL_ACCEPTED:
2121da177e4SLinus Torvalds case ROSE_CLEAR_REQUEST:
2131da177e4SLinus Torvalds case ROSE_CLEAR_CONFIRMATION:
2141da177e4SLinus Torvalds case ROSE_RESET_REQUEST:
2151da177e4SLinus Torvalds case ROSE_RESET_CONFIRMATION:
2161da177e4SLinus Torvalds return frame[2];
2171da177e4SLinus Torvalds default:
2181da177e4SLinus Torvalds break;
2191da177e4SLinus Torvalds }
2201da177e4SLinus Torvalds
2211da177e4SLinus Torvalds if ((frame[2] & 0x1F) == ROSE_RR ||
2221da177e4SLinus Torvalds (frame[2] & 0x1F) == ROSE_RNR) {
2231da177e4SLinus Torvalds *nr = (frame[2] >> 5) & 0x07;
2241da177e4SLinus Torvalds return frame[2] & 0x1F;
2251da177e4SLinus Torvalds }
2261da177e4SLinus Torvalds
2271da177e4SLinus Torvalds if ((frame[2] & 0x01) == ROSE_DATA) {
2281da177e4SLinus Torvalds *q = (frame[0] & ROSE_Q_BIT) == ROSE_Q_BIT;
2291da177e4SLinus Torvalds *d = (frame[0] & ROSE_D_BIT) == ROSE_D_BIT;
2301da177e4SLinus Torvalds *m = (frame[2] & ROSE_M_BIT) == ROSE_M_BIT;
2311da177e4SLinus Torvalds *nr = (frame[2] >> 5) & 0x07;
2321da177e4SLinus Torvalds *ns = (frame[2] >> 1) & 0x07;
2331da177e4SLinus Torvalds return ROSE_DATA;
2341da177e4SLinus Torvalds }
2351da177e4SLinus Torvalds
2361da177e4SLinus Torvalds return ROSE_ILLEGAL;
2371da177e4SLinus Torvalds }
2381da177e4SLinus Torvalds
rose_parse_national(unsigned char * p,struct rose_facilities_struct * facilities,int len)2391da177e4SLinus Torvalds static int rose_parse_national(unsigned char *p, struct rose_facilities_struct *facilities, int len)
2401da177e4SLinus Torvalds {
2411da177e4SLinus Torvalds unsigned char *pt;
2421da177e4SLinus Torvalds unsigned char l, lg, n = 0;
2431da177e4SLinus Torvalds int fac_national_digis_received = 0;
2441da177e4SLinus Torvalds
2451da177e4SLinus Torvalds do {
2461da177e4SLinus Torvalds switch (*p & 0xC0) {
2471da177e4SLinus Torvalds case 0x00:
248e0bccd31SBen Hutchings if (len < 2)
249e0bccd31SBen Hutchings return -1;
2501da177e4SLinus Torvalds p += 2;
2511da177e4SLinus Torvalds n += 2;
2521da177e4SLinus Torvalds len -= 2;
2531da177e4SLinus Torvalds break;
2541da177e4SLinus Torvalds
2551da177e4SLinus Torvalds case 0x40:
256e0bccd31SBen Hutchings if (len < 3)
257e0bccd31SBen Hutchings return -1;
2581da177e4SLinus Torvalds if (*p == FAC_NATIONAL_RAND)
2591da177e4SLinus Torvalds facilities->rand = ((p[1] << 8) & 0xFF00) + ((p[2] << 0) & 0x00FF);
2601da177e4SLinus Torvalds p += 3;
2611da177e4SLinus Torvalds n += 3;
2621da177e4SLinus Torvalds len -= 3;
2631da177e4SLinus Torvalds break;
2641da177e4SLinus Torvalds
2651da177e4SLinus Torvalds case 0x80:
266e0bccd31SBen Hutchings if (len < 4)
267e0bccd31SBen Hutchings return -1;
2681da177e4SLinus Torvalds p += 4;
2691da177e4SLinus Torvalds n += 4;
2701da177e4SLinus Torvalds len -= 4;
2711da177e4SLinus Torvalds break;
2721da177e4SLinus Torvalds
2731da177e4SLinus Torvalds case 0xC0:
274e0bccd31SBen Hutchings if (len < 2)
275e0bccd31SBen Hutchings return -1;
2761da177e4SLinus Torvalds l = p[1];
277e0bccd31SBen Hutchings if (len < 2 + l)
278e0bccd31SBen Hutchings return -1;
2791da177e4SLinus Torvalds if (*p == FAC_NATIONAL_DEST_DIGI) {
2801da177e4SLinus Torvalds if (!fac_national_digis_received) {
281e0bccd31SBen Hutchings if (l < AX25_ADDR_LEN)
282e0bccd31SBen Hutchings return -1;
2831da177e4SLinus Torvalds memcpy(&facilities->source_digis[0], p + 2, AX25_ADDR_LEN);
2841da177e4SLinus Torvalds facilities->source_ndigis = 1;
2851da177e4SLinus Torvalds }
2861da177e4SLinus Torvalds }
2871da177e4SLinus Torvalds else if (*p == FAC_NATIONAL_SRC_DIGI) {
2881da177e4SLinus Torvalds if (!fac_national_digis_received) {
289e0bccd31SBen Hutchings if (l < AX25_ADDR_LEN)
290e0bccd31SBen Hutchings return -1;
2911da177e4SLinus Torvalds memcpy(&facilities->dest_digis[0], p + 2, AX25_ADDR_LEN);
2921da177e4SLinus Torvalds facilities->dest_ndigis = 1;
2931da177e4SLinus Torvalds }
2941da177e4SLinus Torvalds }
2951da177e4SLinus Torvalds else if (*p == FAC_NATIONAL_FAIL_CALL) {
296e0bccd31SBen Hutchings if (l < AX25_ADDR_LEN)
297e0bccd31SBen Hutchings return -1;
2981da177e4SLinus Torvalds memcpy(&facilities->fail_call, p + 2, AX25_ADDR_LEN);
2991da177e4SLinus Torvalds }
3001da177e4SLinus Torvalds else if (*p == FAC_NATIONAL_FAIL_ADD) {
301e0bccd31SBen Hutchings if (l < 1 + ROSE_ADDR_LEN)
302e0bccd31SBen Hutchings return -1;
3031da177e4SLinus Torvalds memcpy(&facilities->fail_addr, p + 3, ROSE_ADDR_LEN);
3041da177e4SLinus Torvalds }
3051da177e4SLinus Torvalds else if (*p == FAC_NATIONAL_DIGIS) {
306e0bccd31SBen Hutchings if (l % AX25_ADDR_LEN)
307e0bccd31SBen Hutchings return -1;
3081da177e4SLinus Torvalds fac_national_digis_received = 1;
3091da177e4SLinus Torvalds facilities->source_ndigis = 0;
3101da177e4SLinus Torvalds facilities->dest_ndigis = 0;
3111da177e4SLinus Torvalds for (pt = p + 2, lg = 0 ; lg < l ; pt += AX25_ADDR_LEN, lg += AX25_ADDR_LEN) {
312be20250cSDan Rosenberg if (pt[6] & AX25_HBIT) {
313be20250cSDan Rosenberg if (facilities->dest_ndigis >= ROSE_MAX_DIGIS)
314be20250cSDan Rosenberg return -1;
3151da177e4SLinus Torvalds memcpy(&facilities->dest_digis[facilities->dest_ndigis++], pt, AX25_ADDR_LEN);
316be20250cSDan Rosenberg } else {
317be20250cSDan Rosenberg if (facilities->source_ndigis >= ROSE_MAX_DIGIS)
318be20250cSDan Rosenberg return -1;
3191da177e4SLinus Torvalds memcpy(&facilities->source_digis[facilities->source_ndigis++], pt, AX25_ADDR_LEN);
3201da177e4SLinus Torvalds }
3211da177e4SLinus Torvalds }
322be20250cSDan Rosenberg }
3231da177e4SLinus Torvalds p += l + 2;
3241da177e4SLinus Torvalds n += l + 2;
3251da177e4SLinus Torvalds len -= l + 2;
3261da177e4SLinus Torvalds break;
3271da177e4SLinus Torvalds }
3281da177e4SLinus Torvalds } while (*p != 0x00 && len > 0);
3291da177e4SLinus Torvalds
3301da177e4SLinus Torvalds return n;
3311da177e4SLinus Torvalds }
3321da177e4SLinus Torvalds
rose_parse_ccitt(unsigned char * p,struct rose_facilities_struct * facilities,int len)3331da177e4SLinus Torvalds static int rose_parse_ccitt(unsigned char *p, struct rose_facilities_struct *facilities, int len)
3341da177e4SLinus Torvalds {
3351da177e4SLinus Torvalds unsigned char l, n = 0;
3361da177e4SLinus Torvalds char callsign[11];
3371da177e4SLinus Torvalds
3381da177e4SLinus Torvalds do {
3391da177e4SLinus Torvalds switch (*p & 0xC0) {
3401da177e4SLinus Torvalds case 0x00:
341e0bccd31SBen Hutchings if (len < 2)
342e0bccd31SBen Hutchings return -1;
3431da177e4SLinus Torvalds p += 2;
3441da177e4SLinus Torvalds n += 2;
3451da177e4SLinus Torvalds len -= 2;
3461da177e4SLinus Torvalds break;
3471da177e4SLinus Torvalds
3481da177e4SLinus Torvalds case 0x40:
349e0bccd31SBen Hutchings if (len < 3)
350e0bccd31SBen Hutchings return -1;
3511da177e4SLinus Torvalds p += 3;
3521da177e4SLinus Torvalds n += 3;
3531da177e4SLinus Torvalds len -= 3;
3541da177e4SLinus Torvalds break;
3551da177e4SLinus Torvalds
3561da177e4SLinus Torvalds case 0x80:
357e0bccd31SBen Hutchings if (len < 4)
358e0bccd31SBen Hutchings return -1;
3591da177e4SLinus Torvalds p += 4;
3601da177e4SLinus Torvalds n += 4;
3611da177e4SLinus Torvalds len -= 4;
3621da177e4SLinus Torvalds break;
3631da177e4SLinus Torvalds
3641da177e4SLinus Torvalds case 0xC0:
365e0bccd31SBen Hutchings if (len < 2)
366e0bccd31SBen Hutchings return -1;
3671da177e4SLinus Torvalds l = p[1];
368be20250cSDan Rosenberg
369be20250cSDan Rosenberg /* Prevent overflows*/
370be20250cSDan Rosenberg if (l < 10 || l > 20)
371be20250cSDan Rosenberg return -1;
372be20250cSDan Rosenberg
3731da177e4SLinus Torvalds if (*p == FAC_CCITT_DEST_NSAP) {
3741da177e4SLinus Torvalds memcpy(&facilities->source_addr, p + 7, ROSE_ADDR_LEN);
3751da177e4SLinus Torvalds memcpy(callsign, p + 12, l - 10);
3761da177e4SLinus Torvalds callsign[l - 10] = '\0';
377baed16a7SRalf Baechle asc2ax(&facilities->source_call, callsign);
3781da177e4SLinus Torvalds }
3791da177e4SLinus Torvalds if (*p == FAC_CCITT_SRC_NSAP) {
3801da177e4SLinus Torvalds memcpy(&facilities->dest_addr, p + 7, ROSE_ADDR_LEN);
3811da177e4SLinus Torvalds memcpy(callsign, p + 12, l - 10);
3821da177e4SLinus Torvalds callsign[l - 10] = '\0';
383baed16a7SRalf Baechle asc2ax(&facilities->dest_call, callsign);
3841da177e4SLinus Torvalds }
3851da177e4SLinus Torvalds p += l + 2;
3861da177e4SLinus Torvalds n += l + 2;
3871da177e4SLinus Torvalds len -= l + 2;
3881da177e4SLinus Torvalds break;
3891da177e4SLinus Torvalds }
3901da177e4SLinus Torvalds } while (*p != 0x00 && len > 0);
3911da177e4SLinus Torvalds
3921da177e4SLinus Torvalds return n;
3931da177e4SLinus Torvalds }
3941da177e4SLinus Torvalds
rose_parse_facilities(unsigned char * p,unsigned packet_len,struct rose_facilities_struct * facilities)395e0bccd31SBen Hutchings int rose_parse_facilities(unsigned char *p, unsigned packet_len,
3961da177e4SLinus Torvalds struct rose_facilities_struct *facilities)
3971da177e4SLinus Torvalds {
3981da177e4SLinus Torvalds int facilities_len, len;
3991da177e4SLinus Torvalds
4001da177e4SLinus Torvalds facilities_len = *p++;
4011da177e4SLinus Torvalds
40295c96174SEric Dumazet if (facilities_len == 0 || (unsigned int)facilities_len > packet_len)
4031da177e4SLinus Torvalds return 0;
4041da177e4SLinus Torvalds
405e0bccd31SBen Hutchings while (facilities_len >= 3 && *p == 0x00) {
4061da177e4SLinus Torvalds facilities_len--;
4071da177e4SLinus Torvalds p++;
4081da177e4SLinus Torvalds
4091da177e4SLinus Torvalds switch (*p) {
4101da177e4SLinus Torvalds case FAC_NATIONAL: /* National */
4111da177e4SLinus Torvalds len = rose_parse_national(p + 1, facilities, facilities_len - 1);
4121da177e4SLinus Torvalds break;
4131da177e4SLinus Torvalds
4141da177e4SLinus Torvalds case FAC_CCITT: /* CCITT */
4151da177e4SLinus Torvalds len = rose_parse_ccitt(p + 1, facilities, facilities_len - 1);
4161da177e4SLinus Torvalds break;
4171da177e4SLinus Torvalds
4181da177e4SLinus Torvalds default:
4191da177e4SLinus Torvalds printk(KERN_DEBUG "ROSE: rose_parse_facilities - unknown facilities family %02X\n", *p);
420e0bccd31SBen Hutchings len = 1;
4211da177e4SLinus Torvalds break;
4221da177e4SLinus Torvalds }
423e0bccd31SBen Hutchings
424e0bccd31SBen Hutchings if (len < 0)
425e0bccd31SBen Hutchings return 0;
426e0bccd31SBen Hutchings if (WARN_ON(len >= facilities_len))
427e0bccd31SBen Hutchings return 0;
428e0bccd31SBen Hutchings facilities_len -= len + 1;
429e0bccd31SBen Hutchings p += len + 1;
4301da177e4SLinus Torvalds }
4311da177e4SLinus Torvalds
432e0bccd31SBen Hutchings return facilities_len == 0;
4331da177e4SLinus Torvalds }
4341da177e4SLinus Torvalds
rose_create_facilities(unsigned char * buffer,struct rose_sock * rose)4351da177e4SLinus Torvalds static int rose_create_facilities(unsigned char *buffer, struct rose_sock *rose)
4361da177e4SLinus Torvalds {
4371da177e4SLinus Torvalds unsigned char *p = buffer + 1;
4381da177e4SLinus Torvalds char *callsign;
439f75268cdSRalf Baechle char buf[11];
4401da177e4SLinus Torvalds int len, nb;
4411da177e4SLinus Torvalds
4421da177e4SLinus Torvalds /* National Facilities */
4431da177e4SLinus Torvalds if (rose->rand != 0 || rose->source_ndigis == 1 || rose->dest_ndigis == 1) {
4441da177e4SLinus Torvalds *p++ = 0x00;
4451da177e4SLinus Torvalds *p++ = FAC_NATIONAL;
4461da177e4SLinus Torvalds
4471da177e4SLinus Torvalds if (rose->rand != 0) {
4481da177e4SLinus Torvalds *p++ = FAC_NATIONAL_RAND;
4491da177e4SLinus Torvalds *p++ = (rose->rand >> 8) & 0xFF;
4501da177e4SLinus Torvalds *p++ = (rose->rand >> 0) & 0xFF;
4511da177e4SLinus Torvalds }
4521da177e4SLinus Torvalds
4531da177e4SLinus Torvalds /* Sent before older facilities */
4541da177e4SLinus Torvalds if ((rose->source_ndigis > 0) || (rose->dest_ndigis > 0)) {
4551da177e4SLinus Torvalds int maxdigi = 0;
4561da177e4SLinus Torvalds *p++ = FAC_NATIONAL_DIGIS;
4571da177e4SLinus Torvalds *p++ = AX25_ADDR_LEN * (rose->source_ndigis + rose->dest_ndigis);
4581da177e4SLinus Torvalds for (nb = 0 ; nb < rose->source_ndigis ; nb++) {
4591da177e4SLinus Torvalds if (++maxdigi >= ROSE_MAX_DIGIS)
4601da177e4SLinus Torvalds break;
4611da177e4SLinus Torvalds memcpy(p, &rose->source_digis[nb], AX25_ADDR_LEN);
4621da177e4SLinus Torvalds p[6] |= AX25_HBIT;
4631da177e4SLinus Torvalds p += AX25_ADDR_LEN;
4641da177e4SLinus Torvalds }
4651da177e4SLinus Torvalds for (nb = 0 ; nb < rose->dest_ndigis ; nb++) {
4661da177e4SLinus Torvalds if (++maxdigi >= ROSE_MAX_DIGIS)
4671da177e4SLinus Torvalds break;
4681da177e4SLinus Torvalds memcpy(p, &rose->dest_digis[nb], AX25_ADDR_LEN);
4691da177e4SLinus Torvalds p[6] &= ~AX25_HBIT;
4701da177e4SLinus Torvalds p += AX25_ADDR_LEN;
4711da177e4SLinus Torvalds }
4721da177e4SLinus Torvalds }
4731da177e4SLinus Torvalds
4741da177e4SLinus Torvalds /* For compatibility */
4751da177e4SLinus Torvalds if (rose->source_ndigis > 0) {
4761da177e4SLinus Torvalds *p++ = FAC_NATIONAL_SRC_DIGI;
4771da177e4SLinus Torvalds *p++ = AX25_ADDR_LEN;
4781da177e4SLinus Torvalds memcpy(p, &rose->source_digis[0], AX25_ADDR_LEN);
4791da177e4SLinus Torvalds p += AX25_ADDR_LEN;
4801da177e4SLinus Torvalds }
4811da177e4SLinus Torvalds
4821da177e4SLinus Torvalds /* For compatibility */
4831da177e4SLinus Torvalds if (rose->dest_ndigis > 0) {
4841da177e4SLinus Torvalds *p++ = FAC_NATIONAL_DEST_DIGI;
4851da177e4SLinus Torvalds *p++ = AX25_ADDR_LEN;
4861da177e4SLinus Torvalds memcpy(p, &rose->dest_digis[0], AX25_ADDR_LEN);
4871da177e4SLinus Torvalds p += AX25_ADDR_LEN;
4881da177e4SLinus Torvalds }
4891da177e4SLinus Torvalds }
4901da177e4SLinus Torvalds
4911da177e4SLinus Torvalds *p++ = 0x00;
4921da177e4SLinus Torvalds *p++ = FAC_CCITT;
4931da177e4SLinus Torvalds
4941da177e4SLinus Torvalds *p++ = FAC_CCITT_DEST_NSAP;
4951da177e4SLinus Torvalds
496f75268cdSRalf Baechle callsign = ax2asc(buf, &rose->dest_call);
4971da177e4SLinus Torvalds
4981da177e4SLinus Torvalds *p++ = strlen(callsign) + 10;
4991da177e4SLinus Torvalds *p++ = (strlen(callsign) + 9) * 2; /* ??? */
5001da177e4SLinus Torvalds
5011da177e4SLinus Torvalds *p++ = 0x47; *p++ = 0x00; *p++ = 0x11;
5021da177e4SLinus Torvalds *p++ = ROSE_ADDR_LEN * 2;
5031da177e4SLinus Torvalds memcpy(p, &rose->dest_addr, ROSE_ADDR_LEN);
5041da177e4SLinus Torvalds p += ROSE_ADDR_LEN;
5051da177e4SLinus Torvalds
5061da177e4SLinus Torvalds memcpy(p, callsign, strlen(callsign));
5071da177e4SLinus Torvalds p += strlen(callsign);
5081da177e4SLinus Torvalds
5091da177e4SLinus Torvalds *p++ = FAC_CCITT_SRC_NSAP;
5101da177e4SLinus Torvalds
511f75268cdSRalf Baechle callsign = ax2asc(buf, &rose->source_call);
5121da177e4SLinus Torvalds
5131da177e4SLinus Torvalds *p++ = strlen(callsign) + 10;
5141da177e4SLinus Torvalds *p++ = (strlen(callsign) + 9) * 2; /* ??? */
5151da177e4SLinus Torvalds
5161da177e4SLinus Torvalds *p++ = 0x47; *p++ = 0x00; *p++ = 0x11;
5171da177e4SLinus Torvalds *p++ = ROSE_ADDR_LEN * 2;
5181da177e4SLinus Torvalds memcpy(p, &rose->source_addr, ROSE_ADDR_LEN);
5191da177e4SLinus Torvalds p += ROSE_ADDR_LEN;
5201da177e4SLinus Torvalds
5211da177e4SLinus Torvalds memcpy(p, callsign, strlen(callsign));
5221da177e4SLinus Torvalds p += strlen(callsign);
5231da177e4SLinus Torvalds
5241da177e4SLinus Torvalds len = p - buffer;
5251da177e4SLinus Torvalds buffer[0] = len - 1;
5261da177e4SLinus Torvalds
5271da177e4SLinus Torvalds return len;
5281da177e4SLinus Torvalds }
5291da177e4SLinus Torvalds
rose_disconnect(struct sock * sk,int reason,int cause,int diagnostic)5301da177e4SLinus Torvalds void rose_disconnect(struct sock *sk, int reason, int cause, int diagnostic)
5311da177e4SLinus Torvalds {
5321da177e4SLinus Torvalds struct rose_sock *rose = rose_sk(sk);
5331da177e4SLinus Torvalds
5341da177e4SLinus Torvalds rose_stop_timer(sk);
5351da177e4SLinus Torvalds rose_stop_idletimer(sk);
5361da177e4SLinus Torvalds
5371da177e4SLinus Torvalds rose_clear_queues(sk);
5381da177e4SLinus Torvalds
5391da177e4SLinus Torvalds rose->lci = 0;
5401da177e4SLinus Torvalds rose->state = ROSE_STATE_0;
5411da177e4SLinus Torvalds
5421da177e4SLinus Torvalds if (cause != -1)
5431da177e4SLinus Torvalds rose->cause = cause;
5441da177e4SLinus Torvalds
5451da177e4SLinus Torvalds if (diagnostic != -1)
5461da177e4SLinus Torvalds rose->diagnostic = diagnostic;
5471da177e4SLinus Torvalds
5481da177e4SLinus Torvalds sk->sk_state = TCP_CLOSE;
5491da177e4SLinus Torvalds sk->sk_err = reason;
5501da177e4SLinus Torvalds sk->sk_shutdown |= SEND_SHUTDOWN;
5511da177e4SLinus Torvalds
5521da177e4SLinus Torvalds if (!sock_flag(sk, SOCK_DEAD)) {
5531da177e4SLinus Torvalds sk->sk_state_change(sk);
5541da177e4SLinus Torvalds sock_set_flag(sk, SOCK_DEAD);
5551da177e4SLinus Torvalds }
5561da177e4SLinus Torvalds }
557