/*
 * lib/x25_sr.c	This file contains an implementation of the "X.25"
 *		route change support functions.
 *
 * Author:	Stephane Fillod, <sfillod@charybde.gyptis.frmug.org>
 *		based on inet_sr.c
 *
 *		This program is free software; you can redistribute it
 *		and/or  modify it under  the terms of  the GNU General
 *		Public  License as  published  by  the  Free  Software
 *		Foundation;  either  version 2 of the License, or  (at
 *		your option) any later version.
 */
#include "config.h"

#if HAVE_AFX25
#include <asm/types.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <linux/x25.h>
#include <ctype.h>
#include <errno.h>
#include <netdb.h>
#include <resolv.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include "version.h"
#include "net-support.h"
#include "pathnames.h"
#define  EXTERN
#if 0
#include "net-locale.h"
#endif
#include "intl.h"
#include "util.h"

#include "net-features.h"

extern     struct aftype   x25_aftype;

static int skfd = -1;


static int usage(const int rc)
{
  fprintf(stderr,"Usage: x25_route [-v] del Target[/mask] [dev] If\n");
  fprintf(stderr,"       x25_route [-v] add Target[/mask] [dev] If\n");
  return(rc);
}


static int X25_setroute(int action, int options, char **args)
{
  struct x25_route_struct rt;
  struct sockaddr_storage sas;
  struct sockaddr_x25 *sx25 = (struct sockaddr_x25 *)&sas;
  char target[128];
  signed int sigdigits;

  if (*args == NULL)
	return usage(E_OPTERR);

  safe_strncpy(target, *args++, sizeof(target));

  /* Clean out the x25_route_struct structure. */
  memset((char *) &rt, 0, sizeof(rt));


  if ((sigdigits = x25_aftype.input(0, target, &sas)) < 0) {
	x25_aftype.herror(target);
	return (E_LOOKUP);
  }
  rt.sigdigits=sigdigits;

  /* this works with 2.4 and 2.6 headers struct x25_address vs. typedef */
  memcpy(&rt.address, &sx25->sx25_addr, sizeof(sx25->sx25_addr));

  while (*args) {
	if (!strcmp(*args,"device") || !strcmp(*args,"dev")) {
		args++;
		if (!*args)
			return usage(E_OPTERR);
	} else
		if (args[1])
			return usage(E_OPTERR);
	if (rt.device[0])
		return usage(E_OPTERR);
	safe_strncpy(rt.device, *args, sizeof(rt.device));
	args++;
  }
  if (rt.device[0]=='\0')
	return usage(E_OPTERR);

  /* sanity checks.. */
	if (rt.sigdigits > 15) {
		fprintf(stderr, _("route: bogus netmask %d\n"), rt.sigdigits);
		return usage(E_OPTERR);
	}

	if (rt.sigdigits > strlen(rt.address.x25_addr)) {
		fprintf(stderr, _("route: netmask doesn't match route address\n"));
		return usage(E_OPTERR);
	}

  /* Create a socket to the X25 kernel. */
  if ((skfd = socket(AF_X25, SOCK_SEQPACKET, 0)) < 0) {
	perror("socket");
	return(E_SOCK);
  }

  /* Tell the kernel to accept this route. */
  if (action==RTACTION_DEL) {
	if (ioctl(skfd, SIOCDELRT, &rt) < 0) {
		perror("SIOCDELRT");
		close(skfd);
		return(E_SOCK);
	}
  } else {
	if (ioctl(skfd, SIOCADDRT, &rt) < 0) {
		perror("SIOCADDRT");
		close(skfd);
		return(E_SOCK);
	}
  }

  /* Close the socket. */
  (void) close(skfd);
  return(0);
}

int X25_rinput(int action, int options, char **args)
{
  if (action == RTACTION_FLUSH) {
  	fprintf(stderr,"Flushing `x25' routing table not supported\n");
  	return usage(E_OPTERR);
  }
  if (options & FLAG_CACHE) {
  	fprintf(stderr,"Modifying `x25' routing cache not supported\n");
  	return usage(E_OPTERR);
  }
  if (action == RTACTION_HELP)
	return usage(E_USAGE);

  return(X25_setroute(action, options, args));
}
#endif	/* HAVE_AFX25 */
