18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * X.25 Packet Layer release 002 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * This is ALPHA test software. This code may break your machine, randomly fail to work with new 68c2ecf20Sopenharmony_ci * releases, misbehave and/or generally screw up. It might even work. 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * This code REQUIRES 2.1.15 or higher 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * History 118c2ecf20Sopenharmony_ci * X.25 001 Jonathan Naylor Started coding. 128c2ecf20Sopenharmony_ci * 2000-09-04 Henner Eisen Prevent freeing a dangling skb. 138c2ecf20Sopenharmony_ci */ 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#define pr_fmt(fmt) "X25: " fmt 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include <linux/kernel.h> 188c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 198c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 208c2ecf20Sopenharmony_ci#include <linux/slab.h> 218c2ecf20Sopenharmony_ci#include <net/sock.h> 228c2ecf20Sopenharmony_ci#include <linux/if_arp.h> 238c2ecf20Sopenharmony_ci#include <net/x25.h> 248c2ecf20Sopenharmony_ci#include <net/x25device.h> 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_cistatic int x25_receive_data(struct sk_buff *skb, struct x25_neigh *nb) 278c2ecf20Sopenharmony_ci{ 288c2ecf20Sopenharmony_ci struct sock *sk; 298c2ecf20Sopenharmony_ci unsigned short frametype; 308c2ecf20Sopenharmony_ci unsigned int lci; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci if (!pskb_may_pull(skb, X25_STD_MIN_LEN)) 338c2ecf20Sopenharmony_ci return 0; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci frametype = skb->data[2]; 368c2ecf20Sopenharmony_ci lci = ((skb->data[0] << 8) & 0xF00) + ((skb->data[1] << 0) & 0x0FF); 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci /* 398c2ecf20Sopenharmony_ci * LCI of zero is always for us, and its always a link control 408c2ecf20Sopenharmony_ci * frame. 418c2ecf20Sopenharmony_ci */ 428c2ecf20Sopenharmony_ci if (lci == 0) { 438c2ecf20Sopenharmony_ci x25_link_control(skb, nb, frametype); 448c2ecf20Sopenharmony_ci return 0; 458c2ecf20Sopenharmony_ci } 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci /* 488c2ecf20Sopenharmony_ci * Find an existing socket. 498c2ecf20Sopenharmony_ci */ 508c2ecf20Sopenharmony_ci if ((sk = x25_find_socket(lci, nb)) != NULL) { 518c2ecf20Sopenharmony_ci int queued = 1; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci skb_reset_transport_header(skb); 548c2ecf20Sopenharmony_ci bh_lock_sock(sk); 558c2ecf20Sopenharmony_ci if (!sock_owned_by_user(sk)) { 568c2ecf20Sopenharmony_ci queued = x25_process_rx_frame(sk, skb); 578c2ecf20Sopenharmony_ci } else { 588c2ecf20Sopenharmony_ci queued = !sk_add_backlog(sk, skb, READ_ONCE(sk->sk_rcvbuf)); 598c2ecf20Sopenharmony_ci } 608c2ecf20Sopenharmony_ci bh_unlock_sock(sk); 618c2ecf20Sopenharmony_ci sock_put(sk); 628c2ecf20Sopenharmony_ci return queued; 638c2ecf20Sopenharmony_ci } 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci /* 668c2ecf20Sopenharmony_ci * Is is a Call Request ? if so process it. 678c2ecf20Sopenharmony_ci */ 688c2ecf20Sopenharmony_ci if (frametype == X25_CALL_REQUEST) 698c2ecf20Sopenharmony_ci return x25_rx_call_request(skb, nb, lci); 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci /* 728c2ecf20Sopenharmony_ci * Its not a Call Request, nor is it a control frame. 738c2ecf20Sopenharmony_ci * Can we forward it? 748c2ecf20Sopenharmony_ci */ 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci if (x25_forward_data(lci, nb, skb)) { 778c2ecf20Sopenharmony_ci if (frametype == X25_CLEAR_CONFIRMATION) { 788c2ecf20Sopenharmony_ci x25_clear_forward_by_lci(lci); 798c2ecf20Sopenharmony_ci } 808c2ecf20Sopenharmony_ci kfree_skb(skb); 818c2ecf20Sopenharmony_ci return 1; 828c2ecf20Sopenharmony_ci } 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci/* 858c2ecf20Sopenharmony_ci x25_transmit_clear_request(nb, lci, 0x0D); 868c2ecf20Sopenharmony_ci*/ 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci if (frametype != X25_CLEAR_CONFIRMATION) 898c2ecf20Sopenharmony_ci pr_debug("x25_receive_data(): unknown frame type %2x\n",frametype); 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci return 0; 928c2ecf20Sopenharmony_ci} 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ciint x25_lapb_receive_frame(struct sk_buff *skb, struct net_device *dev, 958c2ecf20Sopenharmony_ci struct packet_type *ptype, struct net_device *orig_dev) 968c2ecf20Sopenharmony_ci{ 978c2ecf20Sopenharmony_ci struct sk_buff *nskb; 988c2ecf20Sopenharmony_ci struct x25_neigh *nb; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci if (!net_eq(dev_net(dev), &init_net)) 1018c2ecf20Sopenharmony_ci goto drop; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci nskb = skb_copy(skb, GFP_ATOMIC); 1048c2ecf20Sopenharmony_ci if (!nskb) 1058c2ecf20Sopenharmony_ci goto drop; 1068c2ecf20Sopenharmony_ci kfree_skb(skb); 1078c2ecf20Sopenharmony_ci skb = nskb; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci /* 1108c2ecf20Sopenharmony_ci * Packet received from unrecognised device, throw it away. 1118c2ecf20Sopenharmony_ci */ 1128c2ecf20Sopenharmony_ci nb = x25_get_neigh(dev); 1138c2ecf20Sopenharmony_ci if (!nb) { 1148c2ecf20Sopenharmony_ci pr_debug("unknown neighbour - %s\n", dev->name); 1158c2ecf20Sopenharmony_ci goto drop; 1168c2ecf20Sopenharmony_ci } 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci if (!pskb_may_pull(skb, 1)) { 1198c2ecf20Sopenharmony_ci x25_neigh_put(nb); 1208c2ecf20Sopenharmony_ci goto drop; 1218c2ecf20Sopenharmony_ci } 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci switch (skb->data[0]) { 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci case X25_IFACE_DATA: 1268c2ecf20Sopenharmony_ci skb_pull(skb, 1); 1278c2ecf20Sopenharmony_ci if (x25_receive_data(skb, nb)) { 1288c2ecf20Sopenharmony_ci x25_neigh_put(nb); 1298c2ecf20Sopenharmony_ci goto out; 1308c2ecf20Sopenharmony_ci } 1318c2ecf20Sopenharmony_ci break; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci case X25_IFACE_CONNECT: 1348c2ecf20Sopenharmony_ci x25_link_established(nb); 1358c2ecf20Sopenharmony_ci break; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci case X25_IFACE_DISCONNECT: 1388c2ecf20Sopenharmony_ci x25_link_terminated(nb); 1398c2ecf20Sopenharmony_ci break; 1408c2ecf20Sopenharmony_ci } 1418c2ecf20Sopenharmony_ci x25_neigh_put(nb); 1428c2ecf20Sopenharmony_cidrop: 1438c2ecf20Sopenharmony_ci kfree_skb(skb); 1448c2ecf20Sopenharmony_ciout: 1458c2ecf20Sopenharmony_ci return 0; 1468c2ecf20Sopenharmony_ci} 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_civoid x25_establish_link(struct x25_neigh *nb) 1498c2ecf20Sopenharmony_ci{ 1508c2ecf20Sopenharmony_ci struct sk_buff *skb; 1518c2ecf20Sopenharmony_ci unsigned char *ptr; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci switch (nb->dev->type) { 1548c2ecf20Sopenharmony_ci case ARPHRD_X25: 1558c2ecf20Sopenharmony_ci if ((skb = alloc_skb(1, GFP_ATOMIC)) == NULL) { 1568c2ecf20Sopenharmony_ci pr_err("x25_dev: out of memory\n"); 1578c2ecf20Sopenharmony_ci return; 1588c2ecf20Sopenharmony_ci } 1598c2ecf20Sopenharmony_ci ptr = skb_put(skb, 1); 1608c2ecf20Sopenharmony_ci *ptr = X25_IFACE_CONNECT; 1618c2ecf20Sopenharmony_ci break; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_LLC) 1648c2ecf20Sopenharmony_ci case ARPHRD_ETHER: 1658c2ecf20Sopenharmony_ci return; 1668c2ecf20Sopenharmony_ci#endif 1678c2ecf20Sopenharmony_ci default: 1688c2ecf20Sopenharmony_ci return; 1698c2ecf20Sopenharmony_ci } 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci skb->protocol = htons(ETH_P_X25); 1728c2ecf20Sopenharmony_ci skb->dev = nb->dev; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci dev_queue_xmit(skb); 1758c2ecf20Sopenharmony_ci} 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_civoid x25_terminate_link(struct x25_neigh *nb) 1788c2ecf20Sopenharmony_ci{ 1798c2ecf20Sopenharmony_ci struct sk_buff *skb; 1808c2ecf20Sopenharmony_ci unsigned char *ptr; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_LLC) 1838c2ecf20Sopenharmony_ci if (nb->dev->type == ARPHRD_ETHER) 1848c2ecf20Sopenharmony_ci return; 1858c2ecf20Sopenharmony_ci#endif 1868c2ecf20Sopenharmony_ci if (nb->dev->type != ARPHRD_X25) 1878c2ecf20Sopenharmony_ci return; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci skb = alloc_skb(1, GFP_ATOMIC); 1908c2ecf20Sopenharmony_ci if (!skb) { 1918c2ecf20Sopenharmony_ci pr_err("x25_dev: out of memory\n"); 1928c2ecf20Sopenharmony_ci return; 1938c2ecf20Sopenharmony_ci } 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci ptr = skb_put(skb, 1); 1968c2ecf20Sopenharmony_ci *ptr = X25_IFACE_DISCONNECT; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci skb->protocol = htons(ETH_P_X25); 1998c2ecf20Sopenharmony_ci skb->dev = nb->dev; 2008c2ecf20Sopenharmony_ci dev_queue_xmit(skb); 2018c2ecf20Sopenharmony_ci} 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_civoid x25_send_frame(struct sk_buff *skb, struct x25_neigh *nb) 2048c2ecf20Sopenharmony_ci{ 2058c2ecf20Sopenharmony_ci unsigned char *dptr; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci skb_reset_network_header(skb); 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci switch (nb->dev->type) { 2108c2ecf20Sopenharmony_ci case ARPHRD_X25: 2118c2ecf20Sopenharmony_ci dptr = skb_push(skb, 1); 2128c2ecf20Sopenharmony_ci *dptr = X25_IFACE_DATA; 2138c2ecf20Sopenharmony_ci break; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_LLC) 2168c2ecf20Sopenharmony_ci case ARPHRD_ETHER: 2178c2ecf20Sopenharmony_ci kfree_skb(skb); 2188c2ecf20Sopenharmony_ci return; 2198c2ecf20Sopenharmony_ci#endif 2208c2ecf20Sopenharmony_ci default: 2218c2ecf20Sopenharmony_ci kfree_skb(skb); 2228c2ecf20Sopenharmony_ci return; 2238c2ecf20Sopenharmony_ci } 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci skb->protocol = htons(ETH_P_X25); 2268c2ecf20Sopenharmony_ci skb->dev = nb->dev; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci dev_queue_xmit(skb); 2298c2ecf20Sopenharmony_ci} 230