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/module.h> 128c2ecf20Sopenharmony_ci#include <linux/timer.h> 138c2ecf20Sopenharmony_ci#include <linux/string.h> 148c2ecf20Sopenharmony_ci#include <linux/sockios.h> 158c2ecf20Sopenharmony_ci#include <linux/net.h> 168c2ecf20Sopenharmony_ci#include <linux/slab.h> 178c2ecf20Sopenharmony_ci#include <net/ax25.h> 188c2ecf20Sopenharmony_ci#include <linux/inet.h> 198c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 208c2ecf20Sopenharmony_ci#include <linux/if_arp.h> 218c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 228c2ecf20Sopenharmony_ci#include <net/sock.h> 238c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 248c2ecf20Sopenharmony_ci#include <linux/fcntl.h> 258c2ecf20Sopenharmony_ci#include <linux/termios.h> /* For TIOCINQ/OUTQ */ 268c2ecf20Sopenharmony_ci#include <linux/mm.h> 278c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 288c2ecf20Sopenharmony_ci#include <linux/notifier.h> 298c2ecf20Sopenharmony_ci#include <linux/proc_fs.h> 308c2ecf20Sopenharmony_ci#include <linux/stat.h> 318c2ecf20Sopenharmony_ci#include <linux/sysctl.h> 328c2ecf20Sopenharmony_ci#include <net/ip.h> 338c2ecf20Sopenharmony_ci#include <net/arp.h> 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci/* 368c2ecf20Sopenharmony_ci * IP over AX.25 encapsulation. 378c2ecf20Sopenharmony_ci */ 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci/* 408c2ecf20Sopenharmony_ci * Shove an AX.25 UI header on an IP packet and handle ARP 418c2ecf20Sopenharmony_ci */ 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci#ifdef CONFIG_INET 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_cistatic int ax25_hard_header(struct sk_buff *skb, struct net_device *dev, 468c2ecf20Sopenharmony_ci unsigned short type, const void *daddr, 478c2ecf20Sopenharmony_ci const void *saddr, unsigned int len) 488c2ecf20Sopenharmony_ci{ 498c2ecf20Sopenharmony_ci unsigned char *buff; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci /* they sometimes come back to us... */ 528c2ecf20Sopenharmony_ci if (type == ETH_P_AX25) 538c2ecf20Sopenharmony_ci return 0; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci /* header is an AX.25 UI frame from us to them */ 568c2ecf20Sopenharmony_ci buff = skb_push(skb, AX25_HEADER_LEN); 578c2ecf20Sopenharmony_ci *buff++ = 0x00; /* KISS DATA */ 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci if (daddr != NULL) 608c2ecf20Sopenharmony_ci memcpy(buff, daddr, dev->addr_len); /* Address specified */ 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci buff[6] &= ~AX25_CBIT; 638c2ecf20Sopenharmony_ci buff[6] &= ~AX25_EBIT; 648c2ecf20Sopenharmony_ci buff[6] |= AX25_SSSID_SPARE; 658c2ecf20Sopenharmony_ci buff += AX25_ADDR_LEN; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci if (saddr != NULL) 688c2ecf20Sopenharmony_ci memcpy(buff, saddr, dev->addr_len); 698c2ecf20Sopenharmony_ci else 708c2ecf20Sopenharmony_ci memcpy(buff, dev->dev_addr, dev->addr_len); 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci buff[6] &= ~AX25_CBIT; 738c2ecf20Sopenharmony_ci buff[6] |= AX25_EBIT; 748c2ecf20Sopenharmony_ci buff[6] |= AX25_SSSID_SPARE; 758c2ecf20Sopenharmony_ci buff += AX25_ADDR_LEN; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci *buff++ = AX25_UI; /* UI */ 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci /* Append a suitable AX.25 PID */ 808c2ecf20Sopenharmony_ci switch (type) { 818c2ecf20Sopenharmony_ci case ETH_P_IP: 828c2ecf20Sopenharmony_ci *buff++ = AX25_P_IP; 838c2ecf20Sopenharmony_ci break; 848c2ecf20Sopenharmony_ci case ETH_P_ARP: 858c2ecf20Sopenharmony_ci *buff++ = AX25_P_ARP; 868c2ecf20Sopenharmony_ci break; 878c2ecf20Sopenharmony_ci default: 888c2ecf20Sopenharmony_ci printk(KERN_ERR "AX.25: ax25_hard_header - wrong protocol type 0x%2.2x\n", type); 898c2ecf20Sopenharmony_ci *buff++ = 0; 908c2ecf20Sopenharmony_ci break; 918c2ecf20Sopenharmony_ci } 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci if (daddr != NULL) 948c2ecf20Sopenharmony_ci return AX25_HEADER_LEN; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci return -AX25_HEADER_LEN; /* Unfinished header */ 978c2ecf20Sopenharmony_ci} 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_cinetdev_tx_t ax25_ip_xmit(struct sk_buff *skb) 1008c2ecf20Sopenharmony_ci{ 1018c2ecf20Sopenharmony_ci struct sk_buff *ourskb; 1028c2ecf20Sopenharmony_ci unsigned char *bp = skb->data; 1038c2ecf20Sopenharmony_ci ax25_route *route; 1048c2ecf20Sopenharmony_ci struct net_device *dev = NULL; 1058c2ecf20Sopenharmony_ci ax25_address *src, *dst; 1068c2ecf20Sopenharmony_ci ax25_digi *digipeat = NULL; 1078c2ecf20Sopenharmony_ci ax25_dev *ax25_dev; 1088c2ecf20Sopenharmony_ci ax25_cb *ax25; 1098c2ecf20Sopenharmony_ci char ip_mode = ' '; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci dst = (ax25_address *)(bp + 1); 1128c2ecf20Sopenharmony_ci src = (ax25_address *)(bp + 8); 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci ax25_route_lock_use(); 1158c2ecf20Sopenharmony_ci route = ax25_get_route(dst, NULL); 1168c2ecf20Sopenharmony_ci if (route) { 1178c2ecf20Sopenharmony_ci digipeat = route->digipeat; 1188c2ecf20Sopenharmony_ci dev = route->dev; 1198c2ecf20Sopenharmony_ci ip_mode = route->ip_mode; 1208c2ecf20Sopenharmony_ci } 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci if (dev == NULL) 1238c2ecf20Sopenharmony_ci dev = skb->dev; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL) { 1268c2ecf20Sopenharmony_ci kfree_skb(skb); 1278c2ecf20Sopenharmony_ci goto put; 1288c2ecf20Sopenharmony_ci } 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci if (bp[16] == AX25_P_IP) { 1318c2ecf20Sopenharmony_ci if (ip_mode == 'V' || (ip_mode == ' ' && ax25_dev->values[AX25_VALUES_IPDEFMODE])) { 1328c2ecf20Sopenharmony_ci /* 1338c2ecf20Sopenharmony_ci * We copy the buffer and release the original thereby 1348c2ecf20Sopenharmony_ci * keeping it straight 1358c2ecf20Sopenharmony_ci * 1368c2ecf20Sopenharmony_ci * Note: we report 1 back so the caller will 1378c2ecf20Sopenharmony_ci * not feed the frame direct to the physical device 1388c2ecf20Sopenharmony_ci * We don't want that to happen. (It won't be upset 1398c2ecf20Sopenharmony_ci * as we have pulled the frame from the queue by 1408c2ecf20Sopenharmony_ci * freeing it). 1418c2ecf20Sopenharmony_ci * 1428c2ecf20Sopenharmony_ci * NB: TCP modifies buffers that are still 1438c2ecf20Sopenharmony_ci * on a device queue, thus we use skb_copy() 1448c2ecf20Sopenharmony_ci * instead of using skb_clone() unless this 1458c2ecf20Sopenharmony_ci * gets fixed. 1468c2ecf20Sopenharmony_ci */ 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci ax25_address src_c; 1498c2ecf20Sopenharmony_ci ax25_address dst_c; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci if ((ourskb = skb_copy(skb, GFP_ATOMIC)) == NULL) { 1528c2ecf20Sopenharmony_ci kfree_skb(skb); 1538c2ecf20Sopenharmony_ci goto put; 1548c2ecf20Sopenharmony_ci } 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci if (skb->sk != NULL) 1578c2ecf20Sopenharmony_ci skb_set_owner_w(ourskb, skb->sk); 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci kfree_skb(skb); 1608c2ecf20Sopenharmony_ci /* dl9sau: bugfix 1618c2ecf20Sopenharmony_ci * after kfree_skb(), dst and src which were pointer 1628c2ecf20Sopenharmony_ci * to bp which is part of skb->data would not be valid 1638c2ecf20Sopenharmony_ci * anymore hope that after skb_pull(ourskb, ..) our 1648c2ecf20Sopenharmony_ci * dsc_c and src_c will not become invalid 1658c2ecf20Sopenharmony_ci */ 1668c2ecf20Sopenharmony_ci bp = ourskb->data; 1678c2ecf20Sopenharmony_ci dst_c = *(ax25_address *)(bp + 1); 1688c2ecf20Sopenharmony_ci src_c = *(ax25_address *)(bp + 8); 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci skb_pull(ourskb, AX25_HEADER_LEN - 1); /* Keep PID */ 1718c2ecf20Sopenharmony_ci skb_reset_network_header(ourskb); 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci ax25=ax25_send_frame( 1748c2ecf20Sopenharmony_ci ourskb, 1758c2ecf20Sopenharmony_ci ax25_dev->values[AX25_VALUES_PACLEN], 1768c2ecf20Sopenharmony_ci &src_c, 1778c2ecf20Sopenharmony_ci &dst_c, digipeat, dev); 1788c2ecf20Sopenharmony_ci if (ax25) { 1798c2ecf20Sopenharmony_ci ax25_cb_put(ax25); 1808c2ecf20Sopenharmony_ci } 1818c2ecf20Sopenharmony_ci goto put; 1828c2ecf20Sopenharmony_ci } 1838c2ecf20Sopenharmony_ci } 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci bp[7] &= ~AX25_CBIT; 1868c2ecf20Sopenharmony_ci bp[7] &= ~AX25_EBIT; 1878c2ecf20Sopenharmony_ci bp[7] |= AX25_SSSID_SPARE; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci bp[14] &= ~AX25_CBIT; 1908c2ecf20Sopenharmony_ci bp[14] |= AX25_EBIT; 1918c2ecf20Sopenharmony_ci bp[14] |= AX25_SSSID_SPARE; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci skb_pull(skb, AX25_KISS_HEADER_LEN); 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci if (digipeat != NULL) { 1968c2ecf20Sopenharmony_ci if ((ourskb = ax25_rt_build_path(skb, src, dst, route->digipeat)) == NULL) { 1978c2ecf20Sopenharmony_ci kfree_skb(skb); 1988c2ecf20Sopenharmony_ci goto put; 1998c2ecf20Sopenharmony_ci } 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci skb = ourskb; 2028c2ecf20Sopenharmony_ci } 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci ax25_queue_xmit(skb, dev); 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ciput: 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci ax25_route_lock_unuse(); 2098c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 2108c2ecf20Sopenharmony_ci} 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci#else /* INET */ 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_cistatic int ax25_hard_header(struct sk_buff *skb, struct net_device *dev, 2158c2ecf20Sopenharmony_ci unsigned short type, const void *daddr, 2168c2ecf20Sopenharmony_ci const void *saddr, unsigned int len) 2178c2ecf20Sopenharmony_ci{ 2188c2ecf20Sopenharmony_ci return -AX25_HEADER_LEN; 2198c2ecf20Sopenharmony_ci} 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_cinetdev_tx_t ax25_ip_xmit(struct sk_buff *skb) 2228c2ecf20Sopenharmony_ci{ 2238c2ecf20Sopenharmony_ci kfree_skb(skb); 2248c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 2258c2ecf20Sopenharmony_ci} 2268c2ecf20Sopenharmony_ci#endif 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_cistatic bool ax25_validate_header(const char *header, unsigned int len) 2298c2ecf20Sopenharmony_ci{ 2308c2ecf20Sopenharmony_ci ax25_digi digi; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci if (!len) 2338c2ecf20Sopenharmony_ci return false; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci if (header[0]) 2368c2ecf20Sopenharmony_ci return true; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci return ax25_addr_parse(header + 1, len - 1, NULL, NULL, &digi, NULL, 2398c2ecf20Sopenharmony_ci NULL); 2408c2ecf20Sopenharmony_ci} 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ciconst struct header_ops ax25_header_ops = { 2438c2ecf20Sopenharmony_ci .create = ax25_hard_header, 2448c2ecf20Sopenharmony_ci .validate = ax25_validate_header, 2458c2ecf20Sopenharmony_ci}; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ax25_header_ops); 2488c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ax25_ip_xmit); 249