1/*
2 First pass at a common ethernet link-up message.  Comments/bugs to guyton.
3
4    kextname:	name of the driver or NULL if ok to use last word of the CFBundleIdentifier
5    netif:	the network interface (used to get the bsd name)
6    megabits:	10, 100 or 1000
7    fullDuplex:	true if full duplex, else half
8    flowState:	results of negotiating flow control (who's sending pause)
9    port:	string that matches the label printed next to the physcial port or null
10    loopback:	loopback mode string or null
11    phyregs:	six debug phy registers.
12 */
13
14typedef enum {
15    kLinkUpFlow_None	= 0,
16    kLinkUpFlow_PauseTxOnly = 1,
17    kLinkUpFlow_PauseRxOnly = 2,
18    kLinkUpFlow_Symmetric = 3,
19    /* as bits to construct above */
20    kLinkFlow_Mask_TxPause= 0x1,
21    kLinkFlow_Mask_RxPause= 0x2
22} LinkUpFlow;
23
24enum {				// recommended contents of phyregs, but driver & phy specific
25    kLinkUp_Phy_OurStatus = 0,
26    kLinkUp_Phy_ExtendedStatus,
27    kLinkUp_Phy_OurAdvertised,
28    kLinkUp_Phy_OurGigAdvertised,
29    kLinkUp_Phy_PeerAdvertised,
30    kLinkUp_Phy_PeerGigAdvertised,
31
32    LinkUp_Phy_Count	// size of the array
33};
34
35extern kmod_info_t KMOD_INFO_NAME;	// generated by xcode for kexts
36
37static inline void LinkUpMessage(
38    char *buffer,			// or null to only do the IOLog
39    int	  bufsize,			// size of the buffer
40    const char *kextname,
41    IONetworkInterface *netif,
42    int	    megabits,
43    bool    fullDuplex,
44    LinkUpFlow	flowState,
45    const char *port,
46    UInt16 phyregs[LinkUp_Phy_Count],
47    const char *loopback
48)
49{
50    char line[256];
51
52    if (buffer == NULL || bufsize == 0) {
53	buffer = line;
54	bufsize = sizeof(line);
55    }
56    if (kextname && *kextname == 0) kextname = NULL;
57    if (port && *port == 0) port = NULL;
58    if (loopback && *loopback == 0) loopback = NULL;
59
60    // first find our kextname if null is passed in
61    if (kextname == NULL) {
62	char *period;
63	//kextname = rindex(KMOD_INFO_NAME.name, '.');
64	kextname = KMOD_INFO_NAME.name;
65	while ((period = strchr(kextname, '.')) != NULL) {
66	    kextname = ++period;
67	}
68	if (kextname == NULL || *kextname == 0)
69	    kextname = "????";
70    }
71
72    snprintf(buffer, bufsize, "Ethernet [%s]: Link up on %s%d, %d-%s, %s-duplex, %s flow-control%s%s, Debug [%04x,%04x,%04x,%04x,%04x,%04x]%s%s",
73	  kextname, netif->getNamePrefix(), netif->getUnitNumber(),
74	  (megabits > 999) ? (int)(megabits / 1000) : megabits,
75	  (megabits > 999) ? "Gigabit" : "Megabit",
76	  (fullDuplex) ? "Full" : "Half",
77	  (flowState == kLinkUpFlow_None) ? "No" :
78	  ((flowState == kLinkUpFlow_Symmetric) ? "Symmetric" :
79	   ((flowState == kLinkUpFlow_PauseTxOnly) ? "Symmetric Sending" :
80	    ((flowState == kLinkUpFlow_PauseRxOnly) ? "Asymmetric Receiving" : "unknnown"))),
81	  (port) ? ", Port " : "",
82	  (port) ? port : "",
83	  phyregs[0], phyregs[1], phyregs[2], phyregs[3], phyregs[4], phyregs[5],
84    (loopback) ? ", Loopback " : "",
85    (loopback) ? loopback : "");
86
87    IOLog("%s\n", buffer);
88}
89