Re: [PATCH net-next 2/2] appletalk: tashtalk: Add LocalTalk line discipline driver for AppleTalk using a TashTalk adapter

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Sat, Aug 17, 2024, at 11:33, Rodolfo Zitellini wrote:
> This is the TashTalk driver, it perits for a modern machine to
> participate in a Apple LocalTalk network and is compatibile with
> Netatalk.
>
> Please see the included documentation for details:
> Documentation/networking/device_drivers/appletalk/index.rst
>
> Signed-off-by: Rodolfo Zitellini <rwz@xxxxxxxxx>

Hi Rodolfo,

Nice to see you got this into a working state! I vaguely
remember discussing this in the past, and suggesting you
try a user space solution, so it would be good if you can
add in the patch description why you ended up with a kernel
driver after all.

My main concern at this point is the usage of .ndo_do_ioctl.
I had previously sent patches to completely remove that
from the kernel, but never got around to send a new version
after the previous review. I still have them in my tree
and should be able to send them again, but that will obviously
conflict with your added use.

> +static struct net_device **tashtalk_devs;
> +
> +static int tash_maxdev = TASH_MAX_CHAN;
> +module_param(tash_maxdev, int, 0);
> +MODULE_PARM_DESC(tash_maxdev, "Maximum number of tashtalk devices");

You should not need to keep a list of the devices
or a module parameter to limit the number. I'm fairly sure
the devices are already tracked by the network stack in a
way that lets you enumerate them later.

> +static void tashtalk_send_ctrl_packet(struct tashtalk *tt, unsigned 
> char dst,
> +				      unsigned char src, unsigned char type);
> +
> +static unsigned char tt_arbitrate_addr_blocking(struct tashtalk *tt, 
> unsigned char addr);

Please try to avoid forward declations and instead reorder the
functions to put the callers after the calles.

> +static void tash_setbits(struct tashtalk *tt, unsigned char addr)
> +{
> +	unsigned char bits[33];
> +	unsigned int byte, pos;
> +
> +	/* 0, 255 and anything else are invalid */
> +	if (addr == 0 || addr >= 255)
> +		return;
> +
> +	memset(bits, 0, sizeof(bits));
> +
> +	/* in theory we can respond to many addresses */
> +	byte = addr / 8 + 1; /* skip initial command byte */
> +	pos = (addr % 8);
> +	bits[byte] = (1 << pos);

This is basically set_bit_le(), so you could use that
for clarity and use an array of 'unsigned long' words.

> +	set_bit(TTY_DO_WRITE_WAKEUP, &tt->tty->flags);
> +	tt->tty->ops->write(tt->tty, bits, sizeof(bits));
> +}

> +
> +static u16 tt_crc_ccitt_update(u16 crc, u8 data)
> +{
> +	data ^= (u8)(crc) & (u8)(0xFF);
> +	data ^= data << 4;
> +	return ((((u16)data << 8) | ((crc & 0xFF00) >> 8)) ^ (u8)(data >> 4) ^
> +		((u16)data << 3));
> +}

Can you use the global crc_ccitt() function instead of implementing
your own?

> +static int tt_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
> +{
> +	struct sockaddr_at *sa = (struct sockaddr_at *)&ifr->ifr_addr;
> +	struct tashtalk *tt = netdev_priv(dev);
> +	struct atalk_addr *aa = &tt->node_addr;
> +
> +	switch (cmd) {
> +	case SIOCSIFADDR:
> +
> +		sa->sat_addr.s_node =
> +			tt_arbitrate_addr_blocking(tt, sa->sat_addr.s_node);
> +
> +		aa->s_net = sa->sat_addr.s_net;
> +		aa->s_node = sa->sat_addr.s_node;
> +
> +		/* Set broadcast address. */
> +		dev->broadcast[0] = 0xFF;
> +
> +		/* Set hardware address. */
> +		dev->addr_len = 1;
> +		dev_addr_set(dev, &aa->s_node);
> +
> +		/* Setup tashtalk to respond to that addr */
> +		tash_setbits(tt, aa->s_node);
> +
> +		return 0;
> +
> +	case SIOCGIFADDR:
> +		sa->sat_addr.s_net = aa->s_net;
> +		sa->sat_addr.s_node = aa->s_node;
> +
> +		return 0;

As we discussed in the past, I think this really should
not use ndo_do_ioctl(), which instead should just disappear.

Please change the caller to use some other method of
setting the address in the driver.

> +static int tashtalk_ioctl(struct tty_struct *tty, unsigned int cmd,
> +			  unsigned long arg)
> +{
> +	struct tashtalk *tt = tty->disc_data;
> +	int __user *p = (int __user *)arg;
> +	unsigned int tmp;
> +
> +	/* First make sure we're connected. */
> +	if (!tt || tt->magic != TASH_MAGIC)
> +		return -EINVAL;
> +
> +	switch (cmd) {
> +	case SIOCGIFNAME:
> +		tmp = strlen(tt->dev->name) + 1;
> +		if (copy_to_user((void __user *)arg, tt->dev->name, tmp))
> +			return -EFAULT;
> +		return 0;
> +
> +	case SIOCGIFENCAP:
> +		if (put_user(tt->mode, p))
> +			return -EFAULT;
> +		return 0;
> +
> +	case SIOCSIFENCAP:
> +		if (get_user(tmp, p))
> +			return -EFAULT;
> +		tt->mode = tmp;
> +		return 0;
> +
> +	case SIOCSIFHWADDR:
> +		return -EINVAL;
> +
> +	default:
> +		return tty_mode_ioctl(tty, cmd, arg);
> +	}

I'm also not a bit fan of using the SIOC* command codes
in a tty device with incompatible argument types. I do
see that slip and x25 do the same, but it would be nice
to find a better interface for these. I have not looked
at all the other line disciplines, but maybe you can
find a better example to copy.

     Arnd




[Index of Archives]     [Kernel Newbies]     [Security]     [Netfilter]     [Bugtraq]     [Linux FS]     [Yosemite Forum]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Samba]     [Video 4 Linux]     [Device Mapper]     [Linux Resources]

  Powered by Linux