1
0
Files
irix-657m-src/eoe/cmd/dhcp_server/sr_common.c
2022-09-29 17:59:04 +03:00

407 lines
11 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <strings.h>
#include <sys/param.h>
#include <sys/types.h>
#include <net/if.h>
#include <netinet/in.h>
#include "dhcp.h"
#include "dhcpdefs.h"
#include <strings.h>
#include <syslog.h>
#include <net/raw.h>
#include <netinet/if_ether.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <netinet/udp.h>
#include <sys/fddi.h>
struct netaddr nets[IFMAX]; /* List of interfaces and other related data */
struct ifreq ifreq[IFMAX]; /* holds interface configuration */
struct ifconf ifconf; /* int. config. ioctl block(points to ifreq) */
extern iaddr_t myhostaddr;
extern struct netaddr *np_recv;
extern int ifcount;
extern int ProclaimServer;
extern int rsockout;
extern int max_addr_alloc;
extern int numaddrs;
extern u_int *myaddrs;
extern int s;
extern struct ether_addr *ether_aton(char *);
void get_aliases(char *);
int ifcount = 0; /* the number of interfaces */
int
sr_initialize_nets(void)
{
int ss, sss;
register struct ifreq* ifrp;
register struct netaddr* np;
struct ifreq ifnetmask;
int len;
int first_alias;
sss = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (sss < 0) {
syslog(LOG_ERR,"Opening DGRAM stream socket (%m)");
exit(1);
}
ss = socket(AF_RAW, SOCK_RAW, 0);
if (ss < 0) {
syslog(LOG_ERR, "Opening RAW stream socket (%m)");
exit(1);
}
ifconf.ifc_len = sizeof ifreq;
ifconf.ifc_req = ifreq;
if (ioctl(sss, SIOCGIFCONF, (caddr_t)&ifconf) < 0 || ifconf.ifc_len <= 0) {
syslog(LOG_ERR, "error in ioctl SIOCGIFCONF (%m)");
exit(1);
}
bzero(nets, sizeof nets);
np = nets;
ifcount = 0;
len = ifconf.ifc_len;
for (ifrp = &ifreq[0]; len > 0; len -= sizeof (struct ifreq), ifrp++) {
if (SINPTR(&ifrp->ifr_addr)->sin_family == AF_INET) {
strncpy(ifnetmask.ifr_name, ifrp->ifr_name,
sizeof(ifnetmask.ifr_name));
if (ioctl(sss, SIOCGIFFLAGS, (caddr_t)&ifnetmask) < 0) {
syslog(LOG_ERR, "'get interface flags' ioctl failed (%m) ");
exit(1);
}
if ((ifnetmask.ifr_flags & (IFF_UP|IFF_LOOPBACK)) != IFF_UP)
continue;
if (ioctl(sss, SIOCGIFNETMASK, (caddr_t)&ifnetmask) < 0) {
syslog( LOG_ERR, "'get interface netmask' ioctl failed (%m)");
exit(1);
}
np->netmask = SINPTR(&ifnetmask.ifr_addr)->sin_addr.s_addr;
np->myaddr = SINPTR(&ifrp->ifr_addr)->sin_addr;
np->net = np->netmask & np->myaddr.s_addr;
strncpy(np->ifname, ifrp->ifr_name, sizeof(np->ifname));
if (ioctl(ss, SIOCGIFADDR, (caddr_t)&ifnetmask) < 0) {
syslog(LOG_ERR,"Error in ioctl(SIOCGIFADDR) (%m)");
exit(1);
}
bcopy(ifnetmask.ifr_addr.sa_data, np->etheraddr, 6);
/* This call will add all the addresses associated
* with a given interfaceto the list of my
* addresses, including all the aliases
*/
if (numaddrs >= max_addr_alloc) {
max_addr_alloc *= 2;
myaddrs = (u_int *)realloc((u_int *)myaddrs,
max_addr_alloc*sizeof(u_int));
}
myaddrs[numaddrs++] = np->myaddr.s_addr;
first_alias = numaddrs;
get_aliases(ifrp->ifr_name);
if (numaddrs > first_alias) { /* some aliases added */
np->first_alias = first_alias; /* note 0 is not a valid alias
* index */
np->last_alias = numaddrs -1;
}
np++;
ifcount++;
}
}
close (sss);
close (ss);
return ifcount;
}
int
sr_initialize_broadcast_sockets(void)
{
struct sockaddr_raw braw_addr; /* raw socket addr struct */
int sockbufsiz;
int on = 1;
int i;
register struct netaddr *np;
/* SEND SOCKET */
np = nets;
for (i=0; i < ifcount; i++, np++) {
if ((np->rsockout = socket(AF_RAW, SOCK_RAW, RAWPROTO_SNOOP)) < 0) {
syslog(LOG_ERR, "Cannot create socket for broadcast rpc:(%m)");
return 1;
}
braw_addr.sr_family = AF_RAW;
strncpy(braw_addr.sr_ifname, np->ifname, sizeof(braw_addr.sr_ifname));
braw_addr.sr_port = 0;
if(bind(np->rsockout, &braw_addr, sizeof(braw_addr))) {
syslog(LOG_ERR, "send bind error(%m)");
return 1;
}
if (setsockopt(np->rsockout, SOL_SOCKET, SO_BROADCAST,
&on, sizeof(on)) < 0) {
syslog(LOG_ERR, "Cannot set socket option SO_BROADCAST:(%m)");
return 1;
}
sockbufsiz = 8096;
if(setsockopt(np->rsockout, SOL_SOCKET, SO_SNDBUF,
(caddr_t)&sockbufsiz, sizeof(sockbufsiz)) < 0) {
syslog(LOG_ERR, "Cannot set socket option SO_SNDBUF:(%m)");
return 1;
}
}
return 0;
}
/* not_my_address - checks given address against all my address
* return the net that matches, if does not match with any return 0
*/
struct netaddr*
sr_match_address(u_long addr)
{
register struct netaddr *np;
np = nets;
while (np->myaddr.s_addr) {
if (addr == np->myaddr.s_addr)
return np;
np++;
}
return 0;
}
/*
** Simple routine to calculate the checksum.
*/
static int
in_cksum(u_short *addr, int len)
{
register u_short *ptr;
register int sum;
u_short *lastptr;
sum = 0;
ptr = (u_short *)addr;
lastptr = ptr + (len/2);
for (; ptr < lastptr; ptr++) {
sum += *ptr;
if (sum & 0x10000) {
sum &= 0xffff;
sum++;
}
}
return (~sum & 0xffff);
}
int
sr_get_interface_type(char *i_name)
{
if(!i_name || (*i_name == '\0'))
return TYPE_UNSUPPORT;
if( (strncmp(i_name, "ec", 2) == 0) || (strncmp(i_name, "enp", 3) == 0) ||
(strncmp(i_name, "et", 2) == 0) || (strncmp(i_name, "ep", 2) == 0) ||
(strncmp(i_name, "ee", 2) == 0) || (strncmp(i_name, "ef", 2) == 0) ||
(strncmp(i_name, "fxp", 3) == 0) || (strncmp(i_name, "gfe", 3) == 0) ||
(strncmp(i_name, "eg", 2) == 0) || (strncmp(i_name, "vfe", 3) == 0) )
return TYPE_ETHER;
if( (strncmp(i_name, "ipg", 3) == 0) || (strncmp(i_name, "xpi", 3) == 0) )
return TYPE_FDDI;
return TYPE_UNSUPPORT;
}
int
sr_create_ip_send_packet(char **bufp, int *bsz, struct bootp *bp, int itype)
{
char *sbuf;
int bufsize, cnt;
int nbytes;
struct ether_addr *eh;
u_long val, mltaddr;
/* not needed
int bsum, isum, usum, psudpsum;
*/
int isum;
u_short *usp;
struct ether_header seh;
struct ip sip;
struct udphdr sudp;
struct fddi sfddi;
if(itype == TYPE_ETHER)
bufsize = sizeof(struct ether_header) + sizeof(struct ip) +
sizeof(struct udphdr) + sizeof(struct bootp);
else if(itype == TYPE_FDDI)
bufsize = sizeof(struct fddi) + sizeof(struct ip) +
sizeof(struct udphdr) + sizeof(struct bootp);
else
return 1;
cnt = bufsize;
sbuf = (char *)malloc(bufsize);
usp = (u_short *)bp;
nbytes = sizeof(struct bootp);
/* not needed
bsum = in_cksum(usp, nbytes);
*/
cnt -= sizeof(struct bootp);
bcopy(bp, &sbuf[cnt], sizeof(struct bootp));
sip.ip_v = IPVERSION;
sip.ip_hl = 5;
sip.ip_tos = 0;
sip.ip_len = sizeof(struct ip) +sizeof(struct udphdr) +sizeof(struct bootp);
sip.ip_id = 2; /* FOR NOW: LATER */
sip.ip_off = 0;
sip.ip_ttl = IPFRAGTTL;
sip.ip_p = IPPROTO_UDP;
sip.ip_sum = 0;
mltaddr = MULTIHMDHCP ? np_recv->myaddr.s_addr : myhostaddr.s_addr;
sip.ip_src.s_addr = mltaddr;
val = inet_addr("255.255.255.255");
sip.ip_dst.s_addr = val;
/* calculate sip.ip_sum */
usp = (u_short *)&sip;
nbytes = sizeof(struct ip);
isum = in_cksum(usp, nbytes);
sip.ip_sum = isum; /* Only contains the header checksum */
sudp.uh_sport = htons((u_short)IPPORT_BOOTPS);
sudp.uh_dport = htons((u_short)IPPORT_BOOTPC);
sudp.uh_ulen = sizeof(struct udphdr) + sizeof(struct bootp);
sudp.uh_sum = 0;
/* calculate sudp.uh_sum */
/* not needed
usp = (u_short *)&sudp;
nbytes = sizeof(struct udphdr);
usum = in_cksum(usp, nbytes);
psudpsum = in_cksum((u_short *)&sip.ip_src.s_addr, 4) +
in_cksum((u_short *)&sip.ip_dst.s_addr, 4) +
in_cksum((u_short *)&sip.ip_p, 1) +
in_cksum((u_short *)&sudp.uh_ulen, 2);
sudp.uh_sum = usum + bsum + psudpsum;
*/
cnt -= sizeof(struct udphdr);
bcopy(&sudp, &sbuf[cnt], sizeof(struct udphdr));
cnt -= sizeof(struct ip);
bcopy(&sip, &sbuf[cnt], sizeof(struct ip));
/* Broadcast Address */
eh = (struct ether_addr *) ether_aton("ff:ff:ff:ff:ff:ff");
if(itype == TYPE_ETHER) {
if(MULTIHMDHCP)
bcopy(np_recv->etheraddr, seh.ether_shost, sizeof seh.ether_shost);
else
bcopy(nets[0].etheraddr, seh.ether_shost, sizeof seh.ether_shost);
bcopy(eh, seh.ether_dhost, sizeof seh.ether_dhost);
seh.ether_type = ETHERTYPE_IP;
bcopy(&seh, sbuf, sizeof(struct ether_header));
}
else if(itype == TYPE_FDDI) {
bzero(&sfddi, sizeof(sfddi));
/* The driver will bit swap the ether address */
if(MULTIHMDHCP)
bcopy(np_recv->etheraddr, &sfddi.fddi_mac.mac_sa,
sizeof(sfddi.fddi_mac.mac_sa));
else
bcopy(nets[0].etheraddr, &sfddi.fddi_mac.mac_sa,
sizeof(sfddi.fddi_mac.mac_sa));
bcopy(eh, &sfddi.fddi_mac.mac_da, sizeof(sfddi.fddi_mac.mac_da));
sfddi.fddi_mac.mac_fc = MAC_FC_ALEN|MAC_FC_LLC_FF|1;
sfddi.fddi_mac.mac_bits = 0;
sfddi.fddi_llc.llc_c1 = RFC1042_C1;
sfddi.fddi_llc.llc_c2 = RFC1042_C2;
sfddi.fddi_llc.llc_etype = htons(ETHERTYPE_IP);
bcopy(&sfddi, sbuf, sizeof(struct fddi));
}
*bsz = bufsize;
*bufp = sbuf;
return 0;
}
int
sr_initialize_single_broadcast_socket(void)
{
struct sockaddr_raw braw_addr;
int sockbufsiz;
int on = 1;
/* SEND SOCKET */
if ((rsockout = socket(AF_RAW, SOCK_RAW, RAWPROTO_SNOOP)) < 0) {
syslog(LOG_ERR, "Cannot create socket for broadcast rpc:(%m)");
return 1;
}
braw_addr.sr_family = AF_RAW;
strncpy(braw_addr.sr_ifname, nets[0].ifname, sizeof(braw_addr.sr_ifname));
braw_addr.sr_port = 0;
if(bind(rsockout, &braw_addr, sizeof(braw_addr))) {
syslog(LOG_ERR, "send bind error(%m)");
return 1;
}
if (setsockopt(rsockout, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) < 0) {
syslog(LOG_ERR, "Cannot set socket option SO_BROADCAST:(%m)");
return 1;
}
sockbufsiz = 8096;
if(setsockopt(rsockout, SOL_SOCKET, SO_SNDBUF, (caddr_t)&sockbufsiz,
sizeof(sockbufsiz)) < 0) {
syslog(LOG_ERR, "Cannot set socket option SO_SNDBUF:(%m)");
return 1;
}
return 0;
}
void
get_aliases(char *ifn)
{
struct ifaliasreq ifalias;
struct sockaddr_in *sin;
bzero (&ifalias, sizeof(struct ifaliasreq));
strncpy(ifalias.ifra_name, ifn, sizeof ifalias.ifra_name);
ifalias.ifra_addr.sa_family = AF_INET;
/*
* A cookie of zero means to return the primary address first
* and subsequent calls will return the aliases as the cookie
* value increase linearly. When a -1 is returned we've exhausted
* the alias'es for this interface.
*/
ifalias.cookie = 1;
for (;;) {
if ((ioctl(s, SIOCLIFADDR, (caddr_t)&ifalias)) < 0) {
syslog(LOG_ERR, "'get alias addr' ioctl failed (%m)");
break;
}
if (ifalias.cookie < 0) {
break;
}
if (numaddrs >= max_addr_alloc) {
max_addr_alloc *= 2;
myaddrs = (u_int *)realloc((u_int *)myaddrs,
max_addr_alloc*sizeof(u_int));
}
sin = (struct sockaddr_in *)&ifalias.ifra_addr;
myaddrs[numaddrs++] = sin->sin_addr.s_addr;
}
}