xref: /openbmc/linux/net/ax25/ax25_ip.c (revision 060f35a317ef09101b128f399dce7ed13d019461)
12874c5fdSThomas 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>
1170868eacSRalf Baechle #include <linux/module.h>
121da177e4SLinus Torvalds #include <linux/timer.h>
131da177e4SLinus Torvalds #include <linux/string.h>
141da177e4SLinus Torvalds #include <linux/sockios.h>
151da177e4SLinus Torvalds #include <linux/net.h>
165a0e3ad6STejun Heo #include <linux/slab.h>
171da177e4SLinus Torvalds #include <net/ax25.h>
181da177e4SLinus Torvalds #include <linux/inet.h>
191da177e4SLinus Torvalds #include <linux/netdevice.h>
201da177e4SLinus Torvalds #include <linux/if_arp.h>
211da177e4SLinus Torvalds #include <linux/skbuff.h>
221da177e4SLinus Torvalds #include <net/sock.h>
237c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
241da177e4SLinus Torvalds #include <linux/fcntl.h>
251da177e4SLinus Torvalds #include <linux/termios.h>	/* For TIOCINQ/OUTQ */
261da177e4SLinus Torvalds #include <linux/mm.h>
271da177e4SLinus Torvalds #include <linux/interrupt.h>
281da177e4SLinus Torvalds #include <linux/notifier.h>
291da177e4SLinus Torvalds #include <linux/proc_fs.h>
301da177e4SLinus Torvalds #include <linux/stat.h>
311da177e4SLinus Torvalds #include <linux/sysctl.h>
321da177e4SLinus Torvalds #include <net/ip.h>
331da177e4SLinus Torvalds #include <net/arp.h>
341da177e4SLinus Torvalds 
351da177e4SLinus Torvalds /*
361da177e4SLinus Torvalds  *	IP over AX.25 encapsulation.
371da177e4SLinus Torvalds  */
381da177e4SLinus Torvalds 
391da177e4SLinus Torvalds /*
401da177e4SLinus Torvalds  *	Shove an AX.25 UI header on an IP packet and handle ARP
411da177e4SLinus Torvalds  */
421da177e4SLinus Torvalds 
431da177e4SLinus Torvalds #ifdef CONFIG_INET
441da177e4SLinus Torvalds 
ax25_hard_header(struct sk_buff * skb,struct net_device * dev,unsigned short type,const void * daddr,const void * saddr,unsigned int len)4546d4e47aSEric W. Biederman static int ax25_hard_header(struct sk_buff *skb, struct net_device *dev,
463b04dddeSStephen Hemminger 			    unsigned short type, const void *daddr,
4795c96174SEric Dumazet 			    const void *saddr, unsigned int len)
481da177e4SLinus Torvalds {
491da177e4SLinus Torvalds 	unsigned char *buff;
501da177e4SLinus Torvalds 
511da177e4SLinus Torvalds 	/* they sometimes come back to us... */
521da177e4SLinus Torvalds 	if (type == ETH_P_AX25)
531da177e4SLinus Torvalds 		return 0;
541da177e4SLinus Torvalds 
551da177e4SLinus Torvalds 	/* header is an AX.25 UI frame from us to them */
561da177e4SLinus Torvalds 	buff = skb_push(skb, AX25_HEADER_LEN);
571da177e4SLinus Torvalds 	*buff++ = 0x00;	/* KISS DATA */
581da177e4SLinus Torvalds 
591da177e4SLinus Torvalds 	if (daddr != NULL)
601da177e4SLinus Torvalds 		memcpy(buff, daddr, dev->addr_len);	/* Address specified */
611da177e4SLinus Torvalds 
621da177e4SLinus Torvalds 	buff[6] &= ~AX25_CBIT;
631da177e4SLinus Torvalds 	buff[6] &= ~AX25_EBIT;
641da177e4SLinus Torvalds 	buff[6] |= AX25_SSSID_SPARE;
651da177e4SLinus Torvalds 	buff    += AX25_ADDR_LEN;
661da177e4SLinus Torvalds 
671da177e4SLinus Torvalds 	if (saddr != NULL)
681da177e4SLinus Torvalds 		memcpy(buff, saddr, dev->addr_len);
691da177e4SLinus Torvalds 	else
701da177e4SLinus Torvalds 		memcpy(buff, dev->dev_addr, dev->addr_len);
711da177e4SLinus Torvalds 
721da177e4SLinus Torvalds 	buff[6] &= ~AX25_CBIT;
731da177e4SLinus Torvalds 	buff[6] |= AX25_EBIT;
741da177e4SLinus Torvalds 	buff[6] |= AX25_SSSID_SPARE;
751da177e4SLinus Torvalds 	buff    += AX25_ADDR_LEN;
761da177e4SLinus Torvalds 
771da177e4SLinus Torvalds 	*buff++  = AX25_UI;	/* UI */
781da177e4SLinus Torvalds 
791da177e4SLinus Torvalds 	/* Append a suitable AX.25 PID */
801da177e4SLinus Torvalds 	switch (type) {
811da177e4SLinus Torvalds 	case ETH_P_IP:
821da177e4SLinus Torvalds 		*buff++ = AX25_P_IP;
831da177e4SLinus Torvalds 		break;
841da177e4SLinus Torvalds 	case ETH_P_ARP:
851da177e4SLinus Torvalds 		*buff++ = AX25_P_ARP;
861da177e4SLinus Torvalds 		break;
871da177e4SLinus Torvalds 	default:
886f74998eSRalf Baechle 		printk(KERN_ERR "AX.25: ax25_hard_header - wrong protocol type 0x%2.2x\n", type);
891da177e4SLinus Torvalds 		*buff++ = 0;
901da177e4SLinus Torvalds 		break;
911da177e4SLinus Torvalds 	}
921da177e4SLinus Torvalds 
931da177e4SLinus Torvalds 	if (daddr != NULL)
941da177e4SLinus Torvalds 		return AX25_HEADER_LEN;
951da177e4SLinus Torvalds 
961da177e4SLinus Torvalds 	return -AX25_HEADER_LEN;	/* Unfinished header */
971da177e4SLinus Torvalds }
981da177e4SLinus Torvalds 
ax25_ip_xmit(struct sk_buff * skb)991d5da757SEric W. Biederman netdev_tx_t ax25_ip_xmit(struct sk_buff *skb)
1001da177e4SLinus Torvalds {
1011da177e4SLinus Torvalds 	struct sk_buff *ourskb;
1021da177e4SLinus Torvalds 	unsigned char *bp  = skb->data;
103006f68b8SRalf Baechle DL5RB 	ax25_route *route;
104006f68b8SRalf Baechle DL5RB 	struct net_device *dev = NULL;
1051da177e4SLinus Torvalds 	ax25_address *src, *dst;
106006f68b8SRalf Baechle DL5RB 	ax25_digi *digipeat = NULL;
1071da177e4SLinus Torvalds 	ax25_dev *ax25_dev;
1081da177e4SLinus Torvalds 	ax25_cb *ax25;
109006f68b8SRalf Baechle DL5RB 	char ip_mode = ' ';
1101da177e4SLinus Torvalds 
1111da177e4SLinus Torvalds 	dst = (ax25_address *)(bp + 1);
1121da177e4SLinus Torvalds 	src = (ax25_address *)(bp + 8);
1131da177e4SLinus Torvalds 
11463530abaSEric Dumazet 	ax25_route_lock_use();
115006f68b8SRalf Baechle DL5RB 	route = ax25_get_route(dst, NULL);
116006f68b8SRalf Baechle DL5RB 	if (route) {
117006f68b8SRalf Baechle DL5RB 		digipeat = route->digipeat;
1181da177e4SLinus Torvalds 		dev = route->dev;
119006f68b8SRalf Baechle DL5RB 		ip_mode = route->ip_mode;
1203ff50b79SStephen Hemminger 	}
1211da177e4SLinus Torvalds 
1221da177e4SLinus Torvalds 	if (dev == NULL)
1231da177e4SLinus Torvalds 		dev = skb->dev;
1241da177e4SLinus Torvalds 
125*7705d8a7SEric Dumazet 	rcu_read_lock();
1261da177e4SLinus Torvalds 	if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL) {
127e18dbd05SEric W. Biederman 		kfree_skb(skb);
1281da177e4SLinus Torvalds 		goto put;
1291da177e4SLinus Torvalds 	}
1301da177e4SLinus Torvalds 
1311da177e4SLinus Torvalds 	if (bp[16] == AX25_P_IP) {
132006f68b8SRalf Baechle DL5RB 		if (ip_mode == 'V' || (ip_mode == ' ' && ax25_dev->values[AX25_VALUES_IPDEFMODE])) {
1331da177e4SLinus Torvalds 			/*
1341da177e4SLinus Torvalds 			 *	We copy the buffer and release the original thereby
1351da177e4SLinus Torvalds 			 *	keeping it straight
1361da177e4SLinus Torvalds 			 *
1371da177e4SLinus Torvalds 			 *	Note: we report 1 back so the caller will
1381da177e4SLinus Torvalds 			 *	not feed the frame direct to the physical device
1391da177e4SLinus Torvalds 			 *	We don't want that to happen. (It won't be upset
1401da177e4SLinus Torvalds 			 *	as we have pulled the frame from the queue by
1411da177e4SLinus Torvalds 			 *	freeing it).
1421da177e4SLinus Torvalds 			 *
1431da177e4SLinus Torvalds 			 *	NB: TCP modifies buffers that are still
1441da177e4SLinus Torvalds 			 *	on a device queue, thus we use skb_copy()
1451da177e4SLinus Torvalds 			 *      instead of using skb_clone() unless this
1461da177e4SLinus Torvalds 			 *	gets fixed.
1471da177e4SLinus Torvalds 			 */
1481da177e4SLinus Torvalds 
1491da177e4SLinus Torvalds 			ax25_address src_c;
1501da177e4SLinus Torvalds 			ax25_address dst_c;
1511da177e4SLinus Torvalds 
1521da177e4SLinus Torvalds 			if ((ourskb = skb_copy(skb, GFP_ATOMIC)) == NULL) {
1531da177e4SLinus Torvalds 				kfree_skb(skb);
1541da177e4SLinus Torvalds 				goto put;
1551da177e4SLinus Torvalds 			}
1561da177e4SLinus Torvalds 
1571da177e4SLinus Torvalds 			if (skb->sk != NULL)
1581da177e4SLinus Torvalds 				skb_set_owner_w(ourskb, skb->sk);
1591da177e4SLinus Torvalds 
1601da177e4SLinus Torvalds 			kfree_skb(skb);
1611da177e4SLinus Torvalds 			/* dl9sau: bugfix
1621da177e4SLinus Torvalds 			 * after kfree_skb(), dst and src which were pointer
1631da177e4SLinus Torvalds 			 * to bp which is part of skb->data would not be valid
1641da177e4SLinus Torvalds 			 * anymore hope that after skb_pull(ourskb, ..) our
1651da177e4SLinus Torvalds 			 * dsc_c and src_c will not become invalid
1661da177e4SLinus Torvalds 			 */
1671da177e4SLinus Torvalds 			bp  = ourskb->data;
1681da177e4SLinus Torvalds 			dst_c = *(ax25_address *)(bp + 1);
1691da177e4SLinus Torvalds 			src_c = *(ax25_address *)(bp + 8);
1701da177e4SLinus Torvalds 
1711da177e4SLinus Torvalds 			skb_pull(ourskb, AX25_HEADER_LEN - 1);	/* Keep PID */
172c1d2bbe1SArnaldo Carvalho de Melo 			skb_reset_network_header(ourskb);
1731da177e4SLinus Torvalds 
1741da177e4SLinus Torvalds 			ax25=ax25_send_frame(
1751da177e4SLinus Torvalds 			    ourskb,
1761da177e4SLinus Torvalds 			    ax25_dev->values[AX25_VALUES_PACLEN],
1771da177e4SLinus Torvalds 			    &src_c,
178006f68b8SRalf Baechle DL5RB 			    &dst_c, digipeat, dev);
1791da177e4SLinus Torvalds 			if (ax25) {
1801da177e4SLinus Torvalds 				ax25_cb_put(ax25);
1811da177e4SLinus Torvalds 			}
1821da177e4SLinus Torvalds 			goto put;
1831da177e4SLinus Torvalds 		}
1841da177e4SLinus Torvalds 	}
1851da177e4SLinus Torvalds 
1861da177e4SLinus Torvalds 	bp[7]  &= ~AX25_CBIT;
1871da177e4SLinus Torvalds 	bp[7]  &= ~AX25_EBIT;
1881da177e4SLinus Torvalds 	bp[7]  |= AX25_SSSID_SPARE;
1891da177e4SLinus Torvalds 
1901da177e4SLinus Torvalds 	bp[14] &= ~AX25_CBIT;
1911da177e4SLinus Torvalds 	bp[14] |= AX25_EBIT;
1921da177e4SLinus Torvalds 	bp[14] |= AX25_SSSID_SPARE;
1931da177e4SLinus Torvalds 
1941da177e4SLinus Torvalds 	skb_pull(skb, AX25_KISS_HEADER_LEN);
1951da177e4SLinus Torvalds 
196006f68b8SRalf Baechle DL5RB 	if (digipeat != NULL) {
19753744a4aSVasily Averin 		if ((ourskb = ax25_rt_build_path(skb, src, dst, route->digipeat)) == NULL)
1981da177e4SLinus Torvalds 			goto put;
1991da177e4SLinus Torvalds 
2001da177e4SLinus Torvalds 		skb = ourskb;
2011da177e4SLinus Torvalds 	}
2021da177e4SLinus Torvalds 
20329c4be51SArnaldo Carvalho de Melo 	ax25_queue_xmit(skb, dev);
2041da177e4SLinus Torvalds 
2051da177e4SLinus Torvalds put:
206*7705d8a7SEric Dumazet 	rcu_read_unlock();
20763530abaSEric Dumazet 	ax25_route_lock_unuse();
2081d5da757SEric W. Biederman 	return NETDEV_TX_OK;
2093b6a94beSEric W. Biederman }
2103b6a94beSEric W. Biederman 
2111da177e4SLinus Torvalds #else	/* INET */
2121da177e4SLinus Torvalds 
ax25_hard_header(struct sk_buff * skb,struct net_device * dev,unsigned short type,const void * daddr,const void * saddr,unsigned int len)21346d4e47aSEric W. Biederman static int ax25_hard_header(struct sk_buff *skb, struct net_device *dev,
2143b04dddeSStephen Hemminger 			    unsigned short type, const void *daddr,
21595c96174SEric Dumazet 			    const void *saddr, unsigned int len)
2161da177e4SLinus Torvalds {
2171da177e4SLinus Torvalds 	return -AX25_HEADER_LEN;
2181da177e4SLinus Torvalds }
2191da177e4SLinus Torvalds 
ax25_ip_xmit(struct sk_buff * skb)220787fb2bdSkbuild test robot netdev_tx_t ax25_ip_xmit(struct sk_buff *skb)
2213b6a94beSEric W. Biederman {
2221d5da757SEric W. Biederman 	kfree_skb(skb);
2231d5da757SEric W. Biederman 	return NETDEV_TX_OK;
2243b6a94beSEric W. Biederman }
2251da177e4SLinus Torvalds #endif
2261da177e4SLinus Torvalds 
ax25_validate_header(const char * header,unsigned int len)227ea47781cSWillem de Bruijn static bool ax25_validate_header(const char *header, unsigned int len)
228ea47781cSWillem de Bruijn {
229ea47781cSWillem de Bruijn 	ax25_digi digi;
230ea47781cSWillem de Bruijn 
231ea47781cSWillem de Bruijn 	if (!len)
232ea47781cSWillem de Bruijn 		return false;
233ea47781cSWillem de Bruijn 
234ea47781cSWillem de Bruijn 	if (header[0])
235ea47781cSWillem de Bruijn 		return true;
236ea47781cSWillem de Bruijn 
237ea47781cSWillem de Bruijn 	return ax25_addr_parse(header + 1, len - 1, NULL, NULL, &digi, NULL,
238ea47781cSWillem de Bruijn 			       NULL);
239ea47781cSWillem de Bruijn }
240ea47781cSWillem de Bruijn 
2413b04dddeSStephen Hemminger const struct header_ops ax25_header_ops = {
2423b04dddeSStephen Hemminger 	.create = ax25_hard_header,
243ea47781cSWillem de Bruijn 	.validate = ax25_validate_header,
2443b04dddeSStephen Hemminger };
2453b04dddeSStephen Hemminger 
2463b04dddeSStephen Hemminger EXPORT_SYMBOL(ax25_header_ops);
2471d5da757SEric W. Biederman EXPORT_SYMBOL(ax25_ip_xmit);
248