Index: kern/uipc_domain.c =================================================================== RCS file: /cvs/src/sys/kern/uipc_domain.c,v retrieving revision 1.26 diff -u -p -r1.26 uipc_domain.c --- kern/uipc_domain.c 6 Jun 2007 10:04:36 -0000 1.26 +++ kern/uipc_domain.c 19 Apr 2008 13:26:47 -0000 @@ -80,6 +80,7 @@ domaininit(void) #ifndef lint ADDDOMAIN(unix); #ifdef INET + ADDDOMAIN(link); ADDDOMAIN(inet); #endif #ifdef INET6 Index: net/ethertypes.h =================================================================== RCS file: /cvs/src/sys/net/ethertypes.h,v retrieving revision 1.8 diff -u -p -r1.8 ethertypes.h --- net/ethertypes.h 21 Jul 2007 08:26:10 -0000 1.8 +++ net/ethertypes.h 19 Apr 2008 13:26:47 -0000 @@ -300,6 +300,7 @@ #define ETHERTYPE_LANPROBE 0x8888 /* HP LanProbe test? */ #define ETHERTYPE_PAE 0x888E /* 802.1X Port Access Entity */ #define ETHERTYPE_AOE 0x88A2 /* ATA over Ethernet */ +#define ETHERTYPE_LLDP 0x88CC /* Link Layer Discover Protocol */ #define ETHERTYPE_LOOPBACK 0x9000 /* Loopback */ #define ETHERTYPE_LBACK ETHERTYPE_LOOPBACK /* DEC MOP loopback */ #define ETHERTYPE_XNSSM 0x9001 /* 3Com (Formerly Bridge Communications), XNS Systems Management */ Index: net/if.c =================================================================== RCS file: /cvs/src/sys/net/if.c,v retrieving revision 1.169 diff -u -p -r1.169 if.c --- net/if.c 10 Apr 2008 23:15:45 -0000 1.169 +++ net/if.c 19 Apr 2008 13:26:47 -0000 @@ -2004,3 +2004,45 @@ netrndintr(void) { add_net_randomness(0); } + +#define sizeofa(_a) (sizeof(_a) / sizeof((_a)[0])) + +struct domain linkdomain; + +struct protosw linksw[] = { + { + SOCK_DGRAM, /* type */ + &linkdomain, /* domain */ + IFT_ETHER, /* protocol */ + PR_ATOMIC|PR_ADDR, /* flags */ + + NULL, /* input to protocol */ + NULL, /* output to protocol */ + NULL, /* control input */ + NULL, /* control output */ + + ether_usrreq, /* user request */ + + NULL, /* init */ + NULL, /* fasttimo */ + NULL, /* slowtimo */ + NULL, /* drain */ + ether_sysctl /* sysctl */ + } +}; + +struct domain linkdomain = { + AF_LINK, /* family */ + "link", /* name */ + NULL, /* init */ + NULL, /* externalize */ + NULL, /* dispose */ + linksw, /* protosw */ + &linksw[sizeofa(linksw)], /* protoswNPROTOSW */ + NULL, /* next */ + NULL, /* rtattach */ + 0, /* rtoffset */ + 0, /* maxrtkey */ + NULL, /* ifattach */ + NULL /* ifdetach */ +}; Index: net/if.h =================================================================== RCS file: /cvs/src/sys/net/if.h,v retrieving revision 1.94 diff -u -p -r1.94 if.h --- net/if.h 10 Apr 2008 23:15:45 -0000 1.94 +++ net/if.h 19 Apr 2008 13:26:47 -0000 @@ -756,6 +756,9 @@ int ether_ioctl(struct ifnet *, struct a void ether_input(struct ifnet *, struct ether_header *, struct mbuf *); int ether_output(struct ifnet *, struct mbuf *, struct sockaddr *, struct rtentry *); +int ether_usrreq(struct socket *, int, struct mbuf *, struct mbuf *, + struct mbuf *); +int ether_sysctl(int *, u_int, void *, size_t *, void *, size_t); char *ether_sprintf(u_char *); void if_alloc_sadl(struct ifnet *); Index: net/if_ethersubr.c =================================================================== RCS file: /cvs/src/sys/net/if_ethersubr.c,v retrieving revision 1.116 diff -u -p -r1.116 if_ethersubr.c --- net/if_ethersubr.c 10 Apr 2008 23:15:45 -0000 1.116 +++ net/if_ethersubr.c 19 Apr 2008 13:26:47 -0000 @@ -1129,3 +1123,165 @@ ether_delmulti(ifr, ac) */ return (ENETRESET); } + +#ifdef INET + +#include +#include + +#include + +struct ether_pcb { + struct socket *ep_socket; + struct arpcom *ep_ac; + u_int16_t ep_type; +}; + +int ether_usrsend(struct ether_pcb *, u_int8_t *, u_int16_t, struct mbuf *); + +int +ether_usrreq(struct socket *so, int req, struct mbuf *m, struct mbuf *nam, + struct mbuf *control) +{ + char ifn[IFNAMSIZ]; + struct ether_pcb *ep = so->so_pcb; + struct sockaddr_dl *sdl; + struct ifnet *ifp; + int error = 0; + + if ((req != PRU_ATTACH) == (ep == NULL)) { + error = EINVAL; + goto release; + } + + switch (req) { + case PRU_ATTACH: + if (curproc != NULL && suser(curproc, 0) != 0) { + error = EPERM; + goto release; + } + + error = soreserve(so, 2000, 2000); + if (error) + goto release; + + ep = malloc(sizeof(*ep), M_PCB, M_NOWAIT | M_ZERO); + if (ep == NULL) { + error = ENOMEM; + goto release; + } + + so->so_pcb = ep; + ep->ep_socket = so; + + break; + + case PRU_DETACH: + free(ep, M_PCB); + break; + + case PRU_BIND: + if (nam == NULL) + panic("ether_usrreq PRU_BIND to NULL nam"); + + sdl = mtod(nam, struct sockaddr_dl *); + if (nam->m_len < sizeof(*sdl) - sizeof(sdl->sdl_data) || + nam->m_len != sdl->sdl_len || /* XXX do more checking */ + sdl->sdl_nlen <= 0 || sdl->sdl_nlen >= 16) { + error = EINVAL; + goto release; + } + + if (sdl->sdl_family != AF_LINK || + ntohs(sdl->sdl_index) != ETHERTYPE_LLDP || /* XXX abuse */ + sdl->sdl_type != IFT_ETHER) { + error = EAFNOSUPPORT; + goto release; + } + + bzero(ifn, sizeof(ifn)); + memcpy(ifn, sdl->sdl_data, sdl->sdl_nlen); + + TAILQ_FOREACH(ifp, &ifnet, if_list) { + if (ifp->if_type != IFT_ETHER) + continue; + + if (strncmp(ifn, ifp->if_xname, sizeof(ifn)) == 0) + break; + } + + if (ifp == NULL) { + error = ENXIO; + goto release; + } + + ep->ep_ac = (struct arpcom *)ifp; + ep->ep_type = sdl->sdl_index; /* XXX abuse */ + + break; + + case PRU_SEND: + if (ep->ep_ac == NULL || nam == NULL) { + error = ENOTCONN; + goto release; + } + + sdl = mtod(nam, struct sockaddr_dl *); + if (nam->m_len < sizeof(*sdl) - sizeof(sdl->sdl_data) || + nam->m_len != sdl->sdl_len || /* XXX do more checking */ + sdl->sdl_alen != ETHER_ADDR_LEN) { + error = EINVAL; + goto release; + } + + if (sdl->sdl_family != AF_LINK || + ntohs(sdl->sdl_index) != ETHERTYPE_LLDP || /* XXX abuse */ + sdl->sdl_type != IFT_ETHER) { + error = EAFNOSUPPORT; + goto release; + } + + if (control != NULL) + m_freem(control); + return (ether_usrsend(ep, sdl->sdl_data, sdl->sdl_index, m)); + + default: + printf("%s: unhandled req %d\n", __func__, req); + error = EOPNOTSUPP; + break; + } + +release: + if (control != NULL) + m_freem(control); + if (m != NULL) + m_freem(m); + + return (error); +} + +int +ether_usrsend(struct ether_pcb *ep, u_int8_t *dest, u_int16_t type, + struct mbuf *m) +{ + struct sockaddr sa; + struct ether_header eh; + + memcpy(eh.ether_dhost, dest, ETHER_ADDR_LEN); + memcpy(eh.ether_shost, ep->ep_ac->ac_enaddr, ETHER_ADDR_LEN); + eh.ether_type = type; + + sa.sa_len = sizeof(sa); + sa.sa_family = AF_UNSPEC; + memcpy(sa.sa_data, &eh, sizeof(eh)); + + return (ether_output(&ep->ep_ac->ac_if, m, &sa, NULL)); +} + +int +ether_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, + size_t newlen) +{ + return (EINVAL); +} +#endif