18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci#include <linux/errno.h> 78c2ecf20Sopenharmony_ci#include <linux/types.h> 88c2ecf20Sopenharmony_ci#include <linux/socket.h> 98c2ecf20Sopenharmony_ci#include <linux/in.h> 108c2ecf20Sopenharmony_ci#include <linux/kernel.h> 118c2ecf20Sopenharmony_ci#include <linux/timer.h> 128c2ecf20Sopenharmony_ci#include <linux/string.h> 138c2ecf20Sopenharmony_ci#include <linux/sockios.h> 148c2ecf20Sopenharmony_ci#include <linux/net.h> 158c2ecf20Sopenharmony_ci#include <linux/slab.h> 168c2ecf20Sopenharmony_ci#include <net/ax25.h> 178c2ecf20Sopenharmony_ci#include <linux/inet.h> 188c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 198c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 208c2ecf20Sopenharmony_ci#include <net/sock.h> 218c2ecf20Sopenharmony_ci#include <net/tcp_states.h> 228c2ecf20Sopenharmony_ci#include <linux/fcntl.h> 238c2ecf20Sopenharmony_ci#include <linux/mm.h> 248c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 258c2ecf20Sopenharmony_ci#include <net/rose.h> 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_cistatic int rose_create_facilities(unsigned char *buffer, struct rose_sock *rose); 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci/* 308c2ecf20Sopenharmony_ci * This routine purges all of the queues of frames. 318c2ecf20Sopenharmony_ci */ 328c2ecf20Sopenharmony_civoid rose_clear_queues(struct sock *sk) 338c2ecf20Sopenharmony_ci{ 348c2ecf20Sopenharmony_ci skb_queue_purge(&sk->sk_write_queue); 358c2ecf20Sopenharmony_ci skb_queue_purge(&rose_sk(sk)->ack_queue); 368c2ecf20Sopenharmony_ci} 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci/* 398c2ecf20Sopenharmony_ci * This routine purges the input queue of those frames that have been 408c2ecf20Sopenharmony_ci * acknowledged. This replaces the boxes labelled "V(a) <- N(r)" on the 418c2ecf20Sopenharmony_ci * SDL diagram. 428c2ecf20Sopenharmony_ci */ 438c2ecf20Sopenharmony_civoid rose_frames_acked(struct sock *sk, unsigned short nr) 448c2ecf20Sopenharmony_ci{ 458c2ecf20Sopenharmony_ci struct sk_buff *skb; 468c2ecf20Sopenharmony_ci struct rose_sock *rose = rose_sk(sk); 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci /* 498c2ecf20Sopenharmony_ci * Remove all the ack-ed frames from the ack queue. 508c2ecf20Sopenharmony_ci */ 518c2ecf20Sopenharmony_ci if (rose->va != nr) { 528c2ecf20Sopenharmony_ci while (skb_peek(&rose->ack_queue) != NULL && rose->va != nr) { 538c2ecf20Sopenharmony_ci skb = skb_dequeue(&rose->ack_queue); 548c2ecf20Sopenharmony_ci kfree_skb(skb); 558c2ecf20Sopenharmony_ci rose->va = (rose->va + 1) % ROSE_MODULUS; 568c2ecf20Sopenharmony_ci } 578c2ecf20Sopenharmony_ci } 588c2ecf20Sopenharmony_ci} 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_civoid rose_requeue_frames(struct sock *sk) 618c2ecf20Sopenharmony_ci{ 628c2ecf20Sopenharmony_ci struct sk_buff *skb, *skb_prev = NULL; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci /* 658c2ecf20Sopenharmony_ci * Requeue all the un-ack-ed frames on the output queue to be picked 668c2ecf20Sopenharmony_ci * up by rose_kick. This arrangement handles the possibility of an 678c2ecf20Sopenharmony_ci * empty output queue. 688c2ecf20Sopenharmony_ci */ 698c2ecf20Sopenharmony_ci while ((skb = skb_dequeue(&rose_sk(sk)->ack_queue)) != NULL) { 708c2ecf20Sopenharmony_ci if (skb_prev == NULL) 718c2ecf20Sopenharmony_ci skb_queue_head(&sk->sk_write_queue, skb); 728c2ecf20Sopenharmony_ci else 738c2ecf20Sopenharmony_ci skb_append(skb_prev, skb, &sk->sk_write_queue); 748c2ecf20Sopenharmony_ci skb_prev = skb; 758c2ecf20Sopenharmony_ci } 768c2ecf20Sopenharmony_ci} 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci/* 798c2ecf20Sopenharmony_ci * Validate that the value of nr is between va and vs. Return true or 808c2ecf20Sopenharmony_ci * false for testing. 818c2ecf20Sopenharmony_ci */ 828c2ecf20Sopenharmony_ciint rose_validate_nr(struct sock *sk, unsigned short nr) 838c2ecf20Sopenharmony_ci{ 848c2ecf20Sopenharmony_ci struct rose_sock *rose = rose_sk(sk); 858c2ecf20Sopenharmony_ci unsigned short vc = rose->va; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci while (vc != rose->vs) { 888c2ecf20Sopenharmony_ci if (nr == vc) return 1; 898c2ecf20Sopenharmony_ci vc = (vc + 1) % ROSE_MODULUS; 908c2ecf20Sopenharmony_ci } 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci return nr == rose->vs; 938c2ecf20Sopenharmony_ci} 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci/* 968c2ecf20Sopenharmony_ci * This routine is called when the packet layer internally generates a 978c2ecf20Sopenharmony_ci * control frame. 988c2ecf20Sopenharmony_ci */ 998c2ecf20Sopenharmony_civoid rose_write_internal(struct sock *sk, int frametype) 1008c2ecf20Sopenharmony_ci{ 1018c2ecf20Sopenharmony_ci struct rose_sock *rose = rose_sk(sk); 1028c2ecf20Sopenharmony_ci struct sk_buff *skb; 1038c2ecf20Sopenharmony_ci unsigned char *dptr; 1048c2ecf20Sopenharmony_ci unsigned char lci1, lci2; 1058c2ecf20Sopenharmony_ci int maxfaclen = 0; 1068c2ecf20Sopenharmony_ci int len, faclen; 1078c2ecf20Sopenharmony_ci int reserve; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci reserve = AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + 1; 1108c2ecf20Sopenharmony_ci len = ROSE_MIN_LEN; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci switch (frametype) { 1138c2ecf20Sopenharmony_ci case ROSE_CALL_REQUEST: 1148c2ecf20Sopenharmony_ci len += 1 + ROSE_ADDR_LEN + ROSE_ADDR_LEN; 1158c2ecf20Sopenharmony_ci maxfaclen = 256; 1168c2ecf20Sopenharmony_ci break; 1178c2ecf20Sopenharmony_ci case ROSE_CALL_ACCEPTED: 1188c2ecf20Sopenharmony_ci case ROSE_CLEAR_REQUEST: 1198c2ecf20Sopenharmony_ci case ROSE_RESET_REQUEST: 1208c2ecf20Sopenharmony_ci len += 2; 1218c2ecf20Sopenharmony_ci break; 1228c2ecf20Sopenharmony_ci } 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci skb = alloc_skb(reserve + len + maxfaclen, GFP_ATOMIC); 1258c2ecf20Sopenharmony_ci if (!skb) 1268c2ecf20Sopenharmony_ci return; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci /* 1298c2ecf20Sopenharmony_ci * Space for AX.25 header and PID. 1308c2ecf20Sopenharmony_ci */ 1318c2ecf20Sopenharmony_ci skb_reserve(skb, reserve); 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci dptr = skb_put(skb, len); 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci lci1 = (rose->lci >> 8) & 0x0F; 1368c2ecf20Sopenharmony_ci lci2 = (rose->lci >> 0) & 0xFF; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci switch (frametype) { 1398c2ecf20Sopenharmony_ci case ROSE_CALL_REQUEST: 1408c2ecf20Sopenharmony_ci *dptr++ = ROSE_GFI | lci1; 1418c2ecf20Sopenharmony_ci *dptr++ = lci2; 1428c2ecf20Sopenharmony_ci *dptr++ = frametype; 1438c2ecf20Sopenharmony_ci *dptr++ = ROSE_CALL_REQ_ADDR_LEN_VAL; 1448c2ecf20Sopenharmony_ci memcpy(dptr, &rose->dest_addr, ROSE_ADDR_LEN); 1458c2ecf20Sopenharmony_ci dptr += ROSE_ADDR_LEN; 1468c2ecf20Sopenharmony_ci memcpy(dptr, &rose->source_addr, ROSE_ADDR_LEN); 1478c2ecf20Sopenharmony_ci dptr += ROSE_ADDR_LEN; 1488c2ecf20Sopenharmony_ci faclen = rose_create_facilities(dptr, rose); 1498c2ecf20Sopenharmony_ci skb_put(skb, faclen); 1508c2ecf20Sopenharmony_ci dptr += faclen; 1518c2ecf20Sopenharmony_ci break; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci case ROSE_CALL_ACCEPTED: 1548c2ecf20Sopenharmony_ci *dptr++ = ROSE_GFI | lci1; 1558c2ecf20Sopenharmony_ci *dptr++ = lci2; 1568c2ecf20Sopenharmony_ci *dptr++ = frametype; 1578c2ecf20Sopenharmony_ci *dptr++ = 0x00; /* Address length */ 1588c2ecf20Sopenharmony_ci *dptr++ = 0; /* Facilities length */ 1598c2ecf20Sopenharmony_ci break; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci case ROSE_CLEAR_REQUEST: 1628c2ecf20Sopenharmony_ci *dptr++ = ROSE_GFI | lci1; 1638c2ecf20Sopenharmony_ci *dptr++ = lci2; 1648c2ecf20Sopenharmony_ci *dptr++ = frametype; 1658c2ecf20Sopenharmony_ci *dptr++ = rose->cause; 1668c2ecf20Sopenharmony_ci *dptr++ = rose->diagnostic; 1678c2ecf20Sopenharmony_ci break; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci case ROSE_RESET_REQUEST: 1708c2ecf20Sopenharmony_ci *dptr++ = ROSE_GFI | lci1; 1718c2ecf20Sopenharmony_ci *dptr++ = lci2; 1728c2ecf20Sopenharmony_ci *dptr++ = frametype; 1738c2ecf20Sopenharmony_ci *dptr++ = ROSE_DTE_ORIGINATED; 1748c2ecf20Sopenharmony_ci *dptr++ = 0; 1758c2ecf20Sopenharmony_ci break; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci case ROSE_RR: 1788c2ecf20Sopenharmony_ci case ROSE_RNR: 1798c2ecf20Sopenharmony_ci *dptr++ = ROSE_GFI | lci1; 1808c2ecf20Sopenharmony_ci *dptr++ = lci2; 1818c2ecf20Sopenharmony_ci *dptr = frametype; 1828c2ecf20Sopenharmony_ci *dptr++ |= (rose->vr << 5) & 0xE0; 1838c2ecf20Sopenharmony_ci break; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci case ROSE_CLEAR_CONFIRMATION: 1868c2ecf20Sopenharmony_ci case ROSE_RESET_CONFIRMATION: 1878c2ecf20Sopenharmony_ci *dptr++ = ROSE_GFI | lci1; 1888c2ecf20Sopenharmony_ci *dptr++ = lci2; 1898c2ecf20Sopenharmony_ci *dptr++ = frametype; 1908c2ecf20Sopenharmony_ci break; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci default: 1938c2ecf20Sopenharmony_ci printk(KERN_ERR "ROSE: rose_write_internal - invalid frametype %02X\n", frametype); 1948c2ecf20Sopenharmony_ci kfree_skb(skb); 1958c2ecf20Sopenharmony_ci return; 1968c2ecf20Sopenharmony_ci } 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci rose_transmit_link(skb, rose->neighbour); 1998c2ecf20Sopenharmony_ci} 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ciint rose_decode(struct sk_buff *skb, int *ns, int *nr, int *q, int *d, int *m) 2028c2ecf20Sopenharmony_ci{ 2038c2ecf20Sopenharmony_ci unsigned char *frame; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci frame = skb->data; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci *ns = *nr = *q = *d = *m = 0; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci switch (frame[2]) { 2108c2ecf20Sopenharmony_ci case ROSE_CALL_REQUEST: 2118c2ecf20Sopenharmony_ci case ROSE_CALL_ACCEPTED: 2128c2ecf20Sopenharmony_ci case ROSE_CLEAR_REQUEST: 2138c2ecf20Sopenharmony_ci case ROSE_CLEAR_CONFIRMATION: 2148c2ecf20Sopenharmony_ci case ROSE_RESET_REQUEST: 2158c2ecf20Sopenharmony_ci case ROSE_RESET_CONFIRMATION: 2168c2ecf20Sopenharmony_ci return frame[2]; 2178c2ecf20Sopenharmony_ci default: 2188c2ecf20Sopenharmony_ci break; 2198c2ecf20Sopenharmony_ci } 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci if ((frame[2] & 0x1F) == ROSE_RR || 2228c2ecf20Sopenharmony_ci (frame[2] & 0x1F) == ROSE_RNR) { 2238c2ecf20Sopenharmony_ci *nr = (frame[2] >> 5) & 0x07; 2248c2ecf20Sopenharmony_ci return frame[2] & 0x1F; 2258c2ecf20Sopenharmony_ci } 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci if ((frame[2] & 0x01) == ROSE_DATA) { 2288c2ecf20Sopenharmony_ci *q = (frame[0] & ROSE_Q_BIT) == ROSE_Q_BIT; 2298c2ecf20Sopenharmony_ci *d = (frame[0] & ROSE_D_BIT) == ROSE_D_BIT; 2308c2ecf20Sopenharmony_ci *m = (frame[2] & ROSE_M_BIT) == ROSE_M_BIT; 2318c2ecf20Sopenharmony_ci *nr = (frame[2] >> 5) & 0x07; 2328c2ecf20Sopenharmony_ci *ns = (frame[2] >> 1) & 0x07; 2338c2ecf20Sopenharmony_ci return ROSE_DATA; 2348c2ecf20Sopenharmony_ci } 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci return ROSE_ILLEGAL; 2378c2ecf20Sopenharmony_ci} 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_cistatic int rose_parse_national(unsigned char *p, struct rose_facilities_struct *facilities, int len) 2408c2ecf20Sopenharmony_ci{ 2418c2ecf20Sopenharmony_ci unsigned char *pt; 2428c2ecf20Sopenharmony_ci unsigned char l, lg, n = 0; 2438c2ecf20Sopenharmony_ci int fac_national_digis_received = 0; 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci do { 2468c2ecf20Sopenharmony_ci switch (*p & 0xC0) { 2478c2ecf20Sopenharmony_ci case 0x00: 2488c2ecf20Sopenharmony_ci if (len < 2) 2498c2ecf20Sopenharmony_ci return -1; 2508c2ecf20Sopenharmony_ci p += 2; 2518c2ecf20Sopenharmony_ci n += 2; 2528c2ecf20Sopenharmony_ci len -= 2; 2538c2ecf20Sopenharmony_ci break; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci case 0x40: 2568c2ecf20Sopenharmony_ci if (len < 3) 2578c2ecf20Sopenharmony_ci return -1; 2588c2ecf20Sopenharmony_ci if (*p == FAC_NATIONAL_RAND) 2598c2ecf20Sopenharmony_ci facilities->rand = ((p[1] << 8) & 0xFF00) + ((p[2] << 0) & 0x00FF); 2608c2ecf20Sopenharmony_ci p += 3; 2618c2ecf20Sopenharmony_ci n += 3; 2628c2ecf20Sopenharmony_ci len -= 3; 2638c2ecf20Sopenharmony_ci break; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci case 0x80: 2668c2ecf20Sopenharmony_ci if (len < 4) 2678c2ecf20Sopenharmony_ci return -1; 2688c2ecf20Sopenharmony_ci p += 4; 2698c2ecf20Sopenharmony_ci n += 4; 2708c2ecf20Sopenharmony_ci len -= 4; 2718c2ecf20Sopenharmony_ci break; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci case 0xC0: 2748c2ecf20Sopenharmony_ci if (len < 2) 2758c2ecf20Sopenharmony_ci return -1; 2768c2ecf20Sopenharmony_ci l = p[1]; 2778c2ecf20Sopenharmony_ci if (len < 2 + l) 2788c2ecf20Sopenharmony_ci return -1; 2798c2ecf20Sopenharmony_ci if (*p == FAC_NATIONAL_DEST_DIGI) { 2808c2ecf20Sopenharmony_ci if (!fac_national_digis_received) { 2818c2ecf20Sopenharmony_ci if (l < AX25_ADDR_LEN) 2828c2ecf20Sopenharmony_ci return -1; 2838c2ecf20Sopenharmony_ci memcpy(&facilities->source_digis[0], p + 2, AX25_ADDR_LEN); 2848c2ecf20Sopenharmony_ci facilities->source_ndigis = 1; 2858c2ecf20Sopenharmony_ci } 2868c2ecf20Sopenharmony_ci } 2878c2ecf20Sopenharmony_ci else if (*p == FAC_NATIONAL_SRC_DIGI) { 2888c2ecf20Sopenharmony_ci if (!fac_national_digis_received) { 2898c2ecf20Sopenharmony_ci if (l < AX25_ADDR_LEN) 2908c2ecf20Sopenharmony_ci return -1; 2918c2ecf20Sopenharmony_ci memcpy(&facilities->dest_digis[0], p + 2, AX25_ADDR_LEN); 2928c2ecf20Sopenharmony_ci facilities->dest_ndigis = 1; 2938c2ecf20Sopenharmony_ci } 2948c2ecf20Sopenharmony_ci } 2958c2ecf20Sopenharmony_ci else if (*p == FAC_NATIONAL_FAIL_CALL) { 2968c2ecf20Sopenharmony_ci if (l < AX25_ADDR_LEN) 2978c2ecf20Sopenharmony_ci return -1; 2988c2ecf20Sopenharmony_ci memcpy(&facilities->fail_call, p + 2, AX25_ADDR_LEN); 2998c2ecf20Sopenharmony_ci } 3008c2ecf20Sopenharmony_ci else if (*p == FAC_NATIONAL_FAIL_ADD) { 3018c2ecf20Sopenharmony_ci if (l < 1 + ROSE_ADDR_LEN) 3028c2ecf20Sopenharmony_ci return -1; 3038c2ecf20Sopenharmony_ci memcpy(&facilities->fail_addr, p + 3, ROSE_ADDR_LEN); 3048c2ecf20Sopenharmony_ci } 3058c2ecf20Sopenharmony_ci else if (*p == FAC_NATIONAL_DIGIS) { 3068c2ecf20Sopenharmony_ci if (l % AX25_ADDR_LEN) 3078c2ecf20Sopenharmony_ci return -1; 3088c2ecf20Sopenharmony_ci fac_national_digis_received = 1; 3098c2ecf20Sopenharmony_ci facilities->source_ndigis = 0; 3108c2ecf20Sopenharmony_ci facilities->dest_ndigis = 0; 3118c2ecf20Sopenharmony_ci for (pt = p + 2, lg = 0 ; lg < l ; pt += AX25_ADDR_LEN, lg += AX25_ADDR_LEN) { 3128c2ecf20Sopenharmony_ci if (pt[6] & AX25_HBIT) { 3138c2ecf20Sopenharmony_ci if (facilities->dest_ndigis >= ROSE_MAX_DIGIS) 3148c2ecf20Sopenharmony_ci return -1; 3158c2ecf20Sopenharmony_ci memcpy(&facilities->dest_digis[facilities->dest_ndigis++], pt, AX25_ADDR_LEN); 3168c2ecf20Sopenharmony_ci } else { 3178c2ecf20Sopenharmony_ci if (facilities->source_ndigis >= ROSE_MAX_DIGIS) 3188c2ecf20Sopenharmony_ci return -1; 3198c2ecf20Sopenharmony_ci memcpy(&facilities->source_digis[facilities->source_ndigis++], pt, AX25_ADDR_LEN); 3208c2ecf20Sopenharmony_ci } 3218c2ecf20Sopenharmony_ci } 3228c2ecf20Sopenharmony_ci } 3238c2ecf20Sopenharmony_ci p += l + 2; 3248c2ecf20Sopenharmony_ci n += l + 2; 3258c2ecf20Sopenharmony_ci len -= l + 2; 3268c2ecf20Sopenharmony_ci break; 3278c2ecf20Sopenharmony_ci } 3288c2ecf20Sopenharmony_ci } while (*p != 0x00 && len > 0); 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci return n; 3318c2ecf20Sopenharmony_ci} 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_cistatic int rose_parse_ccitt(unsigned char *p, struct rose_facilities_struct *facilities, int len) 3348c2ecf20Sopenharmony_ci{ 3358c2ecf20Sopenharmony_ci unsigned char l, n = 0; 3368c2ecf20Sopenharmony_ci char callsign[11]; 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci do { 3398c2ecf20Sopenharmony_ci switch (*p & 0xC0) { 3408c2ecf20Sopenharmony_ci case 0x00: 3418c2ecf20Sopenharmony_ci if (len < 2) 3428c2ecf20Sopenharmony_ci return -1; 3438c2ecf20Sopenharmony_ci p += 2; 3448c2ecf20Sopenharmony_ci n += 2; 3458c2ecf20Sopenharmony_ci len -= 2; 3468c2ecf20Sopenharmony_ci break; 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci case 0x40: 3498c2ecf20Sopenharmony_ci if (len < 3) 3508c2ecf20Sopenharmony_ci return -1; 3518c2ecf20Sopenharmony_ci p += 3; 3528c2ecf20Sopenharmony_ci n += 3; 3538c2ecf20Sopenharmony_ci len -= 3; 3548c2ecf20Sopenharmony_ci break; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci case 0x80: 3578c2ecf20Sopenharmony_ci if (len < 4) 3588c2ecf20Sopenharmony_ci return -1; 3598c2ecf20Sopenharmony_ci p += 4; 3608c2ecf20Sopenharmony_ci n += 4; 3618c2ecf20Sopenharmony_ci len -= 4; 3628c2ecf20Sopenharmony_ci break; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci case 0xC0: 3658c2ecf20Sopenharmony_ci if (len < 2) 3668c2ecf20Sopenharmony_ci return -1; 3678c2ecf20Sopenharmony_ci l = p[1]; 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci /* Prevent overflows*/ 3708c2ecf20Sopenharmony_ci if (l < 10 || l > 20) 3718c2ecf20Sopenharmony_ci return -1; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci if (*p == FAC_CCITT_DEST_NSAP) { 3748c2ecf20Sopenharmony_ci memcpy(&facilities->source_addr, p + 7, ROSE_ADDR_LEN); 3758c2ecf20Sopenharmony_ci memcpy(callsign, p + 12, l - 10); 3768c2ecf20Sopenharmony_ci callsign[l - 10] = '\0'; 3778c2ecf20Sopenharmony_ci asc2ax(&facilities->source_call, callsign); 3788c2ecf20Sopenharmony_ci } 3798c2ecf20Sopenharmony_ci if (*p == FAC_CCITT_SRC_NSAP) { 3808c2ecf20Sopenharmony_ci memcpy(&facilities->dest_addr, p + 7, ROSE_ADDR_LEN); 3818c2ecf20Sopenharmony_ci memcpy(callsign, p + 12, l - 10); 3828c2ecf20Sopenharmony_ci callsign[l - 10] = '\0'; 3838c2ecf20Sopenharmony_ci asc2ax(&facilities->dest_call, callsign); 3848c2ecf20Sopenharmony_ci } 3858c2ecf20Sopenharmony_ci p += l + 2; 3868c2ecf20Sopenharmony_ci n += l + 2; 3878c2ecf20Sopenharmony_ci len -= l + 2; 3888c2ecf20Sopenharmony_ci break; 3898c2ecf20Sopenharmony_ci } 3908c2ecf20Sopenharmony_ci } while (*p != 0x00 && len > 0); 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci return n; 3938c2ecf20Sopenharmony_ci} 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ciint rose_parse_facilities(unsigned char *p, unsigned packet_len, 3968c2ecf20Sopenharmony_ci struct rose_facilities_struct *facilities) 3978c2ecf20Sopenharmony_ci{ 3988c2ecf20Sopenharmony_ci int facilities_len, len; 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci facilities_len = *p++; 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci if (facilities_len == 0 || (unsigned int)facilities_len > packet_len) 4038c2ecf20Sopenharmony_ci return 0; 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci while (facilities_len >= 3 && *p == 0x00) { 4068c2ecf20Sopenharmony_ci facilities_len--; 4078c2ecf20Sopenharmony_ci p++; 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci switch (*p) { 4108c2ecf20Sopenharmony_ci case FAC_NATIONAL: /* National */ 4118c2ecf20Sopenharmony_ci len = rose_parse_national(p + 1, facilities, facilities_len - 1); 4128c2ecf20Sopenharmony_ci break; 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci case FAC_CCITT: /* CCITT */ 4158c2ecf20Sopenharmony_ci len = rose_parse_ccitt(p + 1, facilities, facilities_len - 1); 4168c2ecf20Sopenharmony_ci break; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci default: 4198c2ecf20Sopenharmony_ci printk(KERN_DEBUG "ROSE: rose_parse_facilities - unknown facilities family %02X\n", *p); 4208c2ecf20Sopenharmony_ci len = 1; 4218c2ecf20Sopenharmony_ci break; 4228c2ecf20Sopenharmony_ci } 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci if (len < 0) 4258c2ecf20Sopenharmony_ci return 0; 4268c2ecf20Sopenharmony_ci if (WARN_ON(len >= facilities_len)) 4278c2ecf20Sopenharmony_ci return 0; 4288c2ecf20Sopenharmony_ci facilities_len -= len + 1; 4298c2ecf20Sopenharmony_ci p += len + 1; 4308c2ecf20Sopenharmony_ci } 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci return facilities_len == 0; 4338c2ecf20Sopenharmony_ci} 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_cistatic int rose_create_facilities(unsigned char *buffer, struct rose_sock *rose) 4368c2ecf20Sopenharmony_ci{ 4378c2ecf20Sopenharmony_ci unsigned char *p = buffer + 1; 4388c2ecf20Sopenharmony_ci char *callsign; 4398c2ecf20Sopenharmony_ci char buf[11]; 4408c2ecf20Sopenharmony_ci int len, nb; 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci /* National Facilities */ 4438c2ecf20Sopenharmony_ci if (rose->rand != 0 || rose->source_ndigis == 1 || rose->dest_ndigis == 1) { 4448c2ecf20Sopenharmony_ci *p++ = 0x00; 4458c2ecf20Sopenharmony_ci *p++ = FAC_NATIONAL; 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci if (rose->rand != 0) { 4488c2ecf20Sopenharmony_ci *p++ = FAC_NATIONAL_RAND; 4498c2ecf20Sopenharmony_ci *p++ = (rose->rand >> 8) & 0xFF; 4508c2ecf20Sopenharmony_ci *p++ = (rose->rand >> 0) & 0xFF; 4518c2ecf20Sopenharmony_ci } 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci /* Sent before older facilities */ 4548c2ecf20Sopenharmony_ci if ((rose->source_ndigis > 0) || (rose->dest_ndigis > 0)) { 4558c2ecf20Sopenharmony_ci int maxdigi = 0; 4568c2ecf20Sopenharmony_ci *p++ = FAC_NATIONAL_DIGIS; 4578c2ecf20Sopenharmony_ci *p++ = AX25_ADDR_LEN * (rose->source_ndigis + rose->dest_ndigis); 4588c2ecf20Sopenharmony_ci for (nb = 0 ; nb < rose->source_ndigis ; nb++) { 4598c2ecf20Sopenharmony_ci if (++maxdigi >= ROSE_MAX_DIGIS) 4608c2ecf20Sopenharmony_ci break; 4618c2ecf20Sopenharmony_ci memcpy(p, &rose->source_digis[nb], AX25_ADDR_LEN); 4628c2ecf20Sopenharmony_ci p[6] |= AX25_HBIT; 4638c2ecf20Sopenharmony_ci p += AX25_ADDR_LEN; 4648c2ecf20Sopenharmony_ci } 4658c2ecf20Sopenharmony_ci for (nb = 0 ; nb < rose->dest_ndigis ; nb++) { 4668c2ecf20Sopenharmony_ci if (++maxdigi >= ROSE_MAX_DIGIS) 4678c2ecf20Sopenharmony_ci break; 4688c2ecf20Sopenharmony_ci memcpy(p, &rose->dest_digis[nb], AX25_ADDR_LEN); 4698c2ecf20Sopenharmony_ci p[6] &= ~AX25_HBIT; 4708c2ecf20Sopenharmony_ci p += AX25_ADDR_LEN; 4718c2ecf20Sopenharmony_ci } 4728c2ecf20Sopenharmony_ci } 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci /* For compatibility */ 4758c2ecf20Sopenharmony_ci if (rose->source_ndigis > 0) { 4768c2ecf20Sopenharmony_ci *p++ = FAC_NATIONAL_SRC_DIGI; 4778c2ecf20Sopenharmony_ci *p++ = AX25_ADDR_LEN; 4788c2ecf20Sopenharmony_ci memcpy(p, &rose->source_digis[0], AX25_ADDR_LEN); 4798c2ecf20Sopenharmony_ci p += AX25_ADDR_LEN; 4808c2ecf20Sopenharmony_ci } 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci /* For compatibility */ 4838c2ecf20Sopenharmony_ci if (rose->dest_ndigis > 0) { 4848c2ecf20Sopenharmony_ci *p++ = FAC_NATIONAL_DEST_DIGI; 4858c2ecf20Sopenharmony_ci *p++ = AX25_ADDR_LEN; 4868c2ecf20Sopenharmony_ci memcpy(p, &rose->dest_digis[0], AX25_ADDR_LEN); 4878c2ecf20Sopenharmony_ci p += AX25_ADDR_LEN; 4888c2ecf20Sopenharmony_ci } 4898c2ecf20Sopenharmony_ci } 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci *p++ = 0x00; 4928c2ecf20Sopenharmony_ci *p++ = FAC_CCITT; 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci *p++ = FAC_CCITT_DEST_NSAP; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci callsign = ax2asc(buf, &rose->dest_call); 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci *p++ = strlen(callsign) + 10; 4998c2ecf20Sopenharmony_ci *p++ = (strlen(callsign) + 9) * 2; /* ??? */ 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci *p++ = 0x47; *p++ = 0x00; *p++ = 0x11; 5028c2ecf20Sopenharmony_ci *p++ = ROSE_ADDR_LEN * 2; 5038c2ecf20Sopenharmony_ci memcpy(p, &rose->dest_addr, ROSE_ADDR_LEN); 5048c2ecf20Sopenharmony_ci p += ROSE_ADDR_LEN; 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci memcpy(p, callsign, strlen(callsign)); 5078c2ecf20Sopenharmony_ci p += strlen(callsign); 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci *p++ = FAC_CCITT_SRC_NSAP; 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci callsign = ax2asc(buf, &rose->source_call); 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci *p++ = strlen(callsign) + 10; 5148c2ecf20Sopenharmony_ci *p++ = (strlen(callsign) + 9) * 2; /* ??? */ 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci *p++ = 0x47; *p++ = 0x00; *p++ = 0x11; 5178c2ecf20Sopenharmony_ci *p++ = ROSE_ADDR_LEN * 2; 5188c2ecf20Sopenharmony_ci memcpy(p, &rose->source_addr, ROSE_ADDR_LEN); 5198c2ecf20Sopenharmony_ci p += ROSE_ADDR_LEN; 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci memcpy(p, callsign, strlen(callsign)); 5228c2ecf20Sopenharmony_ci p += strlen(callsign); 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci len = p - buffer; 5258c2ecf20Sopenharmony_ci buffer[0] = len - 1; 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci return len; 5288c2ecf20Sopenharmony_ci} 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_civoid rose_disconnect(struct sock *sk, int reason, int cause, int diagnostic) 5318c2ecf20Sopenharmony_ci{ 5328c2ecf20Sopenharmony_ci struct rose_sock *rose = rose_sk(sk); 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci rose_stop_timer(sk); 5358c2ecf20Sopenharmony_ci rose_stop_idletimer(sk); 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci rose_clear_queues(sk); 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci rose->lci = 0; 5408c2ecf20Sopenharmony_ci rose->state = ROSE_STATE_0; 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci if (cause != -1) 5438c2ecf20Sopenharmony_ci rose->cause = cause; 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci if (diagnostic != -1) 5468c2ecf20Sopenharmony_ci rose->diagnostic = diagnostic; 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci sk->sk_state = TCP_CLOSE; 5498c2ecf20Sopenharmony_ci sk->sk_err = reason; 5508c2ecf20Sopenharmony_ci sk->sk_shutdown |= SEND_SHUTDOWN; 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci if (!sock_flag(sk, SOCK_DEAD)) { 5538c2ecf20Sopenharmony_ci sk->sk_state_change(sk); 5548c2ecf20Sopenharmony_ci sock_set_flag(sk, SOCK_DEAD); 5558c2ecf20Sopenharmony_ci } 5568c2ecf20Sopenharmony_ci} 557